由于 CAN 属于异步通讯,没有时钟信号线,连接在同一个总线网络中的各个节点会像串口异步通讯那样,节点间使用约定好的波特率进行通讯。
首先我们要明确几个概念:
波特率:CAN通信1s传输的数据位数,其单位为bps。
Time-quantum(简称Tq):把一个CAN时钟周期称为一个时间份额或时间量子Tq,Tq是构成CAN报文中一位(bit)数据的最小时间单位。
STM32
的
CAN
外设位时序中的一个数据位只包含
3
段,分别是同步段
SYNC_SEG (SS)
、位段 1 (
BS1)
及位段2 (
BS2)
,采样点位于 BS1
及
BS2
段的交界处。其中
SYNC_SEG
段固定长度为
1Tq
,而
BS1
及
BS2
段可以 在位时序寄存器 CAN_BTR
设置它们的时间长度,它们可以在重新同步期间增长或缩短。传输一个数据位所占用的时间即为三者之和。
![](https://i-blog.csdnimg.cn/direct/a1ddbb6906604e5ea718562168a5ff61.png)
通过配置位时序寄存器
CAN_BTR
的
TS1[3:0]
及 TS2[2:0] 寄存器位设定
BS1
及
BS2
段的长度后,我们就可以确定每个
CAN
数据位的时间。
由芯片手册可以得知以下公式
TBS1 = Tq*(TS1[3:0] + 1)TBS2 = Tq*(TS2[2:0] + 1)传输一个数据位所用的时间:T1bit = 1Tq + TBS1 + TBS2 = Tq*(1+(TS1[3:0] + 1)+(TS2[2:0] + 1))Tq = (BRP[9:0]+1) x T PCLK波特率=1s传输的数据位数 = 1/T1bit = 1/(1 + TBS1 + TBS2)*Tq=1/(1 + TBS1 + TBS2)*(BRP[9:0]+1)x T PCLK
有很多同学可能会发现,芯片厂家已经在库文件中将
TS1[3:0] + 1
,
TS2[2:0] + 1用宏定义的形式定义好了,省去了我们计算时再+1的操作,这也就是为什么下图中的CAN_BS1_1tq的值实际上是0x00而不是0x01
![](https://i-blog.csdnimg.cn/direct/3b593c23e6ed4ceabcf18f4c7459020f.png)
同理下图中CAN_Prescaler即为
BRP[9:0]+1,这也就是为什么在对底层寄存器操作时要将其减一
![](https://i-blog.csdnimg.cn/direct/172a673c50a648efa539d1a5949d0dbd.png)
由于公式中涉及到TPCLK的时钟,所以我们首先需要了解CAN挂载在哪条总线下,并且该总线的时钟频率是多少。此处采用STM32F103进行举例,从下图中的用户手册中的系统架构可知,基本扩展CAN总线bxCAN挂载在APB1总线,从下下图中的用户手册中的时钟树可知APB1总线的时钟频率为36MHz,即TPCLK=1/36MHz。
由于上文所提到的宏定义已经帮我们实现了TS1[3:0] + 1,TS2[2:0] + 1,BRP[9:0]+1等操作,所以我们的公式可以精简为:
CAN波特率 = APB总线频率/BRP分频器/(1+TBS1+TBS2)
在这里我们只需要谨记(1+TBS1+TBS2)中的+1,其他直接采用代码中设置的值即可。
以下面的STM32F103的代码为例,公式中的BRP分频器对应着代码中的CAN_Prescaler = 4,TBS1对应着CAN_BS1 = BS1_5tq = 5,TBS2对应着CAN_BS2 = BS2_3tq = 3
所以通过公式可以计算得出波特率 = 36000000/4/(1+5+3) = 1000000 = 1 MBsp
/* ss=1 bs1=5 bs2=3 位时间宽度为(1+5+3) 波特率即为时钟周期tq*(1+3+5) */
CAN_InitStructure.CAN_BS1=CAN_BS1_5tq; //BTR-TS1 时间段1 占用了5个时间单元
CAN_InitStructure.CAN_BS2=CAN_BS2_3tq; //BTR-TS1 时间段2 占用了3个时间单元
/* CAN Baudrate=36/4/(1+5+3)=1MBps (1MBps已为stm32的CAN最高速率) (CAN时钟频率为APB1 = 36 MHz) */
CAN_InitStructure.CAN_Prescaler =4; //BTR-BRP 波特率分频器 定义了时间单元的时间长度
下面附上一图流攻略