嵌入式C语言环境下的CAN总线通讯协议

本文转载在我的微信公众号:古德曼汽车工业。

希望关注本专栏的朋友,也能一并关注微信公众号。

原文地址:嵌入式C语言环境下的CAN总线通讯协议

相信本公众号的读者对CAN通讯协议肯定都不陌生,各位在采集CAN总线信号、分析数据的时候是否想过,这些信号在电控单元(ECU)中通讯协议是如何实现的。本次内容介绍的是如何将CAN总线的通讯协议在C语言环境中实现。下面的内容需要有一点点的C语言基础,希望大家能坚持看完,一定会有所收获的。

1.结构体

通过前面文章《CAN总线(J1939)速成指南【1】》的介绍,对于CAN通讯协议有三个非常重要的信息,分别是报文ID、数据场、解析与偏移。实现通讯协议的第一步就是定义一个报文的结构体。

⚪ 定义报文ID

本次使用的例子是基于扩展ID,ID长度为29个位。由于C语言没有29位长度的数据类型所以使用32位数据类型UINT32。如果是标准ID使用16位数据类型UINT16即可。

小提示:数据类型

标准的C语言是没有UINT32、UINT16等这样的变量,这都是根据选用芯片的类型在宏中预先定义的。如:16位系统的UINT32 对应的C语言表达就是unsigned long,而对于32位系统的UINT32则对应的是usigned int。

⚪ 定义数据场

使用UINT8数据类型定义一个八字节的数组,用来存放数据场信息

⚪ 定义解析与偏移结构体

需要另外在定义一个结构体,用来存放偏移与解析值。如上图,包含两个Float型数据。

在我们的报文结构体中对每一个信号的解析信息进行实例化。上图中的红色部分只用来说明如何调用【解析与偏移】结构体,后面会导入我们真正的例子信息。

2.矩阵

CAN数据帧包含64位的数据场,矩阵就是用来定义数据场如何划分的。这部分在通讯协议中体现在每个信号的起始位置与数据长度。

这是【思想】使用Vetor CANdb++做的矩阵例子,以下称为【一号例子】。这个例子包含了一个16位数据、两个8位数据、一个32位数据,总共64位长度。数据位都对齐,不存在空位,十分完美。但是实际应用就不是这么美丽的了。

上图是【思想】定义的另一个矩阵,以下称为【二号例子】。这个矩阵就比较奇葩,一个12位数据、一个21位数据、一个3位数据、一个2位数据,并且数据与数据之间还存在着空位,整个数据场还剩下后面24位没利用到。

3.共同体

共同体这个知识点在C语言中比较冷门,【思想】在接触CAN协议栈之前也不是很清楚共同体用来干嘛的。所以就先介绍下这个知识点。

所谓共用体,它表示的是几个变量共用一个内存位置,在不同的时间保存不同的数据类型和不同长度的变量。在共用体中,所有的成员共用一个空间,并且同一时间只能储存其中一个成员变量的值。当一个共用体被声明时,编译程序自动地产生一个变量,其长度(以字节byte为单位,一个byte是8个二进制位)为联合中最长的数据类型长度的整数倍。

回到我们的CAN报文的数据场,由8个1字节的内存空间组成。每一个报文根据自身的矩阵信息对这个区域重新划分。

该段代码是【一号例子】,使用共同体描述矩阵信息。定义的共同体既可以通过字节数组(Bytes)数据进行读写,也可以根据位定义位结构体(Bits)的数据变量进行读写。在【解析与偏移】中也对结构体进行实例化,待后序初始化中进行赋值。

【二号例子】由于数据位没有对齐并且存在空位,所以处理起来就稍微麻烦点。首先要处理数据长度不是常见的8、16、32,例如第一个数据是一个12位的数据,这里就使用【UINT16 Bit12:12;】先定义一个UINT16的数据,在通过【:12】定义有效数据长度只有12位。然后就是要处理空位的部分,正如上面矩阵中显示。第12、36、37为空位,就根据空位的长度定义一个UINT8的数据类型将空位补上。本例中的【UINT8 EMPTY_1:2;】。这里注意要优先保证数据位对齐,主要为了大小端字节序的自动化处理,这是一个很恶心的事情,以后会有专门的内容介绍。

补充空位后的数据块位长度一定要为8的倍数,实现上图的对齐效果。其实共同体这个方法,适用于大部分的通讯协议,比如TCPIP、485、RS232等。

4.初始化

以上就已经介绍了如何在结构体中定义通讯协议,真正开始使用前还需要对结构体实例化,并对数据初始化。

根据前面创建的结构体名称,实例化为变量

初始化数据部分从上到下顺序分别为:

  • 对报文ID进行赋值,这里的ID在前面通过使用宏定义;

  • 将64位的数据场全部填0;

  • 对解析偏移结构体的参数进行赋值,填充位是不需要定义解析偏移参数的;

5.接收解析与发送编码

这次【思想】挑选的两个例子,正好一个是发送、一个是接收,就能够很好的来说明解析与编码。

例如对Spd信号的解析,左边的红框为BSW->ASW的接口变量,直接访问结构体中共同体下的Spd变量,与解析偏移结构体中的解析值与偏移值进行运算得到Spd的实际数值。至于ASW与BSW接口如何制作请见本公众号文章《Simulink代码生成应用教程

对于发送报文就需要经过编码处理,红色框为ASW->BSW的接口变量,将接口变量与解析偏移结构体中的解析值与偏移运算。得到需要发送报文结构体中共同体下的发送数据。该运算与上面的解析运算为逆运算。

6.尾声

到目前为止,【思想】介绍了如何在C语言中实现CAN总线的报文结构,及其初始化、解析、编码等数据操作。由于篇幅限制,飞思卡尔与Intel的字节序问题及接口自动生成技术,将放到后续的文章中来讨论。

 

推荐阅读

 

-----=========推荐阅读==========-----

■ Simulink代码生成提高教程

■ 增程式混合动力系统动力经济性仿真

■ S-Funciton应用实例

■ 汽车工程师眼中的C#

■ 工况路普的采集与数据处理

■ 混合动力节油的秘密-发动机万有特性

■ AVL-CRUISE纯电动仿真策略提高教程

■ AVL-CRUISE纯电动模型仿真策略

■ Simulink代码生成应用教程

■ Sinmulink代码生成基础体验教程

■ 燃料电池车(FCHEV)动力经济性建模与仿真

  • 7
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
嵌入式Linux CAN通讯C是指在嵌入式系统中使用Linux操作系统,并使用C语言编程实现CAN通讯功能。 CAN(Controller Area Network)是一种常用于嵌入式系统中的串行通信总线标准,用于连接不同设备和模块,实现数据的传输与通讯。在嵌入式系统中,使用CAN通讯可以方便地实现设备之间的数据交互和协同工作。 嵌入式Linux是Linux操作系统的一个衍生版本,经过特殊的优化和裁剪,适用于嵌入式系统的硬件资源限制和特定需求。使用嵌入式Linux可以充分利用Linux的丰富生态和强大的功能,快速开发出符合嵌入式系统要求的应用。 在嵌入式Linux中实现CAN通讯功能,需要根据硬件平台的要求选择相应的CAN驱动,并通过C语言编程与驱动进行交互。一般来说,通过访问Linux系统中的设备文件或使用相关系统调用来控制和处理CAN总线数据的接收和发送。可以使用Linux提供的套接字(socket)、文件(file)和字符设备(chrdev)等方式来实现CAN的读写操作,并利用C语言的数据结构和函数来处理CAN数据的解析和处理。 可以基于SocketCAN(Socket Controller Area Network)接口来进行CAN通讯,它是Linux每个CAN总线驱动实现的虚拟设备接口。通过SocketCAN,我们可以通过网卡设备文件进行数据收发,并在C程序中使用socket编程接口进行CAN数据包的发送和接收操作。 总之,嵌入式Linux CAN通讯C是一种使用Linux操作系统和C语言编程技术实现的CAN通讯功能。通过选择合适的CAN驱动和使用对应的系统调用和接口,可以实现CAN数据的收发、解析和处理,满足嵌入式系统中设备间的通讯需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值