读取C中的CAN总线显示29位CAN ID的CAN ID不正确

我用C写了一些代码来读取CAN总线数据。当我读取11位CAN ID时,一切正常。只要我尝试读取29位ID,它就会错误地显示ID

示例:

接收具有29位ID的消息:

0x01F0A020

用它打印

printf("%X\n",frame.can\u id);

它打印81F0A020

11位ID消息

0x7DF

并用

printf("%X\n",frame.can\u id);

它可以正确打印7DF

为什么会这样

#包括<标准h>
#包括<stdlib.h>
#包括<unistd.h>
#包括<字符串.h>
#包括<净/如果.h>
#包括<fcntl.h>
#包括<inttypes.h>
#包括<系统/类型h>
#包括<系统/插座h>
#包括<系统/ioctl.h>
#包括<netinet/in.h>
#包括<arpa/inet.h>
#包括<linux/can.h>
#包括<linux/can/raw.h>
#定义最大数据长度8
#定义最大值字段23
#定义最大字段长度64
#包括<极限h>
char data_str[MAX_FIELDS][MAX_FIELD_LEN];
int i;
int
主(空)
{
int-s;
整数字节;
结构sockaddr\u can addr;
结构can_框架;
无符号短数据[最大字段];
int-sockfd=0;
int-bcast=1;
src_addr中的结构sockaddr_;
dst_addr中的结构sockaddr_;
整数单位;
int-fa;
结构ifreq-ifr;
fa=插座(AF_INET,SOCK_DGRAM,0);
ifr.ifr\u addr.sa\u family=AF\u INET;
strncpy(ifr.ifr_名称,“eth0”,IFNAMSIZ-1);
ioctl(fa、SIOCGIFHWADDR和ifr);
关闭(fa);
//
if((sockfd=socket(PF_INET,SOCK_DGRAM,0))=-1)
{
perror(“Udp sockfd创建失败”);
出口(1);
}
//已启用udp的广播模式
如果((设置锁定选择)(sockfd、SOL_插座、SO_广播、,
&bcast,大小(bcast))=-1)
{
perror(“对于广播模式,setsockopt失败”);
出口(1);
}
src_addr.sin_family=AF_INET;
src_addr.sin_port=htons(8888);
src_addr.sin_addr.s_addr=INADDR_ANY;
memset(src_addr.sin_zero,“\0”,src_addr.sin_zero的大小);
if(绑定(sockfd,(结构sockaddr*)和src_addr,src_addr的大小)=-1)
{
佩罗尔(“绑定”);
出口(1);
}
dst_addr.sin_family=AF_INET;
dst地址sin端口=htons(45454);
dst_addr.sin_addr.s_addr=inet_addr(“127.0.0.1”);
memset(dst地址sin(零),\0',dst地址sin(零)的大小);
if((s=插座(PF_CAN、SOCK_RAW、CAN_RAW))<0){
perror(“打开插座时出错”);
返回-1;
}
addr.can_family=AF_can;
地址can\U ifindex=0;
if(绑定(s,(struct sockaddr*)和addr,sizeof(addr))<0){
perror(“套接字绑定错误”);
返回-2;
}
//结构can_框架;
而(1)
{
nbytes=读取(s,和帧,sizeof(struct can_frame));
如果(N字节<0){
perror(“can原始套接字读取”);
返回1;
}
/*偏执狂检查*/
if(n字节<sizeof(结构can_帧)){
fprintf(标准,“读:不完整的CAN帧\n”);
返回1;
}
//打印收到的CAN ID
printf(“X\n”,frame.can\u id);
}
返回0;
}

struct can_framecan_id字段包含can idEFF/RTR/ERR标志。扩展ID有29位,因此有3个空闲位用于表示3个标志

示例ID0x01F0A020必须是扩展帧,但ID0x7DF可以作为基本帧或扩展帧发送。这些是不同的信息。要区分具有相同ID的基本帧或扩展帧,需要EFF标志

在您的示例中,您可以看到值0x81F0A020,它是ID0x01F0A020CAN\u EFF\u标志的组合(0x80000000U

从中提取https://github.com/torvalds/linux/blob/master/include/uapi/linux/can.h

CAN\U ID的特殊地址描述标志*/
#在MSB中设置了define CAN_EFF_标志0x80000000U/*EFF/SFF*/
#定义CAN_RTR_标志0x40000000U/*远程传输请求*/
#定义CAN\U ERR\U标志0x200000U/*错误消息帧*/
/*帧格式的CAN ID中的有效位*/
#定义CAN_SFF_掩码0x000007FFU/*标准帧格式(SFF)*/
#定义CAN\U EFF\U掩码0x1FFFFFFFFU/*扩展帧格式(EFF)*/
#定义CAN\U ERR\U掩码0x1FFFFFFFFU/*忽略EFF、RTR、ERR标志*/

/**
*结构can_框架-基本can框架结构
*@can\U id:帧的can id和can\U*\U标志,请参阅canid\t定义
*@can_dlc:以字节(0..8)表示的帧有效负载长度,也称为数据长度代码
*注意:ISO 11898-1第8.4.2.3章中的数据链接字段的比例为1:1
*将“数据长度代码”映射到实际有效负载长度
*@_pad:填充
*@u res0:保留/填充
*@_res1:保留/填充
*@data:CAN帧有效负载(最多8字节)
*/
结构can_框架{
canid\u t can\u id;/*32位can\u id+EFF/RTR/ERR标志*/
__u8 can_dlc;/*以字节为单位的帧有效负载长度(0..can_最大值)*/
__u8 _u垫;/*垫*/
__u8 u_res0;/*保留/填充*/
__u8 u_res1;/*保留/填充*/
__u8数据[CAN_MAX_DLEN]___属性(对齐(8));
};

要仅获取不带标志的ID,应根据CAN\U EFF\U标志位的值应用CAN\U SFF\U掩码CAN\U EFF\U掩码

示例代码:

//打印收到的CAN ID
printf(“%X\n”,
(frame.can\u id和can\u EFF\u标志)?(frame.can\u id和can\u EFF\u掩码)
:(frame.can_id和can_SFF_MASK));

发表评论