任務相關的API函數的使用
任務的創建與刪除
OSTaskCreateO創建任務函數
UCOSIII是多任務系統,那麼肯定要能創建任務,創建任務就是將任務控制塊、任務堆棧、任務代碼等聯繫在一起,並且初始化任務控制塊的相應字段。在UCOSIII中我們通過函數OSTaskCreate(來創建任務,OSTaskCreate()函 數原型如下(在os_task.c 中有義)。調用OSTaskCreat()創建一一個任務 以後,剛創建的任務就會進入就緒態,注意!不能在中斷服務程序中調用OSTaskCreat( )函數來創建任務。
void OSTaskCreate (OS TCB *p_ tcb,
CPU CHAR *p_ name,
OS TASK PTR p_ task,
void *p_ arg,
OS PRIO prio,
CPU STK *p_ stk_ base,
CPU STK SIZE stk_ limit,
CPU STK_ SIZE stk_ size,
OS MSG QTY q size,
OS TICK time_ quanta,
void *p_ ext,
OS OPT opt,
OS ERR *p_ err)
*p_ tcb: 指向任務的任務控制塊OS_ TCB
*P_ name: 指向任務的名字,我們可以給每個任務取一一個名字
p_ task: 執行任務代碼,也就是任務函數名字.
*P_ arg: 傳遞給任務的參數
prio: 任務優先級,數值越低優先級越高,用戶不能使用系統任務使用的那些優先級!
*p_stk_base: 指向任務堆棧的基地址。
stk_ limit: 任務堆棧的堆棧深度,用來檢測和確保堆棧不溢出。
stk_ size: 任務堆棧大小
q_ size: UCOSIII中每個任務都有一一個可選的內部消息隊列,我們要定義宏OS_ CFG_ TASK_ Q EN>0,這是纔會使用這個內部消息隊列。
time_quanta: 在使能時間片輪轉調度時用來設置任務的時間片長度,默認值爲時鐘節拍除以10。
*P_ ext: 指向用戶補充的存儲區。
opt: 包含任務的特定選項,有如下選項可以設置。
OS OPT TASK NONE | 表示沒有任何選項 |
---|---|
OS_ OPT_ TASK STK_ CHK | 指定是否允許檢測該任務的堆棧 |
OS OPT TASK STK CLR | 指定是否清除該任務的堆棧 |
OS OPT TASK SAVE FP | 指定是否存儲浮點寄存器,CPU 需要有浮點運算硬件並且有專用代碼保存浮點寄存器。 |
*p_ err: 用來保存調用該函數後返回的錯誤碼。
OSTaskDel()刪除任務函數
OSTaskDel()函數用來刪除任務,當一個任務不需要運行的話,我們就可以將其刪除掉,刪除任務不是說刪除任務代碼,而是UCOSIII不再管理這個任務,在有些應用中我們只需要某個任務只運行一一次,運行完成後就將其刪除掉,比如外設初始化任務, OSTaskDel()函數原型如下:
void OSTaskDel (OS_TCB *P_ tcb,
OS_ERR *p_err)
*P_ tcb | 指向要刪除的任務TCB,也可以傳遞一一個NULL指針來刪除調用OSTaskDel()函數的任務自身。 |
---|---|
*p_ err | 指向一個變量用來保存調用OSTaskDel0函數後返回的錯誤碼。 |
雖然UCOSIII允許用戶在系統運行的時候來刪除任務,但是應該儘量的避免這樣的操作,如果多個任務使用同一個共享資源,這個時候任務A正在使用這個共享資源,如果刪除了任務A,這個資源並沒有得到釋放,那麼其他任務就得不到這個共享資源的使用權,會出現各種奇怪的結果。
我們調用OSTaskDel()刪除一個任務後, 這個任務的任務堆棧、OS_ TCB所佔用的內存並沒有釋放掉,因此我們可以利用他們用於其他的任務,當然我們也可以使用內存管理的方法給任務堆棧和OS_ TCB分配內存,這樣當我們刪除掉某個任務後我們就可以使用內存釋放函數將這個任務的任務堆棧和OS_ TCB所佔用的內存空間釋放掉。
任務的掛起與恢復
OSTaskSuspend()函數
有時候有些任務因爲某些原因需要暫停運行,但是以後還要運行,因此我們就不能刪除掉任務,這裏我們可以使用OSTaskSuspend()函 數掛起這個任務,以後再恢復運行,函數OSTaskSuspend()的原型如下:
void OSTaskSuspend (OS TCB *p tcb,OS ERR*p_ err)
OSTaskResume()函數
OSTaskResume()函數用來恢復被OSTaskSuspend()函數掛起的任務,OSTaskResume()函數是唯一能恢復被掛起任務的函數。如果被掛起的任務還在等待別的內核對象,比如事件標誌組、信號量、互斥信號量、消息隊列等,即使使用OSTaskResume()函數恢復了被掛起的任務,該任務也不一定能立即運行,該任務還是要等相應的內核對象,只有等到內核對象後纔可以繼續運行,OSTaskResume()函數原型如下:
void OSTaskResume (OS_ TCB *p_ tcb,OS_ ERR *p_ err)
*p_ tcb:
向需要解掛的任務的OS_ TCB, 指向一個NULL指針是無效的,因爲該任務正
在運行,不需要解掛。
*p err:
指向一個變量,用來保存該函數的錯誤碼。
程序設計
(1)創建開始任務start_ task, start_ task任務用來創建另外兩個任務: task1_ task和task2_ task。
(2)開始任務start_ task 中用來創建任務1: taskl_ task.
(3)開始任務start task 中用來創建任務2: task2_ task.
(4)開始任務start task只是用來創建任務task1_ task 和task2_ task, 那麼這個任務肯定只需要執行–次,兩個任務創建完成以後就可以刪除掉start_task任務了,這裏我們使用OSTaskDel()函數刪除掉任務自身,這裏傳遞給OSTaskDel(函數參數p_ tcb 的值爲0,表示刪除掉任務自身。
(5)根據要求我們在任務1執行5次後由任務1刪除掉任務2,這裏通過調用OSTaskDel()函數刪除掉任務2,注意這時我們傳遞給OSTaskDel)中參數p_ tcb 的值爲任務2的任務控制塊Task2_ TaskTCB的地址,因此這裏我們用了取址號“&”。
(6)調用函數OSTimeDlyHMSM(延時ls, 調用OSTimeDlyHMSM()函數以後就會發起一個任務切換。
主函數:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "includes.h"
//任務優先級
#define START_TASK_PRIO 3
//任務堆棧大小
#define START_STK_SIZE 128
//任務控制塊
OS_TCB StartTaskTCB;
//任務堆棧
CPU_STK START_TASK_STK[START_STK_SIZE];
//任務函數
void start_task(void *p_arg);
//任務優先級
#define TASK1_TASK_PRIO 4
//任務堆棧大小
#define TASK1_STK_SIZE 128
//任務控制塊
OS_TCB Task1_TaskTCB;
//任務堆棧
CPU_STK TASK1_TASK_STK[TASK1_STK_SIZE];
void task1_task(void *p_arg);
//任務優先級
#define TASK2_TASK_PRIO 5
//任務堆棧大小
#define TASK2_STK_SIZE 128
//任務控制塊
OS_TCB Task2_TaskTCB;
//任務堆棧
CPU_STK TASK2_TASK_STK[TASK2_STK_SIZE];
//任務函數
void task2_task(void *p_arg);
//LCD刷屏時使用的顏色
int lcd_discolor[14]={ WHITE, BLACK, BLUE, BRED,
GRED, GBLUE, RED, MAGENTA,
GREEN, CYAN, YELLOW,BROWN,
BRRED, GRAY };
int main(void)
{
OS_ERR err;
CPU_SR_ALLOC();
delay_init(); //時鐘初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中斷分組配置
uart_init(115200); //串口初始化
LED_Init(); //LED初始化
LCD_Init(); //LCD初始化
POINT_COLOR = RED;
LCD_ShowString(30,10,200,16,16,"ALIENTEK STM32F1");
LCD_ShowString(30,30,200,16,16,"UCOSIII Examp 6-1");
LCD_ShowString(30,50,200,16,16,"Task Creat and Del");
LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(30,90,200,16,16,"2015/3/19");
OSInit(&err); //初始化UCOSIII
OS_CRITICAL_ENTER(); //進入臨界區
//創建開始任務
OSTaskCreate((OS_TCB * )&StartTaskTCB, //任務控制塊
(CPU_CHAR * )"start task", //任務名字
(OS_TASK_PTR )start_task, //任務函數
(void * )0, //傳遞給任務函數的參數
(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); //存放該函數錯誤時的返回值
OS_CRITICAL_EXIT(); //退出臨界區
OSStart(&err); //開啓UCOSIII
}
開始任務函數
void start_task(void *p_arg)
{
OS_ERR err;
CPU_SR_ALLOC();
p_arg = p_arg;
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 //當使用時間片輪轉的時候
//使能時間片輪轉調度功能,時間片長度爲1個系統時鐘節拍,既1*5=5ms
OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);
#endif
OS_CRITICAL_ENTER(); //進入臨界區
//創建TASK1任務
//創建TASK1任務
OSTaskCreate((OS_TCB * )&Task1_TaskTCB,
(CPU_CHAR * )"Task1 task",
(OS_TASK_PTR )task1_task,
(void * )0,
(OS_PRIO )TASK1_TASK_PRIO,
(CPU_STK * )&TASK1_TASK_STK[0],
(CPU_STK_SIZE)TASK1_STK_SIZE/10,
(CPU_STK_SIZE)TASK1_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);
//創建TASK2任務
OSTaskCreate((OS_TCB * )&Task2_TaskTCB,
(CPU_CHAR * )"task2 task",
(OS_TASK_PTR )task2_task,
(void * )0,
(OS_PRIO )TASK2_TASK_PRIO,
(CPU_STK * )&TASK2_TASK_STK[0],
(CPU_STK_SIZE)TASK2_STK_SIZE/10,
(CPU_STK_SIZE)TASK2_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_CRITICAL_EXIT(); //退出臨界區
OSTaskDel((OS_TCB*)0,&err); //刪除start_task任務自身
}
tsck1()任務函數
void task1_task(void *p_arg)
{
u8 task1_num=0;
OS_ERR err;
CPU_SR_ALLOC();
p_arg = p_arg;
POINT_COLOR = BLACK;
OS_CRITICAL_ENTER();
LCD_DrawRectangle(5,110,115,314); //畫一個矩形
LCD_DrawLine(5,130,115,130); //畫線
POINT_COLOR = BLUE;
LCD_ShowString(6,111,110,16,16,"Task1 Run:000");
OS_CRITICAL_EXIT();
while(1)
{
task1_num++; //任務執1行次數加1 注意task1_num1加到255的時候會清零!!
LED0= ~LED0;
printf("任務1已經執行:%d次\r\n",task1_num);
if(task1_num==5)
{
OSTaskDel((OS_TCB*)&Task2_TaskTCB,&err); //任務1執行5此後刪除掉任務2
printf("任務1刪除了任務2!\r\n");
}
LCD_Fill(6,131,114,313,lcd_discolor[task1_num%14]); //填充區域
LCD_ShowxNum(86,111,task1_num,3,16,0x80); //顯示任務執行次數
OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err); //延時1s
}
}
task2()任務函數
void task2_task(void *p_arg)
{
u8 task2_num=0;
OS_ERR err;
CPU_SR_ALLOC();
p_arg = p_arg;
POINT_COLOR = BLACK;
OS_CRITICAL_ENTER();
LCD_DrawRectangle(125,110,234,314); //畫一個矩形
LCD_DrawLine(125,130,234,130); //畫線
POINT_COLOR = BLUE;
LCD_ShowString(126,111,110,16,16,"Task2 Run:000");
OS_CRITICAL_EXIT();
while(1)
{
task2_num++; //任務2執行次數加1 注意task1_num2加到255的時候會清零!!
LED1=~LED1;
printf("任務2已經執行:%d次\r\n",task2_num);
LCD_ShowxNum(206,111,task2_num,3,16,0x80); //顯示任務執行次數
LCD_Fill(126,131,233,313,lcd_discolor[13-task2_num%14]); //填充區域
OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err); //延時1s
}
}
任務的掛起與恢復
(1) 根據要求任務1運行5次後調用OSTaskSuspend()函數掛起任務2。
(2)當任務1運行到第10次就調用函數OSTaskResume()函數解掛任務2。