本文使用的STMCube庫爲STM32Cube FW_F1 V1.8.0版本。不同版本的HAL庫使用上有一些的差異。
具體的CAN物理層和通訊協議等建議先找資料瞭解一下(ISO 11898),這裏只講快速應用。
網上關於協議講解的很多,例如:https://www.cnblogs.com/pejoicen/p/3986587.html
1. STM32 CubeMX 配置
首先安裝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裏面生成你想要的工程即可。
2. 工程內配置
這裏主要配置的是 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標準和芯片手冊等資料。