ucos如何保存局部变量到任务堆栈中
学习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中的模拟系统栈,生成任务栈,局部变量在任务栈中的分配,而非在系统栈中。而我之前的困惑是以为任务中的局部变量是分配到系统栈中,待任务切换中把系统栈中的内容负责到任务栈中。