| Controller Area Network 控制器局域网络 是ISO国际标准化的串行通信协议。在汽车产业中,出于对安全性、舒适性、方便性、低公害、低成本的要求,各种各样的电子控制系统被开发了出来。由于这些系统之间通信所用的数据类型及对可靠性的要求不尽相同,由多条总线构成的情况很多,线束的数量也随之增加。为适应“减少线束的数量”、“通过多个LAN,进行大量数据的高速通信”的需要,1986 年德国电气商博世公司开发出面向汽车的CAN 通信协议。此后,CAN 通过ISO11898及ISO11519进行了标准化,在欧洲已是汽车网络的标准协议。CAN 的高性能和可靠性已被认同,并被广泛地应用于工业自动化、船舶、医疗设备、工业设备等方面。现场总线是当今自动化领域技术发展的热点之一,被誉为自动化领域的计算机局域网。它的出现为分布式控制系统实现各节点之间实时、可靠的数据通信提供了强有力的技术支持。近年来,它具有的高可靠性和良好的错误检测能力受到重视,被广泛应用于汽车计算机控制系统和环境温度恶劣、电磁辐射强及振动大的工业环境。
 
 
 CAN信号并不是低电平表示0高电平表示1,而是当两根数据线在同一时刻,如果有电压差表示0无电压差表示1。
 Differential signal 差分信号:
 
   
   相对于单信号线传输的方式,使用差分信号传输具有如下优点:
 1. 抗干扰能力强:当外界存在噪声干扰时,几乎会同时耦合到两条信号线上,而接收端只关心两个信号的差值,所以外界的共模噪声可以被完全抵消。
 2. 有效抑制电磁干扰:同样的道理,由于两根信号的极性相反,他们对外辐射的电磁场可以相互抵消,耦合的越紧密,泄放到外界的电磁能量越少。
 3. 时序定位精确:由于差分信号的开关变化是位于两个信号的交点,而不像普通单端信号依靠高低两个阈值电压判断,因而受工艺,温度的影响小,能降低时序上的误差,同时也更适合于低幅度信号的电路
 
 CH32V307 /317作为沁恒(WCH)高性能 RISCV 架构 MCU,其 CAN 外设具备 多通道、高兼容性、灵活滤波、低功耗 四大核心特点,同时支持 CAN 2.0A/B 协议. CAN控制器局域网是一种用于串行数据通信的高性能通信协议。CAN 控制器提供了一个完整的 CAN 协议实现方案,支持 CAN 协议 2.0A 和 2.0B。CAN 控制器可以用来构建强大的局域网来实现安全的分布式实时控制,以较小的 CPU 负荷来处理大量的数据报文。
 
   
   
 
 
 一、核心硬件特性
 1. 多通道与协议兼容性
 双 CAN 控制器:内置 2 个独立 CAN 通道(CAN1、CAN2),支持同时与两条 CAN 总线通信,或实现主从备份、不同速率总线隔离(如一条 500Kbps 工业总线 + 一条 250Kbps 设备总线)。
 协议支持:完全兼容 CAN 2.0A(标准帧,11 位 ID)和 CAN 2.0B(扩展帧,29 位 ID)协议,支持数据帧(最长 8 字节数据)和远程帧,满足绝大多数 CAN 通信场景。
 2. 灵活的位时序与速率
 宽速率范围:通信速率可配置为 10Kbps ~ 1Mbps,通过调整 同步段(SJW)、时间段 1(BS1)、时间段 2(BS2)、分频系数(BRP) 实现精准适配,支持工业常用的 125Kbps、250Kbps、500Kbps 速率。
 时钟适配:CAN 外设时钟源自 APB1 总线(最高 108MHz),通过分频系数(BRP 范围 1~1024)灵活匹配不同总线时钟,无需额外外部时钟。
 
 3. 强大的滤波机制
 硬件滤波能力:每个 CAN 通道支持 14 个独立滤波组,每个滤波组可配置为 32 位或 16 位模式,支持两种滤波方式:
 掩码模式:通过“ID + 掩码”筛选符合范围的帧(如仅匹配 ID 高 11 位,忽略低 3 位)。
 列表模式:仅接收列表中明确指定的 ID 帧(如只接收 ID 为 0x317、0x318 的帧)。
 软件滤波扩展:支持通过自定义逻辑扩展滤波功能(如你提供的代码中 `USE_SOFT_FILTER` 宏),可实现更复杂的滤波规则(如多 ID 组合、数据段筛选)。
 二、可靠性与错误处理
 1. 完善的错误检测与管理
 错误检测:支持检测 CAN 总线的 位错误、填充错误、CRC 错误、形式错误、应答错误,并记录错误计数器(发送错误计数器 TEC、接收错误计数器 REC)。
 错误处理:
 支持自动离线管理(ABOM):当错误计数器超限(TEC > 127)时,自动进入离线状态,避免影响总线。
 支持自动唤醒(AWUM):离线后可通过总线活动自动唤醒,恢复通信。
 支持禁止自动重发(NART):配置为禁止后,发送失败时不重发,适合对实时性要求高的场景。
 2. 抗干扰设计
 总线引脚配置:CAN_RX 引脚支持上拉输入模式(如代码中 PB8 配置为 GPIO_Mode_IPU),可减少外部噪声干扰。
 错误限制:通过“总线关闭”“错误被动”等状态机,限制故障节点对总线的影响,保证总线整体稳定性。
 三、低功耗与实时性优化
 1. 低功耗模式支持
 支持在 MCU 进入 睡眠模式、停机模式 时,CAN 外设可配置为唤醒源:当总线有数据时,触发中断唤醒 MCU,适合电池供电的低功耗设备(如远程传感器)。
 2. 高效的中断与 FIFO
 多中断源:支持 FIFO 消息 pending、发送完成、错误警告等多种中断,可精准触发 CPU 处理,减少轮询开销。
 双接收 FIFO:每个 CAN 通道配备 2 个接收 FIFO(FIFO0、FIFO1),每个 FIFO 深度为 3 帧,可暂存接收数据,避免数据丢失(尤其在 CPU 处理其他任务时)。
 发送邮箱:配备 3 个发送邮箱,支持连续发送多帧数据,无需等待前一帧发送完成,提升发送效率。
 
 四、易用性与开发支持
 1. 丰富的开发资源
 标准库支持:提供完整的 CAN 外设驱动库(如代码中的 `CAN_Init`、`CAN_FilterInit` 等函数),无需直接操作寄存器,降低开发难度。
 示例代码:官方提供多种 CAN 通信示例(如正常收发、回环测试、软件滤波),可直接基于示例修改(如你提供的代码即为官方典型示例)。
 2. 调试便利性
 支持通过 DBGMCU 模块读取芯片 ID、配置调试模式,方便定位通信故障(如代码中 `DBGMCU_GetCHIPID()` 打印芯片 ID)。
 部分型号支持 CAN 总线调试工具(如 CANoe、USBCAN)直接连接,实时监控总线数据,快速排查问题。
 程序设计
 
 该函数是 CAN 通信的基础,完成 GPIO、CAN 外设、滤波规则的初始化,核心步骤如下:void CAN_Mode_Init( u8 tsjw, u8 tbs2, u8 tbs1, u16 brp, u8 mode )
 {
         GPIO_InitTypeDef GPIO_InitSturcture={0};
         CAN_InitTypeDef CAN_InitSturcture={0};
         CAN_FilterInitTypeDef CAN_FilterInitSturcture={0};
         
         RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE ); 
         RCC_APB1PeriphClockCmd( RCC_APB1Periph_CAN1, ENABLE );        
         
         GPIO_PinRemapConfig( GPIO_Remap1_CAN1, ENABLE);        
         
         GPIO_InitSturcture.GPIO_Pin = GPIO_Pin_9;
         GPIO_InitSturcture.GPIO_Mode = GPIO_Mode_AF_PP;                
         GPIO_InitSturcture.GPIO_Speed = GPIO_Speed_50MHz;
         GPIO_Init( GPIOB, &GPIO_InitSturcture);
         
         GPIO_InitSturcture.GPIO_Pin = GPIO_Pin_8;
         GPIO_InitSturcture.GPIO_Mode = GPIO_Mode_IPU;        
         GPIO_Init( GPIOB, &GPIO_InitSturcture);
         
         CAN_InitSturcture.CAN_TTCM = DISABLE;                
         CAN_InitSturcture.CAN_ABOM = DISABLE;                
         CAN_InitSturcture.CAN_AWUM = DISABLE;                
         CAN_InitSturcture.CAN_NART = ENABLE;                
         CAN_InitSturcture.CAN_RFLM = DISABLE;                
         CAN_InitSturcture.CAN_TXFP = DISABLE;
         CAN_InitSturcture.CAN_Mode = mode;
         CAN_InitSturcture.CAN_SJW = tsjw;                
         CAN_InitSturcture.CAN_BS1 = tbs1;                
         CAN_InitSturcture.CAN_BS2 = tbs2;                
         CAN_InitSturcture.CAN_Prescaler = brp;                
         CAN_Init( CAN1, &CAN_InitSturcture );
         
         CAN_FilterInitSturcture.CAN_FilterNumber = 0;                
 
 #if (Frame_Format == Standard_Frame)
 /* identifier/mask mode, One 32-bit filter, StdId: 0x317 */
         CAN_FilterInitSturcture.CAN_FilterMode = CAN_FilterMode_IdMask;         
         CAN_FilterInitSturcture.CAN_FilterScale = CAN_FilterScale_32bit; 
         CAN_FilterInitSturcture.CAN_FilterIdHigh = 0x62E0;         
         CAN_FilterInitSturcture.CAN_FilterIdLow = 0; 
         CAN_FilterInitSturcture.CAN_FilterMaskIdHigh = 0xFFE0;          
         CAN_FilterInitSturcture.CAN_FilterMaskIdLow = 0x0006;         
         
#ifndef USE_SOFT_FILTER
 /* identifier/mask mode, Two 16-bit filters, StdId: 0x317,0x316 */
 //        CAN_FilterInitSturcture.CAN_FilterMode = CAN_FilterMode_IdMask;        
 //        CAN_FilterInitSturcture.CAN_FilterScale = CAN_FilterScale_16bit;        
 //        CAN_FilterInitSturcture.CAN_FilterIdHigh = 0x62E0;        
 //        CAN_FilterInitSturcture.CAN_FilterIdLow = 0xFFF8;                
 //        CAN_FilterInitSturcture.CAN_FilterMaskIdHigh = 0x62C0;         
 //        CAN_FilterInitSturcture.CAN_FilterMaskIdLow = 0xFFF8;
 #endif                
         
 /* identifier list mode, One 32-bit filter, StdId: 0x317,0x316 */
 //        CAN_FilterInitSturcture.CAN_FilterMode = CAN_FilterMode_IdList;        
 //        CAN_FilterInitSturcture.CAN_FilterScale = CAN_FilterScale_32bit;        
 //        CAN_FilterInitSturcture.CAN_FilterIdHigh = 0x62E0;        
 //        CAN_FilterInitSturcture.CAN_FilterIdLow = 0;
 //        CAN_FilterInitSturcture.CAN_FilterMaskIdHigh = 0x62C0;         
 //        CAN_FilterInitSturcture.CAN_FilterMaskIdLow = 0;        
 #ifndef USE_SOFT_FILTER
 /* identifier list mode, Two 16-bit filters, StdId: 0x317,0x316,0x315,0x314 */
 //        CAN_FilterInitSturcture.CAN_FilterMode = CAN_FilterMode_IdList;        
 //        CAN_FilterInitSturcture.CAN_FilterScale = CAN_FilterScale_16bit;        
 //        CAN_FilterInitSturcture.CAN_FilterIdHigh = 0x62E0;        
 //        CAN_FilterInitSturcture.CAN_FilterIdLow = 0x62C0;        
 //        CAN_FilterInitSturcture.CAN_FilterMaskIdHigh = 0x62A0;         
 //        CAN_FilterInitSturcture.CAN_FilterMaskIdLow = 0x6280;        
 #endif                
 
 #elif (Frame_Format == Extended_Frame)
 /* identifier/mask mode, One 32-bit filter, ExtId: 0x12124567 */
         CAN_FilterInitSturcture.CAN_FilterMode = CAN_FilterMode_IdMask;                
         CAN_FilterInitSturcture.CAN_FilterScale = CAN_FilterScale_32bit;        
         CAN_FilterInitSturcture.CAN_FilterIdHigh = 0x9092;        
         CAN_FilterInitSturcture.CAN_FilterIdLow = 0x2B3C;        
         CAN_FilterInitSturcture.CAN_FilterMaskIdHigh = 0xFFFF;         
         CAN_FilterInitSturcture.CAN_FilterMaskIdLow = 0xFFFE;        
         
 #endif
 
         CAN_FilterInitSturcture.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;
         CAN_FilterInitSturcture.CAN_FilterActivation = ENABLE;
 
 #ifdef USE_INTERRUPT
         CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
         NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
 #endif
 
 #ifdef USE_SOFT_FILTER
        (*(__IO uint32_t *)(0x40006600)) |= 0x1;         
        (*(__IO uint32_t *)(0x4000660C)) |= 0x3;        
        (*(__IO uint32_t *)(0x40006640)) = 0;        
        (*(__IO uint32_t *)(0x40006644)) = 0;        
        (*(__IO uint32_t *)(0x4000661C)) |= 0x3;        
        (*(__IO uint32_t *)(0x40006600)) &= ~0x1;                 
         CAN_SoftFilterInit( &CAN_FilterInitSturcture );
 #else
         CAN_FilterInit( &CAN_FilterInitSturcture );
 #endif // USE_SOFT_FILTER        
         
 }
1..时钟使能:开启 GPIOB(CAN 引脚)、AFIO(引脚重映射)、CAN1 的时钟。
 2. GPIO 配置:
 PB9(CAN_TX):推挽复用输出模式,速率 50MHz。
 PB8(CAN_RX):上拉输入模式,防止信号干扰。
 3.引脚重映射:通过GPIO_Remap1_CAN1将 CAN1 的 TX/RX 映射到 PB9/PB8(部分 CH32 型号默认引脚可能不同,需重映射)。
 4.  CAN 外设配置:设置 CAN 工作模式(正常 / 回环 / 静默等)、位时序(决定通信速率)、错误处理方式(如是否自动离线管理)。
 滤波初始化:根据USE_SOFT_FILTER宏,选择初始化硬件滤波(CAN_FilterInit)或软件滤波(CAN_SoftFilterInit)。
 
 滤波机制(硬件 / 软件滤波)
 CAN 滤波的作用是筛选需要接收的 CAN 帧,忽略无关帧,减少 CPU 负担,代码支持两种滤波模式:
 硬件滤波(USE_SOFT_FILTER关闭):直接使用 CH32 的 CAN 硬件滤波模块,支持 32 位 / 16 位的 “掩码模式” 和 “列表模式”:
 掩码模式:通过 “ID + 掩码” 筛选符合范围的帧(如掩码0xFFE0表示只匹配 ID 的高 11 位)。
 列表模式:仅接收列表中明确指定的 ID 的帧(如只接收 ID 为 0x317 和 0x316 的帧)。
 软件滤波(USE_SOFT_FILTER开启):通过自定义结构体CANFilterStruct存储滤波规则,在CAN_ReceiveViaSoftFilter函数中遍历滤波组,软件判断接收帧是否符合规则,灵活性更高(支持更多滤波组)。
 
 USB逻辑分析仪测试:
 
 
   
 
 |