20. STM32- MEGA2560 MCP2515 & STM32 CANBus通讯

前几篇有关於CANBus的文章都是利用环回模式去做测试~这一篇会透过Arduino+MCP2515与STM32完成CANBus通讯~


接线

  1. MEGA2560 & MCP2515
MEGA2560 MCP2515
D52 SCK
D53 CS
D50 MISO
D51 MOSI
5V VCC
GND GND
  1. MCP2515 & STM32
MCP2515 STM32 L476RG
CAN H PA12
CAN L PA11

Arduino

这部分有已经写好的库可以使用,我是使用连结 这个库来完成的

这边要注意MCP2515的Baud Rate设定,这边设定是8MHZ选择125k bit/s

#include <SPI.h>
#include <mcp2515.h>
struct can_frame canMsg;
struct can_frame canMsg1;
MCP2515 mcp2515(53); //CSS
void setup() {
  canMsg1.can_id  = 0x1876AC23 | CAN_EFF_FLAG;
  canMsg1.can_dlc = 8;
  canMsg1.data[0] = 0x05;
  canMsg1.data[1] = 0x06;
  canMsg1.data[2] = 0x07;
  canMsg1.data[3] = 0x08;
  canMsg1.data[4] = 0x09;
  canMsg1.data[5] = 0x0A;
  canMsg1.data[6] = 0x0B;
  canMsg1.data[7] = 0x0C;
  
  while (!Serial);
  Serial.begin(115200);
  
  mcp2515.reset();
  mcp2515.setBitrate(CAN_125KBPS,MCP_8MHZ);
  //mcp2515.setLoopbackMode();
  mcp2515.setNormalMode();
  Serial.println("********MCP2515&STM32_CAN_Test*********");
  Serial.println("********Send Message*********");
  mcp2515.sendMessage(&canMsg1);
  Serial.print(canMsg1.can_id, HEX); 
  Serial.print(" "); 
  Serial.print(canMsg1.can_dlc, HEX); 
  Serial.print(" ");
    
  for (int i = 0; i<canMsg1.can_dlc; i++)  
  {  
    Serial.print(canMsg1.data[i],HEX);
    Serial.print(" ");
  }
  Serial.println();
  delay(100);
}
void loop() {
  //mcp2515.sendMessage(&canMsg1);
  //delay(100);

  if (mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK)
  {
    Serial.print(canMsg.can_id, HEX); 
    Serial.print(" "); 
    Serial.print(canMsg.can_dlc, HEX); 
    Serial.print(" ");
    
    for (int i = 0; i<canMsg.can_dlc; i++)  
    {  // print the data
      Serial.print(canMsg.data[i],HEX);
      Serial.print(" ");
    }
    Serial.println();
    delay(100);
    mcp2515.sendMessage(&canMsg1);
    Serial.print(canMsg1.can_id, HEX); 
    Serial.print(" "); 
    Serial.print(canMsg1.can_dlc, HEX); 
    Serial.print(" ");
    for (int i = 0; i<canMsg1.can_dlc; i++) 
    {  // print the data
      Serial.print(canMsg1.data[i],HEX);
      Serial.print(" ");
    }
    Serial.println();
    delay(100);
  }
}

IOC设置

先确认一下系统时钟是多少 後续再设定TQ与Baud Rate时才不会出错~
在这边我系统时钟是16Mhz
https://ithelp.ithome.com.tw/upload/images/20220329/20146325fz6L0KDRE1.png

接着来看看CAN的设置
PSC的部分设定为16 TQ会等於1000ns
BS1 选择4 BS2选择3 采样点会落在62.5%
最後Baud Rate会等於125k bit/s (这边要与另一端设备相同)

https://ithelp.ithome.com.tw/upload/images/20220329/20146325zSG3TppZHm.png


全域变数宣告

uint8_t TxBuffer[8] = {0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88};
uint8_t RxBuffer[8];
CAN_TxHeaderTypeDef TxHeader;
CAN_RxHeaderTypeDef RxHeader;
uint32_t TxMailBox;

接收中断回调函数

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{	
	HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &RxHeader, RxBuffer);
}

设置Filter模式 这边我选择LIST也就是所有ID必须完全相符才会接收

void ConfigFliter(void)
{
	CAN_FilterTypeDef CAN1Filter;
	CAN1Filter.FilterActivation = CAN_FILTER_ENABLE;
	CAN1Filter.FilterFIFOAssignment = CAN_RX_FIFO0;
	CAN1Filter.FilterMode = CAN_FILTERMODE_IDLIST;
	CAN1Filter.FilterScale = CAN_FILTERSCALE_32BIT;
	CAN1Filter.FilterBank = 0;
	CAN1Filter.FilterIdHigh = ((0x1876AC23<<3)>>16) & 0xffff;
	CAN1Filter.FilterIdLow =((0x1876AC23<<3)& 0xffff) | CAN_ID_EXT;
	CAN1Filter.SlaveStartFilterBank = 0;
	HAL_CAN_ConfigFilter(&hcan1, &CAN1Filter);
}

main

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_CAN1_Init();
  /* USER CODE BEGIN 2 */
  ConfigFliter();
  HAL_CAN_Start(&hcan1);
  HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
  TxHeader.DLC =8;
  TxHeader.ExtId = 0x08C53451;
  TxHeader.IDE = CAN_ID_EXT;
  TxHeader.RTR = CAN_RTR_DATA;
  TxHeader.TransmitGlobalTime = DISABLE;
  HAL_CAN_AddTxMessage(&hcan1, &TxHeader, TxBuffer, &TxMailBox);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

测试结果

这边我先将MCP2515做环回测试确定传送与接收正常後才与STM32对接做测试~

下图为Arduino & MCP2515 LoopBack 测试画面
https://ithelp.ithome.com.tw/upload/images/20220329/20146325RHWgXVPgET.png
Arduino传送端
https://ithelp.ithome.com.tw/upload/images/20220329/20146325V2zxlGCZNi.png
STM32所接收到的资料
https://ithelp.ithome.com.tw/upload/images/20220329/20146325sl0fbpahqL.png

由於我只有一块STM32,所以用MCP2515来当作另一端设备,手边有两块的话可以直接将CANRX与另一端TX相连做测试就可以了~/images/emoticon/emoticon37.gif


<<:  在Heroku一键架好Ubuntu,并用浏览器配noVNC连进去

>>:  新书上市 : Azure 云端运算实战 : 使用 PaaS 服务快速打造交谈式聊天机器人

第一章 之一 苦苦思索网域与购买

第一小节 Godaddy网域费用 对於购买网域一开始就已经打定主意想来个类似整套包含SSL与空间,於...

如何设计SQL 表格来提升查询非过往历史资料的效能?

个人正在写一个场地租借系统, 提前开放2周给人预约, 租借的过期纪录要保留起来作系统或规则改善研究,...

[2021铁人赛 Day20] General Skills 17

今天我们稍微调动一下顺序,先解 General Skills 系列的最後一题, 因为跟昨天的题目算...

Day 02 - 环境安装(中) Docker & MySQL

作业系统建置完成後就可以安装资料库环境,这里的做法是让MySQL 运行在Docker 上,原因只是未...

Day 28 / DL x RL / RL 不只会打电动?

RL 比较知名的应用场合和研究成果大部分都分布於游戏、自驾车、和机器人领域。事实上 RL 可以有非常...