目的

本笔记的学习目的是了解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自动生成的,需要注意的是里面默认的数据结构与类型,如下表:

数据类型命名变量名
ModelRT_MODEL_modelmodel_m
ParametersP_modelmodel_p
external inputsExtU_modelmodel_U
External outputsExtY_modelmodel_Y
Block signalsB_modelmodel_B
Block statesDW_modelmodel_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

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐