18. STM32-CAN-BUS (上)

前几篇有介绍过CANBus~透过MCP2515模块去完成通讯。
这篇会使用STM32当中的CAN-Bus来实现通讯~


与之前介绍Can不同的是在STM32当中将一个bit分为3个区段而已,将传播段与相位缓冲段1结合。
https://ithelp.ithome.com.tw/upload/images/20220326/20146325iCrgPyrniY.png
https://ithelp.ithome.com.tw/upload/images/20220326/20146325kvpgVsPi6H.jpg
可以看到在STM32当中将Bit仅分为3个区段,而同步区段固定为1Tq ; BS1为0-16TQ ;BS2为0-8TQ,采样点同样落在BS1与BS2交界。


计算说明

计算Time Quantum (TQ)

TQ = (BRP+1) x Tpclk

TQ= (15+1) x (1/16) = 0.9375(us) = 937.5(ns)

BPR : 预分频系数 Tpclk : APB Clock 周期

计算Bit Timing

这时可以知道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

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数量时要注意采样点位置!


传送与接收

  1. 发送 :
  • 3 个 Tx Buffer (Tx0 Tx1 Tx2)
  • 可设置Buffer优先级,根据优先级决定哪个Buffer优先发送
  1. 接收 :
  • 2 个 FIFO Rx Buffer (RX0 RX1)
  • 每个Rx Buffer当中可以接收3笔资料

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)信箱已经满了,所以当第四封信件就会放置在信箱外面(溢出)。

针对信箱满了的情况下可以分为两种处理方法:

  1. 新的信件直接覆盖掉刚刚接收的最後一封信件也就是编号3的信件 (CAN_MCR→RFLM = 0)
  2. 丢弃新信件,保留前面所接收到的3封信(CAN_MCR→RFLM = 1)

CAN 中断说明

在STM32当中CAN具有4个向量中断 :

  1. TX Interrupt : 传送中断,有3个Tx Buffer (0 1 2)
  • 当Tx Buffer 0 当中为空时,触发传送中断(CAN_TSR→RQCP0 = 1)
  • 当Tx Buffer 1 当中为空时,触发传送中断(CAN_TSR→RQCP1 = 1)
  • 当Tx Buffer 2 当中为空时,触发传送中断(CAN_TSR→RQCP2 = 1)
  1. FIFO0 Interrupt : 接收中断,有2个Rx Buffer (0 1),每一个Buffer可以储存3笔资料
  • 当FIFO0接收到一笔讯息,触发中断
  • 当FIFO0当中接收满3讯息时,触发中断(CAN_RF0R→FULL0 = 1)
  • 当FIFO0接收满3讯息时又接收了第4笔,发生溢位触发中断(CAN_RF0R→FOVR0 = 1)
  1. FIFO1 Interrupt : 接收中断,有2个Rx Buffer (0 1),每一个Buffer可以储存3笔资料
  • 当FIFO1接收到一笔讯息,触发中断
  • 当FIFO1当中接收满3讯息时,触发中断(CAN_RF1R→FULL1 = 1)
  • 当FIFO1接收满3讯息时又接收了第4笔,发生溢位触发中断(CAN_RF1R→FOVR1 = 1)
  1. SCE Interrupt (status change error interrupt) : 状态改变与错误中断
  • 当出现错误导致中断(CAN_ESR) EX: 接收错误计数器>127、离线
  • 唤醒节点时
  • 进入睡眠模式时

.IOC设置说明

我使用的板子是L476RG,只具备一个CAN通讯(CAN1)。
https://ithelp.ithome.com.tw/upload/images/20220326/20146325zDRvc7aoKg.png

  • 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。
    https://ithelp.ithome.com.tw/upload/images/20220326/20146325Foe7DH04EC.png
    上方图为基本模式设定,这边就都选Disable即可。
    而最後的是工作模式选择 : 分为正常模式、环回模式、静默模式等等,因为我手边只有一块就先选环回模式来测试。
    https://ithelp.ithome.com.tw/upload/images/20220326/201463256z1weYUx9u.png
    四个中断向量则是上方说明的四个,根据需要可以开启对应的中断。


相关函数

  • 设定CAN接收的Filter
HAL_StatusTypeDef HAL_CAN_ConfigFilter(CAN_HandleTypeDef *hcan, CAN_FilterTypeDef *sFilterConfig)
  • 启动CAN
HAL_StatusTypeDef HAL_CAN_Start(CAN_HandleTypeDef *hcan)
  • 停止CAN
HAL_StatusTypeDef HAL_CAN_Stop(CAN_HandleTypeDef *hcan)
  • CAN发送讯息: 将一笔讯息送至Buffer当中,同时会请求传送
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)
  • 检查所选的TxBuffer是否有传送请求
uint32_t HAL_CAN_IsTxMessagePending(CAN_HandleTypeDef *hcan, uint32_t TxMailboxes)
  • 从RXBuffer获取接收的讯息
HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan, uint32_t RxFifo, CAN_RxHeaderTypeDef *pHeader, uint8_t aData[])
  • 检查指定的RxBuffer内所接收到的讯息数(FIFO = 1 2 3)
uint32_t HAL_CAN_GetRxFifoFillLevel(CAN_HandleTypeDef *hcan, uint32_t RxFifo)
  • CAN中断处理函数 : 依照状态调用下方对应接收与传送回调函数
void HAL_CAN_IRQHandler(CAN_HandleTypeDef *hcan)
  • Tx Buffer 0 传送中断回调函数
__weak void HAL_CAN_TxMailbox0CompleteCallback(CAN_HandleTypeDef *hcan)
  • Tx Buffer 1 传送中断回调函数
__weak void HAL_CAN_TxMailbox1CompleteCallback(CAN_HandleTypeDef *hcan)
  • Tx Buffer 2 传送中断回调函数
__weak void HAL_CAN_TxMailbox2CompleteCallback(CAN_HandleTypeDef *hcan)
  • Rx Buffer 0 接收中断回调函数
__weak void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	if(hcan->Instance==CAN1)
	{
		HAL_CAN_GetRxMessage(&hcan1,CAN_FILTER_FIFO0,&rxheader1,msg);
	}
}
  • Rx Buffer 0 溢出中断回调函数 : 当接收满3笔讯息时
__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
   */
}
  • Rx Buffer 1 接收中断回调函数
__weak void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	if(hcan->Instance==CAN1)
	{
		HAL_CAN_GetRxMessage(&hcan1,CAN_FILTER_FIFO0,&rxheader1,msg);
	}
}
  • Rx Buffer 1 溢出中断回调函数 : 当接收满3笔讯息时
__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
   */
}

<<:  [前端/JavaScript] 实作汇出excel下载按钮的超好用套件:ExcelJS(下)- 用React汇出excel (export excel)

>>:  Organizing Data

2021-Day1. 开箱 Google Cloud Jam 活动背包

今年参赛的另一个主题,也请大家多多支持,感恩~ https://ithelp.ithome.com...

Day9 HTML 常用标签: table

表格 (table) 表格是一个由列和栏组成的结构化资料(tabular data)。表格能帮助你快...

Day 06: 测试驱动开发 (Test Driven Development)

「然而,没有测试套件,他们就丧失确保『程序修改後是否仍能照预期般工作』的能力,他们没办法保证『对系...

来讲讲 Cypher 的 Coding Style 吧

前情提要 除结尾倒数两篇 (゚∀゚) 来看看能不能在今天一次性写完w 现在时间 10/11 aka....

.NET Core第29天_Model验证配置准备流程_各种验证资料注解使用方式

新建一个.net core mvc专案後 预设每一个检视之所以都能套用版面配置页 主要是在於藉由.\...