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模块知识结构图 CMS32 CAN模块知识结构 CMS32 CAN控制器 MCU系列概述 CAN控制器外设特性 时钟配置与引脚分配 ARM Cortex-M0+ 48MHz主频 CAN 2.0B协议 3发2收缓冲区 验收过滤 波特率计算 引脚复用配置 GPIO模式设置 💡 核心要点 时钟配置决定波特率精度,引脚分配影响信号质量 验收过滤是降低CPU负载的关键手段

这张图把CMS32 CAN模块的知识点分成了三大块:MCU概述、外设特性、时钟与引脚。你可以把它当作一个快速索引,后面讲到具体配置时,随时回来对照。

好了,这一章的内容就到这儿。记住,CAN模块的配置核心就三件事:时钟算准、引脚配对、过滤用好。这三件事做好了,后面调试就顺了。