ライブラリ(CANドライバ)の使い方を説明し、リレーノードのプログラムを説明します。なお、ライブラリ”wCan2515.h”については書籍「Arduino実験キットで楽ちんマイコン開発」でも解説しています。
今回は、CAN送信とCAN受信の手順をそれぞれサンプルコードで示しますが、これらのコードはCAN制御アプリの基本形となります。このコードをテンプレートとして利用するとわりと簡単にオリジナルのコードが書けると思います。
●CAN送信処理 (can_sample1.ino)
実際のコード(該当部分抜粋)を元に説明します。
#include <wCan2515.h> wCan2515 Can(2, 4, 3, 5, CAN_BRP_16MHz_125KBPS); // CANインスタンス // D2:SCK, D3:SO, D4:SI, D5:SS (SI/SOクロス) byte CanBuf[14]; // CAN送受信バッファ int LedPin = 13; // オンボードLEDのポート番号 // 初期化 void setup(void) { byte dat[8]; // データ用バッファ int msg = 0x001; // メッセージID(SID値) byte dlc = 0; // データ長(0バイト) pinMode(LedPin, OUTPUT); // D13のLED用出力ポート Can.setOpMode(CAM_MODE_NORMAL); // CAN送信バッファへ送信メッセージ、データを設定 Can.setTxBuf(0, msg, dat, dlc, true); Can.txReq(0); // 送信要求発行 digitalWrite(LedPin, HIGH); // LED ON(送信中) } // メインループ void loop(void) { if(Can.checkTxComp(0)) { // 送信完了チェック digitalWrite(LedPin, LOW); // LED OFF(送信完了) } }
まず、ドライバを使用するにあたり、1行目でライブラリ”wCan2515.h”をリンクし、3行目でCANオブジェクトのインスタンスを生成します。このとき、接続しているポートの番号を設定します。ビットレートは125kbpsです。
初期化処理の18行目でオペレーションモードをノーマルに切り替えてCANコントローラを運用状態にします。
21行目の”Can.setTxBuf()”で送信バッファへメッセージを設定します。引数の最初の”0″は送信バッファの0番を指定しています。msgが11ビットのメッセージID、dat[]が送信するデータ(最大8バイト、今回は空)、dlcが送信するデータ長(今回は0バイト)です。最後のtrueはデータフレームを指定するフラグです。
22行目の”TxReq()”で送信要求を出します。引数の”0″は送信バッファの0番を指定しています。これで、CANバスが空いていればすぐに送信が始まります。空いていない場合は、空くの待って送信が始まります。
23行目では送信開始を示すためにD13のLEDを点灯させています。
メインループの29行目で送信が完了するのを待ちます。送信が完了したら、31行目でD13のLEDを消灯して送信完了を示します。
送信は基本的にはこれだけです。
●CAN受信処理 (can_sample2.ino)
受信もコードで説明します。
#include <wCan2515.h> wCan2515 Can(2, 4, 3, 5, CAN_BRP_16MHz_125KBPS); // CANインスタンス // D2:SCK, D3:SO, D4:SI, D5:SS (SI/SOクロス) byte CanBuf[14]; // 初期化 void setup(void) { Can.setFilterMode(0, FILTER_MOD_ALL_HIT); // RxBuf0 フィルタ使用せず Can.setFilterMode(1, FILTER_MOD_ALL_HIT); // RxBuf1 フィルタ使用せず Can.setOpMode(CAM_MODE_NORMAL); } // メインループ void loop(void) { byte size, datfrm; int msg; byte dat[8]; if(Can.rxCheck()) { // 受信しているとき msg = Can.getRxBuf(0, dat, &size, &datfrm); // データとメッセージIDを取り出す。 // // ToDo:ここで受信したデータを使って何らかの処理を実行 // } }
送信時と同様、1、3行目でライブラリをリンクしてインスタンスを生成します。
初期化処理の10、11行目でフィルタとマスクを使用しないように設定します。詳細は省略しますが、この設定ですべてのメッセージを受信するようになります。
13行目でノーマル・モードに設定して運用を開始します。
メインループの22行目でCANメッセージの受信をチェックします。受信があると、”rxCheck()”はTRUEを返します。
メッセージを受信したときに24行目で”getRxBuf()”でバッファ0よりメッセージを取り出します。”dat”は受信したメッセージのデータ部分(最大8バイト),”size”に受信したデータのバイト数が入ります。”datfrm”はデータフレームのときにtrueになるフラグです。”getRxBuf()”はメッセージID(SID値)を返します。これを”msg”へ保存しておきます。
このあと、受信したメッセージ(“msg”)とデータ(“dat[]“)で何らかの処理を行います。なお、このコードではすべてのメッセージを受信するため、自分に必要がないメッセージの場合は読み捨てます。
特定のメッセージIDだけを選択して受信することも可能です。この場合は、10、11行目でマスク値とフィルタ値を適当な値に設定しますが、今回は省略します。
●リレー・ノードの処理 (can_node_relay.ino)
リレー・ノードは先に説明したCAN受信処理に、メッセージ内容を判定してそれに応じた処理を実行させるように処理を追加すれば作成できます。
リレーノードのメッセージIDは前回定義した”cmRELAY1_ON”~”cmRELAY5_OFF”の10個です。データフィールドは使っていないため、前述の受信処理の”msg”を調べるだけで判断できます。単純にswitch-case文で分類してリレー用ポートをON/OFFさせるのが簡単でしょう。
コードを次に示します。
// // CAN リレー・ノード // 13/11/19 www.wsnak.com // // リレーポート D6~D10 // #include <wCan2515.h> wCan2515 Can(2, 4, 3, 5, CAN_BRP_16MHz_125KBPS); // D2:SCK, D3:SO, D4:SI, D5:SS (SI/SOクロス) byte CanBuf[14]; // CANメッセージ リレー操作 #define cmRELAY1_OFF 0x090 // "000 1001 0000" #define cmRELAY1_ON 0x091 // "000 1001 0001" #define cmRELAY2_OFF 0x0A0 // "000 1010 0000" #define cmRELAY2_ON 0x0A1 // "000 1010 0001" #define cmRELAY3_OFF 0x0B0 // "000 1011 0000" #define cmRELAY3_ON 0x0B1 // "000 1011 0001" #define cmRELAY4_OFF 0x0C0 // "000 1100 0000" #define cmRELAY4_ON 0x0C1 // "000 1100 0001" #define cmRELAY5_OFF 0x0D0 // "000 1101 0000" #define cmRELAY5_ON 0x0D1 // "000 1101 0001" #define cmRELAY6_OFF 0x0E0 // "000 1110 0000" #define cmRELAY6_ON 0x0E1 // "000 1110 0001" // 初期化 void setup(void) { // リレー用出力ポート pinMode(6, OUTPUT); // リレー1 pinMode(7, OUTPUT); // リレー2 pinMode(8, OUTPUT); // リレー3 pinMode(9, OUTPUT); // リレー4 pinMode(10, OUTPUT); // リレー5 digitalWrite(6, LOW); // リレー1 OFF digitalWrite(7, LOW); // リレー2 OFF digitalWrite(8, LOW); // リレー3 OFF digitalWrite(9, LOW); // リレー4 OFF digitalWrite(10, LOW); // リレー5 OFF Can.setFilterMode(0, FILTER_MOD_ALL_HIT); // RxBuf0 フィルタ使用せず Can.setFilterMode(1, FILTER_MOD_ALL_HIT); // RxBuf1 フィルタ使用せず Can.setOpMode(CAM_MODE_NORMAL); } // メインループ void loop(void) { byte size, datfrm; int msg; byte dat[8]; if(Can.rxCheck()) { // 受信しているとき msg = Can.getRxBuf(0, dat, &size, &datfrm); // データとメッセージIDを取り出す。 // CANメッセージ リレー操作 switch(msg) { case cmRELAY1_ON: digitalWrite(6, HIGH); // リレー1 ON break; case cmRELAY1_OFF: digitalWrite(6, LOW); // リレー1 OFF break; case cmRELAY2_ON: digitalWrite(7, HIGH); // リレー2 ON break; case cmRELAY2_OFF: digitalWrite(7, LOW); // リレー2 OFF break; case cmRELAY3_ON: digitalWrite(8, HIGH); // リレー3 ON break; case cmRELAY3_OFF: digitalWrite(8, LOW); // リレー3 OFF break; case cmRELAY4_ON: digitalWrite(9, HIGH); // リレー4 ON break; case cmRELAY4_OFF: digitalWrite(9, LOW); // リレー4 OFF break; case cmRELAY5_ON: digitalWrite(10, HIGH); // リレー5 ON break; case cmRELAY5_OFF: digitalWrite(10, LOW); // リレー5 OFF break; } } }
初期化処理の33行目から、リレー用のポートを定義して全リレーをOFFにする処理を追加しています。
メインループの59行目で”msg”にメッセージIDを取り出し、62行目からのswitch-case文でメッセージIDを分類し、それに応じたリレーのポートをHIGHまたはLOWに設定しています。
次回はCANホスト側のプログラムを説明します。
CANについては下記書籍で説明していますのでよろしければ、ご覧ください。
書籍「動かして学ぶCAN通信」 → 書籍紹介ページ
ArduinoのCAN関係の記事は下記書籍でも扱っています(WSN292など使用)。CANなどの専用ライブラリに付いても解説しています。
書籍「Arduino実験キットで楽ちんマイコン開発」 → 書籍紹介ページ
図やテキストの無断転写はお断りします。