DBC_2_C上位机

DBC_2_C上位机

前言

时隔半年,我又回来了,今天带来的是一款相对实用一点的工具------DBC_2_C。在汽车电子圈里混的各位佬都知道,主机厂定义信号矩阵,像lin啊,can啊这些,8个字节分成了十几个或者几十个信号,每个信号的意义也不同,如何从一帧数据截取对应的信号,如何将信号打包到一帧数据里边再发送到总线。本人之前使用到的是位域,相比移位,我更喜欢位域,清晰简单。第一次接触到位域也是刚进入行业的时候。当时很感叹位域设计的精妙,这不就是为解析lin报文而生的嘛!直到那次,我意识到位域的局限性,这是后话了,下面会介绍到。然后我又去咨询了两位同事,他们的之前做法是移位。"手写" 移位函数。虽然已经猜到他们是这么做的,但是还是对他们的回答很失望。没有让我眼前一亮的方案,一个个信号去移位,要累死个人啊,要是真得舍弃掉位域,移位运算我也是真不想要。有没有一个好的折中的简单的方案。有!工具生成。python提供了一个可以解析can报文的库cantools,搭建好环境,选择dbc,直接就给你生成两个全是移位函数的文件。是不是这个cantools的存在感比较低,好多人都没怎么听说,我也是deekseek推荐才知道的。好了。如果只是为了找到一个可以生成移位函数的工具,文章到这里就可以结束了。哈哈哈。但是我就不,死犟的我打算打造出属于我的工具!!!

位域的局限

好了,上面废话有点多了,进入正题。

c 复制代码
#include"stdio.h" 

typedef union 
{
    struct 
    {
        unsigned char AS_NtcOpen_Fault  : 3;
        unsigned char DR_NtcOpen_Fault  : 3;
        unsigned char AS_DOOR_STA       : 2;
        unsigned char DR_DOOR_STA       : 3;
        unsigned char reserved1:5;
        unsigned char reserved2:5;
        unsigned char reserved3:5;
        unsigned char reserved4:5;
        unsigned char reserved5:5;
        unsigned char reserved6:5;
        unsigned char reserved7:5;
    }Bit;
    unsigned char Byte[8];
}BCM_LIN_DRVR_UNION;


int main() 
{ 
    BCM_LIN_DRVR_UNION look;
    look.Bit.AS_NtcOpen_Fault = 7;
    look.Bit.DR_NtcOpen_Fault = 2;
    printf("0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",look.Byte[0],look.Byte[1],look.Byte[2],look.Byte[3],look.Byte[4],look.Byte[5],look.Byte[6],look.Byte[7]);
    return 0; 
}

拿这段代码来说,之前在芯旺微的芯片上跑,输出的是0xE8 0x00...

同样的代码,在nxp的s32k144上跑,却是

0x17 0x00...

看下边这个图片就可以一目了然是因为什么

deepseek给出的解释就是不同的编译器,位域在内存中的布局是不一样的,像gcc,iar都会有差别。在来看看下边两张图片,这个是c语言在线编译器,采用gcc的两个不同的版本,编译相同的代码,输出也存在差别。

不同的编译器,对位域的实现是会有影响的。一方面不太方便移植到不同的平台上边去。另一方面把信号映射到位域上边去,还要根据存储规则去做运算,就太多此一举了,直接采用移位运算。可能有些芯片可以更改lsb还是msb,但是s32ds我没找到哪里可以设置,我太菜了。

cantools简介

python环境搭建

根据上边的链接自己搭建一下python环境还有安装下cantools这个库。接下来,让我来介绍一下生成了些什么东西。

cantools生成.c文件

DBC_2_C简介

这个上位机界面很简单,几个按钮,几个文本框就完了,主要功能也仅是生成文件,所以就单线程了,一般不会导致界面卡死的。主要生成的就是pack、unpack、encode、decode、is_in_range函数,以及不同id的结构体包含的哪些信号。在cantools的基础上,对代码排布,代码功能做了点优化。

dbc_2_c生成.c文件

新建一个Generate_File_DBC2C_wby_dbc_mess_0x501_t结构体,然后将这个结构体调用pack函数,给到目标数组,底层根据这个目标数组,发送到总线;

底层接收到一帧数据,然后将缓存unpack到Generate_File_DBC2C_wby_dbc_mess_0x501_t就完成了信号的截取。

到这里其实以及够了,但是,怎么感觉有点膈应这一块,老感觉这一块会经常出问题。所以,我又做了优化,新增了.c和.h中/start / 到 /end/中间的那一块代码

新增代码部分

DBC_2_C生成文件使用

生成文件的使用

c 复制代码
void DBC2C_Update_device(void)
{
	uint8_t *data_buffer = NULL;

	if(dbc_2_c_find_array(Generate_File_DBC2C_wby_dbc_mess_0x503_FRAME_ID , &data_buffer) != -1)
	{
		//wby_dbc_mess_0x503_pack(data_buffer,&wby_dbc_mess_0x503_w);
	}

	if(dbc_2_c_find_array(Generate_File_DBC2C_CANV_CCM_0x18000001_CAN14_FRAME_ID , &data_buffer) != -1)
	{
		CANV_CCM_0x18000001_CAN14_pack(data_buffer,&CANV_CCM_0x18000001_CAN14_w);
	}
}

应应层把所有id的pack函数都统一写到这里,会查找dbc有无对应的id,把信号映射到对应的缓冲区。这个缓冲区驱动层同样要使用到,驱动层利用dbc_2_c_find_array找到对应的缓冲区。

c 复制代码
/*main函数里边调用*/
native_CAN0_writge_tmp_extension(1,0x18000001);
native_CAN0_writge_tmp_standard(3,0x501,0x506,0x502);

/*写函数实现*/
void native_CAN0_writge_tmp_extension(int count, ...)
{

	can_message_t Tx_msg_1;
	Tx_msg_1.cs = 0U;
	int8_t array_length = 0;
	uint32_t canid;
	uint8_t *data_buffer = NULL;
	va_list args;
    va_start(args, count);
    for(int i=0;i<count;i++)
    {
    	canid = va_arg(args, int);
    	array_length = dbc_2_c_find_array(canid,&data_buffer);
    	if(array_length == -1)
    	{
    		//警告
    	}
    	else
    	{
    		Tx_msg_1.id = canid;
    		memcpy(Tx_msg_1.data,data_buffer,array_length);
        	Tx_msg_1.length = array_length;
        	while(CAN_Send(&can_pal0_instance, TX_MAILBOX_CAN0, &Tx_msg_1) != STATUS_SUCCESS);
    	}
    }
    va_end(args);
}

/*读函数实现*/
void DBC2C_Update_standard_driver(uint32_t canid,uint8_t *data_buffer)
{
	int8_t data_length;

	data_length = dbc_2_c_find_array(recvMsg_CAN1.id,&data_buffer);
	if(data_length != -1)
	{
		memcpy(data_buffer,recvMsg_CAN1.data,data_length);
		if(recvMsg_CAN1.id == Generate_File_DBC2C_wby_dbc_mess_0x503_FRAME_ID)
		{
			wby_dbc_mess_0x503_unpack(&wby_dbc_mess_0x503_r,data_buffer);
		}
	}
}

这里使用到可变参数,第一个形参是参数的个数,后边跟随的是要发送的id,如果id在dbc中没有找到,就不会去发送。另外驱动层相对麻烦一点,哪个id放在哪个can口,通过哪个邮箱发送出去,从哪个邮箱接收,接收的can还是canfd。所以很难做到在Generate_File_DBC2C.c生成一个函数供底层调用。如果大佬们有好的想法也可以一起沟通改进。

DBC_2_C的局限性

视频中也讲到了关于这个上位机的一些不足

1、虽然qt的代码可以识别哪个些d是can,哪些id是canfd,但是生成代码是没有开放给底层去调用的。如果有需要后边会做一个接口。

2、上位机要求导入的dbc必须全是大端或者全是小端,如果一个id中大小端相间,解析会出错!一方面这种大端插小端的场景很少见,另一方面大端插小端实现的难度有点大,特别的pack和unpack函数,先这样子吧,后边心血来潮再来解决这个问题。

3、不对dbc文件进行检查。生成之前一定要确保dbc是正确的,DBC_2_C只会将错就错,不提供纠错功能。

尾声

视频录制时间有点晚,我都有点不知道在说什么了,大家凑合着看,虽然 "DBC_2_C" 看起来还是个毛坯房,但是精装修一下,应该还是有点价值的。就这样子吧,下课!

链接

上位机和源码

相关推荐
Luminbox紫创测控6 小时前
太阳光模拟器在汽车智能玻璃的运用
测试工具·汽车
大米粥哥哥9 小时前
Qt 报错qt.qpa.plugin: Could not find the Qt platform plugin “xcb“ in ““【已解决】
开发语言·qt·plugin·linuxdeployqt·xcb
财经三剑客9 小时前
深蓝汽车3月全球销量31742辆 环比增长87.8%
汽车
云中飞鸿10 小时前
qt中显示日志的一般是哪个控件?
开发语言·qt
森G11 小时前
34、事件的分发机制---------事件系统
c++·qt
Frank_refuel13 小时前
QT->信号与槽详解下(概述、使用、自定义、连接方式、其他说明)
开发语言·qt
manyikaimen14 小时前
博派智能-运动控制技术-RTCP-五轴联动
c++·图像处理·qt·算法·计算机视觉·机器人·c#
源码之家14 小时前
计算机毕业设计:Python新能源汽车数据分析与个性化推荐系统 Django框架 snowNLP 协同过滤推荐算法 requests爬虫 可视化(建议收藏)✅
大数据·python·机器学习·数据分析·django·汽车·课程设计
数智顾问15 小时前
(102页PPT)汽车设备企业信息化系统解决方案(附下载方式)
汽车