1. 程式人生 > >Simlulink學習筆記——C程式碼自動生成解析

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) */
}

      顯然自動生成的程式碼預設變數的資料型別為結構體,因此程式中運用了大量的結構體型別,讀起來額外的費勁,後期可以自己手動完善來增強的程式碼的可讀性。當然原始檔當中沒有主函式,不能直接執行,裡面只是邏輯程式碼,也沒有涉及到硬體的底層驅動。不過,基於模型的設計還是能夠加快專案的研發速度,降低研發成本。