之前在实际项目使用 MM32 MCU CAN 外设过程中会遇到一些问题,本文主要描述和记录调试过程时候的相关问题以及对应的处理意见。
1.直接使用灵动微官网例程调试(附,灵动微MM32 MCU 资料下载链接: http://www.mindmotion.com.cn/download1.aspx),can 盒子与设备不能正常通讯,且一次都不行。
- 需要根据 DS手册中引脚功能定义确定一下实际硬件使用到的 CAN_TX / CAN_RX 脚与程序中默认配置是否一致,且 CAN_H/CAN_L 接线上没有接反 ;
- 需要确定 mcu 与can收发器芯片的电源电压是否匹配,考虑到实际需要抗干扰性更强 ,建议统一使用 5v 供电较好 ;
- 需要确定 mcu 的时钟源是否存在异常,这里强烈建议系统时钟使用 外部晶振,由于 can 通讯本身对于位时间的偏差容忍度极低,不像 uart 能到 3%-6% 还可以通讯上 ;
- 需要确定 can 盒子上位机的配置中波特率选项是否与程序中配置匹配得上,或者用自动波特率识别。
以上几点检查完毕用再使用官网例程基本就可以正常通讯了。
2.在总线上的设备中,会有不固定的某几个设备出现 发送数据丢帧率较大,偶尔还会一直发送不出去必须通过复位方可恢复,但接收正常的情况。
- 引发的原因可能是 can 总线上存在较大竞争关系,比如使用了 同一个 ID 号去发送数据,或者循环发送时间间隔太短,导致数据没有正常发出 ;
- 可以尝试在发送前去判断一下所有与发送相关的 can 状态位 , 直到判断为没有发送任务占用总线时再去发送 ;
- 可以尝试在发送前延时几个 ms ,增加错开数据帧碰撞的几率 ;
- 可以在 Send_CANFrame 发送函数里面调用 CAN_Peli_TransmitRepeat 而不用 CAN_Peli_Transmit ,这样相当于增加了硬件重发机制 ,且 CAN_Peli_TransmitRepeat 的定义需要改写为如下:
- void CAN_Peli_TransmitRepeat(CanPeliTxMsg* PeliTxMessage)
- {
- CAN1_PELI->FF = (PeliTxMessage->FF << 7) | (PeliTxMessage->RTR << 6) | (PeliTxMessage->DLC);
- if (((FunctionalState)PeliTxMessage->FF) != ENABLE) {
- CAN1_PELI->ID0 = (PeliTxMessage->IDHH);
- CAN1_PELI->ID1 = (PeliTxMessage->IDHL & 0xE0);
- if ((FunctionalState)(PeliTxMessage->RTR) != ENABLE) {
- CAN1_PELI->DATA0 = PeliTxMessage->Data[0];
- CAN1_PELI->DATA1 = PeliTxMessage->Data[1];
- CAN1_PELI->DATA2 = PeliTxMessage->Data[2];
- CAN1_PELI->DATA3 = PeliTxMessage->Data[3];
- CAN1_PELI->DATA4 = PeliTxMessage->Data[4];
- CAN1_PELI->DATA5 = PeliTxMessage->Data[5];
- CAN1_PELI->DATA6 = PeliTxMessage->Data[6];
- CAN1_PELI->DATA7 = PeliTxMessage->Data[7];
- }
- }
- else {
- CAN1_PELI->ID0 = PeliTxMessage->IDHH;
- CAN1_PELI->ID1 = PeliTxMessage->IDHL;
- CAN1_PELI->DATA0 = PeliTxMessage->IDLH;
- CAN1_PELI->DATA1 = PeliTxMessage->IDLL;
- if ((FunctionalState)(PeliTxMessage->RTR) != ENABLE) {
- CAN1_PELI->DATA2 = PeliTxMessage->Data[0];
- CAN1_PELI->DATA3 = PeliTxMessage->Data[1];
- CAN1_PELI->DATA4 = PeliTxMessage->Data[2];
- CAN1_PELI->DATA5 = PeliTxMessage->Data[3];
- CAN1_PELI->DATA6 = PeliTxMessage->Data[4];
- CAN1_PELI->DATA7 = PeliTxMessage->Data[5];
- CAN1_PELI->DATA8 = PeliTxMessage->Data[6];
- CAN1_PELI->DATA9 = PeliTxMessage->Data[7];
- }
- }
- (CAN1_PELI->MOD & CAN_MOD_STM) ? (CAN1->CMR = CAN_CMR_GTS | CAN_CMR_AT) : (CAN1->CMR = CAN_CMR_TR);
- }
3. 在总线上的设备中,会有不固定的某几个设备出现接收不到数据或者数据错乱情况,表现为 can 死机或者异常现象。
- 导致该问题发生可能由于负载量加大后 can 总线异常概率加大,或者挂在总线上的设备间 位时间存在一些差异也会造成 can 总线异常和错误增加 ;
- 如果应用允许可以适当降低 can 波特率,适当调高主频加快程序处理速率 ;
- 如果应用限制只能用内部时钟 ,那只能再尝试调低主频 ,连接线缆改用抗干扰性更强的双绞带屏蔽 RVVP 线 ;
- 如果条件允许,可以将总线上的 can 设备都校对一下波特率(汽车前装应用上有标准规定 总线上的设备出厂前都必须做好校对,防止一个设备的差异性影响到整个can总线),具体可以这样做 : 通过示波器抓取 can 发送数据的位时间 ,将其与配置的理想波特率对比看有多大差异,再在 CAN_AutoCfg_BaudParam 这个函数中将底层寄存器做适当调整,具体的 can 波特率计算可以参见 UM 手册的 can 章节 - 位时间特性 ;
- 对于发送端,软件架构中需要增加超时重传机制 ;对于接收端,需要在软件中加入实时判断 can 异常状态 ,还有 can 的错误计数是否大于127,有异常或者错误计数满了的话对 can 时钟进行复位并且重新配置 can 模块 ;
- 接收时可以尝试做清除 FIFO 处理 ,如以下:
- 当然在实际整机测试或者应用过程中还会遇到 CAN 外设其它的一些问题,本文不做过多扩展。为增强通讯的健壮性,掌握以上提及到的一些措施显得尤为重要。
- //在大循环里面 判断一下接收缓冲器状态 如果满了就清一下 FIFO
- if((CAN1_PELI->SR & 0X01) || ((CAN1_PELI->SR & 0X02) == 0x02))
- {
- CAN1_PELI->CMR |= 0x08;
- CAN1_PELI->CMR |= 0x04;
- }