文章目录
目的
本笔记的学习目的是了解Simulink的自动生成的代码,并通过51单片机实例学习将MCU的驱动程序与Simulink自动生成的代码相结合
利用51单片机实现LED点亮程序
这部分比较简单,这里P0点亮LED,程序如下:
/* ------------------------------
Function : 点亮LED实例
Author: Sprinkle_WPD
Date : 2019-04-26
--------------------------------*/
#include "reg52.h"
sbit LED = P0^0;
/* -------Function main--------------
Input : void
Output: void
------------------------------------*/
void main(){
LED = 1;
while(1){
}
}
烧录到51单片机中之后的现象为P0^0对应的LED灯点亮。
Simulink代码生成基础
Simulink针对MCU生成的代码,其结构包括了:
- main program主函数
- model application 算法
- rutime library 库函数
- I/O device底层驱动
- data logging interface数据记录接口
- data exchange interface 数据通信接口
针对嵌入式系统,Simulink生成代码时需要设置为Fixed-step定步长求解器
同时,Simulink提供了针对嵌入式的tlc以及对应的cgt模板
如果是针对MCU的代码生成,可以进行下列设置: - create code generation 创建代码生成报告
- open report automatically 自动打开报告
- code-to-model 代码高亮显示对应的模型
- generate model web view 在同一窗口显示代码以及与之对应的模型
- generate code only 仅生成代码,不便宜链接生成可执行文件
Simulink ert.tlc自动生成的代码分析
打开Simulink,建模如下:
建模后,选择ert.tlc
后进行编译,其他参数设置如下:
- Solver选择Fixed-step
- Code Generation中勾选Generate code only
- Code Generation > Interface > 勾选Remove error status field in real-time model data structure
编译后生成的代码被保存在了5个文件中,分别是
- ert_main.c —— 默认生成的主程序函数
- model.c —— 模型算法
- model.h —— 算法头文件
- untitled_private.h —— 模型与子系统的局部宏和局部数据
- untitled_types.h —— 模型数据结构和参数数据结构的预先声明
- rtwtypes.h —— 定义数据类型、结构体和宏
ert_main.c
- 主程序调用main函数
- model_initialize
- rt_onestep(定时器/中断函数,与手写代码集成)
- rt_onestep()函数
- model_step()具体的算法
其他5个文件为Simulink自动生成的,需要注意的是里面默认的数据结构与类型,如下表:
数据类型命名 | 变量名 | |
---|---|---|
Model | RT_MODEL_model | model_m |
Parameters | P_model | model_p |
external inputs | ExtU_model | model_U |
External outputs | ExtY_model | model_Y |
Block signals | B_model | model_B |
Block states | DW_model | model_DW |
在上面的模型生成的model.c文件中,可以看到对output1的定义:
model.c 中 ExtY_model_T model_Y;
model.h中
typedef struct {
real_T Out1; /* '<Root>/Out1' */
} ExtY_model_T;
extern ExtY_model_T model_Y;
这种方式很明显不适用于代码的理解,因此,可以利用Simulink.Signal进行代码的优化。下图就是可以Simulink.Signal对代码进行了优化:
具体如何设置,之前的笔记中记录过。
代码集成的两种方法
上面生成的代码仅仅是算法部分,要想在MCU上实现,还需要对应的驱动等代码,这涉及到代码的集成。
代码集成有两种方法:
- 在Simulink内部集成,Simulink提供了主流MCU的TSP(Target Support Package),其实背后就是TLC,通过模块的拖入,在代码生成时调用对应的TLC生成与模块对应的C代码
- 在Simulink外部集成,Simulink生成的代码在其他IDE环境中与手写代码做匹配
两种方法各有特点,个人理解 [暂时只能理解到这个程度]:
- 利用S-Function和TLC进行集成,前期开发工作量大,但开发好之后,使用较为方便,且可直接调用外部IDE进行程序烧录
- 在外部集成,省去了编写模块的步骤,同时驱动部分的灵活性更高
很明显,第2种方法更合理一些,但是目前工作过程中,研发工程师更关心的是算法的执行效果,为了弥补研发工程师应对较短的开发周期,同时降低对代码集成工作的负荷,可以采用第1种方法,并在此基础上配合标定工具,进行快速原型开发
外部代码集成
这个部分其实是源自上一篇笔记,主要是因为上一篇笔记学习的时候,是针对<基于模型的设计 MCU篇>中的实例,这个地方对main.c文件做了自定义.
为了便于说明其过程,这里用STC89C52的开发板为例, 对外部代码集成做说明
要进行外部代码集成, 就需要调用model.c中的函数,因此需要在手写代码中加入#include model.h
在Simulink中做如下设置:
- 取消勾选 generate an example main program
- 勾选 package code and artifacts 自动打包生成代码,生成一个zip的压缩文件
编写main.c文件
#include "untitled.h"
/*这里添加驱动.c和.h文件*/
#include "reg52.h"
#define P0 led
void main(void){
/*初始化模型*/
model_initialize();
while(1){
/*这里定义其他需要执行的任务*/
}
/*model终止函数,可以在Simulink.Interface的界面中进行定义是否出现*/
#model_terminate();
}
这里的比例很简单,因为model_step()函数中什么也没有执行, 编译后,将main.c文件同生成的代码一起复制到IDE中,编译并烧录即可.
这里提到一个main.c文件, 这个文件怎么写比较合适?
模板文件
这里的模板文件配置是在Configuration中的Template中进行设置,其中file customization template就是控制用户自定义的代码生成效果用的tlc文件, 具体怎么写这个tlc可以参考waijung blockset.
内部集成 S Function and TLC
既然我们有了自定义的main.c文件, 再加上之前学习过的TLC生成模块级的代码,我们就可以实现自己制作一套底层驱动的模块了.
这两天出差中, 51单片机不在手边,回家后补充后续的51实例.
参考资料:
Mathworks
waijung blockset
华海科技 Rapid-ECU