學習ucos好長一段時間,一直沒明白在os中任務是怎么保存局部變量在自己的棧中。今天終於弄明白了。
1.沒有OS時,任務如何保存局部變量
在我的知識體系里,我一直以為單片機中就只有一個棧,以stm32為例,在啟動文件中有怎么一段:
; Amount of memory (in bytes) allocated for Stack
; Tailor this value to your application needs
; <h> Stack Configuration
; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Stack_Size EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
假設stm32的內存有16Kb,起始地址為,棧向下生長,從啟動文件中可以看到,棧的大小為0x400,我稱之為系統棧,系統棧的范圍為0x0x20000000~0x20000400 。在沒有OS的應用中(裸奔),cpu其實有兩個任務,一個是中斷任務,一個是main函數中的后台任務。當函數調用或者發生中斷時,就使用系統棧保存局部變量和寄存器狀態,也就是SP指向0x0x20000000~0x20000400。
2.ucos中如何保存局部變量
其實有沒有操作系統都一樣,都把任務中的局部變量和當前的寄存器狀態保存在棧中,在UCOS中一個任務就分配一個棧,假設有兩個任務,申請分配對應的任務棧如下:
static OS_STK Task1Stk[128]; //假設任務1的堆棧地址為0x20000500,那么任務1中的局部變量和寄存器狀態將保存在0x20000500~0x20000580
static OS_STK Task2Stk[256]; //假設任務1的堆棧地址為0x20000600,那么任務2中的局部變量和寄存器狀態將保存在0x20000600~0x20000700
當任務1運行時,系統使用的棧不再是0x0x20000000~0x20000400,而是0x20000500~0x20000580,任務2運行時,系統中的棧指向0x20000600~0x20000700。那么如何切換SP呢?假設切換到任務1SP:
;保存任務1SP
LDR R1, =Task1Stk ; 把SP存在R1中,在任務1中R1等於0x20000500~0x20000580
LDR R1, [R1]
STR R0, [R1] ; R0 is SP of process being switched out
;切換到任務1的SP
MSR PSP, R0 ; Load PSP with new process SP
就這樣,在UCOS中的模擬系統棧,生成任務棧,局部變量在任務棧中的分配,而非在系統棧中。而我之前的困惑是以為任務中的局部變量是分配到系統棧中,待任務切換中把系統棧中的內容負責到任務棧中。
