软件集成:Simulink与STM32联合开发

2024-09-03 11:32

本文主要是介绍软件集成:Simulink与STM32联合开发,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文首先通过一个简单的Simulink模型生成代码,然后将代码copy到一个STM32工程中去编译软件。最后将软件下载到STM32F407中,通过串口输出Simulink计算的结果。

阅读本文需要有一定的STM32开发调试经验和Simulink代码生成经验。关于Simulink代码生成可以参考博主的专栏《Simulink代码生成》。

文章目录

  • 1 问题引入
  • 2 集成方案
  • 3 建模与编程过程
    • 3.1 Simulink模型搭建
    • 3.2 代码生成配置
    • 3.3 STM32工程搭建
    • 3.4 STM32的main.c文件修改
      • 3.4.1 #include "demo.h"
      • 3.4.2 float Demo_Input;
      • 3.4.3 demo_initialize()
      • 3.4.4 Demo_Input = Demo_Input + 1;
      • 3.4.5 demo_step();
      • 3.4.6 printf()
    • 3.5 软件编译、串口打印
  • 4 多模型的集成
    • 4.1 多模型集成方案
    • 4.2 新增Demo2模型
    • 4.3 修改Stm32工程
    • 4.4 软件编译、串口打印
  • 5 总结与注意点

1 问题引入

博主在《Simulink代码生成》专栏的博客中,通过将模型生成代码,然后研究C代码的逻辑和结构。但是,在汽车ECU软件开发的过程中,代码并不是最终产物,还需要将代码编译成可执行文件,刷入控制器中。过程如下示意图:
在这里插入图片描述
如果自己在家学习MBD,想要验证一下自己生成的代码到底能不能在硬件中跑起来,首先就需要一个目标硬件。这个硬件当然不能是公司项目用的TC27X以及刷新工具,因为价格太贵了,只为了学习MBD犯不着花这么大价钱。所以博主选择了创客们比较喜欢的STM32开发板来验证模型开发的结果,只需要一个STM32开发板和ST-LINK下载工具。

最后通过串口验证了Simulink生成的代码能在STM32中正确的跑起来,Simulink与STM32联合开发就算是成功了。

2 集成方案

第3章会通过一个例程,将Simulink生成的代码添加到STM32工程中进行编译。例程的方案如下:
1)在STM32的main.c主函数中定义一个全局变量Demo_Input,作为Simulink模型的输入接口;
2)在Simulink模型demo.slx中建模实现将Demo_Input输入接口乘以2,然后作为Demo_Output输出;
3)在信号线上定义输入和输出的Storage Class,配置Embedded Coder和目标硬件;
4)在main.c主函数中调用Simulink生成的step函数;
5)通过串口打印出Demo_InputDemo_Output全局变量的数值,观察Simulink的代码是否成功的将输入放大了2倍;
在这里插入图片描述

3 建模与编程过程

本章节会详细地讲解博主从零开始建模和编程,直到控制器跑起来,并打印出正确的结果。

3.1 Simulink模型搭建

根据上一章的方案介绍,Simulink模型里面就是简单实现了将输入放大两倍的功能。具体搭建过程如下:
1)打开Simulink模型,建立一个Inport模块、一个Outport模块和一个Gain模块。将Gain模块的放大系数设置为2,并用信号线将三者连接。
在这里插入图片描述
2)右键点击Inport和Gain之间的信号线,点击properties,打开该信号线的属性面板。
在这里插入图片描述
2)将属性面板中的Signal Name填写为Demo_Input
在这里插入图片描述
3)切换到Code Generation,将Storage Class选为ImportedExtern,然后点击OK。
在这里插入图片描述
4)对于输出的信号线也做2~3的操作,但是Storage Class要改成ExportedGlobal
在这里插入图片描述
对于Storage Class可以参考以前的博客《Simulink代码生成: Storage Class配置》,博主不再细说。
5)OK以后可以看到信号线上出现了设置好的名字。
在这里插入图片描述
6)双击Inport模块,将Data Type设为single,模型的single类型在代码中对应的就是float类型。
在这里插入图片描述

3.2 代码生成配置

紧接着上一个小节。

1)打开Simulink配置,配置离散求解器、代码生成的目标文件,以及目标硬件。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
关于Embedded Coder配置和目标硬件配置,这里不再赘述,可以参考博客《Simulink代码生成: Embedded Coder配置》和《Simulink代码生成:目标硬件配置》。

2)Ctrl + B生成代码后,可以简单地看一下接口和step函数。在demo.c文件中先是定义了输出接口Demo_Output变量,然后在step函数中将Demo_Inport乘以2再赋值给Demo_Output。
在这里插入图片描述
在demo_private.h头文件中,对输入接口Demo_Inport进行了外部声明。通过这种外部声明,demo.c中就可以引用main.c文件中定义的Demo_Inport。
在这里插入图片描述
3)在模型目录下会生成一个demo_ert_rtw文件夹,其中包含了生成的源文件和头文件。这1个源文件和5个头文件会在后文加入到STM32工程之中。
在这里插入图片描述

3.3 STM32工程搭建

1)首先从STM32开发板教程中拷贝一个《跑马灯实验》的工程出来,在此基础上修改其中的代码。博主这里用的是正点原子的STM32F407开发板及其配套教程。这里没有自己从头开始写主函数是因为移植stm32的库函数会比较复杂,不是本文的重点内容。
在这里插入图片描述
2)打开\HARDWARE文件夹,在其中新建一个demo文件夹,并把Simulink生成的1个源文件和5个头文件拷贝进去。
在这里插入图片描述
3)打开USER文件夹下的LED.uvprojx项目文件,把demo.c添加到工程目录中。
在这里插入图片描述
4)把demo模型生成的头文件路径添加到环境配置中。
在这里插入图片描述

3.4 STM32的main.c文件修改

将main.c文件修改如下

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"#include "demo.h"  //包含demo.h头文件才能访问其中的函数和全局变量float Demo_Input;  //定义demo.slx模型的输入端口int main(void)
{ Demo_Input = 0;		//定义Demo_Input初始值为0delay_init(168);	//初始化延时函数	uart_init(115200);	//串口初始化波特率为115200demo_initialize();  //调用demo.slx模型的初始化函数while(1){Demo_Input = Demo_Input + 1;	//Demo_Input每个周期加1demo_step();		//调用demo.slx模型生成的step函数printf("Demo_Input = %f;Demo_Output = %f;\r\n\r\n",Demo_Input,Demo_Output);//串口打印Demo_Input,Demo_Outputdelay_ms(1000);     //延时1000ms}
}

这里对代码做一些简单的解释:

3.4.1 #include “demo.h”

#include "demo.h"是为了让main.c文件能够通过demo的头文件访问到demo.c的函数。因为在后面的代码中,main函数中要调用demo_step函数和Demo_Output全局变量。

3.4.2 float Demo_Input;

在main.c中定义了全局变量Demo_Input,使得demo.c可以通过demo_private.h中访问到。这样的话,Demo_Input全局变量就传递到了demo.c中进行计算了。

3.4.3 demo_initialize()

在while(1)循环之前先调用一下demo_initialize();初始化函数,将Demo_Output初始化为0.

3.4.4 Demo_Input = Demo_Input + 1;

让每个while循环中,Demo_Input的值加1。

3.4.5 demo_step();

调用了step函数,对Demo_Input的数值做乘以2的计算,再赋值给Demo_Output。那么通过模型的放大2倍,Demo_Output应该一直是Demo_Input的两倍。也就是说,Demo_Input的输出值是0,1,2,3…,Demo_Output的输出值是0,2,4,6…。

3.4.6 printf()

printf把输入Demo_Input和输出Demo_Output通过串口打印到电脑上。

3.5 软件编译、串口打印

将STM32工程重新编译,并通过ST-LINK下载到硬件中。

通过串口,可以打印出输入和输出的值:

在这里插入图片描述
从图中可以看出,串口打印的输入每隔1秒钟会加1,输出一直是输入的2倍。从而验证了模型的2倍增益效果已经体现在整个STM32工程中了。

4 多模型的集成

4.1 多模型集成方案

在汽车软件开发中,应用层控制策略通常都比较复杂,所以一般会将项目分成很多个子模型进行分布式开发。对于多模型的集成,一般会有两种集成方案:

  1. 先将多个模型通过模型引用,或者手动组合成一个模型,然后生成一个模型的代码,再拿去编译。
  2. 将多个模型分别生成代码,然后将各个模型的代码放到一起编译。

博主比较推荐第二种方案,因为完整地生成一个集成式模型的代码,需要花费很多时间,降低了效率。所以本章节主要演示一下如何将多个模型分别生成代码,然后放到STM32项目环境中去编译。

4.2 新增Demo2模型

在第三章地基础上,新增一个demo2模型,将demo模型的输出接口demo_Output再次乘以2,再输出到STM32的main.c文件中。

与demo.slx模型一样,配置好模型的输入输出接口但是接口名称和demo.slx中的不一样,数据类型、Storage Class配置都和demo.slx中完全相同。
在这里插入图片描述
然后将模型生成代码,并拷贝到STM32工程中。

4.3 修改Stm32工程

1)首先将demo2.c文件加入Stm32的项目中。
在这里插入图片描述
2)修改main.c文件,包括以下几方面。

  • 包含demo2.h头文件,以便调用demo2.c中定义的Demo2_Output全局变量;
  • 在while循环之前调用demo2_initialize();初始化函数;
  • 在while循环中调用demo2_step();的step函数;
  • 修改printf函数,把Demo2_Output也打印出来;

对应的main.c如下所示:

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"#include "demo.h"  //包含demo.h头文件才能访问其中的函数和全局变量
#include "demo2.h"  //包含demo2.h头文件才能访问其中的函数和全局变量
float Demo_Input;  //定义demo.slx模型的输入端口int main(void)
{ Demo_Input = 0;		//定义Demo_Input初始值为0delay_init(168);		  //初始化延时函数uart_init(115200);	//串口初始化波特率为115200demo_initialize();  //调用demo.slx模型的初始化函数demo2_initialize();  //调用demo2.slx模型的初始化函数while(1){Demo_Input = Demo_Input + 1;	//Demo_Input每个周期加1demo_step();		//调用demo.slx模型生成的step函数demo2_step();		//调用demo2.slx模型生成的step函数printf("Demo_Input = %f;Demo_Output = %f;Demo2_Output = %f;\r\n\r\n",Demo_Input,Demo_Output,Demo2_Output);//串口打印Demo_Input,Demo_Output,Demo2_Outputdelay_ms(1000);                     //延时1000ms}
}

4.4 软件编译、串口打印

将修改后的工程编译并下载到Stm32中,通过串口打印出如下内容:
在这里插入图片描述
通过Demo2_Output返回的数值,可以看出新增的demo2.slx也在while循环中不断地运行。

5 总结与注意点

虽然demo模型和STM32工程都比较简单,但是本文在博主的所有系列博客中,是具有重要意义的。

  • 首先,本文把MBD的流程从模型到代码,拓展到了模型–>代码–>可执行文件,并且能够刷到硬件中去验证模型的正确性。
  • 其次,通过本文的方法,可以把控制策略和寄存器配置剥离开来,通过全局变量作为底层和应用层沟通的桥梁。
  • 最后,本文为MBD实战打下了基础,也就是说以后可以通过建模并生成代码去开发遥控小车或者四旋翼飞行器之类的创客制作,而不用去通过C代码实现复杂的控制算法。

本文中的例子源自于博主的工作经验,是汽车软件开发的高度精简版。因此,对于工作中的经验和教训,在本文中也可以很好地体现出来。总结起来有如下的注意点:

  • 注意目标硬件要选择正确,因为这背后是该控制器所规定的不同数据类型的字长。
  • 不要手动修改模型生成的代码,即使是策略上的一点小的修改,也应该先改模型,再生成代码,否则模型与代码上的管理会非常混乱,或者在复杂的项目中容易导致代码的重大缺陷。
  • 输入输出接口非常重要,这方面经常容易出错。另外也可以不用本文的方式定义Storage Class,接口的数据字典管理也可以放在sldd文件中。
  • 由于Simulink本身也只是一个工程软件,自身也有bug,因此生成的代码也有可能与模型的策略不一致。但是这是一个概率极低的事件,如果出现了不符合预期的测试结果,还是应该先去寻找建模过程中的逻辑错误。

以上很多概念在博主的其他博客中也都有更详细的说明。

>>返回个人博客总目录

这篇关于软件集成:Simulink与STM32联合开发的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1132851

相关文章

软件设计师备考——计算机系统

学习内容源自「软件设计师」 上午题 #1 计算机系统_哔哩哔哩_bilibili 目录 1.1.1 计算机系统硬件基本组成 1.1.2 中央处理单元 1.CPU 的功能 1)运算器 2)控制器 RISC && CISC 流水线控制 存储器  Cache 中断 输入输出IO控制方式 程序查询方式 中断驱动方式 直接存储器方式(DMA)  ​编辑 总线 ​编辑

【区块链 + 人才服务】区块链集成开发平台 | FISCO BCOS应用案例

随着区块链技术的快速发展,越来越多的企业开始将其应用于实际业务中。然而,区块链技术的专业性使得其集成开发成为一项挑战。针对此,广东中创智慧科技有限公司基于国产开源联盟链 FISCO BCOS 推出了区块链集成开发平台。该平台基于区块链技术,提供一套全面的区块链开发工具和开发环境,支持开发者快速开发和部署区块链应用。此外,该平台还可以提供一套全面的区块链开发教程和文档,帮助开发者快速上手区块链开发。

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

免费也能高质量!2024年免费录屏软件深度对比评测

我公司因为客户覆盖面广的原因经常会开远程会议,有时候说的内容比较广需要引用多份的数据,我记录起来有一定难度,所以一般都用录屏工具来记录会议内容。这次我们来一起探索有什么免费录屏工具可以提高我们的工作效率吧。 1.福晰录屏大师 链接直达:https://www.foxitsoftware.cn/REC/  录屏软件录屏功能就是本职,这款录屏工具在录屏模式上提供了多种选项,可以选择屏幕录制、窗口

HomeBank:开源免费的个人财务管理软件

在个人财务管理领域,找到一个既免费又开源的解决方案并非易事。HomeBank 正是这样一个项目,它不仅提供了强大的功能,还拥有一个活跃的社区,不断推动其发展和完善。 开源免费:HomeBank 是一个完全开源的项目,用户可以自由地使用、修改和分发。用户友好的界面:提供直观的图形用户界面,使得非技术用户也能轻松上手。数据导入支持:支持从 Quicken、Microsoft Money

STM32(十一):ADC数模转换器实验

AD单通道: 1.RCC开启GPIO和ADC时钟。配置ADCCLK分频器。 2.配置GPIO,把GPIO配置成模拟输入的模式。 3.配置多路开关,把左面通道接入到右面规则组列表里。 4.配置ADC转换器, 包括AD转换器和AD数据寄存器。单次转换,连续转换;扫描、非扫描;有几个通道,触发源是什么,数据对齐是左对齐还是右对齐。 5.ADC_CMD 开启ADC。 void RCC_AD

STM32内部闪存FLASH(内部ROM)、IAP

1 FLASH简介  1 利用程序存储器的剩余空间来保存掉电不丢失的用户数据 2 通过在程序中编程(IAP)实现程序的自我更新 (OTA) 3在线编程(ICP把整个程序都更新掉) 1 系统的Bootloader写死了,只能用串口下载到指定的位置,启动方式也不方便需要配置BOOT引脚触发启动  4 IAP(自己写的Bootloader,实现程序升级) 1 比如蓝牙转串口,

FreeRTOS-基本介绍和移植STM32

FreeRTOS-基本介绍和STM32移植 一、裸机开发和操作系统开发介绍二、任务调度和任务状态介绍2.1 任务调度2.1.1 抢占式调度2.1.2 时间片调度 2.2 任务状态 三、FreeRTOS源码和移植STM323.1 FreeRTOS源码3.2 FreeRTOS移植STM323.2.1 代码移植3.2.2 时钟中断配置 一、裸机开发和操作系统开发介绍 裸机:前后台系

【Shiro】Shiro 的学习教程(三)之 SpringBoot 集成 Shiro

目录 1、环境准备2、引入 Shiro3、实现认证、退出3.1、使用死数据实现3.2、引入数据库,添加注册功能后端代码前端代码 3.3、MD5、Salt 的认证流程 4.、实现授权4.1、基于角色授权4.2、基于资源授权 5、引入缓存5.1、EhCache 实现缓存5.2、集成 Redis 实现 Shiro 缓存 1、环境准备 新建一个 SpringBoot 工程,引入依赖:

寻迹模块TCRT5000的应用原理和功能实现(基于STM32)

目录 概述 1 认识TCRT5000 1.1 模块介绍 1.2 电气特性 2 系统应用 2.1 系统架构 2.2 STM32Cube创建工程 3 功能实现 3.1 代码实现 3.2 源代码文件 4 功能测试 4.1 检测黑线状态 4.2 未检测黑线状态 概述 本文主要介绍TCRT5000模块的使用原理,包括该模块的硬件实现方式,电路实现原理,还使用STM32类