JUGEMテーマ:電子工作
ARDUINO+MCP2515+MCP2561でCAN通信してみた。の巻
最近CANの通信とRS485の通信とかいろいと記事を書いております。
過去記事
ESP32+MCP2561-EPでCAN
https://ameblo.jp/fc2miha/entry-12833773103.html
ESP32+LTC485CN8でRS485
https://ameblo.jp/fc2miha/entry-12833773102.html
ESP32+MCP2562でCAN
https://ameblo.jp/fc2miha/entry-12833773100.html
ARDUINO+LTC485CN8でRS485
https://ameblo.jp/fc2miha/entry-12833773099.html
これを見ると、ARDUINOでCANが無かったので、
今回はarduino+MCP2515+MCP2561の組み合わせでCAN通信するやり方を整理しておきたいと思います。
調べていてわかったことですが、
CAN通信するときに必要なものとして3つあることが判明しておりまして、
1.マイコン
2.CANコントローラー
3.CANトランシーバー
です。他にも通信ケーブルとか、マイコン用の電源とかありますがそこは共通なので、省略して考えます。
で、
1のマイコンに2のコントローラーを内蔵しているものがあり、
それがESP32だったりとかします。
なので、ESP32から直接MCP2561とかMCP2562を繋げばCAN通信可能なんです。
でも、
ARDUINOにはCANコントローラー内蔵していないのでCANコントローラーであるMCP2515の出番となります。
参考記事
https://siroyantech.hatenablog.com/entry/2021/01/31/150751
https://github.com/sandeepmistry/arduino-CAN/blob/master/examples/CANReceiver/CANReceiver.ino
https://qiita.com/Yu-Tomo/items/9bb85145c9aebb2385e8
今回使用するのは
MCP2515です。あと、MCP2561です。
データシート
https://akizukidenshi.com/download/ds/microchip/mcp2515_j.pdf
全部5V動作なので、MAKERUNOを使っていきます。
写真
左下がESP32で、これがマスターです。
左上がMAKERUNOで、これがスレーブです。
CANのアーキテクチャ的にはマスタースレーブの概念が無いと思いますが、
前の記事と比べ易くする為にそんなプログラムになっています。
なお、ESP32の中のプログラムは前と同じです。
https://ameblo.jp/fc2miha/entry-12833773100.html
間にあるLAN線の長さは前の記事と同じ7メートルになっております。
■回路図
ARDUINO(ATMEGA328)→MCP2515→MCP2561→LAN線 今回のスレーブ側ですが、マスター側も同じです。
ただし、今回、水晶発振(セラロックでもOK)の手持ち一つしかなかったのと、
マスター側はESP32の方が実用的と思い、ESP32は前のまま利用しています。
間の接続はCANHはCANHにCANLはCANLに接続します。
■プログラム
Arduino用に書かなきゃならないのかと思っていたのですが、
ESP32と同じライブラリが使えることからほぼ同じでよく
先頭にある#defineを追加。
setupのCAN.setPins(26, 27);をコメントアウトしているのみです。
□マスター側プログラム
プログラムは前と同じです。
ESP32です。
https://ameblo.jp/fc2miha/entry-12833773100.html
□スレーブ側プログラム
ARDUINOです。
#define CAN_CS 6
#define CAN_INT 2
#include <CAN.h>
#include <string.h>
void setup() {
Serial.begin(115200);
while (!Serial);
Serial.println("CAN Receiver");
//CAN.setPins(26, 27);
// start the CAN bus at 500 kbps
if (!CAN.begin(500E3)) {
Serial.println("Starting CAN failed!");
while (1);
}
}
int receive(char *buf)
{
// try to parse packet
int packetSize = CAN.parsePacket();
if (packetSize || CAN.packetId() != -1) {
// received a packet
//Serial.print("Received ");
if (CAN.packetExtended()) {
Serial.print("extended ");
}
if (CAN.packetRtr()) {
// Remote transmission request, packet contains no data
Serial.print("RTR ");
}
//Serial.print("packet with id 0x");
//Serial.print(CAN.packetId(), HEX);
if (CAN.packetRtr()) {
//Serial.print(" and requested length ");
//Serial.println(CAN.packetDlc());
} else {
//Serial.print(" and length ");
//Serial.println(packetSize);
// only print packet data for non-RTR packets
if(CAN.available()){
int size = 0;
while (CAN.available()) {
//Serial.print((char)CAN.read());
buf[size] = CAN.read();
size++;
}
//Serial.println();
return size;
}
}
//Serial.println();
}
return 0;
}
int nCount = 0;
void loop()
{
char buf[256];
memset(buf, '¥0', sizeof(buf));
int size = receive(buf);
if(size>0){
Serial.println(buf);
//
//ack
//
CAN.beginPacket(0x12);
//char buf[256];
sprintf(buf, "A:%d", nCount);
CAN.write((uint8_t*)buf, strlen(buf));
CAN.endPacket();
nCount++;
}
}
■実験結果
通信速度ですが、
CANで設定上の通信速度は500Kbpsです。
しかし、ざっと10秒で1000往復になりました。
ESP32同士でやると3000往復なので、このあたりでCPUの性能差出てしまうようです。
1往復あたりは10ミリ秒ですね。
でもまぁ価格差など考慮すると十分高速で実用的と言えると思います。
あと、時々止まるのは調整で何とかなる認識です。
→ この問題はARDUINOだからの問題ではなくて単に作者がサポっているだけです。
マスター側をリセットすると同じ調子で送信始めるので、
一定期間受信できなかったときは再送するなど、何か仕掛けが必要になります。
あとは、通信速度を意図的に下げておくとかかなと思います。