導言-一個基于模型的例子
使用Arduino在simulink中搭建的LED閃爍的一個例子如圖1所示,相比之前C語言代碼實現的方式,這里沒有寫一行代碼就實現了LED閃爍。讀者有沒有感覺這種開發方式即簡單又方便,要實現什么功能就直奔主題,不用一行一行的敲代碼、排查代碼錯誤。圖1只是arduino其中的I/O輸出外設,在圖2中還有其它很多外設可以使用,再結合matlab強大的功能,讀者可以實現很多實際應用。
圖1 Arduino-simulink的LED閃爍模型
圖2 simulink中arduino其它外設的模型
任意單片機基于模型開發方式
并不是每一個芯片廠商都有足夠的人力和資金投入到主流開發軟件的生態適配,目前除了市面上用的比較火的幾款單片機(STM32、TMS320F28xx、S32K等)和Arduino平臺可以直接使用Matlab的硬件支持包直接開發外,其它單片機沒辦法直接使用,這里給大家介紹一種萬能的方式,可以在任意單片機上使用基于Simulink模型開發方式。
1、8051單片機上運行Simulink模型代碼
第1步:搭建Simulink模型
如圖3 所示,,這里使用了三個庫,分別是“Delay(延時模型)”、“Logical Operator-NOT(邏輯操作-非模型)”和“out(輸出端口模型)”,這里的輸出端口為了方便代碼移植將名字改為LED。
圖3 LED閃爍simulink模型
第2步:設置模型生成參數并生成代碼
如圖4所示,點擊按鈕“Model Configuration Parameters”對simulink進行設置。
圖4 simulink設置按鈕
如圖5所示,在彈出的“Configuration Parameters:xxxx”窗口中找到“Solver”欄,并點擊設置運行參數,按照圖中的設置,完成后點擊“Apply”。
圖5 “Solver”欄參數設置
如圖6所示,在“Hardware Implementtation”欄中設置硬件參數,按照圖中的設置進行操作,完成后點擊“Apply”。
圖6 “Hardware Implementtation”欄參數設置
如圖7所示,點擊“Code Generation”欄,設置代碼生成參數,完成后點擊“Apply”。
圖7 “Code Generation”參數設置
如圖8所示,點開“Code Generation”左邊的“>”符號,在子欄目中找到“Code Style”項設置代碼生成風格,完成后點擊“Apply”。
圖8 “Code Style”欄設置
如圖9所示,點開“Code Generation”左邊的“>”符號,在子欄目中找到“Code Placement”中設置“File packaging format”參數,完成后點擊“Apply”,到這一步,所有參數都設置完成,然后點擊“OK”按鈕。
圖9 “Code Placement”欄設置
如圖10所示,點擊按鈕“Build Model”生成代碼。
圖10 點擊生成模型代碼
代碼生成根據電腦性能不同,需要的時間也不一樣,稍等一會兒,彈出“Code Generation Report”窗口報告,如圖11所示,在這個窗口中可以看到整個模型生成了三個文件,分別是“ert_main.c”、"LED_Blink.c"和"LED_Blink.h",然后在LED_Blink.slx文件所在的目錄下多了一個“LED_Blink_ert_rtw”名字的文件夾,生成的三個文件也包含在當中;看這三個代碼有點像之前講的模塊化編程方式命名。
圖11 LED_Blink模型代碼生成報告
第3步:將simulink生產的代碼添加到8051單片機工程中
這一步也是整個過程中最關鍵部分,也是在很多資料中一直沒講清楚的部分,將生成的代碼移植到51單片機工程中去。先新建一個名字(其它名字也可以,只要正確建立Keil工程即可)為“LED_Blink”的Keil工程,工程的存放路徑放在剛剛模型生成代碼"Blink→LED_Blink_ert_rtw“文件夾下,如圖12所示。
圖12 在生成模型文件夾下建一個Keil工程
打開剛剛建立的Keil工程,將ert_main.c和LED_Blink.c文件添加到”Source Group 1“中,如圖13所示。
圖13 模型代碼添加
在剛剛添加的文件中雙擊打開ert_main.c,在下面代碼位置處加入8051單片機的內容,代碼如下所示:
#include < stddef.h >
#include < stdio.h > /* This ert_main.c example uses printf/fflush */
#include "LED_Blink.h" /* Model's header file */
#include "rtwtypes.h"
#include < REGX52.H > /* 添加51單片機頭文件 */
/*********** 變量定義 *************/
#define MAIN_CLOCK 12000000
#define SYSTEM_DELAY 1000 /* 系統周期1ms */
#define LED_TASK_TIME 500 /* SYSTEM_DELAY*0.500 = 500ms任務 */
uint16_T LED_Task_Count = LED_TASK_TIME; /* 任務定時器變量 */
void SYSTEM_T0_Init( void ); /* 定時器0初始化函數 */
添加單片機代碼
然后在ert_main.c文件中添加定時器初始化代碼,如下所示:
void SYSTEM_T0_Init( void )
{
/* 定時器0配置為16位定時器,當溢出時手工重裝 */
/* 清除所有有關T0的位 (T1不變) */
TMOD &= 0xF0;
/* 設置所需的T0相關位 (T1 不變) */
TMOD |= 0x01;
/* 停止定時器0 */
TR0 = 0;
/* 設置定時器重裝值 */
/* 我們這里設置1ms產生一次中斷 */
/* 定時器低8位賦值 */
TL0 = 65536 -(MAIN_CLOCK/SYSTEM_DELAY/12);
/* 定時器高8位賦值 */
TH0 = (65536-(MAIN_CLOCK/SYSTEM_DELAY/12)) >>8;
/* 啟動T0 */
TR0 = 1;
/* 使能定時器T0中斷 */
ET0 = 1;
}
在ert_main.c中編寫定時器中斷代碼,如下所示:
/*************************************
** 函 數 名:SYSTEM_Tick_Update() interrupt 1
** 輸入參數:none
** 返 回 值:none
** 說 明:定時器T0中斷入口函數
**************************************/
void SYSTEM_Tick_Update( void ) interrupt 1
{
/* 停止定時器0 */
TR0 = 0;
/* 設置定時器重裝值 */
/* 我們這里設置1ms產生一次中斷 */
/* 定時器低8位賦值 */
TL0 = 65536 -(MAIN_CLOCK/SYSTEM_DELAY/12);
/* 定時器高8位賦值 */
TH0 = (65536-(MAIN_CLOCK/SYSTEM_DELAY/12)) >>8;
/* 啟動T0 */
TR0 = 1;
/* LED Task 任務計時器*/
LED_Task_Count--;
}
定時器中斷函數代碼
在main主函數中對代碼進行修改,如下所示:
int_T main()
{
/* Initialize model */
LED_Blink_initialize();
/* 定時器0 初始化 */
SYSTEM_T0_Init();
/* 使能總中斷,這樣定時器0才會啟動 */
EA = 1;
/* Attach rt_OneStep to a timer or interrupt service routine with
* period 0.2 seconds (the model's base sample time) here. The
* call syntax for rt_OneStep is
*
* rt_OneStep();
*/
while (rtmGetErrorStatus(LED_Blink_M) == (NULL)) {
/* Perform other application tasks here */
if(LED_Task_Count<=0)
{
LED_Task_Count = LED_TASK_TIME;
rt_OneStep();
/*輸入/輸出接口放置位置*/
P1_0 = LED_Blink_Y.LED;
}
}
/* Disable rt_OneStep() here */
/* Terminate model */
LED_Blink_terminate();
return 0;
}
main函數中代碼
第4步:編譯Keil工程并運行代碼
點擊Keil編譯按鈕編譯代碼,然后將代碼燒錄到實際芯片中或使用Pretous仿真驗證代碼。到這里大家就完成了在51單片機上實現LED閃爍Simulink模型代碼移植的例子,LED閃爍的頻率實際由宏定義#define LED_TASK_TIME 500來控制,在8051單片機上運行該代碼時LED將以500ms的周期翻轉。
2、simulink生成模型代碼剖析
關于8051單片機怎么搭建簡單操作系統框架可以參考網絡上其他文章或關注作者的后續文章,這里就不再贅述,如圖14所示的LED閃爍模型,實際上就是運行模型生成的rt_OneStep()函數,每個Simulink生成的模型里面都會有這個函數,rt_OneStep()運行完之后所有通過輸入端的數據都會在搭建的模型邏輯中處理,然后通過輸出端輸出處理完后的數據,在LED閃爍模型中,沒有輸入端,只有輸出端,所以模型每運行完一次,里面的邏輯翻轉一次輸出端口LED狀態,即LED_Blink_Y.LED的數據,然后只需將模型輸出端口與實際物理端口關聯即可,這里關聯的是P1_0端口,則最終表現出來的效果就是P1_0狀態,即模型每運行一次,P1_0端口電平發生一次翻轉,P1_0端口有連接LED,LED就會一直閃爍。
圖14 基于模型LED程序執行流程
下面再深入到rt_OneStep()函數詳細了解下它到底在里面做了什么事情,是不是與前面所說的一致,rt_OneStep()函數詳細內容,函數中的其它內容暫時不管,可以看到里面關鍵的一步,調用了LED_Blink_step()函數,具體代碼如下所示:
void rt_OneStep(void)
{
static boolean_T OverrunFlag = false;
/* Disable interrupts here */
/* Check for overrun */
if (OverrunFlag) {
rtmSetErrorStatus(LED_Blink_M, "Overrun");
return;
}
OverrunFlag = true;
/* Save FPU context here (if necessary) */
/* Re-enable timer or interrupt here */
/* Set model inputs here */
/* Step the model */
LED_Blink_step();
/* Get model outputs here */
/* Indicate task complete */
OverrunFlag = false;
/* Disable interrupts here */
/* Restore FPU context here (if necessary) */
/* Enable interrupts here */
}
然后再到LED_Blink_step()函數中查看具體內容,在主函數中調用的LED_Blink_Y.LED在該函數中可以找到具體的邏輯。至此,LED閃爍模型的整個代碼分析完成。其它模型也可以采用類似的方式來分析,具體代碼如下所示:
void LED_Blink_step(void)
{
boolean_T rtb_Delay;
/* Delay: '< Root >/Delay' */
rtb_Delay = LED_Blink_DW.Delay_DSTATE[0];
/* Outport: '< Root >/LED' incorporates:
* Delay: '< Root >/Delay'
*/
LED_Blink_Y.LED = LED_Blink_DW.Delay_DSTATE[0];
/* Update for Delay: '< Root >/Delay' incorporates:
* Logic: '< Root >/Logical Operator'
*/
LED_Blink_DW.Delay_DSTATE[0] = LED_Blink_DW.Delay_DSTATE[1];
LED_Blink_DW.Delay_DSTATE[1] = !rtb_Delay;
}
-
單片機
+關注
關注
6037文章
44558瀏覽量
635355 -
C語言
+關注
關注
180文章
7604瀏覽量
136841 -
Simulink
+關注
關注
22文章
535瀏覽量
62402 -
模型
+關注
關注
1文章
3243瀏覽量
48842 -
Arduino
+關注
關注
188文章
6469瀏覽量
187091
發布評論請先 登錄
相關推薦
評論