前幾篇有介紹過CANBus~透過MCP2515模塊去完成通訊。
這篇會使用STM32當中的CAN-Bus來實現通訊~
與之前介紹Can不同的是在STM32當中將一個bit分為3個區段而已,將傳播段與相位緩衝段1結合。
可以看到在STM32當中將Bit僅分為3個區段,而同步區段固定為1Tq ; BS1為0-16TQ ;BS2為0-8TQ,採樣點同樣落在BS1與BS2交界。
TQ = (BRP+1) x Tpclk
TQ= (15+1) x (1/16) = 0.9375(us) = 937.5(ns)
BPR : 預分頻係數 Tpclk : APB Clock 週期
這時可以知道1個TQ為937.5ns,同時SyncSeg固定為1TQ 後續BS1為4TQ BS2為3TQ:
Bit Timing : TQ timing x (1+BS1+BS2)
937.5ns x 8 = 7500ns
TQ Timing : 上方計算出來1 TQ的時間
BS1 : BS1 的TQ數量 BS2 : BS2的TQ數量
Baud Rate = 1 / Bit Timing
1 / 7500ns x 1000000000 = 133333 bit/s
1000000000是因為ns換為s
(SyncSeg + BS1 )/ 總TQ數量 *100%
以上方來說即為 5 / 8 x 100% = 62.5%
採樣點在通訊過程最好是落在60~70%,所以在選擇TQ數量時要注意採樣點位置!
FIFO (First In First Out) : 先進先出,在RX Buffer當中可以儲存3筆資料,會按照接收到的訊息順序,讀取最先接收到的訊息。
換個方式說假如今天郵差送了一封信到信箱當中而且信箱大小只能容納3封,那這封信就會變成編號1的信件(CAN_RFR→FMP = 0b01),這時候可以選擇去收信或是晚點收。
馬上收信 : 從信箱當中拿走信(CAN_RFR→RFOM = 1),信箱當中是空的了,這時候信箱會將編號歸0,可以重複這個步驟接收下一封信件。
晚點收信 : 信箱中還是有著一封信,假設又收到一封信但由於剛剛沒有取走第一封,這時候就會改為編號2的信件(CAN_RFR→FMP = 0b10),當累積到第三封信件時(CAN_RFR→FMP = 0b11)信箱已經滿了,所以當第四封信件就會放置在信箱外面(溢出)。
針對信箱滿了的情況下可以分為兩種處理方法:
在STM32當中CAN具有4個向量中斷 :
我使用的板子是L476RG,只具備一個CAN通訊(CAN1)。
Prescaler : 等於上方計算公式的BPR,影響的是TQ的時間。
這邊我APB Clock為16 ,Prescaler 設為15
(15+1) x (1/16) = 0.9375(us) = 937.5(ns)
Time Quanta Bit Segment 1 : 傳播段與相位緩衝段1結合,會影響到採樣點的位置
Time Quanta Bit Segment 2 : 相位緩衝段2,會影響到採樣點的位置
以上我設置為4TQ與3TQ,而同步段固定為1TQ共8TQ,所以看以看到下方Time for One Bit 為7500ns (937.5ns x 8 = 7500ns)
Baud Rate : 1 / 7500ns x 1000000000 = 133333 bit/s
ReSynchronization Jump Width : 重新同步跳轉寬度,用來彌補兩設備間的通訊誤差,可設置範圍0-4TQ。
上方圖為基本模式設定,這邊就都選Disable即可。
而最後的是工作模式選擇 : 分為正常模式、環回模式、靜默模式等等,因為我手邊只有一塊就先選環回模式來測試。
四個中斷向量則是上方說明的四個,根據需要可以開啟對應的中斷。
HAL_StatusTypeDef HAL_CAN_ConfigFilter(CAN_HandleTypeDef *hcan, CAN_FilterTypeDef *sFilterConfig)
HAL_StatusTypeDef HAL_CAN_Start(CAN_HandleTypeDef *hcan)
HAL_StatusTypeDef HAL_CAN_Stop(CAN_HandleTypeDef *hcan)
HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan, CAN_TxHeaderTypeDef *pHeader, uint8_t aData[], uint32_t *pTxMailbox)
HAL_StatusTypeDef HAL_CAN_AbortTxRequest(CAN_HandleTypeDef *hcan, uint32_t TxMailboxes)
uint32_t HAL_CAN_IsTxMessagePending(CAN_HandleTypeDef *hcan, uint32_t TxMailboxes)
HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan, uint32_t RxFifo, CAN_RxHeaderTypeDef *pHeader, uint8_t aData[])
uint32_t HAL_CAN_GetRxFifoFillLevel(CAN_HandleTypeDef *hcan, uint32_t RxFifo)
void HAL_CAN_IRQHandler(CAN_HandleTypeDef *hcan)
__weak void HAL_CAN_TxMailbox0CompleteCallback(CAN_HandleTypeDef *hcan)
__weak void HAL_CAN_TxMailbox1CompleteCallback(CAN_HandleTypeDef *hcan)
__weak void HAL_CAN_TxMailbox2CompleteCallback(CAN_HandleTypeDef *hcan)
__weak void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
if(hcan->Instance==CAN1)
{
HAL_CAN_GetRxMessage(&hcan1,CAN_FILTER_FIFO0,&rxheader1,msg);
}
}
__weak void HAL_CAN_RxFifo0FullCallback(CAN_HandleTypeDef *hcan)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hcan);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_CAN_RxFifo0FullCallback could be implemented in the user
file
*/
}
__weak void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
if(hcan->Instance==CAN1)
{
HAL_CAN_GetRxMessage(&hcan1,CAN_FILTER_FIFO0,&rxheader1,msg);
}
}
__weak void HAL_CAN_RxFifo1FullCallback(CAN_HandleTypeDef *hcan)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hcan);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_CAN_RxFifo0FullCallback could be implemented in the user
file
*/
}