0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

英创信息技术C/C#开发基于WEC7的CAN通讯介绍

英创信息技术 来源:英创信息技术 作者:英创信息技术 2020-01-17 10:01 次阅读

英创EM335x工控主板,使用的Cortex-A8及WEC7操作系统。本文以EM335x工控主板光盘例程为例,简单介绍一下C和C#代码如何调用WEC7平台下CAN驱动,实现CAN通信的方法。

C代码

客户可以在自己工程中添加例程中的EM335X_CAN.h及EM335X_CAN.cpp,使用里面封装好的EM335X_CAN类。
#include 'EM335X_CAN.h'
EM335X_CAN can;

打开CAN
调用EM335X_CAN类的OpenCAN方法。比如用250Kbps打开CAN1(默认只有CAN1)。
DWORD dwCanNo = 1;
DWORD dwBaudRate = 250000;
can.OpenCAN( dwCanNo, dwBaud );

关闭CAN
调用EM335X_CAN类的CloseCAN方法。
can.CloseCAN( );

发CAN数据包
调用EM335X_CAN类的WriteCAN方法。
can.WriteCAN(&canmsg );

接收CAN数据包

例程中使用了一个独立的线程来接收。然后将收到的数据传递给PackagePro函数处理。参数一为数据buffer指针,参数二为数据的长度。
int EM335X_CAN::PackagePro(char* pBuf , int len)

用户可以根据应用具体需求,添加相应的逻辑代码。

CAN发送接收数据包结构体定义
不论是CAN发送,还是CAN接收,都是以数据包为单位发送接收的。单个数据包大小为16字节,结构体定义如下:
typedef struct {
CAN_ID id;
BYTE dlc;
BYTE data[8];
}CAN_MESSAGE,*PCAN_MESSAGE;

id,一个CAN_ID的结构体,该结构体定义在下面说明。
dlc,1字节,数据长度,取值0-8;
data,8字节,传输的数据。

注:因为结构体对齐的原因,该结构体大小为16字节。

CAN_ID结构体是一个整型,32位,用来记录CAN通信所需的ID信息
typedef struct{
unsigned int id:29;
unsigned int reserved:1;
unsigned int remote:1;
unsigned int extended:1;
}CAN_ID;

id,结构体整型的低29位,表示id号。
reserved,第30位,用来标记是接收的数据包,还是发送的数据包,默认设置为0即可。
remote,第31位,用来设置是数据帧还是远程帧。0为数据帧,1为远程帧。
extended,第32位,用来设置是标准帧还是扩展帧。0为标准帧,1为扩展帧。

CAN过滤条件Filter设置
EM335x同样支持数据包过滤功能,设置Filter可以使得CAN只接收自己需要的数据包。

调用EM335X_CAN类的SetFilter方法,可以添加一个过滤条件,或者删除一个已有的过滤条件。例如:
bResult = can.SetFilter( &Filter, FALSE );

第一个参数为过滤条件参数,为一个CAN_FILTER的结构体,在下面有说明。第二个参数如果为FALSE,则表示添加该过滤条件,如果为TRUE,则表示删除已有的该过滤条件。

有多个过滤条件的情况下,只要数据包可以满足任意一个过滤条件,那么该数据包就可以被接收。

CAN过滤条件Filter结构体定义
CAN_FILTER结构体定义如下:(CAN_ID结构体的定义前面数据包结构体里有说明)
typedef struct {
CAN_ID id;
CAN_ID mask;
}CAN_FILTER,*PCAN_FILTER;

这里的过滤逻辑如下:


假设收到的数据包里的id,我们记为id_message,与过滤条件中的filter参数里的id和mask满足条件:(id_message&mask) == (id&mask),那么该数据包就可以接收,也就是说,mask表示需要进行对比的位,如果数据包的id这几位与filter设置里的id的这几位相同,那么该数据包就可以接收。

比如:
一个filter的mask = 0x03,即2进制的b0000 0011,即需要比较最后的两位。
filter的id = 0x02,即2进制的b0000 0010。
那么数据包id如果最后两位为 10,该数据包就可以通过过滤条件被接收。
数据包id = 0xF7,即2进制b1111 0111,无法接收。
数据包id = 0xE6,即2进制b1110 0110,可以接收。
数据包id = 0x2E,即2进制b0010 1110,可以接收。

CAN环回模式设置
环回模式为,可以选择板子自己发送的数据包,是否自己也能同时接收到。

调用EM335X_CAN类的CAN_Loopback方法,如果希望自己发送的CAN包,自己也能接收到,那么设置第二个参数为TRUE。如果希望关闭环回功能,那么第二个参数设置为FALSE。

CAN其它命令
EM335X_CAN类的CanCommand方法可以控制CAN复位,启动和停止。
BOOL CanCommand( CAN_COMMAND eCommand);

参数CAN_COMMAND是一个枚举型,它的定义如下,STOP= 0,START =1,RESET=3:
typedef enum {
STOP,
START,
RESET
} CAN_COMMAND;

1、复位CAN
CAN复位会重置CAN驱动里的各个寄存器值,并执行相关的初始化操作。

在打开CAN的时候,OpenCAN函数里已经调用了该函数实现CAN复位。用户可以根据自己应用的实际情况,决定在什么时机执行CAN复位。

2、启动CAN
在设置好CAN波特率,环回,filter等参数后,CAN驱动线程并没有马上启动,需要执行CAN启动,CAN线程才开始工作。

在打开CAN的时候,OpenCAN函数在设置完参数后调用CAN启动。用户可以根据自己应用的实际情况,决定在什么时机执行该函数,例如:当CAN接收线程的接收到错误事件时,可以在错误处理代码里添加停止CAN,和重新启动CAN的调用。

3、停止CAN
停止CAN会关闭CAN驱动线程,在关闭CAN的时候,CloseCAN函数调用CAN停止。

C#代码

C#代码参考了C代码,相对C接口稍微做了调整。我们同样封装了一个CAN的类在EM335x_CAN_API.cs中,方便客户添加到自己工程中。

打开CAN
打开CAN的流程为:打开CAN设备,获得设备句柄,初始化CAN,然后设置CAN的参数(波特率,环回模式),创建CAN接收线程,最后启动CAN,然后CAN驱动线程开始工作。

1、打开CAN设备
int CanNo = 1;
hCAN = CAN.OpenCAN(CanNo);

2、重置CAN
执行Reset操作,初始化CAN。
bRet = CAN.CAN_Command(hCAN, (uint)CAN_COMMAND.RESET);

3、设置波特率
设置CAN的波特率,如250Kbps:
uBaud = 250000;
bRet = CAN.CAN_SetBaudRate(hCAN, uBaud);

4、设置CAN环回模式
如果希望自己发送的CAN包,自己也能接收到,那么可以设置第二个参数为1,例程中暂时关闭该功能,所以设置的0。
bRet = CAN.CAN_Loopback(hCAN, 0);

5、创建单独的接收线程
因为接收时,函数需要等待CAN接收事件,为阻塞状态,不宜直接写在主线程中,这里添加一个接收线程,专门处理CAN数据接收。
创建线程:
revThread = new Thread(new ThreadStart(BeginReceive));
threadStop = false;
revThread.Start();//启动waitforMessage线程

6、启动CAN
当准备就绪,就可以启动CAN设备了。
bRet = CAN.CAN_Command(hCAN, (uint)CAN_COMMAND.START);

关闭CAN
主要是结束接收线程,停止CAN,及关闭CAN设备句柄等。
revThread.Abort();//结束线程
revThread.Join();
bRet = CAN.CAN_Command(hCAN, (uint)CAN_COMMAND.STOP);
bRet = CAN.CloseCAN(hCAN);

发CAN数据包
调用WriteFile发送CAN数据包。
bRet = CAN.WriteFile(hCAN, ref pktSend, CAN.sizePacket, ref uLen, 0);

接收CAN数据包
调用ReadFile发送CAN数据包。
bResult = CAN.ReadFile(hCAN, ref pktRev, CAN.sizePacket, ref uLen, 0);

CAN发送接收数据包结构体定义
不论是CAN发送WriteFile,还是CAN接收ReadFile,都是以数据包为单位发送接收的。单个数据包大小为16字节,结构体定义如下:
[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct CAN_MESSAGE
{
[FieldOffset(0)]
public uint id;
[FieldOffset(4)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public byte[] data;//数据字节
}

id是一个整型4字节,32位,用来记录CAN通信所需的ID信息。
id的低29位,表示id号。
id的第30位,用来标记是接收的数据包,还是发送的数据包。
id的第31位,用来设置是数据帧还是远程帧。该位为0则是数据帧,该位为1则是远程帧。
id的第32位,用来设置是标准帧还是扩展帧。该位为0则是标准帧,该位为1则是扩展帧。

data为12字节byte数组。
data[0]为CAN数据包内数据的长度,取值0-8;
data[1]-data[8],8字节,为CAN数据包内传输的数据。
data[9]-data[11]未使用。

注:结构体这样设计的主要原因还是因为要和C代码的驱动接口,做成这样效率会高些。

例如,我们要发送一个,id为5的标准数据帧,数据长度为3,分别是0x01,0x02,0x03,代码如下:
CAN_MESSAGE pktSend = new CAN_MESSAGE();
pktSend.id = 5;
//如果是数据帧就不变,如果是远程帧就
//pktSend.id = pktSend.id | 0x20000000;//remote
//如果是标准帧就不变,如果是扩展帧就
//pktSend.id = pktSend.id | 0x40000000;//extended
pktSend.data[0] = 3;
pktSend.data[1] = 0x01;
pktSend.data[2] = 0x02;
pktSend.data[3] = 0x03;

例如,我们要发送一个,id为55的扩展帧,数据长度为6,分别是0x04,0x04,0x04,0x05,0x05,0x05,代码如下:
CAN_MESSAGE pktSend = new CAN_MESSAGE();
pktSend.id = 5;
//如果是数据帧就不变,如果是远程帧就
//pktSend.id = pktSend.id | 0x20000000;//remote
//如果是标准帧就不变,如果是扩展帧就
pktSend.id = pktSend.id | 0x40000000;//extended
pktSend.data[0] = 6;
pktSend.data[1] = 0x04;
pktSend.data[2] = 0x04;
pktSend.data[3] = 0x04
pktSend.data[4] = 0x05;
pktSend.data[5] = 0x05;
pktSend.data[6] = 0x05;

CAN过滤条件Filter设置
EM335x同样支持数据包过滤功能,设置Filter可以使得CAN只接收自己需要的数据包。

调用EM335X_CAN类的SetFilter方法,可以添加一个过滤条件,或者删除一个已有的过滤条件。例如:
CAN.CAN_SetFilter (hCAN, Filter, false );

第一个参数为CAN句柄,第二个参数为过滤条件参数,为一个CAN_FILTER的结构体,在下面有说明。第三个参数如果为FALSE,则表示添加该过滤条件,如果为TRUE,则表示删除已有的该过滤条件。

有多个过滤条件的情况下,只要数据包可以满足任意一个过滤条件,那么该数据包就可以被接收。

CAN过滤条件Filter结构体定义
CAN_FILTER结构体定义如下:
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct CAN_FILTER
{
[FieldOffset(0)]
public uint id;
[FieldOffset(4)]
public uint mask;
}

这里的过滤逻辑如下:

假设收到的数据包里的id,我们记为id_message,与过滤条件中的filter参数里的id和mask满足条件:(id_message&mask) == (id&mask),那么该数据包就可以接收,也就是说,mask表示需要进行对比的位,如果数据包的id这几位与filter设置里的id的这几位相同,那么该数据包就可以接收。

比如:
一个filter的mask = 0x03,即2进制的b0000 0011,即需要比较最后的两位。
filter的id = 0x02,即2进制的b0000 0010。
那么数据包id如果最后两位为 10,该数据包就可以通过过滤条件被接收。
数据包id = 0xF7,即2进制b1111 0111,无法接收。
数据包id = 0xE6,即2进制b1110 0110,可以接收。

详细信息,可以电话,邮件或论坛提问方式咨询英创工程师。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式主板
    +关注

    关注

    7

    文章

    6064

    浏览量

    34613
收藏 人收藏

    评论

    相关推荐

    STM32F103C8 UART1, I2C1, CAN冲突问题怎么解决?

    ST芯片型号: STM32F103C8T6 PB7,PB6用于UART1 PB8,PB9用于做CAN. 问题:I2C1_REMAP关闭,影响PB7
    发表于 04-08 08:10

    下位机CY7C68013A发送数据,上位机C#读取数据,会丢帧或者帧内错位的原因?

    下位机CY7C68013A发送数据,上位机C#在1个while循环内不断地读取数据,510字节1帧,1秒333帧、1秒667帧、1秒1333帧,会整帧丢帧或者帧内丢部分字节导致错位(帧头不在开始的位置),这个怎么回事?
    发表于 02-27 07:31

    最简单的总线通讯!I2C通讯总线的原理原来这么好懂

    通讯I2C
    安泰仪器维修
    发布于 :2024年01月02日 11:16:31

    c#桌面应用开发chart控件使用,添加数据到chart中发现它一直添加是为什么?

    c#桌面应用开发chart控件使用,在添加数据到chart中,发现它一直添加,我想让它只保存最新的n个数据,那么前面的数据该怎么删除
    发表于 10-30 08:18

    基于CAN多主通讯技术的煤矿顶板监测系统设计

    电子发烧友网站提供《基于CAN多主通讯技术的煤矿顶板监测系统设计.pdf》资料免费下载
    发表于 10-25 11:13 0次下载
    基于<b class='flag-5'>CAN</b>多主<b class='flag-5'>通讯</b><b class='flag-5'>技术</b>的煤矿顶板监测系统设计

    现场总线CAN原理与应用技术

    了部分先进技术。在国内,周立功单片机公司推销PHILIPS半导体公司的CAN器件,同时开发出了带CAN控制器的单片机P87C591的仿真器和
    发表于 09-26 06:39

    信息技术是干什么?

    广播电子技术信息技术
    橙群微电子
    发布于 :2023年09月22日 09:17:48

    C#语言初步(2)#web开发技术

    Web开发技术
    未来加油dz
    发布于 :2023年07月12日 14:48:32

    C#语言初步(1)#web开发技术

    开发技术
    未来加油dz
    发布于 :2023年07月12日 14:47:25

    2023年中海达星推官系列直播再度启航,与您一起探讨空间信息技术

    信息技术
    中海达
    发布于 :2023年06月21日 11:45:49

    C#:CAN通讯上位机的简单示例

    写在前面:前几周刚刚学习控制CAN通讯电机时过得很痛苦,网上很难找到很基础的资料和控制办法,最后通过逐字逐句看Kvaser的例程、别人的程序终于摸索明 白,现将基础步骤整理出来供大家交流
    发表于 05-29 16:14 10次下载
    <b class='flag-5'>C#</b>:<b class='flag-5'>CAN</b><b class='flag-5'>通讯</b>上位机的简单示例

    【米尔MYD-JX8MMA7开发板-ARM+FPGA架构试用体验】 四、CAN通讯

    【MYD-JX8MMA7】 (四)CAN通讯理论 因为在经过两天的时间研究can通讯发现,can
    发表于 05-23 08:54

    有没有在没有这些错误的情况下在esp和C#应用程序之间进行通信?

    C# 中从 esp8266 发送和接收信息并显示它的最佳方式是什么??? 我使用了一些代码,但它们不起作用:( 在 ESP 上: 代码:全选void loop() { WiFiClient
    发表于 05-19 13:24

    C#上位机开发常遇问题

    C#上位机开发常遇问题C#引用C++ 动态库/静态库 静态库 动态库 unsafe和fixed关键字的应用 unsafe fixed Path类的使用 写在结尾最近完成了一个小项目的开发
    发表于 05-09 11:21 0次下载
    <b class='flag-5'>C#</b>上位机<b class='flag-5'>开发</b>常遇问题

    C#上位机:串口通讯

    语言与开发技术C#、Winform。 串口通讯是上位机的基础功能,可以通过USB等COM串口进行数据的收发,实现数据采集,自动控制等功能。一套完整的串口
    发表于 05-08 10:23 2次下载
    <b class='flag-5'>C#</b>上位机:串口<b class='flag-5'>通讯</b>