1 延時:os_itv_set(usFrequency) //設定延時周期,配合os_itv_wait使用;os_itv_wait() 是絕對延遲是包含調用前的時間, os_dly_wait() 是相對延遲 ,不包含調用前的時間
二 排程方式:時間片排程,合作式排程;搶占式排程。
2.1 時間片式排程:使能後對相同優先級(需指定時間片)的幾個任務在時間片用完切換,或者遇到阻塞式API調用時間片沒有用完也切換。
2.2合作式排程:對相同優先級任務,若時間片排程被禁止則運作在合作式排程下,此時在遇到阻塞式API調用或者調用主動切換函數os_tsk_pass (),實際中不常用
2.3搶占式排程:基于不同的任務優先級(被搶占)或者阻塞式API調用,對于重要的子產品應用,響應時間快和任務何時被執行是确定的。
三臨界段 中斷鎖任務鎖:為保證明時性,RTX不提供臨界段操作和中斷鎖開關函數(與freertos/USOS不同),但使用者可以通過給排程器上鎖(任何中斷都沒有關閉)和關閉RTOS的核心定時器來禁止OS進行搶占式排程(也即任務鎖),tsk_lock /unlock():不能再ISR中使用不支援嵌套、時間越短越好(和時間有關相關的時間片、延時都不再工作);
使用場合:防止多任務同時調用一個函數(如printf)/共享的外設硬體如序列槽(多任務調用進行發送)
四任務間同步和通訊:
4.1事件标志組:可解決裸機程式下中斷與任務間同步(flag)、多任務通路全局變量沖突(volitle)、任務逾時(這個裸機程式下很複雜)問題。每個任務建立時有16個标志組。
中斷中要使用isr_evt_set ,不要在ISR中進行複雜的處理(消息解析處理)可将處理設定成優先級較高的任務(isr_evt_set 後可得到立即執行),M3/M4建議NVIC分組為4. os_evt_clr
- os_evt_get、os_evt_set、os_evt_clr
- os_evt_wait_and(flags,timeout),flags中16個位響應的bit同時置位。flags||timeout其一滿足就傳回,傳回前已經設定的flags已經清零、os_evt_wait_or
- isr_evt_set
4.1信号量:可以用作任務間或任務與ISR間的同步,或者共享資源的管理(多少個資源占用初始值就等于幾)。先定義一個信号量OS_SEM semaphore //是一個U32型的數組(2個元素)
os_sem_init (semaphore,Val_fault)//初始化信号量,第一個參數可以是semaphore/&semaphore,用于同步時初始值為0,調用os_sem_wait時挂起知道其他地方xx_sem_send
os_sem_send (semaphore)
isr_sem_send (semaphore)
os_sem_wait(semaphore)
5 互斥信号量:對共享資源管理最重要的就是互斥量,用法和二進制信号量差不多(但邏輯剛好相反),互斥量初值為0,初始化後,先os_mut_wait (&mutex, 0xffff)//0XFFFF表示永久等待,若初值為0表示共享資源空閑
可以使用,使用中時互斥量加1表示共享資源正被使用;使用完調用os_mut_release (&mutex);歸還信号量(減一=0,以釋放資源)
五消息郵箱(隊列):消息郵箱可以在ISR與任務或者任務間進行傳遞資訊(傳遞的是位址而不是真實的内容),用消息郵箱而不直接用數組的原因:可支援逾時,解決中斷和任務間的同步,解決多任務間消息共享的沖突,FIFO便于消息的處理共有8個函數:
os_mbx_declare :聲明一個包含多少條消息的的郵箱,其實就是宏定義一個U32型的靜态數組
os_mbx_init:就是将定義的郵箱初始化成隊列
os_mbx_check :發消息前先檢查是否已滿,收消息前檢查是否為空,任務間支援逾時。
os_mbx_send
os_mbx_wait
isr_mbx_check :中斷中使用,不支援逾時
isr_mbx_receive
isr_mbx_send
六定時器組(使用者定時器):使用方法:
OS_ID OneShotTimerID1/* 定時器句柄 */
OneShotTimerID1= os_tmr_create (10, 1)//建立一個延時10個系統周期的定時器1,
void os_tmr_call ( U16 info ); /*定時器回調函數的參數,可用于區分不同的定時器,用SWITCH進行處理*/,此函數在RTX_Conf_CM.c檔案中,在其中支援ISR開頭的APP函數調用,隻支援單次定時器
如果需要周期的,需要反複建立。
七記憶體管理:ANSI中的記憶體配置設定容易造成記憶體碎片且執行的時間是不确定的,為了解決這個問題,RTX采用固定大小記憶體塊的形式進行記憶體池的配置設定,操作上分4位元組和8位元組對其操作的API函數:
#define _declare_box( \
pool, \ /* 記憶體池變量名 */
size, \ /* 記憶體塊大小,機關位元組 */
cnt ) \ /* 記憶體池中記憶體塊的個數 */
U32 pool[((size+3)/4)*(cnt) + 3] //聲明一個固定大小的n歌記憶體塊相當于配置設定一個二維數組,多餘的12位元組是将記憶體塊位址組成連結清單。
#define _declare_box8( \
U64 pool[((size+7)/8)*(cnt) + 2]
_init_box_init_box/_init_bo/_init_box _init_box_init_box8 (mpool, sizeof (mpool), PoolPerBlockSize) //将其形成連結清單
void *_alloc_box ( void* box_mem )
int _free_box ( mpool mpool, /* 記憶體池首位址 */ void* box ); /* 要釋放的記憶體塊首位址 */
八 SVC調用使用者函數:運作在使用者非特權模式下的APP是不能操作有關核心硬體的寄存器,若需要操作隻能通過SVC觸發進入特權級模式下在修改。使用方法:
第1步:添加SVC_Table.s檔案
第2步:使用屬性__svc(x)聲明函數,x從1開始,範圍1-255。函數名随便命名,但是x的數值一
定要保證是連續遞增的。
void __svc(1) SVC_1_FunCall(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4);
void __svc(2) SVC_2_FunCall(void);
第3步:寫__SVC_x的實際函數(統一改成這種命名方式是為了跟RTX系統的調用方式__SVC_0統一)
第4步:将定義的兩個函數添加到SVC_Table.s檔案裡面
首先使用IMPORT 指令聲明下,類似C語言中的extern。然後添加到SVC_Table清單下,整體添加
後的效果如下(紅色字型是使用者添加的):
AREA SVC_TABLE, CODE, READONLY
EXPORT SVC_Count
SVC_Cnt EQU (SVC_End-SVC_Table)/4
SVC_Count DCD SVC_Cnt
; Import user SVC functions here.
IMPORT __SVC_1
IMPORT __SVC_2
EXPORT SVC_Table
SVC_Table
; Insert user SVC functions here. SVC 0 used by RTL Kernel.
DCD __SVC_1 ; user SVC function
DCD __SVC_2 ; user SVC function
SVC_End
END
至此,RTX中SVC中斷的調用就實作了。實際應用的時候,使用者隻需調用函數SVC_1_FunCall和
SVC_1_FunCall即可,這兩個函數就是在SVC中斷裡面實作的
九用獨立看門狗檢測多任務的執行:通過建立一個高優先級的看門狗監視任務,其它所有低優先級的任務通過事件标志組都給看門狗任務發通知,都收到後才進行喂狗操作,否則不喂狗就發生複位,需要注意的是,看門狗複位的時間應該比所有任務觸發标志組的時間長一些
十 RTX下的低功耗:根據最低功耗,最快啟動時間、可使用的喚醒中斷從睡眠、停止、待機模式(1.8V電源域關閉,進入後SRAM和寄存器内容丢失。
隻有備份的寄存器和待機電路維持供電通過外WKUP 引腳上升沿、RTC鬧鐘(鬧鐘A和鬧鐘B)、RTC喚
醒事件、RTC入侵事件、RTC 時間戳事件、NRST引腳外部複位和IWDG 複位,喚醒後除了電源控制盒狀态寄存器所有寄存器複位)中選擇一種。在初始化時選擇DBGMCU_Config(DBGMCU_SLEEP,ENABLE) 或者 DBGMCU_Config(DBGMCU_STOP, ENABLE)或者PWR_EnterSTANDBYMode,在空閑任務中執行_WFI/WFE進入低功耗模式,喚醒源喚醒(停止模式下sram、所有寄存器、IO狀态都保留,喚醒後使用HSI時鐘,如果選擇HSE則需要進行重新的初始化系統時鐘)。待機模式:初始化時RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);