深入解析 CAN 通信:接收、发送与中断处理
1. CAN 通信原理
CAN(Controller Area Network)是一种在汽车电子和工业自动化领域中广泛使用的高可靠性通信协议。本文将探讨 CAN 协议的接收与发送过程,包括中断处理和滤波设计的关键技术点。
1.1 CAN 通信的特点
- 多主通信:多个主节点可以在同一个网络上发送数据。
- 优先级:基于标识符的消息优先级机制确保紧急信息优先传输。
- 非破坏仲裁:网络上如果有多个节点同时发送消息,通过仲裁机制决定哪个节点控制总线。
本文深入解析了 CAN 通信协议,涵盖基本原理、数据帧结构、收发流程、中断处理及滤波设计。详细介绍了标准帧与扩展帧的区别,硬件配置与软件实现策略,包括中断驱动与轮询方式的对比。通过代码示例展示了消息过滤、优先级管理及时间同步机制。此外,还分析了 CAN 在汽车电子与工业自动化领域的具体应用,探讨了网络安全性与 CAN FD 技术的未来趋势。
CAN(Controller Area Network)是一种在汽车电子和工业自动化领域中广泛使用的高可靠性通信协议。本文将探讨 CAN 协议的接收与发送过程,包括中断处理和滤波设计的关键技术点。
硬件上,CAN 通信需要 CAN 控制器和 CAN 收发器,它们共同实现了 CAN 协议的物理层和数据链路层功能。为了减少信号反射,网络通常会使用双绞线,并通过匹配电阻来终止网络。
在工作机制上,CAN 采用非破坏性的位仲裁技术,确保数据传输的稳定性和实时性。数据帧在传输过程中,若发生错误,节点将自动重发该帧。这种自我纠错的能力赋予了 CAN 通信在复杂环境下良好的性能表现。
由于 CAN 的高可靠性、实时性和灵活性,它已经成为工业控制、医疗设备、航空航天等多个领域不可或缺的通信标准。特别是在汽车领域,CAN 总线已经成为现代汽车电子系统的标准通信方式,广泛应用于引擎管理、刹车控制、车载娱乐系统等多个方面。
CAN 总线协议中定义了两种主要的帧格式:标准帧和扩展帧。标准帧使用 11 位标识符,而扩展帧使用 29 位标识符。这种设计允许开发者根据项目需求选择合适的帧类型,以优化网络通信的灵活性和效率。
一个 CAN 数据帧的开始由帧起始位(SOF)标志,这是帧的第一个位,并确保网络上的所有设备同步开始接收数据帧。接下来是控制位,其中包含标识符(ID),这个标识符定义了消息的优先级以及目的地。控制位之后是数据字段,数据长度可以变化,最短为 0 个字节,最长为 8 个字节。
数据字段之后是 CRC 序列,用于错误检测。循环冗余校验(CRC)确保了数据在传输过程中没有被损坏。CRC 后是 CRC 界定符,它由一个固定的位模式构成,用于标示 CRC 序列的结束。最后是帧结束位,标志着数据帧的结束。
帧结束位(EOF)是数据帧的最后一个字段,由 7 个连续的 1 位组成,确保了所有接收器能够识别数据帧的结束。帧间空间(IFS)是数据帧和随后帧之间的间隔。它允许网络上的设备有一个短暂的准备时间,用于处理当前接收到的数据帧,并准备接收下一个数据帧。
| 特征 | 标准帧 | 扩展帧 |
|---|---|---|
| 标识符位数 | 11 位 | 29 位 |
| 应用场景 | 小型系统、节点数量少 | 大型系统、节点数量多 |
| 优先级 | 较低 | 较高 |
| 数据长度 | 最多 8 字节 | 最多 8 字节 |
| 网络复杂性 | 较简单 | 较复杂 |
| 资源冲突处理 | 较困难 | 较容易 |
graph LR
A[开始] --> B[帧起始位]
B --> C[控制位]
C --> D[数据字段]
D --> E[CRC 序列]
E --> F[CRC 界定符]
F --> G[帧结束位]
G --> H[帧间空间]
在任何 CAN 网络中,CAN 控制器和 CAN 收发器是两个关键组件。控制器负责帧的格式化、错误检测与处理以及帧的发送与接收,而收发器则负责信号的电气特性转换。
典型的 CAN 网络拓扑采用'线 + 终端电阻'的形式,最大限度减少反射和信号失真。
CAN 总线支持强大的错误检测机制,包括 CRC、帧检查、消息确认等。软件层面需实现相应的错误处理逻辑,如处理帧冲突、总线错误、节点故障等。
以下是一个简化的 CAN 消息接收示例,使用中断驱动方式:
// CAN 接收中断服务程序示例
void CAN_RX_Interrupt() {
CAN_Message_t rxMessage;
// 检查是否为接收中断
if (CANInterruptReason == RX_INTERRUPT) {
// 清除中断标志
CANClearInterruptFlag();
// 读取接收缓冲区中的消息
rxMessage = CANReadMessageFromBuffer();
// 根据消息 ID 进行过滤
if (FilterMessage(rxMessage)) {
// 处理消息
ProcessMessage(rxMessage);
}
}
}
// 消息过滤函数
bool FilterMessage(CAN_Message_t message) {
return (message.id == FILTER_ID);
}
// 消息处理函数
void ProcessMessage(CAN_Message_t message) {
// 根据实际需求进行消息处理逻辑
}
在构建 CAN 消息帧格式时,需遵循 ISO 11898 标准。主要涉及标识符的设置、数据长度码(DLC)的指定、数据域的填充以及校验部分的计算。
// CAN 消息帧结构体定义
typedef struct {
uint32_t id; // 11/29 bits ID
uint8_t length; // 0-8 bytes
uint8_t data[8]; // data bytes
uint8_t rtr; // remote transmission request
} CAN_MessageFrame;
// 构建标准 CAN 帧的函数
void buildStandardCANFrame(CAN_MessageFrame *frame, uint32_t id, uint8_t length, uint8_t *data, uint8_t rtr) {
frame->id = id;
frame->length = length;
memcpy(frame->data, data, length);
frame->rtr = rtr;
}
发送缓冲区是确保消息按照既定顺序和优先级发送的重要组成部分。在 CAN 网络中,消息优先级是由标识符的数值决定的,数值越小,优先级越高。
// 使用优先队列管理发送缓冲区
#include <queue>
#include <functional>
// CAN 消息帧优先级比较函数
bool compareCANMessage(CAN_MessageFrame a, CAN_MessageFrame b) {
return a.id > b.id; // 标识符越小优先级越高
}
int main() {
std::priority_queue<CAN_MessageFrame, std::vector<CAN_MessageFrame>, decltype(&compareCANMessage)> sendQueue(compareCANMessage);
CAN_MessageFrame frame;
buildStandardCANFrame(&frame, 0x200, 8, (uint8_t *)"Data", 0);
sendQueue.push(frame);
while (!sendQueue.empty()) {
CAN_MessageFrame topMessage = sendQueue.top();
sendQueue.pop();
// 发送消息到 CAN 总线的代码
}
return 0;
}
物理层面上,CAN 总线使用差分信号。推荐使用 120 欧姆的匹配电阻,连接在 CAN_High 和 CAN_Low 之间,位于物理网络的两端。
// 示例代码,设置 CAN 控制器为发送模式
#define CAN_TX_ENABLE 0x01
void enableCANTransmission(CAN_Controller *controller) {
uint8_t controlRegister = readCANControlRegister(controller);
controlRegister |= CAN_TX_ENABLE;
writeCANControlRegister(controller, controlRegister);
}
时间同步机制可以通过硬件或软件来实现,例如使用时间戳或事件触发。
void enableCANTimeStamps(CAN_Controller *controller, bool enable) {
uint8_t controlRegister = readCANControlRegister(controller);
if (enable) {
controlRegister |= TIMESTAMP_ENABLE;
} else {
controlRegister &= ~TIMESTAMP_ENABLE;
}
writeCANControlRegister(controller, controlRegister);
}
低延迟消息处理要求优化流程、减少中断响应时间。在中断服务程序中仅处理必要的逻辑,将工作委托给后台任务。
void CAN_InterruptHandler() {
CAN_MessageFrame frame;
if (isMessageReceived()) {
readMessage(&frame);
if (isHighPriority(frame)) {
handleHighPriorityMessage(&frame);
} else {
signalSEM();
}
}
}
中断源通常包括数据帧接收完成、错误帧接收、状态改变等。数据接收完成通常具有最高优先级。
大多数现代 CAN 控制器允许用户通过软件编程设置中断优先级。需权衡不同中断源的重要性及其对系统性能的影响。
void CAN_InterruptHandler() {
if (CAN_RX_INTERRUPT_FLAG) {
CANReceiveData();
CAN_RX_INTERRUPT_FLAG = 0;
}
if (CAN_ERROR_INTERRUPT_FLAG) {
CANHandleError();
CAN_ERROR_INTERRUPT_FLAG = 0;
}
}
滤波器主要有两种类型:标识符过滤和内容过滤。高优先级的消息可以被赋予较低的滤波器掩码。
CAN_FilterConfigTypeDef canFilterConfig;
canFilterConfig.FilterBank = 0;
canFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
canFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
canFilterConfig.FilterIdHigh = 0x0000;
canFilterConfig.FilterIdLow = 0x0000;
canFilterConfig.FilterMaskIdHigh = 0x0000;
canFilterConfig.FilterMaskIdLow = 0x0000;
canFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
canFilterConfig.FilterActivation = ENABLE;
HAL_CAN_ConfigFilter(&hcan, &canFilterConfig);
评估方法应包括漏检率与误检率、实时性测试、资源占用等。
CAN FD(Flexible Data-rate)提供了更高的数据传输速率,支持高达 5Mbps,兼容现有设备,将在智能交通和自动驾驶领域发挥重要作用。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online