[无线连接] 使用GD32的CAN总线实现多节点传感器数据采集网络

[复制链接]
7|0
spicy 发表于 2026-9-4 10:39 | 显示全部楼层 |阅读模式
使用CAN总线搭建传感器数据采集网络,是工业控制和汽车电子领域非常经典的方案。GD32系列MCU内置的CAN控制器,配合CAN协议本身的优势,很适合用来处理这类“多节点、长距离、高可靠”的分布式采集任务。

下面我们从硬件、协议、软件实现三个层面,把搭建这样一个网络的关键点拆开来看。

🔌 硬件基础:节点设计与总线布线
搭建一个可靠的物理网络是第一步,硬件层面有三个核心环节:

1. 节点电路设计:每个传感器节点需要由GD32 MCU和一个CAN收发器组成。收发器负责将MCU的逻辑信号转换为CAN_H和CAN_L的差分信号。常用型号如TJA1050或SN65HVD230,设计电路时需要注意,收发器电源引脚旁必须放置0.1µF和10µF的电容组合来滤除电源噪声。

2. 总线拓扑与终端电阻:CAN总线采用直线型拓扑,所有节点并联在总线上。总线最远端的两个节点必须在CAN_H和CAN_L之间各接一个120欧姆的终端电阻,用来消除信号反射。实际项目中,可以在PCB上为这个电阻预留一个可通过跳线帽或0欧电阻切换的焊盘,方便根据节点在总线上的实际位置灵活启用或关闭。

3. 总线保护:工业现场静电和浪涌很常见,在CAN_H和CAN_L对地之间并联双向TVS管,可以对后续电路起到很好的保护作用。

🧠 通信逻辑:从“广播”到“精确接收”
CAN总线的精髓在于其基于标识符(ID)的通信机制。总线上任何一个节点发送报文,所有节点都能物理上接收到,但只有通过验收滤波器审查的报文才会被保留到接收FIFO供CPU处理。

滤波器配置模式:GD32提供了两种灵活的滤波器模式。

列表模式:精确匹配。只接收你明确列出的那几个ID的报文。

掩码模式:范围匹配。你可以定义一个“验证码”和一个“屏蔽码”,屏蔽码为1的位必须匹配,为0的位则忽略。

在实际的多传感器网络中,如果所有传感器节点都向主控上报数据,可以为每个传感器分配一个唯一的ID,然后使用列表模式精确接收;如果某类传感器(比如同一区域的所有温度传感器)需要被集中处理,则可以用掩码模式接收一个ID范围内的报文,再用软件做二次区分。

⚙️ 软件核心:GD32 CAN驱动配置与实现
以GD32F303系列为例,配置一个CAN节点的核心代码如下:

1. 初始化CAN并配置波特率:配置波特率需要精确计算预分频器、时间段1(BS1)、时间段2(BS2)等参数。一个经过验证的配置是BS1=6Tq, BS2=1Tq,配合适当的预分频值,可以产生稳定的250kbps或500kbps通信速率。

c
// 以GD32F303为例,配置CAN0,波特率250kbps
void can_init(void) {
    /* 使能CAN和GPIO时钟 */
    rcu_periph_clock_enable(RCU_CAN0);
    rcu_periph_clock_enable(RCU_GPIOB);
   
    /* 配置CAN引脚:PB8-RX, PB9-TX,复用功能 */
    gpio_af_set(GPIOB, GPIO_AF_6, GPIO_PIN_8 | GPIO_PIN_9);
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_8 | GPIO_PIN_9);
   
    /* 初始化CAN参数 */
    can_parameter_struct can_init_para;
    can_deinit(CAN0);
    can_struct_para_init(&can_init_para);
    can_init_para.time_triggered = DISABLE;   // 非时间触发
    can_init_para.auto_bus_off_recovery = DISABLE;
    can_init_para.auto_wake_up = DISABLE;
    can_init_para.no_auto_retrans = DISABLE;
    can_init_para.rec_fifo_overwrite = DISABLE;
    can_init_para.rec_fifo_order = DISABLE;
    can_init_para.working_mode = CAN_NORMAL_MODE;
    can_init_para.resync_jump_width = CAN_SJW_1TQ;
    can_init_para.time_segment_1 = CAN_BS1_6TQ;  // BS1 = 6Tq
    can_init_para.time_segment_2 = CAN_BS2_1TQ;  // BS2 = 1Tq
    /* 预分频值计算:PCLK=16MHz, 目标速率250kbps, Tq=0.5us, Prescaler = 16MHz * 0.5us = 8 */
    can_init_para.prescaler = 8;
    can_init(CAN0, &can_init_para);
}
2. 过滤器配置(关键难点):配置过滤器时有两个容易踩的坑。

位域映射:在32位宽的过滤器寄存器中,标准帧ID占据高11位,即[31:21]位。配置时,需要将你的目标ID左移21位再写入寄存器。

资源分配:GD32F407等多CAN型号中,0~13号过滤器组固定分配给CAN0,14~27号固定分配给CAN1。为CAN1配置过滤器时编号不能搞混,否则CAN1会收不到任何报文。

c
// 配置过滤器组0,掩码模式,只接收标准ID为0x301的数据帧
void can_filter_config(void) {
    can_filter_parameter_struct filter;
    can_filter_struct_para_init(&filter);
    filter.filter_number = 0;                    // 使用过滤器组0 (给CAN0用)
    filter.filter_mode = CAN_FILTERMODE_MASK;    // 掩码模式
    filter.filter_bits = CAN_FILTERBITS_32BIT;   // 32位宽
   
    /* 设置列表值:标准ID 0x301 左移21位 */
    filter.filter_list_high = (uint16_t)(((0x301 << 21) | (0x02 << 1)) >> 16);
    filter.filter_list_low = (uint16_t)((0x301 << 21) | (0x02 << 1));
   
    /* 设置掩码值:高11位全为1,要求ID完全匹配;其余位为0,忽略 */
    filter.filter_mask_high = 0xFFE0;
    filter.filter_mask_low = 0x0000;
   
    filter.filter_fifo_number = CAN_FIFO0;       // 匹配的报文存入FIFO0
    filter.filter_enable = ENABLE;
    can_filter_init(&filter);
}
🛠️ 避坑提醒:几个实战中的“老生常谈”
时钟源影响:CAN模块的时钟源配置会直接影响通信稳定性。官方应用笔记(AN222)指出,当系统时钟在某些特定配置下,CAN的位时间可能出现偏差,需要调整同步跳转宽度(SJW)等参数来规避。

中断实时性:建议将CAN接收中断设置为最高优先级,确保数据能及时从FIFO中读取,避免因处理不及时导致FIFO溢出丢帧。

CAN FD:对于更高速率(如2Mbps以上)和大数据量(>8字节)的场景,可以考虑支持CAN FD协议的GD32型号,它在兼容传统CAN的同时,提供了更高的数据吞吐率。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

130

主题

1228

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部
0