我的學習過程有幾個關鍵點;
1、MCP2515 CAN總線模塊與ARDUINO UNO R3的接線方式;
2、程序set_mask_filter_recv的參數設置,mcp_can_dfs.h庫文件設置;
3、MCP2515 CAN總線模塊與mcp_can.cpp庫文件的關聯;
第一點看下面圖片:
<ignore_js_op>
<ignore_js_op>
首先在ARDUINO UNO R3找到SCK,MIOS,MOIS,INT0,5V,GND,連接到MCP2515 CAN總線模塊的對應接口;
CANH,CANL接到can總線上;
CS管腳接到arduino的9號管腳,單獨拿出來講,是因為此管腳位置可以在程序里面設置,設置如下;
const int SPI_CS_PIN = 9;
INT管腳接到arduino的2號管腳,單獨拿出來講,是因為此管腳位置可以在程序里面設置,設置如下;
attachInterrupt(0,MCP2515_ISR, FALLING); //0代表INT01代表INT1,看ARDUINO UNO R3管腳定義。
延伸一下,關於不同版本的ARDUINO的INT管腳位置,
參考如下鏈接
Arduino——外部中斷的使用
接線圖如下
第二點,上代碼和庫文件
在GITHUB里面搜索Seeed-Studio/CAN_BUS_Shield得到
GITHUB里面的MCP_CAN庫文件
https://github.com/Seeed-Studio/CAN_BUS_Shield
程序set_mask_filter_recv代碼(我做了些修改)如下
- #include <SPI.h>
- #include "mcp_can.h"
- // the cs pin of the version after v1.1 is default to D9
- // v0.9b and v1.0 is default D10
- const int SPI_CS_PIN = 9;
- MCP_CAN CAN(SPI_CS_PIN); // Set CS pin
- unsigned char flagRecv = 0;
- unsigned char len = 0;
- unsigned char buf[8];
- char str[20];
- void setup()
- {
- Serial.begin(115200);
- while (CAN_OK != CAN.begin(CAN_1000KBPS)) // init can bus : baudrate = 500k
- {
- Serial.println("CAN BUS Shield init fail");
- Serial.println(" Init CAN BUS Shield again");
- delay(100);
- }
- Serial.println("CAN BUS Shield init ok!");
- attachInterrupt(0,MCP2515_ISR, FALLING); // start interrupt
- /*
- * set mask, 0x代表16進制,0b代表2進制,屏蔽器的0xf代表0b1111
- */
- // 屏蔽器序號 是否接受擴展楨 0 不接受 1:接受 32位屏蔽器 f 位置必須匹配 0 不關心
- CAN.init_Mask(0, 1, 0xffff00ff);
- CAN.init_Mask(1, 1, 0xffff00ff);
- Serial.println("MASK IS OK");
- /*
- * set filter,以上MASK函數0xffff00ff中,can總線內 幀 ID中f位置必須符合Filt設置的數值,才會將幀的DATA存入緩存器
- */
- // 過濾器序號 是否接受擴展楨 0 不接受 1:接受 32位過濾器:屏蔽器為1的位必須匹配 0 不關心
- CAN.init_Filt(0, 1, 0x14fa0003); // mcp2515 0號過濾器
- CAN.init_Filt(1, 1, 0x14fa0004); // mcp2515 1號過濾器
- CAN.init_Filt(2, 1, 0x14fa0005); // mcp2515 2號過濾器
- CAN.init_Filt(3, 1, 0x14fa0010); // mcp2515 3號過濾器
- CAN.init_Filt(4, 1, 0x14fa0050); // mcp2515 4號過濾器
- CAN.init_Filt(5, 1, 0x14fa0051); // mcp2515 5號過濾器
- Serial.println("FILT OK");
- }
- void MCP2515_ISR()
- {
- flagRecv = 1;
- }
- void loop()
- {
- if(flagRecv) // check if get data
- {
- flagRecv = 0; // clear flag
- CAN.readMsgBuf(&len, buf); // read data, len: data length, buf: data buf
- Serial.println("READ MESSAGE OK");
- CAN.printMessage();
- }
- }
- /*********************************************************************************************************
- END FILE
此程序是屏蔽接收can信息,所以需要打開mcp_can_dfs.h找到下面兩行代碼置0
<ignore_js_op>
整個程序的思路就是如下:
1、調用<SPI.h>, "mcp_can.h"兩個庫文件,至於怎么添加庫文件自己找教程;
2、設置CS管腳為9號IO管腳
3、預設flagRecv=0,len=0,buf=[8], str[20],意思是flagRecv,len默認狀態為0,,buf為8組8個字節的數據組,str不知道是什么,有知道的高手請告知,個人臆斷歡迎指正。
4、SETUP()函數,設置串口通訊碼率為115200,can通訊波特率為1000KBPS(這里做一個記號)
5、設置中斷函數attachInterrupt(0,MCP2515_ISR, FALLING),意思是:中斷INT接2號IO管腳,自定義中斷函數名為MCP2515_ISR,使用下降沿觸發中斷。
6、 CAN.init_Mask(0, 1, 0xffff00ff)設置0號屏蔽器,可以接收擴展楨,幀的ID符合0xffff00ff這個格式, 32位屏蔽器 f 位置必須匹配 0 不關心,f相當於開關來啟動下面的過濾器。
7、 CAN.init_Filt(0,1,0x14fa0003)設置0號過濾器,可以接收擴展楨,ID符合0x14fa0003的擴展楨都可進入緩存器。
8、設置中斷函數 MCP2515_ISR的狀態標志,flagRecv=1。
9、循環函數loop(),每當一個下降沿信號進來,flagRecv置0,CAN.readMsgBuf(&len, buf)讀取緩存器內的信息,CAN.printMessage()can打印出信息。
以上是一個菜鳥的理解,歡迎大神門指正。
=========分割線=====================分割線===================分割線====================
關於怎么理解程序中各個函數的意思和使用方法——————沒什么特別的方法,自己分別打開【mcp_can.cpp】【mcp_can.h】【mcp_can_dfs.h】【MCP2515中文詳解.pdf】,一個個不懂的翻譯和搜索學習。
例如:CAN.init_Mask() CAN.readMsgBuf() CAN.printMessage() 這幾個函數在哪里定義的,內容是怎樣的都可以在上面的文件找到。
=========分割線=====================分割線===================分割線====================
上面有一個記號的地方需要重點說明的
如果你的can總線波特率是500KBPS
CAN.begin(CAN_1000KBPS) can通訊波特率設置為1000KBPS
差了1倍,原因是mcp_can.cpp的代碼是以16MHz晶振的CAN總線模塊編寫的,而我們使用的MCP2515 CAN總線模塊的晶振是8M的。所以代碼里面要把CAN.begin()設高一倍。
<ignore_js_op>
看上面的模塊照片,晶振上打字是8.000M。
=========分割線=====================分割線===================分割線====================
代碼寫好了需要自己搭建測試台架,一個can發送裝置提供CAN信號。
下面的照片是我在串口接收到的信息,顯示了ID和DATA
<ignore_js_op>