SSブログ

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スケッチの該当部分は以下になります。


#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時間をとても少なくすることができます。
 なお、今回、横着しており、オシロで波形を見ておりません・・・。


コメント(0) 

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

※ブログオーナーが承認したコメントのみ表示されます。

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。