CAN(Controller Area Network)总线是嵌入式系统,尤其是汽车电子和工业控制领域,实现高可靠、实时多节点通信的核心技术。STM32系列微控制器普遍集成了高性能的CAN控制器(bxCAN),为开发者提供了强大的硬件支持。本文将系统性地介绍STM32 CAN通信的原理、硬件架构、配置步骤和关键代码实现。
一、CAN总线核心原理与优势
CAN总线由博世公司开发,是一种多主、异步串行通信协议。其核心优势在于非破坏性仲裁 、差分信号传输带来的高抗干扰性 、强大的错误检测与恢复机制,以及支持远距离通信(如125kbps时可达500米)。
-
物理层与电平逻辑 :CAN使用一对差分信号线CAN_H和CAN_L进行通信。总线电平分为显性电平 (逻辑0)和隐性电平(逻辑1)。显性电平具有优先权,当多个节点同时发送时,总线呈现显性状态。典型电平值为:显性时CAN_H约3.5V,CAN_L约1.5V,压差约2V;隐性时两者均为约2.5V,压差为0V。
-
帧结构与类型 :CAN协议定义了多种帧类型,其中数据帧 最为重要,用于传输实际数据。数据帧由帧起始、仲裁段、控制段、数据段、CRC段、ACK段和帧结束 7个部分构成。帧格式分为标准帧 (11位标识符ID)和扩展帧(29位标识符ID)。
-
非破坏性仲裁 :这是CAN协议的关键特性。当多个节点同时开始发送时,它们会从标识符(ID)的最高位开始逐位比较。数值更小的ID(即更多显性位0)拥有更高的优先级。仲裁失败的节点会自动退出并转为接收模式,而获胜者继续发送,整个过程不会破坏数据或造成总线冲突。
二、STM32 bxCAN控制器架构
STM32内置的CAN控制器称为bxCAN(Basic Extended CAN),其主要特性包括:
- 支持CAN 2.0A和2.0B协议。
- 最高通信速率可达1 Mbps。
- 3个发送邮箱:用于缓存待发送的报文,支持优先级管理。
- 2个接收FIFO(每个深度为3级):用于缓存接收到的报文,减轻CPU负担。
- 可配置的筛选器(过滤器)组:用于过滤接收到的报文ID,普通STM32F1有14组,互联型和F4系列有28组。
- 支持多种工作模式:正常模式、环回模式、静默模式等,便于调试。
三、STM32 CAN通信配置与编程实战
以下以STM32 HAL库为例,概述配置CAN通信的关键步骤。
1. 硬件连接
一个完整的CAN节点需要:STM32(CAN控制器)、CAN收发器 (如TJA1050、SN65HVD230)和终端电阻 (通常为120Ω,接在总线两端)。STM32的CAN_TX和CAN_RX引脚分别连接收发器的TXD和RXD引脚。
2. 软件配置(以STM32CubeMX为例)
-
启用CAN外设:在CubeMX的引脚配置中,启用CAN1或CAN2,并分配正确的TX/RX引脚(如PA11/PA12 for CAN1 on F1)。
-
配置工作模式与波特率 :在CAN配置界面,选择
Normal模式。波特率设置是关键,它由预分频器(Prescaler)和位时序 参数共同决定。- 位时间被划分为同步段(SS)、传播段(PS)、相位缓冲段1(BS1)和相位缓冲段2(BS2),这些段由时间量子(Tq)构成。
- 波特率计算公式为:
波特率 = APB1时钟频率 / (Prescaler * (SS + BS1 + BS2))。例如,APB1时钟为42MHz,Prescaler=6,总Tq数=14,则波特率约为500kbps。
-
配置过滤器 :过滤器用于决定哪些ID的报文可以被接收。可以配置为屏蔽位模式 (类似掩码,指定哪些位必须匹配)或列表模式 (精确匹配ID)。例如,以下代码配置一个32位屏蔽位模式的过滤器,只接收标准ID为0x123的报文:
CAN_FilterTypeDef sFilterConfig; sFilterConfig.FilterBank = 0; sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; sFilterConfig.FilterIdHigh = 0x123 << 5; // 标准ID左移5位对齐 sFilterConfig.FilterMaskIdHigh = 0x7FF << 5; // 只关心11位标准ID,需完全匹配 sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0; sFilterConfig.FilterActivation = ENABLE; HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig); -
启用中断 :在NVIC设置中启用CAN接收中断(如
CAN1_RX0_IRQn),以便在收到报文时及时处理。
3. 关键代码实现
-
发送数据 :填充发送报文头和数据,然后请求发送。
CAN_TxHeaderTypeDef TxHeader; uint8_t TxData[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; uint32_t TxMailbox; TxHeader.StdId = 0x123; // 标准ID TxHeader.IDE = CAN_ID_STD; // 标准帧 TxHeader.RTR = CAN_RTR_DATA; // 数据帧 TxHeader.DLC = 8; // 数据长度(0-8字节) // 扩展帧需设置 ExtId 并将 IDE 设为 CAN_ID_EXT if (HAL_CAN_AddTxMessage(&hcan1, &TxHeader, TxData, &TxMailbox) != HAL_OK) { // 错误处理 } -
接收数据(中断方式) :在中断回调函数中读取报文。
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) { CAN_RxHeaderTypeDef RxHeader; uint8_t RxData[8]; if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData) == HAL_OK) { // 处理RxHeader.StdId/ExtId 和 RxData } }在主函数初始化后,需要激活接收通知:
HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);。
4. 错误处理
CAN控制器具备完善的错误检测功能,包括位错误、填充错误、CRC错误、格式错误和应答错误等。可以通过轮询HAL_CAN_GetError()或配置错误中断CAN_IT_ERR来获取和处理错误状态,这对于构建高可靠系统至关重要。
总结
掌握STM32 CAN通信需要理解其差分信号、仲裁机制和帧格式等协议基础,并熟悉bxCAN控制器的邮箱、FIFO和过滤器等硬件资源。通过STM32CubeMX进行图形化配置,再结合HAL库的API进行发送、接收和错误管理,可以高效地实现稳定可靠的多节点网络通信。对于更复杂的系统,还需合理规划报文ID优先级,并精细配置过滤器以优化总线负载和CPU开销。