1. 程式人生 > >基於STM32f429中ucosiii+emWin應用

基於STM32f429中ucosiii+emWin應用

第一篇 介紹

在這裡就是稍微介紹一下ucosiii和emWin,f429在網上資源也是非常成熟了,在此就不囉嗦了。
**uC/OS-III**:(Micro C OS Three 微型的C 語言編寫的作業系統第3版)是一個可升級的,可固化的,基於優先順序的實時核心。它對任務的個數無限制(uC/OS-II在2.80版本之前 最多允許任務個數為64個,之後達到255個)。uC/OS-III 是一個第3 代的系統核心,支援現代的實時核心所期待的大部分功能。例如資源管理,同步,任務間的通訊等等。然而,uC/OS-III 提供的特色功能在其它的實時核心中是找不到的,比如說完備的執行時間測量效能,直接地傳送訊號或者訊息到任務,任務可以同時等待多個核心物件等。
**emWin/UCGUI**:是一款影象介面製作工具,在影象製作這一塊應用相當廣泛,可使用 M4 核心 MCU 的時候會移植 UCGUI 來製作精美的 UI, UCGUI 的高階版本就是 emWin,而 STemWin是 SEGGER授權給ST的 emWin版本,ST的晶片可以免費使用 STemWin,而且 STemWin 針對 ST 的晶片做了優化。 本章我們將向大家介紹如何STM32F429 開發板上移植 STemWin, 在文章通過使用原子配套開發板 ALIENTEK 及配套液晶屏來實現對圖片製作, 硬體搭載包括 8080 介面的 2.8寸, 3.5 寸, 4.3 寸和 7 寸(SSD1963),還有 RGB 介面的 4.3 寸(480*272), 7 寸(800*480), 7 寸(1024*600)這七種不同尺寸和解析度的螢幕。

第二篇 uC/OS-III實現與應用

(1)系統概念

在應用之前首先了解 UCOSII 相關的概念需要大家瞭解一下: 任務優先順序,任務堆疊,任務控制塊,任務就緒表和任務排程器。
任務優先順序:這個概念比較好理解, ucos 中,每個任務都有唯一的一個優先順序。優先順序是任務的唯一標識。在 UCOSII 中, 使用 CPU 的時候,優先順序高(數值小)的任務比優先順序低的任務具有優先使用權,即任務就緒表中總是優先順序最高的任務獲得 CPU 使用權,只有高優先順序的任務讓出 CPU 使用權(比如延時)時,低優先順序的任務才能獲得 CPU 使用權。 UCOSII 不支援多個任務優先順序相同,也就是每個任務的優先順序必須不一樣。在軟體中可以類比成是執行緒,我們WINDOWS採用的也是單執行緒,即在同一時間下只有一個任務在允許,通過調節應用執行緒的優先順序可以確認執行緒搶佔順序。
任務堆疊

:就是儲存器中的連續儲存空間。為了滿足任務切換和響應中斷時儲存 CPU 暫存器中的內容以及任務呼叫其他函式時的需要,每個任務都有自己的堆疊。在建立任務的時候,任務堆疊是任務建立的一個重要入口引數。
任務控制塊 :OS_TCB,用來記錄任務堆疊指標,任務當前狀態以及任務優先順序等任務屬性。UCOSII 的任何任務都是通過任務控制塊(TCB)的東西來控制的,一旦任務建立了,任務控制塊 OS_TCB 就會被賦值。每個任務管理塊有3個最重要的引數:1任務函式指標;2任務堆疊指標;3任務優先順序;任務控制塊就是任務在系統裡面的身份證(UCOSII 通過優先順序識別任務),任務控制塊我們就不再詳細介紹了,詳細介紹請參考任哲老師的《嵌入式實時作業系統 UCOSII 原理及應用》一書第二章。
任務就緒表
:簡而言之就是用來記錄系統中所有處於就緒狀態的任務。 它是一個位圖,系統中每個任都在這個點陣圖中佔據一個進位制位,該位置的狀態( 1 或者 0)就表示任務是否處於就緒狀態。
任務排程:作用一是在任務就緒表中查詢優先順序最高的就緒任務,二是實現任務的切換。比如說,當一個任務釋放 cpu 控制權後,進行一次任務排程,這個時候任務排程器首先要去任務就緒表查詢優先順序最高的就緒任務,查到之後,進行一次任務切換,轉而去執行下一個任務。
UCOSII 的每個任務都是一個死迴圈。每個任務都處在以下 5 種狀態之一的狀態下,這 5種狀態是:睡眠狀態、 就緒狀態、 執行狀態、 等待狀態(等待某一事件發生)和中斷服務狀態。將執行狀態結合起來就是系統中一個任務的生命週期,即單個程式被呼叫從開始到結束的生命週期。
睡眠狀態:任務在沒有被配備任務控制塊或被剝奪了任務控制塊時的狀態。
就緒狀態: 系統為任務配備了任務控制塊且在任務就緒表中進行了就緒登記, 任務已經準備好了, 但由於該任務的優先順序比正在執行的任務的優先順序低, 還暫時不能執行, 這時任務的狀態叫做就緒狀態。
執行狀態:該任務獲得 CPU 使用權,並正在執行中,此時的任務狀態叫做執行狀態。
等待狀態: 正在執行的任務,需要等待一段時間或需要等待一個事件發生再執行時,該任務就會把 CPU 的使用權讓給別的任務而使任務進入等待狀態。
中斷服務狀態: 一個正在執行的任務一旦響應中斷申請就會中止執行而去執行中斷服務程式,這時任務的狀態叫做中斷服務狀態。狀態關係如下圖所示
這裡寫圖片描述

(2)任務操作

接下來 就到程式這一塊,主要是對系統任務進行建立、刪除、掛起和恢復進行操作。

任務建立

在這裡建立的是一個開始任務,其他的任務可在開始任務中按照這種格式進行建立多個任務,相當於在開始任務中進行main()函式的操作,即任務初始化以及系統死迴圈。任務操作程式碼意思見註釋。在任務建立之前要確定好任務的優先順序和任務堆疊大小

    //建立開始任務
    OSTaskCreate((OS_TCB    * )&StartTaskTCB,       //建立任務控制塊
                 (CPU_CHAR  * )"start task",        /*非任務函式名稱,系統本身不知道任務名稱,
                                                      僅知道任務地址與指標,此為輸出或除錯時使
                                                      用任務名稱的代替字串*/
                 (OS_TASK_PTR )start_task,          //任務函式
                 (void      * )0,                   /*定義函式形參,可以為&取址全域性變數。若只
                                                      有區域性變數,可用static定義區域性變數*/
                 (OS_PRIO     )START_TASK_PRIO,     //任務優先順序
                 (CPU_STK   * )&START_TASK_STK[0],  //任務堆疊基地址
                 (CPU_STK_SIZE)START_STK_SIZE/10,   //任務堆疊深度限位
                 (CPU_STK_SIZE)START_STK_SIZE,      //任務堆疊大小
                 (OS_MSG_QTY  )0,                   //任務內部訊息佇列能夠接收的最大訊息數目,為0時禁止接收訊息
                 (OS_TICK     )0,                   //當使能時間片輪轉時的時間片長度,為0時為預設長度,
                 (void      * )0,                   //使用者補充的儲存區
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, 
                                      //任務選項,是否需要清零該任務堆疊/是否儲存浮點運算暫存器
                 (OS_ERR    * )&err);               //存放該函式錯誤時的返回值

通過建立任務執行函式任務start_task()函式內容,如下:


    CPU_Init();
#if OS_CFG_STAT_TASK_EN > 0u
   OSStatTaskCPUUsageInit(&err);    //統計任務                
#endif

#ifdef CPU_CFG_INT_DIS_MEAS_EN      //如果使能了測量中斷關閉時間
    CPU_IntDisMeasMaxCurReset();    
#endif

#if OS_CFG_SCHED_ROUND_ROBIN_EN  //當使用時間片輪轉的時候
    //使能時間片輪轉排程功能,設定預設的時間片長度
    OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);  
#endif      
    __HAL_RCC_CRC_CLK_ENABLE();     //使能CRC時鐘
    GUI_Init();             //STemWin初始化
    WM_MULTIBUF_Enable(1);  //開啟STemWin多緩衝,RGB屏可能會用到
    OS_CRITICAL_ENTER();    //進入臨界區
    //STemWin Demo任務    
    OSTaskCreate((OS_TCB*     )&EmwindemoTaskTCB,       
                 (CPU_CHAR*   )"Emwindemo task",        
                 (OS_TASK_PTR )emwindemo_task,          
                 (void*       )0,                   
                 (OS_PRIO     )EMWINDEMO_TASK_PRIO,     
                 (CPU_STK*    )&EMWINDEMO_TASK_STK[0],  
                 (CPU_STK_SIZE)EMWINDEMO_STK_SIZE/10,   
                 (CPU_STK_SIZE)EMWINDEMO_STK_SIZE,      
                 (OS_MSG_QTY  )0,                   
                 (OS_TICK     )0,                   
                 (void*       )0,                   
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                 (OS_ERR*     )&err);
    //觸控式螢幕任務
    OSTaskCreate((OS_TCB*     )&TouchTaskTCB,       
                 (CPU_CHAR*   )"Touch task",        
                 (OS_TASK_PTR )touch_task,          
                 (void*       )0,                   
                 (OS_PRIO     )TOUCH_TASK_PRIO,     
                 (CPU_STK*    )&TOUCH_TASK_STK[0],  
                 (CPU_STK_SIZE)TOUCH_STK_SIZE/10,   
                 (CPU_STK_SIZE)TOUCH_STK_SIZE,      
                 (OS_MSG_QTY  )0,                   
                 (OS_TICK     )0,                   
                 (void*       )0,                   
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                 (OS_ERR*     )&err);            
    //LED0任務
    OSTaskCreate((OS_TCB*     )&Led0TaskTCB,        
                 (CPU_CHAR*   )"Led0 task",         
                 (OS_TASK_PTR )led0_task,           
                 (void*       )0,                   
                 (OS_PRIO     )LED0_TASK_PRIO,     
                 (CPU_STK*    )&LED0_TASK_STK[0],   
                 (CPU_STK_SIZE)LED0_STK_SIZE/10,    
                 (CPU_STK_SIZE)LED0_STK_SIZE,       
                 (OS_MSG_QTY  )0,                   
                 (OS_TICK     )0,                   
                 (void*       )0,                   
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                 (OS_ERR*     )&err);                    
    OS_TaskSuspend((OS_TCB*)&StartTaskTCB,&err);        //掛起開始任務             
    OS_CRITICAL_EXIT(); //退出臨界區
}

start_task()函式內容包括了emwindemo_task任務(emWin介面顯示任務)、touch_task 任務(液晶觸控任務)和 led0_task任務(LED指示燈閃爍任務),每個任務需設定任務優先順序以及堆疊空間大小,具體大小可結合實際需求設定。在 start_task 中建立了另外三個任務,在建立之後將自身( start_task)掛起。這裡,我們單獨建立 start_task,是為了提供一個單一任務,實現應用程式開始執行之前的準備工作(比如:外設初始化、建立訊號量、建立郵箱、建立訊息佇列、建立訊號量集、建立任務、初始化
統計任務等等)。任務建立完之後就執行任務定義的工作函式。

知道任務建立了,那麼接下來就是任務的其他操作

刪除任務

刪除任務主要就是呼叫OSTaskDel()函式進行實現,函式原型如下

void  OSTaskDel (OS_TCB  *p_tcb,   //指向要刪除的任務 TCB,也可以傳遞一個 NULL 指標來刪除呼叫 
                                   //OSTaskDel()函式的任務自身。
                 OS_ERR  *p_err)   //指向一個變數用來儲存呼叫 OSTaskDel()函式後返回的錯誤碼。
{

比如我需要刪除建立任務中的emWin,只需要呼叫這個函式,函式執行後將刪除函式任務,不再執行。但是這個任務的任務堆疊、 OS_TCB 所佔用的記憶體並沒有釋放掉,因此我們可以利用他們用於其他的任務,當然我們也可以使用記憶體管理的方法給任務堆疊和 OS_TCB 分配記憶體,這樣當我們刪除掉某個任務後我們就可以使用記憶體釋放函式將這個任務的任務堆疊和 OS_TCB 所佔用的記憶體空間釋放掉。刪除emWin任務操作如下

OSTaskDel((OS_TCB*)&EmwindemoTaskTCB,&err);

掛起任務和恢復任務

掛起任務意思就是將在搶佔CPU資源的任務給暫停,讓出資源給其他任務呼叫資源,此時不再有作用,保留了使用功能。當需要再次使用的時候,給任務進行恢復即可繼續執行。比如我需要對emWin任務進行掛起和恢復,只需進行一下操作就好了

OSTaskSuspend((OS_TCB*)&EmwindemoTaskTCB,&err);  //將emWin任務進行掛起
OSTaskResume((OS_TCB*)&EmwindemoTaskTCB,&err);   //將emWin任務進行恢復

第三篇 emWin實現與應用

emWin是一種圖形化介面操作庫,能夠對介面進行一系列的操作。如文字、顏色、控制元件、圖片等等。還有專門的圖形制作軟體,可根據需求通過呼叫API函式對介面進行任意操作。

1 GUIBuilder應用
(1)在軟體上模擬
emWin在vc++和vs上面都是可以通過模擬來模擬介面的,由於在實際過程中在硬體上每次編譯和燒錄都需要消耗很多時間,所以可以通過在模擬器上進行模擬,仿好之後就可以將介面移植到硬體上
首先開啟GUIBuilder,介面中現在是什麼都沒有的,在新增控制元件之前,首先需要建立視窗,新增Franewin(有邊框)或者Window(無邊框)
這裡寫圖片描述
(2)在硬體上使用
2 BMP圖片生成
BMP圖片顯示可參照以下地址,其實emwin的操作在原子、野火、安富來都有操作,可以直接用pdf教程
http://blog.csdn.net/efm32/article/details/8496812
**

第四篇 ucosiii+emwin

emwin的顯示需要在ucosiii分配一個任務,ucosiii的任務優先順序不能太低,由於系統的任務優先順序是從3開始,前面的任務用於系統任務計數和系統定時器。建議任務定義優先順序為4-5,可視實際情況而定。由於emwin相對ucgui所需記憶體要大,所以需要保證有足夠的ram空間執行emwin,則必須加入外部sram,建議給emwin分配ram為2M,就這樣,系統就能夠跑emwin了
如有問題可加QQ875213753聯絡,謝謝

**