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