2. CAN总线基础
各位好,欢迎来到咱们的实战课程。今天咱们聊聊CMS32系列MCU的CAN模块。说实话,我第一次接触这个芯片时,第一反应是——嗯,这外设挺全的。尤其是CAN控制器,设计得相当规整,没有那么多花里胡哨的东西,上手很快。
CMS32系列MCU概述
CMS32系列是中微半导体推出的32位ARM Cortex-M0+内核MCU。我个人的理解是,它瞄准的是那些对成本敏感、但对可靠性要求不低的工业场景。比如汽车电子、工业控制、传感器节点这些地方。
这个系列有几个特点让我印象深刻:
- 主频最高48MHz——跑CAN协议绰绰有余,不会成为瓶颈
- 内置CAN控制器——支持CAN 2.0B协议,标准帧和扩展帧都行
- 丰富的定时器和PWM——做电机控制时很顺手
- 宽电压范围——2.5V到5.5V,工业环境适应性好
我在一个车载诊断项目中用过CMS32F103x系列。当时选它的原因很简单:CAN外设够用,价格合适,而且供货稳定。你想想看,如果芯片动不动缺货,项目再牛也白搭。
CAN控制器外设特性
CMS32的CAN控制器,说白了就是一个独立的CAN协议引擎。它负责处理CAN总线上的帧收发、错误检测、仲裁这些脏活累活。CPU只需要把数据写到发送缓冲区,或者从接收缓冲区读出来就行。
我整理了一下它的核心特性:
| 特性 | 说明 |
|---|---|
| 协议支持 | CAN 2.0B,标准帧(11位ID)和扩展帧(29位ID) |
| 波特率 | 最高1Mbps,可编程分频 |
| 发送缓冲区 | 3个独立发送邮箱,支持优先级发送 |
| 接收缓冲区 | 2个深度FIFO,配合硬件过滤 |
| 验收过滤 | 支持单ID过滤和掩码过滤两种模式 |
| 中断源 | 发送完成、接收有效、错误状态、总线关闭等 |
| 工作模式 | 正常模式、只听模式、自测模式、静默模式 |
这里我想特别提一下验收过滤。我在项目里吃过亏——一开始没配好过滤,结果MCU被大量无关报文中断淹没,CPU占用率直接飙到80%。后来改成掩码过滤,只接收我关心的几个ID,CPU瞬间就轻松了。所以,验收过滤一定要用起来,别偷懒。
关键点:CMS32的CAN控制器有3个发送邮箱,但接收FIFO只有2个深度。如果你的总线负载很高,建议开启硬件过滤,否则接收溢出会丢帧。
时钟配置与引脚分配
时钟配置这块,我习惯先理清楚时钟树。CMS32的CAN模块挂载在APB总线上,它的时钟源来自系统时钟经过分频后的结果。
具体来说:
- 系统时钟(SYSCLK)最高48MHz
- APB时钟(PCLK)默认等于SYSCLK,也可以分频
- CAN模块时钟(CAN_CLK)来自PCLK,再经过CAN内部的分频器
波特率的计算公式很简单:
波特率 = CAN_CLK / (CAN_BRP + 1) / (1 + TSEG1 + TSEG2 + 1)
其中:
- CAN_BRP:波特率预分频器,0~255
- TSEG1:时间段1,2~16
- TSEG2:时间段2,1~8
举个例子,如果CAN_CLK=48MHz,想要500kbps的波特率:
CAN_BRP = 5 // 分频后CAN_CLK = 48 / (5+1) = 8MHz
TSEG1 = 13 // 13个时间量子
TSEG2 = 2 // 2个时间量子
// 总时间量子 = 1 + 13 + 2 + 1 = 17
// 波特率 = 8MHz / 17 ≈ 470.6kbps
嗯,这个值离500kbps有点偏差。所以我一般会调整一下:
CAN_BRP = 3 // 分频后CAN_CLK = 48 / (3+1) = 12MHz
TSEG1 = 12 // 12个时间量子
TSEG2 = 3 // 3个时间量子
// 总时间量子 = 1 + 12 + 3 + 1 = 17
// 波特率 = 12MHz / 17 ≈ 705.9kbps
还是不对。实际上,要精确得到500kbps,需要让CAN_CLK能被16整除:
CAN_BRP = 5 // CAN_CLK = 8MHz
TSEG1 = 13
TSEG2 = 2
// 总时间量子 = 1 + 13 + 2 + 1 = 17
// 8MHz / 17 = 470.6kbps —— 误差约5.9%
或者换个思路:
CAN_BRP = 2 // CAN_CLK = 16MHz
TSEG1 = 14
TSEG2 = 1
// 总时间量子 = 1 + 14 + 1 + 1 = 17
// 16MHz / 17 = 941.2kbps —— 这个接近1Mbps
所以,500kbps在48MHz下不是整数倍,会有约5.9%的误差。这在CAN总线规范允许范围内(一般要求误差<1.5%),但如果你对时序要求严格,建议换一个晶振频率,比如用8MHz或16MHz的外部晶振。
我的经验:实际项目中,470.6kbps和500kbps的设备可以正常通信,只要总线上的所有节点都用同一个波特率。但如果你要跟标准CAN设备对接,最好把误差控制在1%以内。我曾经因为时钟配置偏差太大,导致总线偶尔出现错误帧,排查了两天才发现是分频系数没算对。
引脚分配
CMS32的CAN控制器通常占用两个引脚:
- CANTX:发送引脚,推挽输出
- CANRX:接收引脚,浮空输入
具体映射到哪个GPIO,要看芯片型号。以CMS32F103x为例:
| 引脚 | 默认复用 | 可选复用 |
|---|---|---|
| CANTX | PA12 | PB6, PD1 |
| CANRX | PA11 | PB7, PD0 |
我个人习惯把CAN引脚放在PA11/PA12上,因为这两个引脚离CAN收发器近,走线短,信号质量好。如果你用其他复用功能,记得在代码里配置GPIO模式:
// 配置CANTX为推挽输出,复用功能
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置CANRX为浮空输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
注意:CANRX引脚必须配置为浮空输入,不能配置成上拉或下拉。否则会影响总线电平,导致通信异常。我曾经见过有人把CANRX配置成上拉输入,结果总线一直处于隐性状态,怎么都发不出数据。
知识结构总览
下面这张图把本章的核心内容串起来了,你可以对照着看:
这张图把CMS32 CAN模块的知识点分成了三大块:MCU概述、外设特性、时钟与引脚。你可以把它当作一个快速索引,后面讲到具体配置时,随时回来对照。
好了,这一章的内容就到这儿。记住,CAN模块的配置核心就三件事:时钟算准、引脚配对、过滤用好。这三件事做好了,后面调试就顺了。