使用STM32的CAN通讯,利用回环模式,按键控制发送CAN数据,中断接收CAN数据并通过串口助手打印出来。
7.2、配置引脚信息
由于每次新建工程都需要配置信息,比较麻烦,好在STM32CubeIDE提供了导入.ioc文件的功能,可以帮我们节省时间。
1.从Serial的项目里导入ioc文件,并命名为CAN。
在Connectivity里找到CAN,并打勾Activated使能CAN外设。
2.根据原理图可知,CAN总线连接的引脚为PB8和PB9,而默认的CAN总线引脚为PA11和PA12,所以需要手动修改CAN总线的引脚为PB8和PB9。
3.设置CAN外设的参数,这里我们设置波特率为1000kbps,模式设置为Loopback。
由于这里只用来测试通讯,所以选择Loopback回环模式(数据自发自收);如果需要连接第三方CAN设备,请选择为Normal常规模式(数据收/发独立)。
4.中断设置里将CAN RX0中断打开,如果不打开中断就无法接收到数据。
核心代码解释
1.在BSP中新建蜂鸣器的驱动库bsp_can.h和bsp_can.c文件。在bsp_can.h中增加以下内容:
/*
* bsp_can.h
*
* Created on: Mar 7, 2022
* Author: Administrator
*/
#ifndef BSP_CAN_H_
#define BSP_CAN_H_
void Can_Init(void);
void Can_Test_Send(void);
#endif /* BSP_CAN_H_ */
2.在bsp_can.c中添加以下内容:
Can_Init():初始化CAN外设相关内容,设置CAN接收过滤器,开启CAN总线通讯。
#include "bsp_can.h"
#include "bsp.h"
// Define related variables 定义相关变量
CAN_TxHeaderTypeDef TxHeader;
CAN_RxHeaderTypeDef RxHeader;
CAN_FilterTypeDef sFilterConfig;
// Initialize the CAN 初始化CAN
void Can_Init(void)
{
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
sFilterConfig.SlaveStartFilterBank = 27;
sFilterConfig.FilterActivation = CAN_FILTER_ENABLE;
// Setting the CAN Filter 设置CAN过滤器
if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
// Start the CAN peripheral 启动CAN
if (HAL_CAN_Start(&hcan) != HAL_OK)
{
Error_Handler();
}
// Activate CAN RX notification 启动CAN RX通知
if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
{
Error_Handler();
}
}
// The test sends data through CAN 测试通过CAN发送数据
void Can_Test_Send(void)
{
uint8_t TxData[8];
uint32_t TxMailbox = 0;
TxHeader.StdId = 0x000F;
TxHeader.ExtId = 0x00;
TxHeader.RTR = CAN_RTR_DATA;
TxHeader.IDE = CAN_ID_STD;
TxHeader.DLC = 8;
TxHeader.TransmitGlobalTime = DISABLE;
for (int i = 0; i < 8; i++)
{
TxData[i] = 1 << i;
}
printf("CAN Send:%02X %02X %02X %02X %02X %02X %02X %02X \n",
TxData[0], TxData[1], TxData[2], TxData[3],
TxData[4], TxData[5], TxData[6], TxData[7]);
// Send Data 发送数据
if (HAL_CAN_AddTxMessage(&hcan, &TxHeader, TxData, &TxMailbox) != HAL_OK)
{
Error_Handler();
}
}
// CAN receives interrupt callbacks CAN接收中断回调
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
if (hcan->Instance == CAN1)
{
uint8_t RxData[8];
if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK)
{
Error_Handler();
}
else
{
printf("CAN Receive:%02X %02X %02X %02X %02X %02X %02X %02X \n",
RxData[0], RxData[1], RxData[2], RxData[3],
RxData[4], RxData[5], RxData[6], RxData[7]);
}
}
}
3.为了测试发送数据,新建Can_Test_Send()函数把数据通过CAN发送出去,并打印到串口助手上。如果需要修改发送的数据,在发送前修改TxData数组即可。
4.CAN接收中断回调函数,将接收到CAN数据通过串口打印出来。此函数名称不能修改,否则无法调用到此函数。
5.在BSP初始化中,调用Can_Init()函数初始化CAN外设。
//bsp.c
#include "bsp.h"
// LED显示当前运行状态,每10毫秒调用一次,LED灯每200毫秒闪烁一次。
// The LED displays the current operating status, which is invoked every 10 milliseconds, and the LED blinks every 200 milliseconds.
void Bsp_Led_Show_State_Handle(void)
{
static uint8_t led_count = 0;
led_count++;
if (led_count > 20)
{
led_count = 0;
LED_TOGGLE();
}
}
// The peripheral device is initialized 外设设备初始化
void Bsp_Init(void)
{
Can_Init();
USART1_Init();
Beep_On_Time(50);
printf("start\n");
}
// main.c中循环调用此函数,避免多次修改main.c文件。
// This function is called in a loop in main.c to avoid multiple modifications to the main.c file
void Bsp_Loop(void)
{
// Detect button down events 检测按键按下事件
if (Key1_State(KEY_MODE_ONE_TIME))
{
Beep_On_Time(50);
Can_Test_Send();
}
Bsp_Led_Show_State_Handle();
// The buzzer automatically shuts down when times out 蜂鸣器超时自动关闭
Beep_Timeout_Close_Handle();
HAL_Delay(10);
}
6.在按键按下后,增加发送CAN数据的功能。
实验效果
烧录程序后,LED灯每隔200毫秒闪一次,将扩展板通过micro-USB数据线与电脑连接后并打开串口助手(具体参数如下图所示),每按一次按键,蜂鸣器都会响50毫秒,可以看到串口助手会显示CAN发送的数据以及CAN接收到的数据。