扯扯任务切换 最近在玩STM32,32位的单片机,寄存器太多了,直接面对寄存器不太适合我这种初学者,也由于实验室的一些原因,所以直接从OS开始学习,这次学习的系统叫msOS,可以说他是从ucOS的精简出来,只有两个任务,逻辑任务(logic)和界面任务(menu),当然少不了消息机制等,麻雀虽小,五脏俱全。 下面我来说说在这个系统的学习过程中我对任务切换的了解。在开始之前我们首先来科普下: 1.栈 栈是一种先进后出的数据结构。一般栈是由高地址向低地址生长的,这也就是为什么经常会有人说往栈里加入数据时,栈顶下降,而从栈里取出数据时栈顶上升。 2.中断 基于cortex内核的单片机发生中断时,会有一个保护现场的动作,就是自动 把一些数据压入栈中,其中首先入栈的是状态寄存器(XPSR)中的数据,接着是PC,然后是LR、R12、R3、R2、R1、R0,这八个寄存器中的数据压栈完毕之后,栈顶地址由MSP/PSP保存,那么退出中断后从MSP/PSP里得到的栈顶地址就可以把数据重新加载回相应的寄存器中,其中就包含返回断点的断点地址,因为这一步涉及PC指针的赋值,所以一般任务切换都是从这里着手。(PS:XPSR是状态寄存器;PC寄存器保存的是中断退出时的返回地址;R3-R0在父函数调用子函数时用于函数传递,所以中断的时候会把它们里面的数据也一起压栈) 我们都知道单片机里面程序准确的说是指令存储在程序存储空间(flash)里面,而单片机从哪取出指令是由PC指针的指向决定的,可以这么理解PC指向哪程序就运行到哪,那么如果我们想要从A任务切换到B任务的话,只要把原本指向A任务的PC指向B就可以了,当然在切换的时候要保存当前A任务执行时产生的一些数据,而从B任务切换回A任务也是同样的道理,这样的话我们就需要用到两个栈来分别保存A任务和B任务运行时产生的数据。那么好,基于以上的简单了解,下面我们来看看该怎么样实现任务切换。 首先,我们要创建两个栈分别用于保存A任务和B任务运行时产生的数据,并进行如下初始化(为了不绕,现用a表示任务A中的某一条指令的地址,b表示任务B中的某一条指令的地址,也就是当把a赋值给PC时,PC指向A任务,准确的说应该是单片机执行A任务,b同理。): 这两个栈各有64个字节的空间,其中栈底往下32个字节用于保存中断发生时单片机自动保存数据,后32个字节主要是考虑到当程序运行产生的数据过多时,用于保存R4-R11这八个寄存器中的数据(这部分数据是手动保存的)。 当系统开始运行的时候,会一直在优先级最低的任务中循环,每当节拍到来的时候进入节拍函数程序段执行,只有在需要的时候才会切换任务。那么现在我们假设任务A的优先级最低,假如在执行A任务的时候突然进来一个消息,需要执行B任务进行处理,单片机会触发中断,然后cpu会自动把当前的一些数据压入栈中,cortex内核的单片机第一次进入中断时默认把数据压入MSP,接着执行中断服务程序,在中断服务中我们可以这样处理,首先把B任务栈中自栈顶开始往上取出32个字节的数据加载到 R4-R11这八个寄存器中,再让栈顶上升8个字,然后把栈顶地址赋值给PSP,接着激活PendSV中断然后退出。中断退出后我们的单片机会自动加载一些数据到cpu里面,因为我们退出中断的时候激活了PendSV,所以单片机会根据PSP中的地址开始往上取出32个字节的数据加载到相应的寄存器中,其中就包括把b加载到PC寄存器里面,这样PC就指向了任务B,单片机开始执行B任务。这就完成了第一次切换,我们再来看后续的切换。 因为A任务的优先级最低,所以执行完B任务之后会切换回A任务。一样的,单片机先触发中断,不过这次是把数据压入PSP指向的存储空间也就是B任务的栈中,接着执行中断服务程序,在中断服务程序里面,我们需要手动的把R4-R11这八个寄存器里的数据保存到B任务的栈里面,然后栈顶下降8个字,接着切换栈顶,切换栈顶是从B任务栈切换到A任务栈,切换到A任务栈后先把栈顶开始往上取32个字节的数据加载到R4-R11这八个寄存器里面,然后栈顶上升32个字节,再把栈顶地址赋值给PSP后退出中断,接下来单片机会根据PSP中指向的地址开始往上取出32个字节的数据加载到相应的寄存器里面,其中就包括把a加载到PC寄存器,这样子PC就指向了A任务,单片机开始执行A任务...... 下面再上个图,这样可以比较形象点 上图看不太清楚的文字是: 1.触发中断时单片机自动加载XPSR、PC、R12、R3-R0中的数据到栈里面 2.进入中断服务函数后手动加载R4-R11这八个寄存器的数据到栈里面 3.切换栈之后,把新栈里面的数据从栈顶开始往上取32个字节的数据加载到R4-R11这八个寄存器中 4.退出中断后单片机自动把栈里面剩余的数据加载到XPSR、PC、R12、R3-R0这八个寄存器中 1、4步骤都是单片机自动完成的,2、3步时我们手动完成的,这样就完成了任务切换 总的来说,任务切换其实就是人为的改变PC的指向,但是因为单片机不允许我们随意的去更改PC的值,所以我们就需要用触发中断的方式更改PC指针,又任务切换的时候需要保存数据和往CPU中加载新的数据,而这个保存和加载数据的过程分自动保存/加载和手动保存/加载 在这个版块发这种帖子还是比较有压力的,毕竟前辈能人那么多,STM32和OS是刚开始接触,学的不是很深,如果有说的不对的地方还请各位指正
|