スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

ArduinoでCAN通信(その5:送信)

前にも記載しましたが、中華製 J1939 送信エミュレータは 通信が最速0.1秒間隔なので、実機が最速 20msec 間隔で送ってくるデータ処理ができるかどうかの判断には使えない。

【J1939 送信エミュレータ】
Arduino_CAN_2.jpg

そこで Arduino + MCP2551 + MCP2515 による2台のノードで、送受信させようというわけです。

・・・2日程度かけてやっと送信ができました。

【送受信中の2台のCAN機器】
Arduino_CAN_23.jpg

左が送信機として動作している Atmega328P マイコン搭載機、右が受信中の Atmega168P搭載機です。
Atmega328Pの在庫が切れたので 168 を使ったが、コンパイル後のソースが9kByte弱なのでOKです。
受信機の赤いLEDが点灯していますが、上側がRX受信端子、下側がINT受信割り込み端子に接続してます。

MCP2515には送信バッファが3個用意されていますが、今回のテストでは1個しか使ってません。
データ転送は 0.1秒(100msec)間隔で同時6個送信するプログラムですが、実際には1データ 20~30msec 間隔ぐらいが最速のようです。

後に記載するプログラムでは、送信バッファにガンガン送信しても、送信できない場合はデータを喪失してしまうので、コントロールレジスタのフラグをチェックしながら転送制御する必要があります(今回はまだ未実装です)

【正常に受信できている場合のシリアル・モニタ】   注:拡張idの一部を非表示にしています
Arduino_CAN_25.jpg

モニタ初期はid末尾3桁が300,400,111の3個だけですが、途中から100も現れます。
送信は6個のデータ・セットを100msec間隔で送出(個々のデータでは計算上 17msec 間隔)するようにしていますが、これはとても無理のようで、実質は 20~30msec間隔が最速のようです(送信バッファ1個での条件です)

実機での最速インターバルが 20msec ということなのでまずまずかなと思います。
実際の使用環境では、受信したデータはデータエリアに記録して置き、一定時間間隔(100msec程度)でそれを参照して使うので、受信が少々遅れても大きな問題にはなりません。(変化量が比較的少ないので、大きな誤差に至らないという意味です)

尚、6種のデータを送ってますが、4種のidだけが受信されるように、受信側でフィルタを設定しています。

【送信プログラム】

受信に使ったプログラムをベースに、メインプログラムの不要な部分を削除し、送信部を追加しました。

1.不変部分
 ・CAN初期化
 ・SPI設定
 ・タイマ設定
 ・LCD設定(実際にはLCDは使っていない)
 ・他

2.削除部分
 ・フィルタ・マスク
 ・受信割り込み

3.追加部分
 ・送信データ(拡張id、8Byteデータ、各々6個)
 ・送信バッファのIDレジスタ用データ、4種×各6個、処理速度を上げるために用意しておく
 ・送信手順

追加した部分のプログラム・コード(***部分は非表示です)

// --------------
// N258_TX.ino
// ---------------
// 拡張id
long id[7] = { 0x0000000,0x18F**400,0x18F**300, 0x18F**111,0x1CF**100,0x18F**200,0x18F**E00 };  //、0番は無効ID 
byte dat[7][8] = { {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},  //7個並べる、0番は無効 
                          {0xFF,0xFF,0xFF,0x3E,0x78,0xFF,0xFF,0xFF},
                          {0xFF,0xAC,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
                          {0xFF,0x63,0x00,0xFF,0xFF,0xFF,0xFF,0xFF},
                          {0xFF,0x0D,0x05,0xFF,0xFF,0xFF,0xFF,0xFF},
                          {0x00,0x78,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
                          {0x7B,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}  };
//SID,EID 変数エリア
byte SIDH[7] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00};
byte SIDL[7] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00};
byte EID8[7] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00};
byte EID0[7] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00};

// ・・・

void make_id( byte num, long id);  //送信バッファを事前に作る処理宣言
void alldataTx();  // 全6データを送信する処理宣言

// ・・・

// 事前にidを作っておく処理の実体
// SIDH,SIDL,EID8,EID0 を複数作るときの処理
void make_id( byte num, long id) {
  word canid;

  canid = (word)(id & 0x0FFFF);
  EID0[num] = (byte)(canid & 0xFF);
  EID8[num] = (byte)(canid >> 8);
  canid = (word)(id >> 16);
  SIDL[num] = (byte)(canid & 0x03);
  SIDL[num] += (byte)((canid & 0x1C) << 3);
  SIDL[num] |= 0x08;
  SIDH[num] = (byte)(canid >> 5);
}

// ・・・

//全データを送信する処理実体
void alldataTx(){
  struct tag_TXBnCTRL *pctrl;
  struct tag_TXBnDLC *pdlc;
  byte i, j, k, reg, p;
  word msgL,msgH;
  long msg2;
  byte ctrl, dlc;
 
  for(i = 1; i < 7; i++){
    MsgBuf[1] = SIDH[i];
    MsgBuf[2] = SIDL[i];
    MsgBuf[3] = EID8[i];
    MsgBuf[4] = EID0[i];
    MsgBuf[5] = 0x08;
    for(j = 6; j < 14; j++){
      MsgBuf[j] = dat[i][j-6];
    }
   
    CANTxB0Write(&MsgBuf[1],8);   //送信バッファシーケンシャルライト
    /*
    ctrl = 0;
    pctrl = &ctrl;
    pctrl -> TXP = 0;
    pctrl -> TXREQ = 1;
    */
    //ctrl = 0;
    ctrl = 0x08;
    //CANWriteReg(TXB0CTRL, ctrl);     // これは参考書にあった記述だが不要だった(動かない)
   
    CANRTS();  // あるページで見つけた上の行に対する代替え機能
    delay(10);
}

ここで注釈します。参考書では、CANWriteReg(TXB0CTRL, ctrl); と記述すれば、MCP2515のコントロールビットがONになり送信が開始されると書かれている。・・・しかし動かない。
データシートを見ると同様のことが書かれているが、その後をよく読むとRTSで起動させることが必要とある。

その方法は、
1.SPIによる書き込みコマンドによってレジスタに書き込み、
2.SPI RTS コマンドを送る
3.RTSピンをLOWにするハード的な起動、

この記述で最も不明だったのが、これらは and なのか or なのか、はたまたそれらの組み合わせなのかが判らない。
で、あるページで成功したという記述を見つけました。

それは、2.です。

これに準じてコードを生成すると動きました(最初しばらくは動作不安定でしたが・・・)

以下を追記します
// ------------------
// CAN2515.h
// ------------------
// --------------------------------------------------------------------
// CAN送信
// --------------------------------------------------------------------
void CANRTS(void) {
  byte i;
  byte cmd = SPI_INST_RTS;
  cmd |= _BV(0);

  CAN_SPI_CS_L;

  for(i = 0; i < 8; i++) {
    if(cmd & 0x80) {
      // 1
      CAN_SPI_SO_H;
    } else {
      // 0
      CAN_SPI_SO_L;
    }
    cmd <<= 1;
    CAN_SPI_SCK_H;    // SCK パルス出力
    CAN_SPI_SCK_L;
  }

  CAN_SPI_CS_H;
}

/////
はい、以上で J1939 CAN のデータ送信・受信までのプロセスを習得できました。

これらのスキルを活かし、次のステップは、応用豊か&実用できるCANツールの構築です。

以下はご要望あれば送付します。エントリーください。
// --------------------
// プログラム・ファイル
// --------------------

Arduino 送信プログラム
P258_TX.zip

Arduino受信プログラム
P258_N2.zip






コメントの投稿

非公開コメント

プロフィール

haiga

Author:haiga
私のブログへようこそ!
電気オンチが始めた自作オーディオです
2010/3/17 電子工作をプラスしました。

自作オーディオの楽しみ共有のため、私が作ったパーツ提供をしてます。質問や要望を遠慮なくコメント欄に書き込んでください。

FC2カウンター
その日1回目にアクセスいただいた方の総カウントです
最新記事
最新コメント
最新トラックバック
カテゴリ
月別アーカイブ
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。