STM32 CAN基础知识
CAN 波特率计算:
Fpclk1 / ( (CAN_BS1+CAN_BS2+1) * CAN_Prescaler)
pclk1 频率在 CubeMX Clock Configuration 中设置,其余三个在 CubeMX -> CAN1 -> Parameter Setting 中
CAN工作模式讲解
综合参考
一个简单的发送消息的程序
CubeMX 配置
-
配置引脚
板子原理图上查找 CAN 接的是哪两个引脚
main函数编辑
在 main 中添加
/* USER CODE BEGIN 2 */
HAL_CAN_Start(&hcan1);
static uint32_t TxMailBox=0;
uint8_t pData[8]={1,2,3,4,5,6,7,8};
CAN_TxHeaderTypeDef Header;
Header.StdId=2;
Header.ExtId=3;
Header.IDE=CAN_ID_STD;
Header.RTR=CAN_RTR_DATA;
Header.DLC=8;
/* USER CODE END 2 */
在 while(1)中
我在D10接了一个灯
HAL_CAN_AddTxMessage(&hcan1,&Header,pData,&TxMailBox);
HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_10);
HAL_Delay(1000);
发送消息
封装自己的消息发送函数
can.h 中声明
/* USER CODE BEGIN Prototypes */
uint8_t CANSendMsg(uint8_t* msg, uint8_t len, uint8_t std_can_id);
/* USER CODE END Prototypes */
can.c 中编写函数
/* USER CODE BEGIN 1 */
uint8_t CANSendMsg(uint8_t* msg, uint8_t len, uint8_t std_can_id)
{
uint32_t TxMailbox;
CAN_TxHeaderTypeDef CAN_TxHeader;
// 设置发送参数
CAN_TxHeader.StdId = std_can_id; // 标准标识符(12bit)
// CAN_TxHeader.ExtId = 0x00; // 扩展标识符(29bit)
CAN_TxHeader.IDE = CAN_ID_STD; // 使用标准帧
CAN_TxHeader.RTR = CAN_RTR_DATA; // 数据帧
CAN_TxHeader.DLC = len; // 发送长度
CAN_TxHeader.TransmitGlobalTime = DISABLE;
// 发送CAN消息
if(HAL_CAN_AddTxMessage(&hcan1, &CAN_TxHeader, msg, &TxMailbox) != HAL_OK)
{
return 1;
}
// while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan) != 3)
// {
// }
return 0;
}
/* USER CODE END 1 */
main
函数while
中调用
测试代码只发送了前 5个 字节
uint8_t msg[8]={0,1,2,3,4,5,6,7};
uint8_t std_can_id = 3;
CANSendMsg(msg, 5,std_can_id);
接收消息
STM32 过滤器配置
过滤模式介绍
CAN滤波器的主要作用是筛选CAN接收的数据,只有满足设定规则的数据才会被接收,否则会被过滤掉。
掩码模式:对报文ID的每一位可选择必须相同和不管它。
列表模式:只给出接收的ID,其它的一概不接收。
ID : 0xFED0; (1111111011010000)
屏蔽:0xFFE0;(1111111111100000)
那就是表示,接收端接受帧数据时,前11位的数值必须跟ID中定义的前11位一致,后面的5位数据忽略。不管是什么值都可以。也即是说屏蔽位中的数值:
0: 不关心,该位不用于比较;
1: 必须匹配,到来的标识符位必须与滤波器对应的标识符寄存器位相一致。
代码示例
在 can.c
中添加下面函数,在 can.h
中声明。 设置筛选器,要在完成 CAN 初始化之后调用此函数。
void CAN_Config(void)
{
CAN_FilterTypeDef sFilterConfig;
/* Configure the CAN Filter */
sFilterConfig.FilterBank = 0; // 过滤器编号,使用一个CAN,则可选0-13;使用两个CAN可选0-27
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; // 过滤器模式,掩码模式或列表模式
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // 过滤器位宽
sFilterConfig.FilterIdHigh = 0x0000; // 过滤器验证码ID高16位,0-0xFFFF
sFilterConfig.FilterIdLow = 0x0000; // 过滤器验证码ID低16位,0-0xFFFF
sFilterConfig.FilterMaskIdHigh = 0x0000; // 过滤器掩码ID高16位,0-0xFFFF
sFilterConfig.FilterMaskIdLow = 0x0000; // 过滤器掩码ID低16位,0-0xFFFF
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; // FIFOx,0或1
sFilterConfig.FilterActivation = ENABLE; // 使能过滤器
sFilterConfig.SlaveStartFilterBank = 14; // 从过滤器编号,0-27,对于单CAN实例该参数没有意义
if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
{
/* Filter configuration Error */
}
/* Start the CAN peripheral */
if (HAL_CAN_Start(&hcan) != HAL_OK)
{
/* Start Error */
}
/* Activate CAN RX notification */
if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
{
/* Notification Error */
}
}
在 main.c
中
STM32 接收数据
接收部分只要开启了Rx中断,在CAN控制器收到消息时会调用RxFifo的回调函数,此时我们在这里读取数据并根据实际情况做相应的处理即可。
/*******************************************************************************
* Function Name : HAL_CAN_RxFifo0MsgPendingCallback
* Description : 消息接收回调函数
* Input : hcan
* Output : None
* Return : None
****************************************************************************** */
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{// 收到CAN数据会触发接收中断,进入该回调函数
uint32_t i;
uint8_t RxData[8];
CAN_RxHeaderTypeDef CAN_RxHeader;
if(HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &CAN_RxHeader, RxData) == HAL_OK)
{
// 串口打印接收结果
printf("GetRxMessage, CANID:0x%0X, Data:", CAN_RxHeader.StdId);
for(i = 0;i < CAN_RxHeader.DLC; i++)
{
printf("%02x ", RxData[i]);
}
// 把接收的数据用CAN再发回去
CAN_Send_Msg(RxData, CAN_RxHeader.DLC);
}
}
如果想把接收到的数据传出去,在上面函数中删除 RxData 定义,然后再函数外面定义成全局变量。
在 can.c
中
/* USER CODE BEGIN 0 */
uint8_t RxData[8];
/* USER CODE END 0 */
在 can.h
中
/* USER CODE BEGIN Private defines */
extern uint8_t RxData[8];
/* USER CODE END Private defines */