ArduinoとAtom matrix間でCAN通信
標記の内容をやってみたのでメモします。
1.接続図
[送信側]
・Arduino Uno
・MCP2515 CANバスモジュール
[受信側]
・Atom matrix
・M5Stack用CAN-BUSユニット
2.動かしてる様子
見た通りですが、ブレッドボードのボタンを押すことでRGBの色情報を送信しています。
同時押しすることで色の合成ができます。
3.プログラム解説
[送信側]
ボタンを接続するGPIO端子を全て内部プルアップの設定にしています。
pinMode(red_button, INPUT_PULLUP);
pinMode(green_button, INPUT_PULLUP);
pinMode(blue_button, INPUT_PULLUP);
ブレッドボードの配線がシンプルになります。
ポートがLOWに落ちたことをトリガにして状態を変えています。
byte rgb[] = {0x00,0x00,0x00}
この配列が左からR,G,Bの並びになっていて、
赤ボタンが押されたら{0xFF,0x00,0x00}
緑ボタンが押されたら{0x00,0xFF,0x00}
青ボタンが押されたら{0x00,0x00,0xFF}
になります。
赤と緑同時押しで{0xFF,0xFF,0x00}で黄色になります。
そういえば、MCP2515を使うにあたって、まずこちらの記事を参考にしてライブラリを入れました。
今回の作例もこちらのコードを改造しています。一度この記事のコードをそのまま動かして、オシロで波形をモニタしたのが以下の図。
CH1がCAN_H、CH2がCAN_L、赤はCH1とCH2の差分です。
実際にはこの赤の波形で信号を認識することになります。
ちゃんとノイズがキャンセルされています。
この波形は、MCP2515モジュールのジャンパをショートして、120Ωの終端抵抗を有効化しています。
受信側のCAN-BUSユニットにも終端抵抗をつけたほうがいい気がしますが、つけると電圧が半分になったので、つけませんでした。それで通信は成功しました。
電圧レベルとしてどの辺が適当か、調べ切れてないです…
[受信側]
M5.dis.drawpix(j,CRGB(rx_frame.data.u8[0],rx_frame.data.u8[1],rx_frame.data.u8[2]))
この部分でLEDを表示させていて、CRGB(X,X,X)の部分に左からR,G,Bの値が入ります。
その前の for(int j=0; j<25; j++){ で、0から24番目のピクセルまで順番に表示させることになります。
CAN-ID:100を受け取ったらLEDを点灯させますが、受け取っていない時はdisp_clear()関数で消灯させています。
このコードは、M5Atomのサンプルコードを改造しています。
Arduino IDEで ファイル→スケッチ例→M5Atom→Unit→CAN で表示できるコードです。
こちらの記事も参考にしました。
CANの通信速度は送信側・受信側で合わせておく必要があります。
4.コード
送信側
#include <mcp_can.h>
#include <SPI.h>
unsigned long rxId;
byte len;
byte rgb[] = {0x00,0x00,0x00};
MCP_CAN CAN0(10);// CAN0 CS: pin 10
int red_button = 7;
int green_button = 6;
int blue_button = 5;
int red_buttonState = 0;
int green_buttonState = 0;
int blue_buttonState = 0;
void setup()
{
Serial.begin(115200);
// init CAN0 bus, baudrate: 500kbps@8MHz
if(CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) == CAN_OK){
Serial.println("CAN0: Init OK!");
CAN0.setMode(MCP_NORMAL);
} else{
Serial.println("CAN0: Init Fail!");
}
//pinMode(ledPin, OUTPUT);
pinMode(red_button, INPUT_PULLUP);
pinMode(green_button, INPUT_PULLUP);
pinMode(blue_button, INPUT_PULLUP);
}
void loop(){
red_buttonState = digitalRead(red_button);
green_buttonState = digitalRead(green_button);
blue_buttonState = digitalRead(blue_button);
if (red_buttonState == LOW) {
rgb[0]={0xFF};
}
else{
rgb[0]={0x00};
}
if (green_buttonState == LOW) {
rgb[1]={0xFF};
}
else{
rgb[1]={0x00};
}
if (blue_buttonState == LOW) {
rgb[2]={0xFF};
}
else{
rgb[2]={0x00};
}
CAN0.sendMsgBuf(0x100, 0, 8, rgb);
Serial.print(rgb[0],HEX);
Serial.print(rgb[1],HEX);
Serial.print(rgb[2],HEX);
Serial.println();
delay(200); //ここの時間変更でボタン押下のチャタリング対策できる
}
受信側
#include <M5Atom.h>
#include "ESP32CAN.h"
#include "CAN_config.h"
#define TX GPIO_NUM_26
#define RX GPIO_NUM_32
CAN_device_t CAN_cfg;
int i,j = 0;
void disp_clear(){
for(int j=0; j<25; j++){
M5.dis.drawpix(j, 0x000000); //black
}
}
void setup() {
M5.begin(true, false, true);
Serial.println("CAN Unit Send&Received");
CAN_cfg.speed = CAN_SPEED_500KBPS; //Set the Can speed
CAN_cfg.tx_pin_id = TX; //Set the Pin foot
CAN_cfg.rx_pin_id = RX;
CAN_cfg.rx_queue = xQueueCreate(10,sizeof(CAN_frame_t));
ESP32Can.CANInit(); // Init CAN Module
}
void loop() {
CAN_frame_t rx_frame;
if(xQueueReceive(CAN_cfg.rx_queue,&rx_frame, 3*portTICK_PERIOD_MS)==pdTRUE){
Serial.print(millis()); // 受信時間
Serial.print(",");
Serial.print(rx_frame.MsgID,HEX); // Msg ID
Serial.print(",");
Serial.print(rx_frame.FIR.B.DLC); // DLC
Serial.println(",");
for(int i = 0; i < 3; i++){
Serial.print(rx_frame.data.u8[i],HEX); // CANデータ
}
Serial.println();
if(rx_frame.MsgID==256){ //CAN-ID:0x100が10進で256なので。IDは何でもいい。
Serial.println("received");
for(int j=0; j<25; j++){
M5.dis.drawpix(j,CRGB(rx_frame.data.u8[0],rx_frame.data.u8[1],rx_frame.data.u8[2]));
}
}
}
else {
disp_clear();
}
M5.update();
delay(200);
}
以上です。
Discussion