本文使用的STMCube库为STM32Cube FW_F1 V1.8.0版本。不同版本的HAL库使用上有一些的差异。
具体的CAN物理层和通讯协议等建议先找资料了解一下(ISO 11898),这里只讲快速应用。
网上关于协议讲解的很多,例如:https://www.cnblogs.com/pejoicen/p/3986587.html
首先安装STM32CubeMX,然后选择你使用的MCU型号和封装:
配置一下外部晶振和调试下载方式
配置一下APB1 外设时钟,CAN使用的是这个外设时钟。
STM32 使用的是BxCAN,支持CAN2.0 A和 CAN2.0 B(也就是标准帧和拓展帧都支持),HAL库主要需要配置的是CAN的位特性(包括CAN速率和CAN采样点,在Cube配置)和CAN硬件过滤组(在工程中自行配置)两个。
下图是Cube配置 CAN的位特性:
这里我配置的是500Kbps的速率,其他默认即可(默认模式为正常模式)。配置速率的计算方式为 :
CANbps = APB / ( Prescaler * ( Segment1 + Segment2 + JumpWith))
APB1时钟记为APB,本例中为36MHz->36 000 000,
Prescaler 为时钟分频 这里设为 8,
剩下三个参数遵循 Segment1 ≈ Segment2 > JumpWith, 一般 JumpWith取1即可,
例子中算式为 36 000 000 / ( 8 * ( 4 + 4 +1 )) = 500 000 bps -> 500K bps。
使能并配置CAN接收中断(这里只提供一种接收方法)。
修改并配置CAN的引脚位置至你需要的引脚(不赘述)。
最后在project manager里面生成你想要的工程即可。
这里主要配置的是 CAN的硬件过滤器 和 中断接收函数 。本例中使用的是单CAN的芯片,若是双CAN 稍作修改即可。
每一份HAL的库都自带使用说明,位于对应 .C 文件头部,建议开发前详细阅读,这是通用的不管HAL怎么都可以按图索骥。
在系统的CAN初始化好了之后 添加硬件过滤器和激活CAN接收中断回调函数即可使用。
//CAN filter and RX_IT init
void CAN_User_Init(CAN_HandleTypeDef *h_can)
{
CAN_FilterTypeDef sFilterConfig;
HAL_StatusTypeDef HAL_Status;
TxMeg.IDE = CAN_ID_STD;
TxMeg.RTR = CAN_RTR_DATA;
sFilterConfig.FilterBank = 0; //chenal 0
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //mask mode
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
//MASK bit 0 means don't care,bit 0 means match
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
sFilterConfig.FilterActivation = CAN_FILTER_ENABLE; //enable filter
sFilterConfig.SlaveStartFilterBank = 14; //single CAN meaningless para
HAL_Status = HAL_CAN_ConfigFilter(h_can, &sFilterConfig);
if (HAL_Status != HAL_OK)
{
printf("Filter init failed\r\n");
}
HAL_Status = HAL_CAN_Start(h_can); //start CAN
if (HAL_Status != HAL_OK)
{
printf("CAN init failed\r\n");
}
//regist RX_IT
HAL_Status = HAL_CAN_ActivateNotification(h_can, CAN_IT_RX_FIFO0_MSG_PENDING);
if (HAL_Status != HAL_OK)
{
printf("CAN activate failed\r\n");
}
}
上图设置的是CAN 接收全部ID信息 的硬件过滤器通道0的屏蔽模式设置。过滤器可以使用列表模式和屏蔽模式,相应的可以自己查一下概念资料和手册。
接下来是回调函数的处理,上面注册了 CAN_IT_RX_FIFO0_MSG_PENDING 对应的回调函数原型是 void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *h_can);
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *h_can)
{
uint8_t Data[9]={0};
HAL_StatusTypeDef HAL_RetVal;
if (h_can == &hcan)
{
//retrive data by calling HAL_CAN_GetRxMessage
HAL_RetVal = HAL_CAN_GetRxMessage(&hcan, CAN1FIFO, &RxMeg, Data);
}
}
在回调函数中调用 HAL_CAN_GetRxMessage 即可获取接收到的CAN数据。
发送数据前要先查询 BxCAN的发送邮箱是否有位置。 调用 HAL_CAN_GetTxMailboxesFreeLevel(&hcan); 即可返回。
确认有空邮箱之后,调用HAL_CAN_AddTxMessage HAL库会自动帮你发送信息。
uint32_t TxBox = CAN_TX_MAILBOX0;
HAL_RetVal = HAL_CAN_AddTxMessage(&hcan, &TxMeg, pData + SendCNT, (uint32_t *)&TxBox);
硬件相关:CAN要在通讯的两线之间加终端电阻,即便是一对一通讯也要加120Ω,否则通讯会有问题。
至此你就可以测试CAN的收发。
本文只是快速应用,具体深入了解还需要阅读CAN标准和芯片手册等资料。