DCCコントローラ作り直し その3 [DCCコントローラ]
続いて、ファンクションF0~F4部分です。NMRAの9.2.1の仕様をみると、
ファンクションは、{命令バイト}=100DDDDDとするとのことです。
ですので、形は、
{プリアンブル} 0 [0aaa aaaa] 0 {100bcdef} 0 EEEEEEEE 1
aaa aaaa:1-127の車両のアドレス
b:F0
c:F4
d:F3
e:F2
f:F1
で、0:Off,1:Onです。
ということで、Arduinoスケッチの該当部分は以下になります。
・write_Func04_packet(unsigned int address,byte function,bool on_off)
は、F0~F4指令を送る命令です。
ロコアドレスと、F0~F4のどれをOn/Offするかを渡します。byte functionには#defineのF0_MASK~F4_Maskのどれかを渡します。F5~F8,F9~F12も似たような形で作成可能だと思います。
・write_2_packet(byte byte_one,byte byte_two)
は2Byteの送信命令です。
次に、実際に送信部分ですが、以下のようになっています。
・#define BIT_ONE_US 56・・・「1」のパルス幅の時間[us]
・#define BIT_ZERO_US 110・・・「0」のパルス幅の時間[us]
・#define PREAMBLE_NUM 15・・・プリアンブルを何回送るか。12回以上でよかったか?
・write_preamble()
は以前使っていたものを変わりありません。
・write_byte(byte b)
も以前に使っていたものと変わりません。スタートビットの「0」送信後、1ビットずつ送信します。
・bit_one()、bit_zero()
digitalWriteは命令実行に44サイクルかかるらしいというのがあり、高速化しました。
現状では、digitalwriteは一命令で16MHzで62.5ns*44=2.75usこの間だけ、電位が0になる時間が出てしまいますが、
PORTBを使うことで一命令3サイクル、62.5us * 3 = 0.1875usとなり電位0時間をとても少なくすることができます。
なお、今回、横着しており、オシロで波形を見ておりません・・・。
ファンクションは、{命令バイト}=100DDDDDとするとのことです。
ですので、形は、
{プリアンブル} 0 [0aaa aaaa] 0 {100bcdef} 0 EEEEEEEE 1
aaa aaaa:1-127の車両のアドレス
b:F0
c:F4
d:F3
e:F2
f:F1
で、0:Off,1:Onです。
ということで、Arduinoスケッチの該当部分は以下になります。
#define REPEAT_PACKET 3
#define DECODER_ADDRESS 0x03
#define F0F4MASK 0b10000000
#define F0_MASK 0b00010000
#define F1_MASK 0b00000001
#define F2_MASK 0b00000010
#define F3_MASK 0b00000100
#define F4_MASK 0b00001000
void write_Func04_packet(unsigned int address,byte function,bool on_off)
{
//function f0 - f4
//現状addressは0-127のみ受け付ける
static byte past_F0F4 = F0F4MASK;
if(on_off == true)//Onの時
{
past_F0F4 |= function;
}
else
{
past_F0F4 ^= function;
}
for(int i = 0;i < REPEAT_PACKET;i++)
{
write_2_packet((byte)address,past_F0F4);
}
}
void write_2_packet(byte byte_one,byte byte_two)
{
//Idle Packet,2byte order 送信用
write_preamble();
write_byte(byte_one);
write_byte(byte_two);
write_byte(byte_one ^ byte_two);
//packet_end_bit
bit_one();
}
・write_Func04_packet(unsigned int address,byte function,bool on_off)
は、F0~F4指令を送る命令です。
ロコアドレスと、F0~F4のどれをOn/Offするかを渡します。byte functionには#defineのF0_MASK~F4_Maskのどれかを渡します。F5~F8,F9~F12も似たような形で作成可能だと思います。
・write_2_packet(byte byte_one,byte byte_two)
は2Byteの送信命令です。
次に、実際に送信部分ですが、以下のようになっています。
#define BIT_ONE_US 56
#define BIT_ZERO_US 110
#define PREAMBLE_NUM 15
void write_preamble()
{
for(int i = 0; i < PREAMBLE_NUM;i++)
{
bit_one();
}
}
void write_byte(byte b)
{
//start bit
bit_zero();
//data byte
for(int i = 0;i < 8 ;i ++)
{
int current_bit = (b << i) & 0x80;
if(current_bit == 0)
{
bit_zero();
}
else
{
bit_one();
}
}
}
void bit_one()
{
PORTB |= _BV(PB1); //digitalWrite(9, HIGH);
PORTB &= ~_BV(PB2); //digitalWrite(10, LOW);
delayMicroseconds(BIT_ONE_US);
PORTB &= ~_BV(PB1); //digitalWrite(9, LOW);
PORTB |= _BV(PB2); //digitalWrite(10, HIGH);
delayMicroseconds(BIT_ONE_US);
}
void bit_zero()
{
PORTB |= _BV(PB1); //digitalWrite(9, HIGH);
PORTB &= ~_BV(PB2); //digitalWrite(10, LOW);
delayMicroseconds(BIT_ZERO_US);
PORTB &= ~_BV(PB1); //digitalWrite(9, LOW);
PORTB |= _BV(PB2); //digitalWrite(10, HIGH);
delayMicroseconds(BIT_ZERO_US);
}
・#define BIT_ONE_US 56・・・「1」のパルス幅の時間[us]
・#define BIT_ZERO_US 110・・・「0」のパルス幅の時間[us]
・#define PREAMBLE_NUM 15・・・プリアンブルを何回送るか。12回以上でよかったか?
・write_preamble()
は以前使っていたものを変わりありません。
・write_byte(byte b)
も以前に使っていたものと変わりません。スタートビットの「0」送信後、1ビットずつ送信します。
・bit_one()、bit_zero()
digitalWriteは命令実行に44サイクルかかるらしいというのがあり、高速化しました。
現状では、digitalwriteは一命令で16MHzで62.5ns*44=2.75usこの間だけ、電位が0になる時間が出てしまいますが、
PORTBを使うことで一命令3サイクル、62.5us * 3 = 0.1875usとなり電位0時間をとても少なくすることができます。
なお、今回、横着しており、オシロで波形を見ておりません・・・。
2020-02-16 19:58
コメント(0)
コメント 0