0、一些移植、系統相關 OS_CFG_APP.H OS_CFG.H:功能性裁剪 OS_APP_HOOKS.C:鉤子函數 OS_CPU_A.ASM:PendSV中斷、任務切換 OS_CPU_C.C: OSTaskStkInit函數,任務創建時,對堆棧初始化,寄存器地址要參照手冊 1、框架寫法(個人習慣 ...
0、一些移植、系統相關
OS_CFG_APP.H
/* --------------------- MISCELLANEOUS ------------------ */ #define OS_CFG_MSG_POOL_SIZE 100u /* 消息池 大小 */ #define OS_CFG_ISR_STK_SIZE 128u /* Stack size of ISR stack (number of CPU_STK elements) */ #define OS_CFG_TASK_STK_LIMIT_PCT_EMPTY 10u /* Stack limit position in percentage to empty */ /* ---------------------- IDLE TASK --------------------- */ #define OS_CFG_IDLE_TASK_STK_SIZE 128u /* 空閑任務 堆棧空間大小 (一般不做修改) */ /* ------------------ ISR HANDLER TASK ------------------ */ #define OS_CFG_INT_Q_SIZE 10u /* 中斷服務隊列 大小 */ #define OS_CFG_INT_Q_TASK_STK_SIZE 128u /* 中斷服務隊列 堆棧空間大小(一般不做修改) */ /* ------------------- STATISTIC TASK ------------------- */ #define OS_CFG_STAT_TASK_PRIO (OS_CFG_PRIO_MAX-2u) /* 統計任務 優先順序 (一般不做修改) */ #define OS_CFG_STAT_TASK_RATE_HZ 10u /* 統計任務頻率 (1 to 10 Hz) */ #define OS_CFG_STAT_TASK_STK_SIZE 128u /* 統計任務 堆棧空間大小 (一般不做修改) */ /* ------------------------ TICKS ----------------------- */ #define OS_CFG_TICK_RATE_HZ 200u /* 時鐘節拍頻率 200HZ = 5ms (10 to 1000 Hz) */ #define OS_CFG_TICK_TASK_PRIO 1u /* 時鐘節拍優先順序,一般設置一個相對較高的優先順序 */ #define OS_CFG_TICK_TASK_STK_SIZE 128u /* 時鐘節拍堆棧空間大小 (一般不做修改) */ #define OS_CFG_TICK_WHEEL_SIZE 17u /* Number of 'spokes' in tick wheel; SHOULD be prime */ /* ----------------------- TIMERS ----------------------- */ #define OS_CFG_TMR_TASK_PRIO 2u /* 軟體定時器優先順序 */ #define OS_CFG_TMR_TASK_RATE_HZ 100u /* 軟體定時器頻率 100HZ = 10ms,不能小於心跳時鐘節拍 */ #define OS_CFG_TMR_TASK_STK_SIZE 128u /* 軟體定時器堆棧空間大小 (一般不做修改) */ #define OS_CFG_TMR_WHEEL_SIZE 17u /* Number of 'spokes' in timer wheel; SHOULD be prime */
OS_CFG.H:功能性裁剪
OS_APP_HOOKS.C:鉤子函數
OS_CPU_A.ASM:PendSV中斷、任務切換
OS_CPU_C.C: OSTaskStkInit函數,任務創建時,對堆棧初始化,寄存器地址要參照手冊
1、框架寫法(個人習慣相關)
1-1、main 函數里創建一個開始任務
int main(void) { OS_ERR err; CPU_SR_ALLOC(); 初始化外設 OSInit(&err); //初始化UCOSIII OS_CRITICAL_ENTER(); //進入臨界區 OSTaskCreate(); //創建開始任務 OS_CRITICAL_EXIT(); //退出臨界區 OSStart(&err); //開啟UCOSIII while(1); }
1-2、開始任務里,創建我們要運行的多個任務
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 //時間片輪轉 OSSchedRoundRobinCfg(DEF_ENABLED,1,&err); //時間片長度為1個系統時鐘節拍,既1*5=5ms #endif OS_CRITICAL_ENTER(); //進入臨界區 OSTaskCreate(); //創建任務 1 OSTaskCreate(); //創建任務 2 OSTaskCreate(); //創建任務 3 OS_CRITICAL_EXIT(); //進入臨界區 OSTaskDel((OS_TCB*)0,&err); //刪除start_task任務自身 }
2、任務創建、掛起、刪除
2-1、任務創建
//==================任務創建巨集定義,便於修改================== #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); //任務函數 //==================任務創建函數================== 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); //任務 創建成功與否
2-2、任務掛起
OSTaskSuspend((OS_TCB*)&Task1TaskTCB,&err); //掛起開始任務
2-3、任務解掛
OSTaskResume((OS_TCB*)&Task1TaskTCB,&err); //任務解掛
2-4、任務刪除
OSTaskDel((OS_TCB*)0,&err); //刪除start_task任務自身
3、時間片輪轉
3-1、兩個任務優先順序相等
#define Task0_Task_Prio 4 //優先順序4 #define Task0_Stk_Size 128 OS_TCB Task0TaskTCB; CPU_STK Task0_Task_Stk[Task0_Stk_Size]; void Task0Task(void *p_arg); #define Task1_Task_Prio 4 //優先順序4 #define Task1_Stk_Size 128 OS_TCB Task1TaskTCB; CPU_STK Task1_Task_Stk[Task1_Stk_Size]; void Task1Task(void *p_arg);
3-2、使能輪轉調度,調用API,設置單位時間
#if OS_CFG_SCHED_ROUND_ROBIN_EN //使用時間片輪轉 OSSchedRoundRobinCfg(DEF_ENABLED,1,&err); //時間片長度為1個系統時鐘節拍,既1*5=5ms #endif
3-3、創建任務時,設置任務的時間片大小
OSTaskCreate((OS_TCB * )&Task1TaskTCB, (CPU_CHAR * )"Task1 task", (OS_TASK_PTR )Task1Task, (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 )2, //時間片長度為2*5=10ms (void * )0, (OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, (OS_ERR * )&err);
4、鉤子函數。函數指針,UCOS不希望我們去修改他的文件,弄了鉤子函數,比如 App_OS_IdleTaskHook ,在空閑時運行這個函數,功能自己填寫。
4-1、使能鉤子函數功能,並設置所有函數指針
#if OS_CFG_APP_HOOKS_EN > 0u //使能鉤子函數 App_OS_SetAllHooks(); #endif
4-2、在 os_app_hooks.c 里的 App_OS_*Hook,裡面填寫你要的功能。
void App_OS_IdleTaskHook (void) { static int num ; num++; //計算運行了多少次空閑任務 }
5、軟體定時器
5-1、軟體定時器創建
//==============定時器結構體、函數聲明============== OS_TMR Timer0; void timer0CallBack(void *p_tmr, void *p_arg); //==============定時器創建============== //創建定時器0任務 OSTmrCreate ( (OS_TMR *)&Timer0, //定時器 結構體 (CPU_CHAR *)"time0", //定時器 名字 (OS_TICK )10, //定時器 初次延時節拍 10*10 = 100ms (OS_TICK )100, //定時器 以後延時節拍 100*10 = 1000ms = 1s (OS_OPT )OS_OPT_TMR_PERIODIC, //定時器 選項 : 單次 或 周期。 (OS_TMR_CALLBACK_PTR )timer0CallBack, //定時器 回調函數,偽中斷服務函數 (void *)0, //定時器 中斷服務函數的參數 (OS_ERR *)&err); //定時器 創建成功與否
5-2、定時器“中斷服務函數”,回調函數
void timer0CallBack(void *p_tmr, void *p_arg) { //do something }
6、信號量
6-1、信號量創建
OSSemCreate ( (OS_SEM *)&mySem, //信號量 結構體 (CPU_CHAR *)"semtest", //信號量 名字 (OS_SEM_CTR )1, //信號量 初始值, (OS_ERR *)&err); //信號量 創建成功是否
6-2、信號量等待
OSSemPend ((OS_SEM *)&mySem, //信號量 結構體 (OS_TICK )0, //信號量 等待超時時間 (OS_OPT )OS_OPT_PEND_BLOCKING, //信號量 阻塞 或 不阻塞 (CPU_TS *)0, //信號量 時間戳 (OS_ERR *)&err); //信號量 等待錯誤
6-3、信號量發送
OSSemPost ((OS_SEM *)&mySem, //信號量 結構體 (OS_OPT )OS_OPT_POST_1, //信號量 給就緒最高優先順序 (OS_ERR *)&err); //信號量 等待錯誤
用途: 1、訪問共用資源。
2、中斷發送信號,讓處理在任務。
7、任務內建信號量
7-1、等待自身的信號量
OSTaskSemPend ( (OS_TICK )0, //內建信號量 超時時間 (OS_OPT )OS_OPT_PEND_BLOCKING, //內建信號量 阻塞 或 不阻塞 (CPU_TS *)0, //內建信號量 時間戳 (OS_ERR *)&err); //內建信號量 等待錯誤
7-2、其他任務,給等待內建信號量的任務發送信號量
OSTaskSemPost ( (OS_TCB *)&Task0TaskTCB, //內建信號量 等待的任務 (OS_OPT )OS_OPT_POST_NONE, //內建信號量 調度 或 不調度 (OS_ERR *)&err); //內建信號量 等待錯誤
8、互斥信號量
8-1、互斥信號量創建
OSMutexCreate ( (OS_MUTEX *)&myMutex, //互斥信號量 結構體 (CPU_CHAR *)"Mutextest", //互斥信號量 名字 (OS_ERR *)err); //互斥信號量 創建錯誤
8-2、互斥信號量等待
OSMutexPend ( (OS_MUTEX *)&myMutex, //互斥信號量 結構體 (OS_TICK )0, //互斥信號量 等待超時時間 (OS_OPT )OS_OPT_PEND_BLOCKING, //互斥信號量 阻塞 或 不阻塞 (CPU_TS *)0, //互斥信號量 時間戳 (OS_ERR *)&err); //互斥信號量 等待錯誤
8-3、互斥信號量發送
OSMutexPost ( (OS_MUTEX *)&myMutex, //互斥信號量 結構體 (OS_OPT )OS_OPT_POST_NONE, //互斥信號量 調度 或 不調度 (OS_ERR *)&err); //互斥信號量 發送錯誤
用途:防止優先順序反轉,如:2個任務共用一個資源,而,兩者的優先順序,中間隔著多個優先順序(任務)。高優先順序 等待 低優先順序 釋放,而,低優先順序 此時又被 中等優先順序 打斷,變成 高優先順序 要等 中等優先順序。
用互斥信號的話,此時 低優先順序 ,會暫時提高到共用資源的 高優先順序 級別。不會被中等優先順序打算。處理完,降回 低優先順序 ,高優先順序接著訪問。再 中等優先順序。
發現:1、高優先順序 等待時, 低優先順序用OSSched(); 此時達到預計效果,不會被 中等優先順序搶占。
2、高優先順序 等待時,低優先順序用OSTimeDlyHMSM();延時指令,此時,會被中等優先順序搶占。
9、消息隊列
9-1、消息隊列創建
//================消息隊列巨集定義================ OS_Q my_MSG_Q; #define my_MSG_QTY (OS_MSG_QTY)5 //================消息隊列創建================ OSQCreate ( (OS_Q *)&my_MSG_Q, //消息隊列 結構體 (CPU_CHAR *)"MSG_Q_Test", //消息隊列 名字 (OS_MSG_QTY )my_MSG_QTY, //消息隊列 大小 (OS_ERR *)&err); //消息隊列 創建錯誤
9-2、消息發送
u8 *MSG = (u8 *)"testtet"; OSQPost ( (OS_Q *)&my_MSG_Q, //消息隊列 結構體 (void *)MSG, //消息隊列 發送的消息 (OS_MSG_SIZE )8, //消息隊列 發送的消息大小 (OS_OPT )OS_OPT_POST_FIFO, //消息隊列 發送方式,普通FIFO,緊急LIFO,及發送給所有等待該消息、發送調度與否 (OS_ERR *)&err); //消息隊列 發送錯誤
9-3、消息接收
u8 *MSG; u8 Q_size; MSG = OSQPend ( (OS_Q *)&my_MSG_Q, //消息隊列 結構體 (OS_TICK )0, //消息隊列 等待超時 (OS_OPT )OS_OPT_PEND_BLOCKING, //消息隊列 阻塞 或 不阻塞 (OS_MSG_SIZE *)&Q_size, //消息隊列 收到的大小 (CPU_TS *)0, //消息隊列 時間戳 (OS_ERR *)&err); //消息隊列 接收錯誤
10、任務內建消息隊列
10-1、內建消息隊列發送
u8 *MSG = (u8 *)"testtet"; OSTaskQPost ( (OS_TCB *)&MSG_Q_TaskTCB, //內建消息隊列 接收的任務 (void *)MSG, //內建消息隊列 發送的消息 (OS_MSG_SIZE )8, //內建消息隊列 發送的消息大小 (OS_OPT )OS_OPT_POST_FIFO, //內建消息隊列 發送方式,普通FIFO,緊急LIFO,及發送給所有等待該消息、發送調度與否 (OS_ERR *)&err); //內建消息隊列 發送錯誤
10-2、內建消息隊列接收
u8 *MSG; u8 Q_size; MSG = OSTaskQPend ( (OS_TICK )0, //內建消息隊列 等待超時 (OS_OPT )OS_OPT_PEND_BLOCKING, //內建消息隊列 阻塞 或 不阻塞 (OS_MSG_SIZE *)&Q_size, //內建消息隊列 收到的大小 (CPU_TS *)0, //內建消息隊列 時間戳 (OS_ERR *)&err); //內建消息隊列 接收錯誤
11、標記位組
11-1、標記位組創建
OS_FLAG_GRP my_FLAG; #define FLAG_INIT 0x00 #define FLAG_BIT0 0x01 #define FLAG_BIT1 0x02 OSFlagCreate ( (OS_FLAG_GRP *)&my_FLAG, //標記位組 結構體 (CPU_CHAR *)"Flag test", //標記位組 名字 (OS_FLAGS )FLAG_INIT, //標記位組 標記初始值 (OS_ERR *)&err); //標記位組 創建成功與否
11-2、標記位組發送
OSFlagPost ((OS_FLAG_GRP *)&my_FLAG, //標記位組 結構體 (OS_FLAGS )FLAG_BIT0, //標記位組 bit0 (OS_OPT )OS_OPT_POST_FLAG_SET, //標記位組 置1 (OS_ERR *)&err); //標記位組 bit0 置 1 成功與否
11-3、標記為組等待
OS_FLAGS index; index = OSFlagPend ((OS_FLAG_GRP *)&my_FLAG, //標記位組 結構體 (OS_FLAGS )FLAG_BIT0 | FLAG_BIT1, //標記位組 等待的BIT位 (OS_TICK )0, //標記位組 等待超時時間 (OS_OPT )OS_OPT_PEND_FLAG_SET_ANY | OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_BLOCKING, //標記位組 任意1個Bit置1,接收後清0,阻塞 (CPU_TS *)0, //標記位組 時間戳 (OS_ERR *)&err); //標記位組 等待錯誤
12、多個內核對象
12-1、多個內核對象 創建
//=================多個內核對象 結構體================= OS_SEM my_Sem1; OS_SEM my_Sem2; OS_Q my_Q1; #define my_Q1_SIZE 5 //=================多個內核對象 創建================= OSSemCreate ( (OS_SEM *)&my_Sem1, (CPU_CHAR *)"sem1 test", (OS_SEM_CTR )0, (OS_ERR *)&err); OSSemCreate ( (OS_SEM *)&my_Sem2, (CPU_CHAR *)"sem2 test", (OS_SEM_CTR )0, (OS_ERR *)&err); OSQCreate ( (OS_Q *)&my_Q1, (CPU_CHAR *)"my_Q1", (OS_MSG_QTY )my_Q1_SIZE, (OS_ERR *)&err);
12-2、等待多個內核對象
//===============多個內核對象 巨集定義=============== #define MY_OBJ_NUM 3 //多個內核對象 等待數量 //===============多個內核對象 等待=============== OS_PEND_DATA my_OBJ_data[MY_OBJ_NUM]; //多個內核對象 數組 my_OBJ_data[0].PendObjPtr = (OS_PEND_OBJ *)&my_Sem1; //多個內核對象 對象0 my_OBJ_data[1].PendObjPtr = (OS_PEND_OBJ *)&my_Sem2; //多個內核對象 對象1 my_OBJ_data[2].PendObjPtr = (OS_PEND_OBJ *)&my_Q1; //多個內核對象 對象2 my_return_data = OSPendMulti ( (OS_PEND_DATA *)my_OBJ_data, //多個內核對象 對象數組 (OS_OBJ_QTY )MY_OBJ_NUM, //多個內核對象 對象數量 (OS_TICK )0, //多個內核對象 等待超時時間 (OS_OPT )OS_OPT_PEND_BLOCKING, //多個內核對象 阻塞 或 不阻塞 (OS_ERR *)&err); //多個內核對象 等待錯誤
12-3、多個內核對象 發送
任意對象 post ,都會結束等待
13、記憶體管理
13-1、記憶體創建
//==================記憶體 巨集定義================== OS_MEM IN_MEM; #define IN_MEM_Block 5 //必須大於2 #define IN_MEM_Zone 25 * 4 //必須大於4,且為4的倍數,存放下一塊的地址內容,4位元組 CPU_INT08U IN_MEM_DATA[IN_MEM_Block][IN_MEM_Zone]; //==================記憶體 創建================== OSMemCreate ( (OS_MEM *)&IN_MEM, //記憶體 結構體 (CPU_CHAR *)"IN_MEM", //記憶體 名字 (void *)&IN_MEM_DATA[0][0], //記憶體 基地址 (OS_MEM_QTY )IN_MEM_Block, //記憶體 幾個塊,一維數組 (OS_MEM_SIZE )IN_MEM_Zone, //記憶體 每個塊大小,二維數組 (OS_ERR *)&error); //記憶體 創建成功與否
13-2、記憶體申請
u8 *p; p = OSMemGet ( (OS_MEM *)&IN_MEM, //記憶體 結構體 (OS_ERR *)&err); //記憶體 申請成功與否
13-3、記憶體釋放
OSMemPut ( (OS_MEM *)&IN_MEM, //記憶體 結構體 (void *)p, //記憶體 要釋放的地址 (OS_ERR *)&err); //記憶體 釋放成功與否
備註:記憶體有申請,必釋放,如果申請後,不釋放,再申請,那之前申請的地址就找不到了,因為你的指針地址變了。
所以,如果要多次申請的話,1、還要弄個指針數組,2、或者普通數組來存放當前申請的地址,3、或者知道UCOS的記憶體管理機制,直接去記憶體數組裡找到地址。
暫時就這樣,以後再檢查修改,手酸。