嵌入式 开发 软件
csdh11 2024-12-09 11:25 4 浏览
提示:文章撰写完成后,可以自动生成目录,如何生成请参考右侧帮助文档。
目录
前言
在嵌入式开发中,利用Simulink的相关功能模块搭建好逻辑流程之后,很重要的一个步骤就是利用代码生成功能将我们搭建好的函数转换成代码,并与嵌入式平台的芯片软件工程进行融合,使得我们开发出来的函数能够在单片机上运行,??从而实现产品的功能需求。
1. 项目创建
本次用Simulink搭建的项目目标产品是车载智能保险丝盒,前两篇文章中的CAN模块、雨刮器模块都是该项目的函数,这些函数通过一个完整的Simulink项目进行组装和管理,函数之间以文件夹的形式,将相关的函数文件统一归类,我的理解是这样建立的工程和编辑代码时在编译器中建立的工程类似。
和在KEIL或者IAR中编译运行一样,simulink工程也可以进行模型测试、依赖检查、运行检查等。版本管理也集成了SVN或者git,简单设置即可实现。我使用SVN进行版本管理,不过一般都是直接复制文件夹进行更新、提交即可。
2. 代码生成 1. 构建模块
各个模块的操作都一样,设置参数和操作。本文以近光模块为例进行说明,主要是因为近光模块功能比较简单,信号量小,逻辑简单,主要信号如下:
输入信号:
1. 点火开关IGN信号
2. 大灯电源信号
3. 近光灯开关信号
4.短路判断信号
5.开路判断信号
6. 消息刷新标志
输出信号:
1.近光继电器控制信号
2. CAN 报文信号
3. 消息发送标志
消息刷新标志和消息发送标志是系统内部判断信号,不作为对外输出,相当于写代码时设置的标志位是局部变量。
功能逻辑结构如下:
总体结构
2. 内部结构
三状态流
函数搭建完成后点击RUN图标,若无报错则证明语法结构正确,满足生成代码的前提条件。至于控制逻辑是否正确,可以通过搭建仪表盘上的指示灯进行仿真,仿真方法请参考上一篇文章《Simulink模型实现汽车雨刮器基本功能并仿真》。
2.设置参数
点击工具栏模型设置的齿轮图标,进入参数设置界面
以本项目中嵌入代码的生成为例,主要需要调整的参数设置如下:
在求解器下,选择求解器选择,类型选择固定步长,求解器选择离散
细节选项fixed-step size设置为0.01,采样步长为0.01s。这个参数和嵌入式工程中函数循环调用的频率有关,以本工程为例,设置为0.01s表示每10ms调用一次该函数。如果不按照设置值进行定时中断,将会影响模块中的定时操作。
代码生成选项中主要有两个参数需要注意,一是System target file选择为ert.tlc,二是Language选择为C语言。
在Report选项中选择Generate Code Report,一般前两项分别是Generate Report和Automatically Open,第三项Web View是可选的。
根据使用的MCU型号,我们需要在Hardware Implementation中选择对应的MCU厂商和内核类型。本工程采用的是NXP,cortexM4核心的S32k148芯片,选择对应的选项即可。这里的选择不像Keil等编译器那么详细,主要就是确定MCU的一些数据类型定义的位数,是否支持长整型等,点击detail可以查看详细信息。
3.自动生成
完成以上步骤后,就可以生成代码了,首先在APP选项中选择内嵌的coder功能卡,如下图:
选择进入嵌入式编码器APP
单击“Build”按钮生成嵌入式 C 代码
代码生成之后会自动出现在右侧,方便我们查看。
因为我们勾选了生成报告选项,所以会出现一个报告对话框,在报告中可以查看此模块生成的代码的相关内容,包括代码预览,模型信息,内存使用情况等信息。
在生成的代码中我们可以看到很多文件,但是主要用到的是LowBeam.c和LowBeam.h这两个文件,除了ert_main之外的其他文件大家可以忽略,直接复制到我们自己的代码工程目录下即可。我们不需要ert_main,使用我们自己的main函数,但是大家可以参考ert_main中函数函数的调用方法。
3. 代码集成
按照上面的方法自动生成代码之后,还差最后一步就能成功使用了,就是把这些文件添加到工程中,并与驱动代码进行匹配。针对这个芯片,其他同事已经进行了平台开发,并提供了相关接口,包括ADC、GPIO、CAN等资源都已经封装好了,我们需要做的就是接口对应。以近光功能模块为例,LowBeam.c文件几乎可以忽略不计,它是Matlab软件根据我们搭建的Simulink逻辑自动生成的代码,可读性不是很强,但是功能肯定是实现了的,我们会对应好接口,只关注LowBeam.h文件就行。
在.h文件中找到以下代码:
/* External inputs (root inport signals with default storage) */
typedef struct {
IGN IG; /* '/IGN' */
uint8_T Front_Power_Supply; /* '/Front_Power_Supply' */
uint8_T Work_Cmd; /* '/Work_Cmd' */
uint8_T IS_Opencircuit; /* '/DILAMP_Open' */
uint8_T IS_Shortcircuit; /* '/DILAMP_Short' */
uint8_T New_Can_Flag; /* '/New_Can_Flag' */
} ExtU_LowBeam_T;
/* External outputs (root outports fed by signals with default storage) */
typedef struct {
uint8_T Low_Beam_On; /* '/Low_Beam_On' */
uint8_T Can_Send_Flag; /* '/Can_Send_Flag' */
CAN_MESSAGE_BUS CAN_Msg_HighBeam; /* '/CAN_Msg_HighBeam' */
} ExtY_LowBeam_T;
ExtU_LowBeam_T表示输入信号的结构体,ExtY_LowBeam_T表示输出信号的结构体,均以全局变量的形式赋值。
我们自己写一个赋值函数:
/*近光灯模块*/
LowBeam_U.New_Can_Flag = (uint8_T)can_status_store.bit.store_Newflag_LowBeam;
LowBeam_U.Front_Power_Supply = (FrontLampTogether_Y.Left_Together_ON & FrontLampTogether_Y.Right_Together_ON);
LowBeam_U.Work_Cmd = CAN_Receive_Model_Y.LowBeam_WorkCmd;
LowBeam_U.IG = CAN_Receive_Model_Y.IGN_Sig;
LowBeam_U.IS_Opencircuit = (Output_Current_U.DILamp_FL_DRV < LOWBEAM_CURRENT_MIN) ||
(Output_Current_U.DILamp_FR_DRV < LOWBEAM_CURRENT_MIN) ? 1: 0;
LowBeam_U.IS_Shortcircuit = (Output_Current_U.DILamp_FL_DRV > LOWBEAM_CURRENT_MAX) ||
(Output_Current_U.DILamp_FR_DRV > LOWBEAM_CURRENT_MAX) ? 1: 0;
涉及到一些其他模块的信号,但这些都是独立的全局变量,可以直接用于逻辑判断。
输出信号:
if(LowBeam_Y.Low_Beam_On == 1)
{
HSD_SET_LEFT_LOWBEAM_ON; //打开左近光灯
HSD_SET_RIGHT_LOWBEAM_ON; //打开又近光灯
}
else
{
HSD_SET_LEFT_LOWBEAM_OFF; //关闭左近光灯
HSD_SET_RIGHT_LOWBEAM_OFF; //关闭右近光灯
}
输出函数已经封装好了,这里直接调用就可以。
对于总线信号,编写一个赋值函数:
void set_can_LowBeam_output(void)
{
if(LowBeam_Y.Can_Send_Flag)
{
if(can_send_output_set(CAN_INSTANCE_SET, &LowBeam_Y.CAN_Msg_HighBeam) == CAN_EOK) //发送报文
{
LowBeam_Y.Can_Send_Flag = 0;
}
}
}
这里我们直接使用发送消息的接口函数can_send_output_set()。
最后在main函数中调用该函数,我们可以在生成的LowBeam.h文件中看到三个函数声明:
/* Model entry point functions */
extern void LowBeam_initialize(void);
extern void LowBeam_step(void);
extern void LowBeam_terminate(void);
实际上,我们唯一需要的函数是 LowBeam_step(void),它可以在主函数的主循环中每 10ms 调用一次:
if(Get1MsTickInterval(modeldely) >= 10)
{
modeldely = Get1MsTickVal();
LowBeam_step(); //近光灯
}
其它功能模块可以按照同样的方法在近光灯函数下面添加_step函数。
总结
以上就是我们今天要讲的内容,本文简单介绍了如何通过Simulink搭建的逻辑框图生成嵌入式代码,并将生成的代码添加到现有的MCU项目中,实现近光灯模块的功能。
当然,自动代码生成需要在项目调用时多一层封装,占用一定的资源。而且对于一些精通业务的工程师来说,一些简单的手写逻辑,用很简洁的C代码量就可以实现同样的功能。但是我们使用自动代码生成技术也有相应的优势,比如当功能逻辑比较复杂时,我们可以更清晰地理清思路,使用simulink可以很方便地进行功能仿真。验证功能步骤可以放在代码生成之前,而手写代码必须在编译通过后,使用硬件设备进行功能测试后,才能烧录到sample中。这样,使用simulink进行功能仿真和自动代码生成,就省去了重复烧录的过程。
当然,Simulink 的代码生成功能远不止本文所提到的这些,作者会在项目中进行探索,并在后续的文章中与大家进一步探讨。
相关推荐
- Micheal Nielsen's神经网络学习之二
-
依然是跟着MichaelNielsen的神经网络学习,基于前一篇的学习,已经大概明白了神经网络的基本结构和BP算法,也能通过神经网络训练数字识别功能,之后我试验了一下使用神经网络训练之前的文本分类,...
- CocoaPods + XCTest进行单元测试 c单元测试工具
-
在使用XCTest进行单元测试时,我们经常会遇到一些CocoaPods中的开源框架的调用,比如“Realm”或“Alamofire”在测试的时候,如果配置不当,会导致“frameworknotfo...
- Java基础知识回顾第四篇 java基础讲解
-
1、&和&&的区别作为逻辑运算符:&(不管左边是什么,右边都参与运算),&&(如果左边为false,右边则不参与运算,短路)另外&可作为位运算符...
- 项目中的流程及类似业务的设计模式总结
-
说到业务流程,可能是我做过的项目中涉及业务最多的一个方面了。除了在流程设计之外,在一些考核系统、产业审批、还有很多地方,都用到相似的设计思路,在此一并总结一下。再说到模式,并不是因为流行才用这个词,而...
- 联想三款显示器首批获得 Eyesafe Certified 2.0 认证
-
IT之家7月31日消息,据外媒报道,三款全新联想显示器是全球首批满足EyesafeCertified2.0的设备。据报道,联想获得EyesafeCertified2.0认证的显...
- maven的生命周期,插件介绍(二) 一个典型的maven构建生命周期
-
1.maven生命周期一个完整的项目构建过程通常包括清理、编译、测试、打包、集成测试、验证、部署等步骤,Maven从中抽取了一套完善的、易扩展的生命周期。Maven的生命周期是抽象的,其中的具体任务都...
- 多线程(3)-基于Object的线程等待与唤醒
-
概述在使用synchronized进行线程同步中介绍了依赖对象锁定线程,本篇文章介绍如何依赖对象协调线程。同synchronized悲观锁一样,线程本身不能等待与唤醒,也是需要对象才能完成等待与唤醒的...
- jquery mobile + 百度地图 + phonegap 写的一个"校园助手"的app
-
1jquerymobile+百度地图+phonegap写的一个"校园助手"的app,使用的是基于Flat-UI的jQueryMobile,请参考:https://github.com/...
- Apache 服务启动不了 apache系统服务启动不了
-
{我是新手,从未遇到此问题,请各位大大勿喷}事由:今天早上上班突然发现公司网站出现问题。经过排查,发现是Apache出现问题。首先检查配置文件没有出问题后,启动服务发现Apache服务能启动,但是没法...
- 健康债和技术债都不能欠 公众号: 我是攻城师(woshigcs)
-
在Solr4.4之后,Solr提供了SolrCloud分布式集群的模式,它带来的主要好处是:(1)大数据量下更高的性能(2)更好扩展性(3)更高的可靠性(4)更简单易用什么时候应该使用Sol...
- Eye Experience怎么用?HTC告诉你 eyebeam怎么用
-
IT之家(www.ithome.com):EyeExperience怎么用?HTC告诉你HTC上周除了发布HTCDesireEYE自拍机和HTCRE管状运动相机之外,还发布了一系列新的智能手机...
- Android系统应用隐藏和应用禁止卸载
-
1、应用隐藏与禁用Android设置中的应用管理器提供了一个功能,就是【应用停用】功能,这是针对某些系统应用的。当应用停用之后,应用的图标会被隐藏,但apk还是存在,不会删除,核心接口就是Packag...
- 计算机软件技术分享--赠人玫瑰,手遗余香
-
一、Netty介绍Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。也就是说,Netty...
- Gecco爬虫框架的线程和队列模型 爬虫通用框架
-
简述爬虫在抓取一个页面后一般有两个任务,一个是解析页面内容,一个是将需要继续抓取的url放入队列继续抓取。因此,当爬取的网页很多的情况下,待抓取url的管理也是爬虫框架需要解决的问题。本文主要说的是g...
- 一点感悟(一) 初识 初读感知的意思
-
时间过得很快,在IT业已从业了两年多。人这一辈子到底需要什么,在路边看着人来人往,大部分人脸上都是很匆忙。上海真是一个魔都,它有魅力,有底蕴,但是一个外地人在这里扎根置业,真的是举全家之力,还贷3...
- 一周热门
-
-
Boston Dynamics Founder to Attend the 2024 T-EDGE Conference
-
IDC机房服务器托管可提供的服务
-
详解PostgreSQL 如何获取当前日期时间
-
新版腾讯QQ更新Windows 9.9.7、Mac 6.9.25、Linux 3.2.5版本
-
一文看懂mysql时间函数now()、current_timestamp() 和sysdate()
-
流星蝴蝶剑:76邵氏精华版,强化了流星,消失了蝴蝶
-
PhotoShop通道
-
查看 CAD文件,电脑上又没装AutoCAD?这款CAD快速看图工具能帮你
-
WildBit Viewer 6.13 快速的图像查看器,具有幻灯片播放和编辑功能
-
光与灯具的专业术语 你知多少?
-
- 最近发表
-
- Micheal Nielsen's神经网络学习之二
- CocoaPods + XCTest进行单元测试 c单元测试工具
- Java基础知识回顾第四篇 java基础讲解
- 项目中的流程及类似业务的设计模式总结
- 联想三款显示器首批获得 Eyesafe Certified 2.0 认证
- maven的生命周期,插件介绍(二) 一个典型的maven构建生命周期
- 多线程(3)-基于Object的线程等待与唤醒
- jquery mobile + 百度地图 + phonegap 写的一个"校园助手"的app
- Apache 服务启动不了 apache系统服务启动不了
- 健康债和技术债都不能欠 公众号: 我是攻城师(woshigcs)
- 标签列表
-
- serv-u 破解版 (19)
- huaweiupdateextractor (27)
- thinkphp6下载 (25)
- mysql 时间索引 (31)
- mydisktest_v298 (34)
- sql 日期比较 (26)
- document.appendchild (35)
- 头像打包下载 (61)
- oppoa5专用解锁工具包 (23)
- acmecadconverter_8.52绿色版 (39)
- oracle timestamp比较大小 (28)
- f12019破解 (20)
- np++ (18)
- 魔兽模型 (18)
- java面试宝典2019pdf (17)
- beamoff下载 (17)
- unity shader入门精要pdf (22)
- word文档批量处理大师破解版 (36)
- pk10牛牛 (22)
- server2016安装密钥 (33)
- mysql 昨天的日期 (37)
- 加密与解密第四版pdf (30)
- pcm文件下载 (23)
- jemeter官网 (31)
- iteye (18)