【嵌入式开发】单片机CAN配置详解
0 前言
CAN外设作为一种传输速率较高,且连线较为简洁的通信协议,如今很多单片机内部都集成了CAN控制模块,这样只需要再外接一个CAN收发芯片,将TTL/CMOS电平转换成CAN协议的差分电平,就是一个完整的CAN收发节点。
最近在做一个小项目,需要基于GD32的芯片来开发CAN应用,在CAN配置上遇到一些问题,遂整理成本文。
由于CAN节点的电路的核心就是CAN收发芯片,而且一般可以直接使用芯片数据手册的推荐电路,所以这个电路还是比较简单的,因此硬件设计不在本文讨论范围内。
1 终端电阻与接线
CAN电路有两种形式,一种是开环形式,即两根信号线不连接,这种需要在总线上串联一个2.2kΩ的电阻,另一种是闭环的形式,这种需要在两根信号线上跨接(并联)一个120Ω的电阻。一般来说,闭环形式使用较多。
因此,排查CAN总线电路是否正确的一个粗略方式就是拿电表测一下两根信号线之间的的阻值,正常应该是两个120Ω的并起来,即60Ω,如果不对的话,就可以考虑是不是多接了电阻。因为当挂载多个CAN节点时,有可能会多连电阻。
另外,接线上,常规只需要连接两根线即可,CAN_L和CAN_H,但如果干扰比较严重的话,可以考虑再接上地线。
2 波特率配置
CAN波特率的配置是首要的,这个直接决定了CAN分析仪是否能够收到数据。单片机中配置波特率的公式为
波特率 = A P B 1 C l o c k ( 1 + C A N _ B S 1 + C A N _ B S 2 ) ∗ C A N _ P r e s c a l e r \text{波特率}=\frac{APB1Clock}{\left( 1+CAN\_BS1+CAN\_BS2 \right) \,\,* CAN\_Prescaler} 波特率=(1+CAN_BS1+CAN_BS2)∗CAN_PrescalerAPB1Clock
这里最大的问题就是这个+1,到底要不要+1,哪个变量+1,需要深入理解CAN时序以及单片机的固件库。
参考这篇文章,CAN的时序图如下所示。
即一个电平过程包含固定时间的SS段,以及可调时间的PTS段,PBS1段和PBS2段。之所以要调各个段的时间(单位时间的个数),主要是为了设置采样点所在的位置。因为实际的信号曲线绝不是横平竖直的方波,而是带曲率和波动的,那么什么时候采样就很重要。
采样点之前的时间叫做建立时间,即信号稳定所需要的时间,采样点之后叫做保持时间,即采样之后这个信号保持多久。一般来说,频率越高,建立时间的比例要越长。保持时间的长短取决于芯片的硬件特性,即MOS管的导通时间,一般会有一个最低要求(ns级别),CiA(CAN in AUTOMATION,推广CAN协议的非营利性组织)推荐的比例(建立时间 / (建立时间+保持时间))为
波特率 | 比例 |
---|---|
>800K | 75% |
>500K | 80% |
<=500K | 87.5% |
再来看看STM32/GD32中CAN配置对应的时序(还是上面那篇文章)
其实都差不多,只是把PTS和PBS1合并成BS1了,BS2对应PBS2。然后再来看看数据手册(GD32F4)中配置这些参数的寄存器描述
以及固件库代码的写法:
所以可以发现一个问题:寄存器的值和实际表示的值相差1,这是因为计算机里面的范围都是从0开始算的,但是代码上通过宏定义来抹平了这个误差。 即CAN_BT_BS2_3TQ
就是指BS2段占3个单位时间,不必再+1或-1。
那BAUDPSC(也就是prescale参数)参数呢?应该也相 差1才对,比如这里是10位二进制,寄存器中数值范围应该是0-1023,但实际上调用时是直接传入真实值,即1-1024,这是因为在函数定义中,有对这个数值进行处理:
那单位时间是怎么算的?显然,直接用总线时间除以总单位数即可,而总单位数等于SS+BS1+BS2,其中SS固定一个单位时间,所以最后看到的表达式为 总线时间 / (1+BS1+BS2)
最后还有一个是SJW参数,这个是用来同步补偿的,值越大,可补偿的范围越大,可以理解为可以容忍的误差越大,这个需要根据实际系统情况进行调整,不影响波特率的计算。
3 总线收发相关配置
主要就是这个结构体内部字段的配置,只设置ENABLE和DISABLE即可
可以根据实际需要进行设置。