Arduinoを2台使ってデータ通信を行いたいけど、どうすればいいんだろ?
マイコンの通信方法はI2CやSPIがあるけど、やり方がよく分からないし・・・
大容量のデータ通信じゃなくてとりあえず1バイトデータでいいから送受信したい!
今回はそんな疑問にお答えします。
CANモジュールを使って簡単にデータ通信
Arduinoを使って電子工作をある程度やっていると「Arduino同士でデータ通信がしたい!」と思うことがありますよね。
マイコン同士のデータ通信としてはI2CやSPIなどがあるのですが、ネットで調べるとそれなりに記事は出るもののやり方がイマイチよく分からない。
僕もこのマイコン同士のデータ通信については皆さんと同じように落とし穴にハマってしまた口で、そこまで複雑なことをやりたい訳ではないのに、簡単にサクッと説明してくれているところがほとんどありません。
その後色々と試行錯誤した結果、CANモジュールという外部部品を使えば手軽に確実にデータ通信ができると判明したので今日はその解説をします。
CANとは
SPI通信をベースにしたマイコン同士のデータ通信規格で、ノイズに強いことから車載系マイコンにも採用されている通信方法です。
(CAN通信を覚えれば自動車メーカーへの就職も可能になるかも!?)
一回の通信で1~8バイトの送受信が可能で、IDの設定により2048種類ものデータを送ることができます。
ですが今回は「CANモジュールを使って手軽にArduino2台でデータ通信を行おう!」なので、1バイトデータの送受信でLEDをON/OFFするシステムを作ります。
今回作るもの
概要
送信用Arduinoから3秒毎にLEDのON/OFF情報を送信して、受信用Arduinoでその情報を元にLEDを制御します。
配線図
ピン設定
CANモジュールを使う際には下記のようにピン接続を行う必要があります。
Arduino側ピン | CANモジュール側ピン |
2番ピン | INT |
10番ピン | CS |
11番ピン | SI |
12番ピン | SO |
13番ピン | SCK |
5V | VCC |
GND | GND |
終端抵抗
ここで一つ注意点なのですが、CANには終端抵抗というマイコンデータ通信時に電圧(データ送受信)を安定させるためのものがあります。
複数のマイコンをCAN接続している際にはどれか2つのCANモジュールを選んで終端抵抗を有効化しないといけなく、有効化するためにはR2とJ1のピンをメスーメスジャンパプラグでショートさせる必要があります。
今回は2台のArduino同士でデータ送受信を行うため両方とものCANモジュールの終端抵抗を有効化します。
終端抵抗は同じMCP2515を使っていてもメーカーによって有効化/無効化の方法が異なっており、ショートさせることで有効になるものもあれば、ショートで無効化するものもあるため、違うメーカーのものを使用する際は十分お気をつけください。
事前準備
CANモジュールを使う際は必ず以下のサイトからCANモジュール・ライブラリをダウンロードしてArduinoIDEに読み込ませてください。
ソースコード
以下のソースコードをコピペして、送信側には送信側のソースを、受信側には受信側のソースを書き込んでください。
送信側
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
/********************************************************************************************************* CAN-send *********************************************************************************************************/ #include <mcp_can.h> //CAN送受信に必須な.hファイルのインクルード① #include <SPI.h> //CAN送受信に必須な.hファイルのインクルード② MCP_CAN CAN0(10); //CAN送受信に必須なピン設定 //MCP_CAN CAN0("使っているArduinoのCSピンの番号")を引数に設定する void setup() { Serial.begin(9600); //CAN送受信に必須な初期化処理①。今回使うCANモジュールではCAN0.begin(MCP_ANY, CAN_250KBPS, MCP_8MHZ)から変更不要 //初期化に成功すると戻り値としてCAN_OKが返ってくる if(CAN0.begin(MCP_ANY, CAN_250KBPS, MCP_8MHZ) == CAN_OK){ Serial.println("MCP2515 Initialized Successfully!"); } else{ Serial.println("Error Initializing MCP2515..."); } //CAN送受信に必須な初期化処理② //この1文がないとデバッグモードに入ってしまう CAN0.setMode(MCP_NORMAL); } unsigned char led_onoff; //CANで送信するLEDのON・OFF情報(を格納するための変数) void loop() { //LEDがONだったらOFFに、OFFだったらONに反転させる led_onoff = !led_onoff; //CAN0.sendMsgBur(ID,送るデータ長,実際に送るデータ)でデータを送信する //送信に成功すると戻り値としてCAN_OKが返ってくる unsigned char sndStat = CAN0.sendMsgBuf(0x100, 1, &led_onoff); //送信が成功しているか失敗しているかをデバッグ表示 if(sndStat == CAN_OK){ Serial.println("Message Sent Successfully!"); } else { Serial.println("Error Sending Message..."); } delay(3000); } /********************************************************************************************************* END FILE *********************************************************************************************************/ |
受信側
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
/********************************************************************************************************* CAN-receive *********************************************************************************************************/ #include <mcp_can.h> //CAN送受信に必須な.hファイルのインクルード① #include <SPI.h> //CAN送受信に必須な.hファイルのインクルード② long unsigned int rec_id; //受信したデータのIDを格納する変数 unsigned char rec_dlen; //受信したデータのデータ長を格納する変数 unsigned char rec_data; //受信したデータそのものを格納する変数 MCP_CAN CAN0(10); //CAN送受信に必須なピン設定① //MCP_CAN CAN0("使っているArduinoのCSピンの番号")を引数に設定する #define CAN0_INT 2 //CAN送受信に必須なピン設定② //受信処理は割り込みを使うので、INTピンが何番かをdefineする #define LED_CON 3 //LED点灯用のピン番号:3 void setup() { Serial.begin(9600); //CAN送受信に必須な初期化処理①。今回使うCANモジュールではCAN0.begin(MCP_ANY, CAN_250KBPS, MCP_8MHZ)から変更不要 //初期化に成功すると戻り値としてCAN_OKが返ってくる if(CAN0.begin(MCP_ANY, CAN_250KBPS, MCP_8MHZ) == CAN_OK) Serial.println("MCP2515 Initialized Successfully!"); else Serial.println("Error Initializing MCP2515..."); //CAN送受信に必須な初期化処理② //この1文がないとデバッグモードに入ってしまう CAN0.setMode(MCP_NORMAL); //割り込み処理を使うため、割り込み用のピンをINPUTにする pinMode(CAN0_INT, INPUT); //LED点灯用のピンをOUTPUTに設定する pinMode(LED_CON, OUTPUT); } void loop() { //CANを受信した際には立ち下がりになるため、割り込みINTピンが1→0になるタイミングを監視する if(!digitalRead(CAN0_INT)) { //CAN0.readMsgBuf("受信したデータのidを格納","受信したデータの長さを格納","受信したデータそのものを格納") CAN0.readMsgBuf(&rec_id, &rec_dlen, &rec_data); //格納したデータを表示 Serial.print("ID : "); Serial.println(rec_id); Serial.print("Data_length : "); Serial.println(rec_dlen); Serial.print("Receive_data : "); Serial.println(rec_data); Serial.println(); //CANで送られてきたデータを元にLEDをON・OFF制御する digitalWrite(LED_CON, rec_data); } } /********************************************************************************************************* END FILE *********************************************************************************************************/ |
注意事項
送受信共にArduinoに書き込みが終わったら本体のリセットボタンを同時に押して、離すと通信がうまくいくようになりLEDが点灯します。
解説
共通設定
CAN0.begin(①受信データ制限, ②CANモジュールの通信速度, ③CANの周波数)
CAN0.begin(~)でCANの初期化を行います。
①MCP_ANYを設定しておくと、データを受信したい時にいずれのデータも受付可能になります。もし特定のIDのデータだけ受信するようにしたい場合はここをMCP_STDEXTと設定します。
②CAN_250KBPSはCANの通信速度ですが、今回使うモジュールは250KBPSになります。
③MCP_8MHZも同様にハード依存の設定なので、8MHZの設定で問題ありません。
CAN0.setMode(MCP_NOMAL)
CAN0.setMode(MCP_NOMAL)はデバッグモードか通常モードを選ぶためのものですが、このCAN0.setModeの関数コールをしないと自動的にデバッグモードに入ることになります。
ちなみにデバッグモードに入ると1台のCANモジュールで送受信の確認を行うことができます。
送信側設定
CAN0.sendMsgBur(①ID,②送るデータ長,③実際に送るデータのアドレス)
①CANではデータを送信する際に16進数でIDを設定することにより、受信側は特定のデータのみ受信することが可能になります。今回は受信側でIDによる選別を行わないので設定する値はなんでも良いです。
②一回の送信で1~8バイトのデータを送信可能なため、ここには1~8の数字を入れることができますが、今回は1バイトのON/OFFデータを送るだけのため、1といれます。
③データを実際に送る際にはどこかに一度変数を用意し、その変数のアドレスを指定する必要があります。
受信側設定
CAN0.readMsgBuf(①受信したデータを格納するための変数のアドレス, ②受信したデータの長さを格納する変数のアドレス, ③受信したデータそのものを格納する変数のアドレス)
①送信側が設定したIDが入ります
②今回送られてきたデータの長さが入ります
③送られてきたデータそのものが入ります
以上がCANモジュールを使用したArduino2台でのデータ送受信方法でした。
今回はあくまでも1バイトデータの送受信のみに限った話をしましたが、本当であれば8バイトデータや、複数データの送受信も可能なので、そちらについてはまた追々解説していきたいと思います。
▼CANモジュールを使う際はオス-オス/オス-メス/メスーメス のジャンパー線が必要となります▼
-
初心者が組み込み(マイコン制御)を学ぶならWinスクール
初心者が組み込みのことを学ぶならどうすればいいんだろ。 Winスクールっていうプログラミングスクールが評判良さそうだけど、実際はどうなんだ? ほんとに初心者からでも授業を理解できるのかなぁ? & ...
続きを見る