在汽车电子和工业领域里,经常会使用CAN总线方式来进行通信,CAN总线速率高,采用差分通信方式,因此抗干扰性强,常规走线可达十米以上。那么我们需要在实际使用中需要注意哪些问题呢?
CAN协议底层有阻塞和唤醒模式,且有冗余校验和错误帧识别,因此可靠性极高。不同于modbus总线使用485作为通信方式,CAN总线没有主从机之分,总线上的设备均可不定时广播消息,主控制器只需根据帧ID接受相应的有用帧而舍弃其他帧。
现在越来越多的主控制芯片都会集成1到2个CAN控制器,PLC厂商也会提供CAN拓展模块以支持CAN通信(此处不得不吐槽PLC厂商的捆绑销售)。本文将以stm32系列主控芯片为例,重点讲解程序中的要点。
发送部分
大多数芯片的CAN控制器会提供2个以上发送邮箱。所谓发送邮箱,理解为邮差更为合适。当需要向总线发送数据时,要先检查当前是否有空闲邮差,如果能找到空闲邮差则直接发送之,邮差会把你的数据送到总线上。因为发送数据需要时间,所以邮差也有空闲和忙碌一说。当你有多个信息需要发送,则会同时需要多个邮差。
如果邮差都出去送信了,那么此时发送数据一定会是失败的。因此在程序里需要加判断,如果返回值为no_mail,则需要等待。
/*发送数据,获取邮箱号*/
mbox = CAN_Transmit(CANx, &TxMessage);
//若获取邮箱失败,说明发送正忙,需等待重发
while(CAN_TxStatus_NoMailBox == mbox)
{
mbox = CAN_Transmit(CANx, &TxMessage);
__NOP();
}
一般芯片的CAN控制器配置有一个选项,叫做自动重传。如果用户使能这个自动重传的功能,当向总线发送数据出错时,软件会一直阻塞在发送函数处,直到数据重传完成。那么我们就可能会想到一种隐患,如果总线脱落,那么设备会由于数据无法发送出去而导致程序阻塞,对工业设备和汽车电子来说这绝对是致命的隐患。
/**
*MCR-NART 禁止报文自动重传 DISABLE-自动重传 ENABLE-禁止自动重传
*DISABLE:按照CAN标准,CAN硬件在发送报文失败时会一直 自动重传直到发送成功;
*ENABLE: CAN报文只被发送1次,不管发送的结果如何(成功、出错或仲裁丢失)。
*/
CAN_InitStructure.CAN_NART = ENABLE;
因此我们常规的操作是禁用自动重传,通过软件检测CAN数据发送状态,如果发送失败,则尝试自动重传N次,如果N次均失败,则不会继续传输,而是执行主程序。这样的话,即便CAN设备掉线,也不会影响设备的其他功能的运转。
/*在设定的时间内等待发送结束,时间到了未发送完亦退出,发送失败,防止假死*/
while((CAN_TransmitStatus(CANx, mbox) == CAN_TxStatus_Failed) && (Timeout < 0XFFFF))
{
Timeout++; /*等待发送结束*/
}
if(Timeout >= 0XFFFF)
{
CAN_Transmit(CANx, &TxMessage);
return 1; /*发送失败*/
}
但是使用软件检测CAN发送状态并不是万能的,这次我就遇到了一个麻烦,由于总线上挂载的一个设备,可能是阻抗匹配的不太好,导致CAN总线通信质量受影响。以下是用示波器截取到的部分质量不太好的数据。黄色线为CAN_H,蓝色线为CAN_L,正常情况下两者形成差分为显性,两者相等为隐形。但是看到最后的7个帧结束位显性电平不干净,疑似是信号反射引起的阻抗不匹配。
?这种情况下,使用寄存器提供的状态检查不能够检查出帧错误了,而是回报的成功状态,因此驱动层软件会误认为发送成功而直接结束。但是反应到总线上,这一帧的数据,一定是被抛弃了,不能被正确接收到。
可疑的是,stm32的CAN控制器确能够检测到这种发送失败,因为当我们使能自动重传后,总线上不再出现丢帧情况,说明stm32对这帧数据进行了重传。
因此,存在一种传输失败的情况,通过读取芯片的寄存器无法得知失败,但芯片的CAN控制器却能够得知失败并进行重传操作。
如果您觉得这篇文章帮到了你,请点赞或者留下您的评论,您的鼓励是我前进的动力~
关注博主威信平台?“嵌入式电子创客街” 获取更多及时技术分享~
|