目录

1.代码生成的准备

2.Simulink CAN unpack模块建模

3.加载DBC选择报文及信号

4.设置模型的输入与输出

5.模型的参数设置

6.开始代码生成

7.Simulink代码生成报告

8.生成代码的解读

8.1 生成的模型头文件 msg_unpack.h

8.2 模型功能实现函数 msg_unpack.cpp

8.3 模型代码调用示例ert_main.cpp

8.4 Simulink生成的代码使用依赖项

9. Simulink生成代码的使用


1.代码生成的准备

将Matlab根安装目录下 “R2015b\toolbox\shared\can\src\scanutil\can_message.h” can_message.h头文件放入此次建立的simulink模型文件夹下。同时将matlab工作目录切换至simulink模型所在目录,即can_message.h所在的文件夹。

因为can_message.h里声明了CAN报文类:

2.Simulink CAN unpack模块建模

在Simulink中添加Vehicle Network Toolbox——CAN Communication——CAN Unpack模块,要解析几条报文就添加几个unpack模块。

3.加载DBC选择报文及信号

双击can unpack模块,设置为CANdb specified signals 即解析DBC指定报文的信号,下面的CANdb file选择为需要的dbc文件,然后在下面的Message list可以选择需要的报文,下面的表格里会显示报文里的信号的信息。

4.设置模型的输入与输出

设置输入输出

source——in

sinks——out

同时更改in,out的信号名称与DBC一致,这样在生成的代码可读性也会比较好。

勾选Display——Signal & ports——Port Data Types,即可显示信号线传递的变量类型

有时候不能及时显示信号的变量类型,关掉port data types再重新勾选即可,报文的类型为can_message.

5.模型的参数设置

配置参数配置 simulation——Configuration Parameter

选择为定步长fixed-step

设定步长,我这里设置为0.01s

6.开始代码生成

先执行菜单栏Code——C/C++ Code——Build Model

再选择菜单栏的Code——C/C++ Code——Embedded Coder Quicker Start

基本上一路Next,到这里时注意选择产生的代码类型为C++ code。

这里我是准备移植到Ubuntu系统上,因此这里选择"Device Type"为Linux。

同时,菜单栏里的code generation options里tool chain也要设置;

tool chain和上面保持一致,也选择Linux的,这里选择的是cadence incisive (Linux)

这里不设置运行系统保持一致可能会生成代码失败。

7.Simulink代码生成报告

生成好以后,弹出以下界面,点击第一项可以看到代码生成报告。

8.生成代码的解读

代码生成报告的左端有3个重要的程序文件,可以通过点击左侧进入程序看详细的代码:

ert_main.cpp 是主程序示例,我们模型功能被封装到一个类里,这个main函数里将演示如何使用这个类实现我们原有Simulink模型的功能。

msg_unpack.cpp 主要就是我这个生成代码模型的主要实现部分,是通过一个类来实现的;

msg_unpack.h是这个类相关的声明;

8.1 生成的模型头文件 msg_unpack.h

因为我这个Simulink模型命名为msg_unpack,所以生成的.cpp文件和.h文件都是模型名'msg_unpack"。

这个头文件里主要是模型的输入,输出的结构体定义,然后还有模型的实现部分的类的定义。

结构体ExtU为输入报文的定义:

typedef CAN_MESSAGE CAN_DATATYPE; //CAN_DATATYPE类型就是CAN_MESSAGE类型,参见第一小节

结构体ExtY为输出的结构体定义:

封装模型CAN报文解析的类的定义,模型的输入结构体实例 rtU,输出结构体实例rtY,初始化函数 initialize(), 最重要的部分功能实现函数step()。

8.2 模型功能实现函数 msg_unpack.cpp

这里主要是CAN报文各信号的解析实现,主要是通过类msg_unpackModelClass的成员函数step()实现.

8.3 模型代码调用示例ert_main.cpp

模型功能实现类 msg_unpackModelClass 实例化为rtObj对象。

static msg_unpackModelClass rtObj;     // Instance of model class

模型代码的使用示例:

首先设置模型的输入,通过对象rtObj.rtU.报文名 来设定输入的报文长度,id,数据等;

然后通过对象访问成员函数rtObj.step()实现报文解析;

最后通过对象访问成员函数rtObj.rtY. 信号名 访问报文解析出的物理信号值;

8.4 Simulink生成的代码使用依赖项

因为最后代码可能移植到嵌入式设备或者没有Matlab的其他计算机上,需要确定依赖项。

ert_main.cpp只是一个使用的示例代码,我们不需要用,不管。

我们主要把生成的模型实现的.cpp和.h文件是我们需要的,这两个文件才是需要复制到我们实际的C++工程下的。这里是msg_unpack.cpp和msg_unpack.h。

我们看这两个文件的代码确定依赖项:

msg_unpack.cpp依赖于"msg_unpack.h"就是这个模型实现程序本身的头文件:

msg_unpack.h这个头文件又依赖于 string.h (c++标准库,可忽略);rtwtypes.h(matlab安装目录下的一个头文件(也在代码生成的文件夹中产生了,可以直接复制到自己的c++工程中),还有"can_message.h"第一节中已复制到该模型文件夹下,可直接复制到自己的C++工程目录。

rtwtypes.h也在代码生成的文件夹中产生了,可以直接复制到自己的c++工程中

再看这个头文件是不是又有其他依赖项:

rtwtypes.h里不包含头文件

再看can_message.h头文件的依赖项:

依赖rtwtypes.h,和tmwtypes.h(在matlab安装目录下)

最后再看tmwtypes.h的依赖项:

这3个头文件都是c++标准库可以不用管了,依赖项追溯就到此为止。

因此总共的依赖项有:

msg_unpack.h(模型名.h),can_message.h(matlab安装目录),rtwtypes.h(matlab安装目录),tmwtypes.h(matlab安装目录),总共4个头文件加1个源文件msg_unpack.cpp(模型名.cpp)复制到自己的c++工程目录。

9. Simulink生成代码的使用

按照8.4节复制4个头文件,1个源文件到自己的c++工程后即可按照8.3节仿照ert_main.cpp里调用类来实现报文解析了。

如下图是单个报文解析的c++代码运行效果:

每10ms解析一次CAN报文并打印。

可见调用模型代码的核心步骤:

static msg_unpackModelClass rtObj; //定义模型类对象rtObj

rtObj.initialize(); //对象初始化

rtObj.rtU.In1.Length; //设定输入

rtObj.rtU.In1.ID;

rtObj.rtU.In1.Data[];

rtObj.step(); //调用模型CAN报文解析功能实现函数

rtObj.rtY.Out1; //访问输出的解析到的信号物理值

可以看到生成的代码成功的根据DBC的定义对模拟的CAN报文进行了解析得到了物理值。

Simulink生成CAN报文解析代码的好处就是便于维护,减少人为编码产生的Bug。而且速度也非常快。便于扩展。

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐