2. CMS32 CAN模块概览:特性、引脚与时钟
好,咱们正式开始看CMS32的CAN模块。说实话,我第一次拿到CMS32的参考手册时,第一反应是去找CAN章节——毕竟做嵌入式,通信接口就是命脉。这一节我会把CAN控制器的特性、引脚怎么接、时钟怎么配,掰开揉碎了讲清楚。
2.1 CAN控制器核心特性
CMS32系列内置的CAN控制器,其实是一个完整的CAN 2.0B协议引擎。它支持标准帧(11位ID)和扩展帧(29位ID),这点在现在的车载和工业现场基本是标配。但我个人最看重的,是它有几个很实在的特性:
- 3个发送缓冲器:可以挂起3个待发报文,优先级由硬件自动仲裁
- 2个接收缓冲器:每个都能存1个完整报文,配合FIFO机制不容易丢帧
- 可编程的验收滤波器:最多支持4个32位掩码/ID组合,说白了就是能按需过滤,不用CPU一个个去翻
- 总线错误诊断:能直接读出错误计数器和错误状态,调试时特别好用
关键参数速查表
| 参数 | CMS32 CAN控制器 | 备注 |
|---|---|---|
| 协议标准 | CAN 2.0B | 兼容标准帧/扩展帧 |
| 发送缓冲器 | 3个 | 优先级由硬件仲裁 |
| 接收缓冲器 | 2个 + FIFO | 深度可配置 |
| 验收滤波器 | 4组 × 32位 | 支持掩码和ID模式 |
| 位速率 | 最高1 Mbps | 取决于时钟和分频 |
| 错误状态寄存器 | 有 | 可读发送/接收错误计数 |
我记得有一次项目,对方要求CAN总线跑在800kbps,结果我配完发现总是丢帧。查了半天,原来是验收滤波器没配好,把本应接收的报文全给滤掉了。嗯,从那以后我每次配滤波器都会反复确认掩码值。
2.2 引脚配置:CAN_TX 和 CAN_RX
CMS32的CAN接口只有两个引脚:CAN_TX(发送)和 CAN_RX(接收)。别小看这两个脚,接错了整个总线都起不来。
先看引脚功能:
| 引脚名 | 方向 | 功能描述 |
|---|---|---|
| CAN_TX | 输出 | CAN控制器发送数据到收发器 |
| CAN_RX | 输入 | CAN收发器接收数据到控制器 |
实际项目中,这两个引脚通常不会直接连到CAN总线上,而是通过一个CAN收发器(比如TJA1050或SN65HVD230)转成差分信号。我见过有人直接把CAN_TX和CAN_RX接到总线上,结果烧了IO口——收发器的作用就是把单端信号转成CANH/CANL差分,同时提供电平转换和总线保护。
⚠️ 引脚复用注意
CMS32的CAN_TX和CAN_RX通常与GPIO复用。上电后默认是GPIO模式,必须通过寄存器配置为CAN功能。我曾经在调试时发现CAN没反应,查了半天才发现是引脚功能没切过来——这种低级错误最容易浪费半天时间。
配置引脚时,一般需要两步:
- 在GPIO模块中,把对应引脚设为复用功能(AF模式)
- 在CAN模块中,使能CAN_TX和CAN_RX的驱动
具体代码我习惯这样写(以CMS32标准库为例):
// 使能CAN引脚时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN, ENABLE);
// 配置CAN_TX (假设为PA12) 为复用推挽输出
GPIO_InitTypeDef GPIO_InitStructure;
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);
// 配置CAN_RX (假设为PA11) 为浮空输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 将PA11和PA12连接到CAN模块
GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_CAN);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_CAN);
你想想看,如果忘了最后那两行AF配置,CAN_TX和CAN_RX就还是普通GPIO,收发器根本收不到数据。这种坑我踩过不止一次。
2.3 时钟使能与复位
CAN模块要工作,首先得给它喂时钟。CMS32的CAN挂载在APB1总线上,时钟源通常来自系统时钟经过分频后的APB1时钟。
时钟使能很简单,就一个寄存器位:
// 使能CAN时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN, ENABLE);
但这里有个关键点:CAN模块的位时序(Baud Rate)完全依赖于这个时钟频率。如果APB1时钟不准,CAN的波特率就会偏,总线通信就会出错。我建议你在配CAN之前,先确认APB1时钟的实际频率,最好用示波器量一下CAN_TX引脚的波形。
💡 我的调试习惯
每次初始化CAN之前,我都会先读一下RCC寄存器,确认APB1时钟值。然后在CAN初始化结构体里,把波特率参数算好再写进去。别偷懒,直接抄例程里的数值——不同板子的时钟可能不一样。
复位方面,CMS32提供了两种复位方式:
- 软件复位:通过CAN模块的控制寄存器(CAN_MCR)中的RESET位触发,复位后所有寄存器回到默认值
- 硬件复位:系统复位或看门狗复位时,CAN模块自动复位
我个人更常用软件复位,因为可以在不重启整个系统的情况下重新初始化CAN。比如总线出现Bus Off状态时,我会先软件复位CAN,再重新配置,而不是直接复位单片机。
// 软件复位CAN
CAN_DeInit(CAN1);
// 重新初始化
CAN_Init(CAN1, &CAN_InitStructure);
嗯,这里要注意:软件复位后,所有配置都会丢失,包括验收滤波器、中断使能等。所以复位后必须重新做一遍完整的初始化流程。
2.4 整体结构图
下面这张图把CMS32 CAN模块的内部结构和外部连接画清楚了。你可以看到CAN控制器、收发器、总线之间的关系,以及时钟和复位信号怎么进来。
从图上你能看到,CAN控制器在单片机内部,通过CAN_TX和CAN_RX连接到外部收发器,再转成差分信号上总线。时钟和复位是控制器正常工作的前提——少了任何一个,CAN都动不了。
💡 快速检查清单
- CAN_TX和CAN_RX是否已配置为复用功能?
- APB1时钟是否已使能?频率是否正确?
- 收发器供电是否正常?VCC和GND接好了吗?
- 总线终端电阻(120Ω)是否在两端都接了?
好了,这一节的内容就是这些。CMS32的CAN模块其实不复杂,但引脚配置和时钟使能是基础中的基础。我见过太多人一上来就调波特率、配滤波器,结果发现CAN_TX根本没输出——回头一看,时钟没开。嗯,别笑,这种事真不少见。