SSブログ

DCCコントローラ作り直し その1 [DCCコントローラ]

 さて、金曜日は姫路辺りまで日帰り出張したのですが、姫路駅に103系が止まっていたので、写真を撮りました。播但線なのでしょうか?ピンク色の103系初めて見ました。時間があれば乗りたかった気もしますが、時間ありませんでした。黄色い113系か115系かも見かけたので、ゆっくりと見たかった気もするのですが。
re_IMG_20200214_170708.jpg

 あとは、あやのさんから「びーだまのおもちゃ作ったのか?」と聞かれたので、もちろん作りました。作るのは楽しかったですが、そのあとの遊ぶ時間は30分程度ですぐに飽きてしまい、捨て場に困るオブジェ化しています。ガンプラもそうですが、楽しいのは、買うかどうか迷うとき、作っている最中、出来上がった瞬間ぐらいまでです。
re_DSC02906.jpg

 さて、本題です。前回「DCCパルスの全体的な周期を見てみる」でパルス幅のスペクトルアナライザちっくなものを作りましたが、そういえば、ESUのLokProgrammerも家にあることを思い出して、測ってみました。
結果は、
A(0.1ms),2,1749,1286,0,0,0,0,0,0,0,
(1),0,0,0,0,1,0,0,0,0,0,
(2),0,0,0,0,0,0,0,0,0,0,
(3),0,0,0,0,0,0,0,0,0,0,
(4),0,0,0,0,0,0,0,0,0,0,(5),
B(10ms),3038,0,0,0,0,0,0,0,0,0,
(100),0,0,0,0,0,0,0,0,0,0,
(200),0,0,0,0,0,0,0,0,0,0,
(300),0,0,0,0,0,0,0,0,0,0,
(400),0,0,0,0,0,0,0,0,0,0,(500),
で、DCS50K並みに美しいです。ところで1.5ms辺りに一個パルスがありますが、これは、スケッチ側のミスです。修正したものはこちらです。こうすると、300usより大きい周期パルスはありませんでした。

で、DigitraxやESUのコントローラがどちらも300us未満で、連続してDCC信号を出しているのに、私のfujigaya2 DCC Cheap Controllerが70msのDC信号を出しているのが気になってきたので、目指せ、300us以下の周期パルス!でスケッチを作り直すことにしました。
 前回のはdsshieldauto向けの自動運転スケッチから派生させて、開発を省略しました。しかし、このスケッチのライブラリは、S88やMM対応、desktopstationソフト連携など高機能なため、たぶんここら辺で時々大きな周期パルスが必要になっているかもと思います。一瞬、ライブラリとにらめっこしていらない部分をそぎ落とそうかとも思いましたが、人のソース見るのはかなり大変なので、作り直すことにしました。

 最初からコマンドステーションを作るのは敷居が高いので、まずはIdelPacketを出すスケッチを書きます。
 まずはDCC信号がどう出ているのかを確認するため、NMRAの仕様の確認です。適当にグーグル翻訳しながら見ていきます。まずはDCC信号を作り出すということで、DCC信号の1と0について確認です。
「1」について
コマンドステーション側:55us~61usのパルス幅で出す。
デコーダ側:52us~65usで受け取る。
「0」について
コマンドステーション側:95us~9,900usのパルス幅で出す。周期で12,000us超えないようにする?
デコーダ側:90us~10,000usで受け取る。
という感じです。
で、あとは、
無題.png

こんな感じで、Preamble、Address、コマンドデータ、エラー検出データ、と送ればよいようです。
まずは、アイドルパケット送信で試してみるかということで、適当に
111111111111 0 11111111 0 00000000 0 11111111 1
Preamble Byte One Byte Two Byte Three (Error Detection Data Byte)
に合わせて、Arduinoでスケッチを組みます。

#define BIT_ONE_US 56
#define BIT_ZERO_US 110
#define PREAMBLE_NUM 14

void setup()
{
  // put your setup code here, to run once:
  pinMode(9, OUTPUT);   // 出力に設定
  pinMode(10, OUTPUT);  // 出力に設定
}

void loop()
{
  // put your main code here, to run repeatedly:
  //idle Packet
  write_packet(0xFF,0x00);
}

void write_packet(byte byte_one,byte byte_two)
{
  write_preamble();
  write_byte(byte_one);
  write_byte(byte_two);
  write_byte(byte_one ^ byte_two);
  //packet_end_bit
  bit_one();
}

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()
{
    digitalWrite(9, HIGH);   
    digitalWrite(10, LOW);   
    delayMicroseconds(BIT_ONE_US);         
    digitalWrite(9, LOW);   
    digitalWrite(10, HIGH);   
    delayMicroseconds(BIT_ONE_US);        
}

void bit_zero()
{
    digitalWrite(9, HIGH);   
    digitalWrite(10, LOW);   
    delayMicroseconds(BIT_ZERO_US);         
    digitalWrite(9, LOW);   
    digitalWrite(10, HIGH);   
    delayMicroseconds(BIT_ZERO_US);        
}



・#define BIT_ONE_US 56 は「1」パルスのパルス幅です。
・#define BIT_ZERO_US 110 は「0」パルスのパルス幅です。
・#define PREAMBLE_NUM 14 はPreambleを何回出すかです。14個ぐらい出せばよいようなことが書いてあった気がします。

・setup()で出力するピンをアサインします。9,10です。
・loop()でIdlePacketを繰り返し出します。write_packet(0xFF,0x00);です。
・ write_packet(byte byte_one,byte byte_two)はその中身で
preambleを出して、
byte_oneの内容(0xff = 全部1)を書いて、
byte_two(0x00 = 全部0)を書いて
エラー検出はデータのXORで(0xff ^ 0x00 → 0xff)を書いて
最後にパルスの1を出力して終了です。
・write_preamble()は「1」を14回繰り返して送ります。
・write_byteはデータをビットに分けて送る部分です。startにまずパルスの0を送ります。
・bit_one()、bit_zero()は具体的に1,0を出力ピンに出している部分です。
分かりやすく
digitalWrite(9, HIGH);
digitalWrite(10, LOW);
と書いていますが、この書き方だと一つの命令に数usかかってしまい、電圧を供給できない時間が長く発生するようですので、ここの表現はそのうちPORTB = ・・・に変更していきます。

で、この状態でスペクトルを確認したら、こんな感じで美しいです。
A(0.1ms),1,2469,675,0,0,0,0,0,0,0,
(1),0,0,0,0,0,0,0,0,0,0,
(2),0,0,0,0,0,0,0,0,0,0,
(3),0,0,0,0,0,0,0,0,0,0,
(4),0,0,0,0,0,0,0,0,0,0,(5),
B(10ms),3145,0,0,0,0,0,0,0,0,0,
(100),0,0,0,0,0,0,0,0,0,0,
(200),0,0,0,0,0,0,0,0,0,0,
(300),0,0,0,0,0,0,0,0,0,0,
(400),0,0,0,0,0,0,0,0,0,0,(500),

見るだけ君で見てもIdlePacketがちゃんと出ていることを確認できました。
次はいよいよ、いろんな命令を送ります。


コメント(2) 

コメント 2

Yaasan

私のコードは、メルクリンも動かせるように、かつ、DCCの継ぎ接ぎな仕様もカバーするため、かなり複雑に作られてます。

SpeedStep128のみ、ポイントは知らない!等、割り切れば、かなりシンプルに出来ると思います!
by Yaasan (2020-02-16 18:12) 

fujigaya2

コメントありがとうございます。
その割り切りで作成中です。
by fujigaya2 (2020-02-16 19:28) 

コメントを書く

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

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

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