3. CAN初始化实战:模式选择、位时序配置与滤波器设置
好,咱们直接进入正题。CAN模块的初始化,说白了就是给硬件“定规矩”——告诉它用什么模式工作、跑多快、收哪些报文。这一步要是没弄对,后面通信全是乱码。我见过不少工程师,上来就抄例程,结果环回模式调通了,一上总线就翻车。嗯,咱们今天就把这三个核心配置彻底讲透。
3.1 模式选择:正常、环回与静默
CMS32的CAN控制器支持三种工作模式。你想想看,这就像开车——正常模式是上路跑,环回模式是在驾校练车,静默模式是只监听不说话。
| 模式 | 发送 | 接收 | ACK应答 | 典型用途 |
|---|---|---|---|---|
| 正常模式 | 有效 | 有效 | 发送 | 实际总线通信 |
| 环回模式 | 内部回环 | 接收自己发送 | 不发送 | 自测、单板调试 |
| 静默模式 | 禁止 | 有效 | 不发送 | 总线监听、故障分析 |
模式配置在CMS32的CAN控制寄存器里,一般是通过CAN_MCR(模式控制寄存器)的对应位来切换。代码实现很简单:
// CMS32 CAN模式配置示例
void CAN_SetMode(uint8_t mode) {
switch(mode) {
case CAN_MODE_NORMAL:
CAN->MCR &= ~(CAN_MCR_TEST_MASK); // 清除测试模式
CAN->MCR &= ~(CAN_MCR_SLEEP_MASK); // 退出睡眠
break;
case CAN_MODE_LOOPBACK:
CAN->MCR |= CAN_MCR_TEST_MASK; // 进入测试模式
CAN->MCR |= CAN_MCR_LBACK_MASK; // 使能环回
break;
case CAN_MODE_SILENT:
CAN->MCR |= CAN_MCR_TEST_MASK;
CAN->MCR |= CAN_MCR_SILENT_MASK; // 使能静默
break;
}
}
3.2 位时序配置:TSEG1、TSEG2与SJW
位时序是CAN通信的“心跳”。配置不对,两个节点就算波特率一样也聊不到一块去。CMS32的CAN控制器把1个位时间分成3段:同步段(SS)、时间段1(TSEG1)、时间段2(TSEG2)。
为什么这么分?因为CAN总线是异步的,没有单独的时钟线。每个节点靠采样点来“猜”对方发的是0还是1。采样点位置就由TSEG1和TSEG2的比例决定。
位时间 = (1 + TSEG1 + TSEG2) × 时间量子
采样点位置 = (1 + TSEG1) / (1 + TSEG1 + TSEG2) × 100%
我个人习惯把采样点设在87.5%左右。为什么是这个值?因为CAN总线信号在传输过程中会有延迟,采样点靠后一些,能容忍更大的线缆长度和节点数。当然,如果总线很短(比如同一块板子上),75%也行。
| 参数 | 范围 | 说明 |
|---|---|---|
| TSEG1 | 1~16 | 包含传播段和相位缓冲段1,决定采样点位置 |
| TSEG2 | 1~8 | 相位缓冲段2,决定采样点后的时间 |
| SJW | 1~4 | 同步跳转宽度,用于补偿时钟偏差 |
SJW这个参数容易被忽略。它决定了CAN控制器能容忍多大的时钟偏差。举个例子,如果两个节点的晶振精度分别是±0.1%和±0.2%,SJW设得太小,跑久了就会同步失败。我建议SJW至少设为2,保守一点设成3也行。
// CMS32 CAN位时序配置示例(500kbps,8MHz时钟)
void CAN_BitTimingConfig(void) {
// 假设CAN时钟为8MHz,目标波特率500kbps
// 位时间 = 8MHz / 500kbps = 16个时间量子
// 配置:SS=1, TSEG1=12, TSEG2=3, SJW=2
// 采样点 = (1+12)/(1+12+3) = 13/16 ≈ 81.25%
CAN->BTR |= (2 << CAN_BTR_SJW_POS); // SJW = 2
CAN->BTR |= (12 << CAN_BTR_TSEG1_POS); // TSEG1 = 12
CAN->BTR |= (3 << CAN_BTR_TSEG2_POS); // TSEG2 = 3
}
3.3 滤波器设置:只收你想收的
CAN总线上的报文是广播式的——所有节点都能收到。但大多数节点只关心特定ID的报文。滤波器就是干这个的:把不想要的报文挡在门外,减轻CPU负担。
CMS32的CAN控制器支持两种滤波器模式:
- 标识符列表模式:只接收与预设ID完全匹配的报文。适合节点只关心1~2个ID的场景。
- 掩码模式:通过掩码指定哪些位必须匹配,哪些位可以忽略。适合需要接收一组ID的场景。
举个例子,假设你只想接收ID为0x123和0x124的报文:
// CMS32 CAN滤波器配置示例(掩码模式)
void CAN_FilterConfig(void) {
// 配置滤波器组0为掩码模式
CAN->FCTRL |= (1 << CAN_FCTRL_FEN_POS); // 使能滤波器
// 设置ID掩码:只匹配高11位
CAN->FMASK[0] = 0x7FF; // 掩码全1,表示所有位都必须匹配
// 设置期望ID
CAN->FID[0] = 0x123; // 只接收ID=0x123的报文
// 如果需要接收0x123和0x124,可以用掩码模式:
// CAN->FMASK[0] = 0x7FE; // 最低位忽略
// CAN->FID[0] = 0x122; // 匹配0x122和0x123
}
3.4 知识体系总览
下面这张图把CAN初始化的三个核心模块串起来了。你可以把它当作调试时的“地图”——哪个环节出问题,就回来看对应的配置。
3.5 初始化完整流程
最后,我把CAN初始化的完整步骤整理成一个清单。你每次写初始化代码时,按这个顺序来,基本不会漏东西。
- 使能CAN时钟——别笑,我真见过有人忘了开时钟,调了半天以为芯片坏了。
- 配置CAN引脚——TX/RX要配成复用功能,注意上下拉。
- 进入初始化模式——置位CAN_MCR的INIT位。
- 配置模式——正常/环回/静默,按需选择。
- 配置位时序——TSEG1、TSEG2、SJW,算好采样点。
- 配置滤波器——设置ID和掩码。
- 退出初始化模式——清除INIT位,CAN开始工作。
- 验证状态——读状态寄存器,确认CAN已进入运行态。