CANデータを読み取ることができる受信モジュールについてはすでに作成したものの、今後のCANを使った車載ガジェットの開発のために、CANを送信できるプログラムを作成した。CAN送信する機能を実装することで、ガジェットのシミュレーションや、作成したガジェットのデータをCANロガーモジュールで取得することが可能になる。
CAN送信のハードウェア
Arduino用シールドとして販売されているCAN-BUS Shieldや、MCP2515搭載のCANバスモジュールは、基本的にTx関連のAPIが提供されているので、送信はプログラムを変更するだけで対応可能。
CAN-BUS Shield+Arduino Mega(もしくはArduino Uno)を使用する事もできるし、Arduino NanoにCANバスモジュールを結線しても実現可能だが、今回はCAN-BUS Shield+Arduino MegaでCAN送信プログラムを作成する。なお、CAN-BUS ShieldはArduino Unoでの動作を前提に開発されているため、Arduino Unoでも実現可能。
CANの仕組み、およびCANの受信についてはこちらを参照
また、小型化・低価格化を目的としたArduino NanoとCANバスモジュールを用いたCAN受信についてはこちらを参照。
CAN-BUS Shieldを搭載したArduino Megaにプログラム
すでにハードウェアは揃っているため、今回はソフトウェアの改修のみでOK。CAN-BUS ShieldとArduino Megaを用いてCAN送信を実現する。
CAN送信関数 sendMsgBuf()
CANを送信するには、送信メッセージデータが格納された配列を作成し、CAN-BUS Shieldの製造元が提供しているライブラリに格納されたsendMsgBuf()を実行することで実現可能だ。CAN-BUS Shieldの製造元seeedによると、以下の引数を設定する必要がある。
5. Send Data
CAN.sendMsgBuf(INT8U id, INT8U ext, INT8U len, data_buf);
is a function to send data onto the bus. In which:
“id“ represents where the data come from.
“ext“ represents the status of the frame. ‘0’ means standard frame. ‘1’ means extended frame.
“len“ represents the length of this frame.
“data_buf“ is the content of this message.
https://seeeddoc.github.io/CAN-BUS_Shield/
mcp_can.hライブラリに比べてextを追加で指定する必要があるのでややこしいのだが、mcp2515_can.hをincludeして使用するプログラムのため、引数を一つ追加する。ちなみに、extended frameを使用しないため、2番目の引数は0を指定。
タイマ割り込み MsTimer()
CANを定期的に送信するプログラムにしたいため、ArduinoのMsTimer2を使ってタイマ割り込みを実現する。タイマ割り込みとは、下図のように、所定時間が過ぎたら通常処理に比べて優先度が高い「割り込み処理」を行う処理だ。
タイマ割り込みを実現するためには、割り込み処理の関数timer_interrapt()を定義する必要がある。今回は、タイマ割り込みが発生した瞬間に、メッセージを作成してCAN送信を行うようなtimer_interrapt()関数を定義した。CAN送信データの最後のバイトがインクリメントされ、249を超えるとまた0からカウントされる。その値をCANで送信するプログラムだ。
// タイマ割り込み
void timer_interrapt(void){
sendMsg[7] = sendMsg[7] + 1;
if (sendMsg[7] > 250) {
sendMsg[7] = 0;
}
// 時間経過フラグしたらCANメッセージを送信
CAN.sendMsgBuf(0x420, 0, 0, 8, sendMsg);
}
この割り込み処理を有効にするために、setup()関数で、MsTimer2のライブラリを用いてタイマー割り込みを定義する。そして、タイマーをスタートする。今回、CAN_SEND_INTERVALは、20msとした。
void setup() {
~中略~
// タイマー割り込みの設定
MsTimer2::set(CAN_SEND_INTERVAL, timer_interrapt);
~中略~
// 時間計測タイマ開始
MsTimer2::start();
}
これで割り込み処理の実装は完了。
ArduinoのCAN送信プログラム全体
前述の解説の内容を踏まえて、CAN送信を行うプログラムを作成した。こんな感じで、CAN送信可プログラムの作成は完了。
/*
* File: CAN-SEND_ArduinoMEGA_CANBUSshield.c
* Author: 岡本一車
* https://kurumashikou.com/
*/
#include <SPI.h>
#include <SD.h>
#include "string.h"
#include "mcp2515_can.h"
#include "MsTimer2.h"
// ピンの設定
// CAN通信用のCSピン(digital 9)
const int SPI_CAN_CS_PIN = 9;
// SDカード通信用のCSピン(digital 4)
const int SPI_SD_CS_PIN = 4;
// SS_defaultPin Arduino unoは10, megaは53
const int PSI_SS_defaultPin = 53;
// 動作確認用のLED
const int LED_PIN = 13;
// CAN送信周期の周期(msec)
#define CAN_SEND_INTERVAL 20
#define CAN_SEND_ID 0x420
// グローバル変数 ///////////////////////////////////////////
// タイムスタンプ用変数
unsigned long timestamp = 0;
unsigned long timestamp_old = 0;
// 割り込み関数の定義
void timer_interrapt(void);
// 送信メッセージ格納用
unsigned char sendMsg[8] = {0, 0, 0, 0, 0, 0, 0, 1};
// CANトランシーバにCSピン設定をセットし、CAN通信インスタンスを生成
mcp2515_can CAN(SPI_CAN_CS_PIN);
void setup() {
// シリアルモニタの設定
SERIAL_PORT_MONITOR.begin(115200);
// シリアルポートの準備が整うまで待つ
while(!Serial);
// デバッグ用
pinMode(LED_PIN, OUTPUT);
// タイマー割り込みの設定
MsTimer2::set(CAN_SEND_INTERVAL, timer_interrapt);
// CANの初期設定 ///////////////////////////////////////////////
if (CAN.begin(CAN_500KBPS) != CAN_OK) {
SERIAL_PORT_MONITOR.println("CAN initialized error ..............");
while(1);
}else{
SERIAL_PORT_MONITOR.println("CAN initialized OK !!");
}
// 時間計測タイマ開始
MsTimer2::start();
}
void loop() {
//割り込み時のみ制御されるので、ここは処理なし
}
// タイマ割り込み
void timer_interrapt(void){
sendMsg[7] = sendMsg[7] + 1;
if (sendMsg[7] > 250) {
sendMsg[7] = 0;
}
// 時間経過フラグしたらCANメッセージを送信
// https://seeeddoc.github.io/CAN-BUS_Shield/
// CAN.sendMsgBuf(INT8U id, INT8U ext, INT8U len, data_buf);
// is a function to send data onto the bus. In which:
// "id" represents where the data come from.
// "ext" represents the status of the frame. '0' means standard frame. '1' means extended frame.
// "len" represents the length of this frame.
// "data_buf" is the content of this message.
CAN.sendMsgBuf(CAN_SEND_ID, 0, 0, 8, sendMsg);
// デバッグ用(送信時、LED点灯)
digitalWrite(LED_PIN, HIGH);
}
これをベースに、CANを使ったArduino同士の通信や、Arduino Mega + CAN-BUS Shieldを机上テスト用の「仮想車両ECU」として振る舞わせる事ができる。いちいち車両につなげてエンジンをかけなくても効率よく開発ができるというわけだ。
*これは机上での検証を行うためのものなので、車両のCANに接続してはダメ。どこかのECUのCAN送信とバッティングすると、車両側が故障と判断したり、最悪クルマが壊れる可能性がある。今後このプログラムを改修して車両CAN通信ラインに信号を載せるプログラムを作成する際には、自己責任で、かつ車両とバッティングしないIDで、かつ車両に流れるCAN通信を阻害しないようなデータ量でなくてはならない。
ということで、次はこのプログラムを焼き込んだArduino Megaと、CAN受信用プログラムを組んだArduino Nanoを通信させてみようと思う。続きはこちら
コメント