Simlulink学习笔记——C代码自动生成解析

一、理想质量 - 弹簧 - 阻尼系统

        弹簧-质量-阻尼系统是一种比较普遍的机械振动系统,生活中也随处可见这种系统,例如汽车缓冲器就是一种可以耗减运动能量的装置,是保证驾驶员行车安全的必备装置。我们通过建立理想的质量 - 弹簧 - 阻尼系统的二阶物理系统模型,来学习simulink的应用。系统方程的的组成部分为质量,刚度和阻尼,方程如下所示:

接下来我们建立模型如下所示:

我们打开红色文本 Parameter Initialization,里面是一些参数初始化命令,如下所示:

在运行模型前,点击该文本,触发回调函数,完成参数初始化过程,点击之后,我们观察到工作空间中的变量如下:

参数初始化以后,我们运行模型:

二、C代码自动生成

            本示例学习如何为Simulink模型选择目标,生成用于实时模拟的C代码以及查看生成的文件。该模型代表一个8位计数器,为一个触发子系统提供信号,该子系统由常量模块INC,LIMIT和RESET等组成。 输入和输出表示模型的I / O,放大器子系统通过增益系数K放大输入信号,当信号equal_to_count为真时,增益系数K更新。

          模型如下所示:

打开放大器子系统,可以看到内部结构如下:

   变量的参数初始化如下所示:

     建立好模型以后,单击Simulation -> Configuration Parameters,从模型编辑器打开Configuration Parameters对话框:

        为了生成特定目标环境或目的代码,我们需要使用系统目标文件提供一些内置目标选项,系统目标文件控制目标代码的生成过程。 

      设置完成以后,回到模型窗口,使用快捷键Ctrl + B生成代码:

在生成的文件当中,我们找到这几个源文件和头文件:

接下来我们解读自动生成的代码,为了方便起见,我们把它的注释删除掉。

头文件 example2018_7_25.h 如下所示:



#ifndef RTW_HEADER_example2018_7_25_h_
#define RTW_HEADER_example2018_7_25_h_
#include <stddef.h>
#include <string.h>
#ifndef example2018_7_25_COMMON_INCLUDES_
# define example2018_7_25_COMMON_INCLUDES_
#include "rtwtypes.h"
#include "rtw_continuous.h"
#include "rtw_solver.h"
#endif                                

#include "example2018_7_25_types.h"


#include "multiword_types.h"


#ifndef rtmGetErrorStatus
# define rtmGetErrorStatus(rtm)        ((rtm)->errorStatus)
#endif

#ifndef rtmSetErrorStatus
# define rtmSetErrorStatus(rtm, val)   ((rtm)->errorStatus = (val))
#endif



typedef struct {
  uint8_T X;                           
} DW_example2018_7_25_T;



typedef struct {
  ZCSigState Amplifier_Trig_ZCE;       
} PrevZCX_example2018_7_25_T;



typedef struct {
  int32_T Input;                      
} ExtU_example2018_7_25_T;



typedef struct {
  int32_T Output;                     
} ExtY_example2018_7_25_T;


struct tag_RTM_example2018_7_25_T {
  const char_T *errorStatus;
};



extern DW_example2018_7_25_T example2018_7_25_DW;

extern ExtU_example2018_7_25_T example2018_7_25_U;

extern ExtY_example2018_7_25_T example2018_7_25_Y;



extern void example2018_7_25_initialize(void);
extern void example2018_7_25_step(void);
extern void example2018_7_25_terminate(void);



extern RT_MODEL_example2018_7_25_T *const example2018_7_25_M;

#endif                               

头文件 example2018_7_25_private.h 如下所示:



#ifndef RTW_HEADER_example2018_7_25_private_h_
#define RTW_HEADER_example2018_7_25_private_h_
#include "rtwtypes.h"
#include "multiword_types.h"
#endif                              

源文件如下所示:


#include "example2018_7_25.h"
#include "example2018_7_25_private.h"


// UnitDelay Block states  
DW_example2018_7_25_T  example2018_7_25_DW;

// Previous zero-crossings (trigger) states  
PrevZCX_example2018_7_25_T  example2018_7_25_PrevZCX;

// External inputs  
ExtU_example2018_7_25_T  example2018_7_25_U;

// External outputs 
ExtY_example2018_7_25_T example2018_7_25_Y;

// Real-time model  
RT_MODEL_example2018_7_25_T  example2018_7_25_M_;

RT_MODEL_example2018_7_25_T *const example2018_7_25_M = &example2018_7_25_M_;




/* Model step function */
void example2018_7_25_step(void)

{

  boolean_T rtb_equal_to_count;
  // 定义了一个布尔变量,用来表示比较结果

  example2018_7_25_DW.X++;
  //  example2018_7_25_DW.X是延时模块的值,即累加值,
  //  由于模型中的INC为常数1,所以每次加1。
  //  首先呢,变量example2018_7_25_DW是一个结构体,其变量声明语句如下所示:
  //  extern DW_example2018_7_25_T example2018_7_25_DW;
  //  显然,DW_example2018_7_25_T代表一个结构体,我们找到这个结构体的定义如下:
  //  typedef struct{
  //		  uint8_T X;
  //	    } DW_example2018_7_25_T;

  rtb_equal_to_count = (example2018_7_25_DW.X != 16);

  if ( rtb_equal_to_count && (example2018_7_25_PrevZCX.Amplifier_Trig_ZCE != POS_ZCSIG)) 
  {
    
    example2018_7_25_Y.Output = example2018_7_25_U.Input << 1;
	// 对于逻辑(算术)左移,且不发生溢出时,结果增加两倍,
	// 这正好对应于模型中触发子系统中的增益模块的增益值2
  }
  // 首先呢,变量example2018_7_25_PrevZCX 也是一个结构体变量,其变量声明语句如下所示:
  // PrevZCX_example2018_7_25_T  example2018_7_25_PrevZCX;
  // 显然,PrevZCX_example2018_7_25_T是一个结构体,其结构体定义如下:
  //    typedef struct {
  //         ZCSigState Amplifier_Trig_ZCE;      
  //      } PrevZCX_example2018_7_25_T;

  // 那么,变量example2018_7_25_U 的定义如下:
  // ExtU_example2018_7_25_T   example2018_7_25_U;
  // 结构体 ExtU_example2018_7_25_T的定义如下:
  //  typedef struct {
  //	  int32_T Input;                     
  //	} ExtU_example2018_7_25_T;

  //  最后,变量example2018_7_25_Y 的定义如下:
  //  ExtY_example2018_7_25_T   example2018_7_25_Y;
  //  结构体 ExtY_example2018_7_25_T 的定义如下:
  //   typedef struct {
  //		  int32_T Output;                     
  // 	} ExtY_example2018_7_25_T;


  example2018_7_25_PrevZCX.Amplifier_Trig_ZCE = rtb_equal_to_count;
  // 更新触发状态

  if (!rtb_equal_to_count) 

  { 
    example2018_7_25_DW.X = 0U;	
  }
  // 当布尔值rtb_equal_to_count为假时,代表计数器已经计数到16了,
  // 当计数到16时,需要重新将延时模块UnitDelay的状态值(即累加值)归零,
  // 此时0U表示无符号形式存储的零值
  // 在头文件中,还有定义:
  // Logical type definitions  
	/*  #if (!defined(__cplusplus))
				#  ifndef false
				#   define false                       (0U)
				#  endif
		
				#  ifndef true
				#   define true                        (1U)
				#  endif
				#endif
				#endif
   */
}




/* Model initialize function */
void example2018_7_25_initialize(void)

{

  rtmSetErrorStatus(example2018_7_25_M, (NULL));
  // 首先,变量example2018_7_25_M的定义如下:
  // RT_MODEL_example2018_7_25_T * const  example2018_7_25_M  =  &example2018_7_25_M_;
  // 那么,RT_MODEL_example2018_7_25_T又是个什么数据类型呢?可以看到定义如下:
  //  typedef   struct  tag_RTM_example2018_7_25_T    RT_MODEL_example2018_7_25_T;


  (void) memset((void *)&example2018_7_25_DW, 0,sizeof(DW_example2018_7_25_T));
  // 将example2018_7_25_DW所在的内存空间赋0
  // memset函数经常用于清0

  example2018_7_25_U.Input = 0;

  example2018_7_25_Y.Output = 0;

  example2018_7_25_PrevZCX.Amplifier_Trig_ZCE = POS_ZCSIG;

  example2018_7_25_DW.X = 0U;

  example2018_7_25_Y.Output = 0;

}





/* Model terminate function */
void example2018_7_25_terminate(void)
{
  /* (no terminate code required) */
}

      显然自动生成的代码默认变量的数据类型为结构体,因此程序中运用了大量的结构体类型,读起来额外的费劲,后期可以自己手动完善来增强的代码的可读性。当然源文件当中没有主函数,不能直接运行,里面只是逻辑代码,也没有涉及到硬件的底层驱动。不过,基于模型的设计还是能够加快项目的研发速度,降低研发成本。

猜你喜欢

转载自blog.csdn.net/weixin_41695564/article/details/81195939