踩坑了,踩坑了!这次又败在CAN总线手上了!

前言 最近负责的一个项目用的主控芯片是stm32f407igt6,需要和几个电机控制器进行通讯,有很多参数需要进行监控。
有一个问题一直无法解决。在开启can的接收中断,接收不到数据,问题卡了很久,下面简单分享一下解决的过程和思路。 目录 背景
can总线
can控制器
can收发器
调试过程
硬件排查
can分析仪
芯片can控制器调试
总结
can总线 can总线是一种串行通信协议,用于在微控制器和其他设备之间传输数据。can总线通常用于汽车、工业自动化和机器人等领域。本号发过很多can总线干货文章,大家可以点击下方标题直接阅读。 秀!靠这篇我竟然2天理解了can协议!
秒懂can总线,你学会了吗?
can总线不加终端电阻,会出现什么后果?
为什么can总线最高速度为1mbps?
从今天起,你就是can专家了。
3个原因告诉你,can为什么比rs-485更好?
详解can总线协议
...更多can总线可以关注下方公众号在历史消息中搜索
can总线的硬件通常由以下几个部分组成:
控制器区域:包括can控制器和can收发器; 总线电缆:用于连接can总线上的所有设备; 终端电阻:用于终止总线,以减少反射和信号干扰; 外部电源:用于为can总线提供电源; can总线的控制器区域通常包括can控制器和can收发器。 can控制器负责处理can总线上的数据传输,包括数据发送和接收、错误检测和纠正等; can收发器则负责将can控制器的信号转换为总线上的电信号,并将总线上的电信号转换为can控制器可以理解的信号。 can控制器 主板上的芯片stm32f407igt6中带有两路的can控制器,分别为can1 和 can2,具体如下图所示;
can收发器 主板上使用的是芯片sn65hvd230,这是ti公司的一款性能强大且具体低功耗功能的can收发器,具体的典型应用电路如下所示;
调试过程 硬件排查 设备的调试过程中,首先要确保硬件链路上是否正常。最常见的方法就是直接用示波器进行检查。具体如下所示;
检查can控制器和can收发器之间是否正常; 检查can收发器的差分信号是否正常,这里可能要了解一下can总线电平的显性电平和隐性电平的特点,以及can底层协议的细节,会比较复杂; 个人比较推荐使用上述步骤检查硬件链路是否存在问题,那如何对数据进行分析呢?当然可以对着示波器的波形一点一点进行分析,但是这样是很低效的,这里我建议使用can分析仪进行数据抓包,下面我们继续进行介绍。 can分析仪 至于数据传输是否正确,可以使用can盒进行数据监听,下面是我使用的一款can分析仪,如图;
将can分析仪的can_h和can_l分别并联到can收发器的can_h和can_l上,然后打开can分析仪厂家提供的pc软件,就可以对can总线的数据进行监听;
将can分析仪接入到can总线; 将can分析仪连接到电脑(这里是usb接口),需要配置相同的波特率; 打开can分析仪配套的pc软件,进行数据的收发;   进行到这里,我在项目中遇到的问题是,发送正常,但是stm32f407无法接收到连续的数据,可以接收到一次数据,后面便无法再进入中断。这时候,只能再芯片端进行debug了。 芯片can控制器调试 这里的代码用的hal库,库版本相对来说比较老,是v1.7.10版本的,如下图所示;
当时我把项目升级到最新的hal库,发现can部分的驱动改动比较大,另外,下文都是基于v1.7.10版本的hal库。can控制器的初始化代码如下所示;void mx_can_init(void){can_filterconftypedef sfilterconfig;/*can单元初始化*/ hcan.instance = canx; /* can外设 */ hcan.ptxmsg = &txmessage; hcan.prxmsg = &rxmessage; hcan.init.prescaler = 6; /* btr-brp 波特率分频器 定义了时间单元的时间长度 42/(1+6+7)/6 = 500kbps */ hcan.init.mode = can_mode_normal; /* 正常工作模式 */ hcan.init.sjw = can_sjw_1tq; /* btr-sjw 重新同步跳跃宽度 1个时间单元 */ hcan.init.bs1 = can_bs1_6tq; /* btr-ts1 时间段1 占用了6个时间单元 */ hcan.init.bs2 = can_bs2_7tq; /* btr-ts1 时间段2 占用了7个时间单元 */ hcan.init.ttcm = disable; /* mcr-ttcm 关闭时间触发通信模式使能 */ hcan.init.abom = enable; /* mcr-abom 自动离线管理 */ hcan.init.awum = enable; /* mcr-awum 使用自动唤醒模式 */ hcan.init.nart = disable; /* mcr-nart 禁止报文自动重传 disable-自动重传 */ hcan.init.rflm = disable; /* mcr-rflm 接收fifo 锁定模式 disable-溢出时新报文会覆盖原有报文 */ hcan.init.txfp = disable; /* mcr-txfp 发送fifo优先级 disable-优先级取决于报文标示符 */ hal_can_init(&hcan);/*can过滤器初始化*/ sfilterconfig.filternumber = 0; /* 过滤器组0 */ sfilterconfig.filtermode = can_filtermode_idmask; /* 工作在标识符屏蔽位模式 */ sfilterconfig.filterscale = can_filterscale_32bit; /* 过滤器位宽为单个32位。*//* 使能报文标示符过滤器按照标示符的内容进行比对过滤,扩展id不是如下的就抛弃掉,是的话,会存入fifo0。*/ sfilterconfig.filteridhigh = 0x0000; //(((uint32_t)0x131416; /* 要过滤的id高位 */ sfilterconfig.filteridlow = 0x0000; //(((uint32_t)0x1314tsr, can_tsr_rqcp0 | can_tsr_rqcp1 | can_tsr_rqcp2 | can_flag_txok0 | can_flag_txok1 | can_flag_txok2); } } tmp1 = __hal_can_msg_pending(hcan, can_fifo0); tmp2 = __hal_can_get_it_source(hcan, can_it_fmp0);/* check end of reception flag for fifo0 */if((tmp1 != 0u) && tmp2) {/* call receive function */can_receive_it(hcan, can_fifo0); } tmp1 = __hal_can_msg_pending(hcan, can_fifo1); tmp2 = __hal_can_get_it_source(hcan, can_it_fmp1);/* check end of reception flag for fifo1 */if((tmp1 != 0u) && tmp2) {/* call receive function */can_receive_it(hcan, can_fifo1); }/* set error code in handle */ hcan->errorcode |= errorcode; tmp1 = __hal_can_get_flag(hcan, can_flag_ewg); tmp2 = __hal_can_get_it_source(hcan, can_it_ewg); tmp3 = __hal_can_get_it_source(hcan, can_it_err);/* check error warning flag */if(tmp1 && tmp2 && tmp3) {/* set can error code to ewg error */ hcan->errorcode |= hal_can_error_ewg; } tmp1 = __hal_can_get_flag(hcan, can_flag_epv); tmp2 = __hal_can_get_it_source(hcan, can_it_epv); tmp3 = __hal_can_get_it_source(hcan, can_it_err); /* check error passive flag */if(tmp1 && tmp2 && tmp3) {/* set can error code to epv error */ hcan->errorcode |= hal_can_error_epv; } tmp1 = __hal_can_get_flag(hcan, can_flag_bof); tmp2 = __hal_can_get_it_source(hcan, can_it_bof); tmp3 = __hal_can_get_it_source(hcan, can_it_err); /* check bus-off flag */if(tmp1 && tmp2 && tmp3) {/* set can error code to bof error */ hcan->errorcode |= hal_can_error_bof; } tmp1 = hal_is_bit_clr(hcan->instance->esr, can_esr_lec); tmp2 = __hal_can_get_it_source(hcan, can_it_lec); tmp3 = __hal_can_get_it_source(hcan, can_it_err);/* check last error code flag */if((!tmp1) && tmp2 && tmp3) { tmp1 = (hcan->instance->esr) & can_esr_lec;switch(tmp1) {case(can_esr_lec_0):/* set can error code to stf error */ hcan->errorcode |= hal_can_error_stf;break;case(can_esr_lec_1):/* set can error code to for error */ hcan->errorcode |= hal_can_error_for;break;case(can_esr_lec_1 | can_esr_lec_0):/* set can error code to ack error */ hcan->errorcode |= hal_can_error_ack;break;case(can_esr_lec_2):/* set can error code to br error */ hcan->errorcode |= hal_can_error_br;break;case(can_esr_lec_2 | can_esr_lec_0):/* set can error code to bd error */ hcan->errorcode |= hal_can_error_bd;break;case(can_esr_lec_2 | can_esr_lec_1):/* set can error code to crc error */ hcan->errorcode |= hal_can_error_crc;break;default:break; }/* clear last error code flag */ hcan->instance->esr &= ~(can_esr_lec); }/* call the error call back in case of errors */if(hcan->errorcode != hal_can_error_none) {/* clear erri flag */ hcan->instance->msr = can_msr_erri; /* set the can state ready to be able to start again the process */ hcan->state = hal_can_state_ready;/* disable interrupts: *//* - disable error warning interrupt *//* - disable error passive interrupt *//* - disable bus-off interrupt *//* - disable last error code interrupt *//* - disable error interrupt *//* - disable fifo 0 message pending interrupt *//* - disable fifo 0 overrun interrupt *//* - disable fifo 1 message pending interrupt *//* - disable fifo 1 overrun interrupt *//* - disable transmit mailbox empty interrupt */ __hal_can_disable_it(hcan, can_it_ewg |can_it_epv |can_it_bof |can_it_lec |can_it_err |can_it_fmp0|can_it_fov0|can_it_fmp1|can_it_fov1|can_it_tme);/* call error callback function */ hal_can_errorcallback(hcan); } } 最后,找到无法进入接收中断的原因,是can总线出现发送错误的情况,从而触发了错误警告标志位ewgf,进而将关闭了消息挂起中断。 总结 本文简单介绍了在stm32f407上的can总线调试过程,项目中难免会遇到各种问题,解决之后,大家要及时做好总结和复盘,技术在于积累和沉淀。

工程达人对于监控工程报价的分享心得
基于Mistral DT-309B蓝牙真空管放大器简介
风光互补系统运行问题及解决方案
EMUI10可实现双系统同屏操作 打破Windows与Android的系统壁垒
手持式数字万用表 Faith368
踩坑了,踩坑了!这次又败在CAN总线手上了!
共模电感生产厂家教你通过六个参数来做共模电感参数选型gujing
看到科技全景视频会议系统,三合一集成设计即插即用
锂电池行业规范出台 产业集中度将提升
NVIDIA发布NeuralVDB 可将内存占用量减少高达100倍
汽车连接器的应用特点以及未来发展趋势
强大的RFID技术
电压可以是负的吗?
5G融入更多中国智慧 中国有望成为全球最大的5G市场
探索未知,是人类社会进步的源动力
易华录受邀出席上海合作组织产业链供应链论坛数字城市与智慧生态平行论坛
常见的锂电单位符号应该怎么写
机房动力环境监控系统的组成部分及功能特点
Origin Q一周速览:另辟蹊径!为半导体材料研究献计献策
利用电量计芯片实现双节串联锂电池的快速智能充电