前面介紹了MDB的設計思想並對比了它和傳統的嵌入式軟件開發之間的差異,現在開始使用Simulink工具演示模型的搭建和C代碼的自動生成過程。
Matlab版本:R2018B
一、算法模型的搭建
搭建一個具有計數功能模型,當使能計數時,每運行一次該計數模塊計數值加1,當計數值大於目標值時,相應的使能標志位置位,當初始化計數使能時,計數值被初始化為特定的輸入值
模型的輸入量描述:
InitVal:計數器初始化值
B_Init:為1時,計時器模塊被初始化成InitVal值
B_Calc:為1時,計數器模塊每運行一次自加1
模型內部變量:
CntTimer:存儲當前計數值
模型輸出量描述:
B_En: 使能標志位,計數值大於目標值時被置1
CurTimer:當前計數值
設置const、switch block的輸出數據類型為Inherit:Inherit via back propagation(繼承后項的數據類型)
二、代碼的生成
1、使用數據管理,設置變量屬性
數據據管理主要是對Simulink/Stateflow模型中的兩類數據進行管理,一是信號,一是參數。對應於C代碼,我們可以簡單的把信號對應到變量上,而參數,則是不通過程序運行而發生變化的,參數的變化,一般是通過人工調節完成的,也就是參數調節,參數調節的目的是為了選擇合適的參數以得到最佳的性能。
數據管理的方式,使用的是數據對象進行數據管理,這里的“對象”二字,和我們經常聽到的“面向對象編程”里面的“對象”意義相同。Simulink為用戶事先定義好兩個包,一個是Simulink Package,一個是mpt Package。以Simulink Package為例,包里面有類,分別為Simulink.Signal和Simulink.Parameter兩個類。用戶可以通過這兩個類定義相應的對象(Object),然后通過類提供的屬性(Property)定義數據的屬性。其實這兩個類里面除了屬性之外,還定義了方法(Method),一般情況下,我們管理數據,使用屬性就夠了。
點擊Model Explorer圖標,進入Model Explorer界面
在Base Workspace中創建信號對象,信號對象名和simulink使用的信號名一致
step1:選擇Base Workspace
step2:選擇創建一個信號對象,信號對象對應於C代碼中的變量
step3:修改創建信號對象的名稱,名稱應該和模型中的信號一致
step4:設置創建信號對象的屬性
注意:CntTimer使用Data store memory模塊,創建對象時需要設置Dimersions、Complexity兩個屬性,這里CntTimer為一維實數,將維度Dimersions設置成1,Complexity設置為real實數即可
Base Workspace中創建singal對象是用來對simulink中使用的信號進行數據定義,模型中的simulink信號對應於生成的C代碼中的變量。我們知道C代碼中的變量需要指定數據類型,使用前需定義等等,在模型中設置這些屬性就是通過sigal對象來指定生成代碼的對應變量的數據類型。后面我們在生成代碼的配置中會講到如何將這些signal對象和simulink模型中的信號進行聯系起來
2、代碼生成配置
第一步,點擊simulink中的如下圖標,或者使用ctl+e快捷鍵,進入代碼生成和模型仿真的配置界面
第二步,設置slover選項
因為計算機內只能執行離散數據類型,我們想要生成用於單片機器執行的代碼,所以這里的解算器選擇固定步長,解算器選擇離散
fixed-step size:步長的時間,simulink仿真時使用,可根據控制器時鍾頻率進行設置
第三步,設置Diagnostics選項的Data Validity項容
設置其中對signal信號的解析,選擇explicit and implicit項讓解析時將simulink中的siganl信號和workspace中創建的同名的signal對象進行聯系起來,siganl對象即前面我們介紹的在Model Explore中創建的內容。若這里不進行選擇,也就意味着模型的輸入輸出信號沒進行定標,使用默認數據類型生成代碼,生成的代碼使用結構體來描述輸入輸出,這樣的代碼可用性不高。
注:也可以鼠標右鍵單擊signal的信號線,選擇properties,勾選“signal name must resolve to simulink siganl object”來進行signal和signal同名對象直接的捆綁。這種方式需要一個個的點擊信號線進行設置,沒有上述直接選擇explicit and implicit項便捷
第四步, 設置Code generation選項
選擇系統目標文件為ert.tlc,用於生成嵌入式代碼,ert針對嵌入式期間對生成的代碼進行了相應的優化處理
勾選Generater code only選項,選擇僅生成代碼
第五步,設置Code generation選項中的optimization項
這個選項內包含對生成代碼的優化,可設置內容比較多,這里只設置了一小部分
remove root level I/O zero initialization:勾選上,在生成代碼的初始化函數中不進行對輸出變量進行初始化
remove root internal data zero initialization:勾選上,在生成代碼的初始化函數中不進行對內部data store memory變量進行初始化
第六步,設置Code generation選項中的Interface項
修改生成代碼依賴函數庫的存放位置(一般使用定點數計算和查表時會生成相應庫函數),取消浮點數、復數的支持,取消terminate函數生成
remove error status field in real-time model data structure:勾選上,不提供用於錯誤狀態的處理接口
第七部,設置Code generation選項中的Templates項
取消勾選generate an example main porgram,設值生成代碼時不生成一個main函數的調用例子
也可以修改code templates中的生成代碼的模板,自定義生成代碼中變量、函數、宏的排放順序
第八步,點擊Apply,執行ctrl+b編譯模塊,生成代碼
配置完成,生成代碼,可以看出生成的代碼和我們的模型實現的邏輯一致,並且生成的代碼還是比較精簡的,可讀性也很強。
值得注意的是在生成代碼的配置中還有其他部分配置可以設置,這里我把這些選項保持默認內容,當然你在使用時可以根據根據自己的需求設置其他選項,如可以設置生成的代碼中包含那些頭文件,設置編譯工具鏈等等,這里就不一一的介紹了