simulink解析can报文
1. 工程准备
1.1 创建工程
创建一个空白文件夹用于保存工程,将工作目录切换到此目录,打开simulink并创建模型。

模型设置如下:
求解器步长为1

代码生成为嵌入式代码

1.2 DBC准备
简单创建一个dbc文件,这里创建了个有两条报文的dbc,并且也放到工程目录下,或者随便找个有报文的dbc文件就可以。

1.3 外部接口准备
在工程目录下创建interface文件夹,用于存放需要调用的外部接口。
最终目录如下图所示。

其中
can_fd_message.h、can_message.h是从matlab安装目录复制过来的。
E:\R2025bR3\R2025bR3\toolbox\shared\can\src\scanutil\can_message.h
E:\R2025bR3\R2025bR3\toolbox\shared\can\src\scanutil\can_fd_message.h
然后注释/删除最下面没有用的接口,其他的全部保留。

另外两个是用户自己写的接收can消息的接口,实现可以为空,定义在即可。

注意:数据类型CAN_MESSAGE不要修改,结构体类型定义在他提供的那两个文件里。
2. 模型搭建
2.1 仿真运行
Can消息处理主要用到这两个模块CAN Pack 和 CAN Unpack。

CAN Pack:将输入参数按照dbc中的定义,打包为一帧CAN报文格式
CAN Unpack:将一帧CAN报文按照dbc中的定义,解析为多个字段
创建一个CAN Pack模型,双击选择参数,数据格式选择CANdb,数据库文件选择创建的dbc文件,报文列表中选择要打包的报文。
这里将"作为总线输出也勾选上",打包后的数据类型可以使用bus解析模块查看。

再添加一个CAN Unpack模型,同样的,选择数据格式和要处理的报文。

连接Pack 和 Unpack模块,并添加一个固定的输入,然后点击仿真运行。数据会被打包成can报文进入另一个模块,再解析成数据。

为了查看CAN Msg的数据,添加一个Bus Selector模块解析这个数据,可以看到这个结构体是由以下部分组成的。

仿真后结果如下所示(需要勾选Pack的作为总线输出,才可以使用bus解析模块解析)。

注意:CAN Msg是一个结构体类型的数据,就是can_message.h中定义的,只是这里还没有用到那个文件。
2.2 接收模型
创建一个模块,接收can报文,有几条消息,就创建几个模块,这里有两条需要处理的报文,所以创建两个。

这里需要使用一个"C Caller"模块,调用外部接口接收can报文。需要先在模型中添加外部文件的定义。
头文件

源文件

文件路径

添加一个"C Caller"模块,双击模块,点击右侧刷新后选择接收数据的接口(如果刷新不出来接口,说明上面路径或者头文件没配置对)。修改模块的端口设定,将ch设置为input,data这里是输出的报文,设置为Output。

注意:这里多出来一个out端口,是因为定义的函数的返回值是int类型的,如果不需要可以忽略这个输出,或者将函数返回值改成void即可。也可以将其用作是否获取到数据的Enable信号。
完成后重新连接模型,传入一个固定的通道1,读取到can报文后,传入到解析模块进行解析。

2.3 生成代码
此时直接生成代码还是会报错,因为没有数据类型定义。

在命令行中调用如下命令
Simulink.importExternalCTypes('interface\\can_message.h')该命令会将can_message.h中的结构体定义自动在工作区中添加对应的bus类型。

此时,再点击生成代码,就可以正常生成代码了(注意是生成,不是编译,编译肯定过不去的)。

以上就可以正常生成代码了。
但是工作区的内容关闭后下次打开就没有了,为了不用每次打开模型都需要重新创建工作区的内容。
双击创建的can消息类型,在右侧数据域选择已导入,头文件填入can_message.h,然后点击导出,选择对象格式,命名为can_message.m

保存完成之后,生成的是一个创建这个数据类型定义的脚本。

回到模型界面,在空白区域右键,选择模型属性。

在回调界面中的initFcn中填入如下内容后点击确定。
run("can_message.m");
此时关闭模型,在工作区右键并清空工作区,重新打开模型后如下图所示。

然后首次点击生成代码后失败,但左侧工作区中就出现了刚才定义的数据类型。

再次点击生成代码即可正常生成代码了。
2.4 代码集成
生成代码后,代码中会依赖定义数据格式的头文件,因此代码编译时,也需要把can_message.h放过去。

在生成的周期执行的函数中,会调用我们传入的获取数据的接口来读取报文,并顺序判断ID来处理。
