一,前后台系統和RTOS
1,前后台系統
早期嵌入式開發沒有嵌入式操作系統的概念 ,直接操作裸機,在裸機上寫程序,比如用51單片機基本就沒有操作系統的概念。通常把程序分為兩部分:前台系統和后台系統。
簡單的小系統通常是前后台系統,這樣的程序包括一個死循環和若干個中斷服務程序:
應用程序是一個無限循環,循環中調用API函數完成所需的操作,這個大循環就叫做后台系統。
中斷服務程序用於處理系統的異步事件,也就是前台系統。前台是中斷級,后台是任務級。


2,RTOS
RTOS全稱為: Real Time OS,就是實時操作系統,強調的是: 實時性。實時操作系統又分為硬實時和軟實時。
硬實時要求在規定的時間內必須完成操作 ,硬實時系統不允許超時,在軟實時里面處理過程超時的后果就沒有那么嚴格。
在實時操作系統中,我們可以把要實現的功能划分為多個任務,每個任務負責實現其中的一部分,每個任務都是一個很簡單的程序,通常是一個死循環。
RTOS操作系統: UCOS, FreeRTOS, RTX, RT-Thread, DJYOS等。
RTOS操作系統的核心內容在於: 實時內核。
3,可剝奪型內核
RTOS的內核負責管理所有的任務,內核決定了運行哪個任務,何時停止當前任務切換到其他任務,這個是內核的多任務管理能力。
多任務管理給人的感覺就好像芯片有多個CPU,多任務管理實現了CPU資源的最大化利用,多任務管理有助於實現程序的模塊化開發,能夠實現復雜的實時應用。
可剝奪內核顧名思義就是可以剝奪其他任務的CPU使用權,它總是運行就緒任務中的優先級最高的那個任務


UCOS系統簡介
UCOS是Micrium公司出品的RTOS類實時操作系統, UCOS目前有兩個版本:
UCOSII和UCOSIII。
UCOSIII是一個可裁剪、可剝奪型的多任務內核,而且沒有任務數限制。
UCOSIII提供了實時操作系統所需的所有功能,包括資源管理、同步、任務通信等。
UCOSIII是用C和匯編來寫的,其中絕大部分都是用C語言編寫的,只有極少數的與處理器密切相關的部分代碼才是用匯編寫的, UCOSIII結構簡潔,可讀性很強!最主
要的是非常適合初次接觸嵌入式實時操作系統學生、嵌入式系統開發人員和愛好者學習。
#include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "includes.h" #include "dht.h" #include "infra_red.h" //任務1控制塊 OS_TCB Task1_TCB; void task1(void *parg); CPU_STK task1_stk[128]; //任務1的任務堆棧,大小為128字,也就是512字節 //任務2控制塊 OS_TCB Task2_TCB; void task2(void *parg); CPU_STK task2_stk[128]; //任務2的任務堆棧,大小為128字,也就是512字節 //主函數 int main(void) { OS_ERR err; delay_init(168); //時鍾初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中斷分組配置 uart_init(9600); //串口初始化 LED_Init(); //LED初始化 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE); //打開溫濕度模塊控制GPIOG的時鍾 //OS初始化,它是第一個運行的函數,初始化各種的全局變量,例如中斷嵌套計數器、優先級、存儲器 OSInit(&err); //創建任務1 OSTaskCreate( (OS_TCB *)&Task1_TCB, //任務控制塊 (CPU_CHAR *)"Task1", //任務的名字 (OS_TASK_PTR)task1, //任務函數 (void *)0, //傳遞參數 (OS_PRIO)3, //任務的優先級 (CPU_STK *)task1_stk, //任務堆棧基地址 (CPU_STK_SIZE)128/10, //任務堆棧深度限位,用到這個位置,任務不能再繼續使用 (CPU_STK_SIZE)128, //任務堆棧大小 (OS_MSG_QTY)0, //禁止任務消息隊列 (OS_TICK)0, //默認時間片長度 (void *)0, //不需要補充用戶存儲區 (OS_OPT)OS_OPT_TASK_NONE, //沒有任何選項 &err //返回的錯誤碼 ); //創建任務2 OSTaskCreate( (OS_TCB *)&Task2_TCB, //任務控制塊 (CPU_CHAR *)"Task2", //任務的名字 (OS_TASK_PTR)task2, //任務函數 (void *)0, //傳遞參數 (OS_PRIO)4, //任務的優先級 (CPU_STK *)task2_stk, //任務堆棧基地址 (CPU_STK_SIZE)128/10, //任務堆棧深度限位,用到這個位置,任務不能再繼續使用 (CPU_STK_SIZE)128, //任務堆棧大小 (OS_MSG_QTY)0, //禁止任務消息隊列 (OS_TICK)0, //默認時間片長度 (void *)0, //不需要補充用戶存儲區 (OS_OPT)OS_OPT_TASK_NONE, //沒有任何選項 &err //返回的錯誤碼 ); //啟動OS,進行任務調度 OSStart(&err); } void task1(void *parg) { OS_ERR err; uint8_t dht_data[5]={0}; printf("task1 is create ok\r\n"); //紅外初始化 ir_init(); while(1) { if(dht11_read_data(dht_data)==0) { printf("temp=%d.%d\r\n",dht_data[2],dht_data[3]); printf("humi=%d.%d\r\n",dht_data[0],dht_data[1]); printf("\r\n"); } delay_ms(500); delay_ms(500); OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err); //延時1s } } void task2(void *parg) { OS_ERR err; printf("task2 is create ok\r\n"); while(1) { //添加LED2閃爍 printf("task2 is running ...\r\n"); OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err); //延時1s } }

(1)假如任務1和任務2兩個任務的優先級都是一樣的,而且任務1比任務2創建更早,會出現什么結果?例如任務1和任務2的運行代碼是一樣的。如下:
void task1(void *parg) { OS_ERR err; printf("task1 is create ok\r\n"); while(1) { printf("task1 is running ...\r\n"); } } void task2(void *parg) { OS_ERR err; printf("task2 is create ok\r\n"); while(1) { printf("task2 is running ...\r\n"); } }
結果
task1 is running ... task1 is running ... task1 is running ... task1 is running ... task1 is running ... ......
當兩個任務的優先級都是一樣且最高,這個兩個任務都沒有任何的讓出CPU的函數,在執行的時候,只執行創建最早的任務,任務1是比任務2創建更早,只能執行任務1.
(2)任務1的優先級是比任務2高,代碼如下:
void task1(void *parg) { OS_ERR err; printf("task1 is create ok\r\n"); while(1) { printf("task1 is running ...\r\n"); OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_HMSM_STRICT,&err); //延時10ms } } void task2(void *parg) { OS_ERR err; printf("task2 is create ok\r\n"); while(1) { printf("task2 is running ...\r\n"); OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_HMSM_STRICT,&err); //延時10ms } }
結果:
task2task1 is running ... is task1 is running ... runntask1 is running ... ing task1 is running ... ... task1 is running ... task1 is running ... task2task1 is running ...
在任務2在打印的過程當中,打印數據時間超過10ms,所以在打印的中途ucos發現任務1已經就緒了,任務1就會搶奪CPU的使用權,任務2就停止執行,等任務1執行完之后讓出CPU,任務2才繼續執行。
(三)臨界區代碼用於資源保護,以下有兩種的編寫方法,哪一種才是正確的?
1,
//進入臨界區,保護以下的代碼,關閉總中斷,停止了ucos的任務調度,其他任務已經停止執行 OS_CRITICAL_ENTER(); printf("task1 is running ...\r\n"); //退出臨界區,開啟總中斷,允許ucos的任務調度 OS_CRITICAL_EXIT(); OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err); //延時1000ms
2,
//進入臨界區,保護以下的代碼,關閉總中斷,停止了ucos的任務調度,其他任務已經停止執行 OS_CRITICAL_ENTER(); printf("task1 is running ...\r\n"); OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err); //延時1000ms //退出臨界區,開啟總中斷,允許ucos的任務調度 OS_CRITICAL_EXIT();
只有例子1才是正確的,能夠進行准確的延時,唯獨只有例子2延時是失效的。
在進入臨界區代碼,因為它是關閉了總中斷,所以跟阻塞相關、時間管理函數都會失效。
在ucos3,提供的最小毫米級別的延時是多少,依據是什么?
在os_cfg_app.h當中有關於設置ucos3時鍾頻率,時鍾頻率如下: #define OS_CFG_TICK_RATE_HZ 200u /* Tick rate in Hertz (10 to 1000 Hz) */
因此,延時最小只能是5ms。
如果要設置最小的延時為1ms,可以調整當前該宏定義OS_CFG_TICK_RATE_HZ為1000。
OS_CFG_TICK_RATE_HZ的值越小,ucos3能夠實現更低的功耗,但是高優先級任務的執行不會太及時。反過來說,該值越大,功耗就越高,同時高優先級的任務被執行的延遲時間會更及時!
應用場景:如果是電池供電且任務數特別少,可以將OS_CFG_TICK_RATE_HZ調小。如果是普通電源供電且任務數特別多,將OS_CFG_TICK_RATE_HZ調大!
延時函數:delay_us與delay_ms能夠正常地使用!
中斷服務函數,如果在ucos3操作系統使用下,還得添加這兩個函數,示例如下:
void USART1_IRQHandler(void) //串口1中斷服務程序 { //進入中斷,告訴UCOS3停止任務調度,並進行中斷嵌套計數 OSIntEnter(); //添加代碼 //退出中斷,告訴UCOS3已經完成中斷處理,並更新中斷嵌套計數,可以進行任務調度 OSIntExit(); }
