注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
dj狂人的个人空间 https://home.eeworld.com.cn/space-uid-525697.html [收藏] [复制] [分享] [RSS]
日志

扯扯任务切换

已有 522 次阅读2014-12-9 15:23

                                                 扯扯任务切换
最近在玩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中加载新的数据,而这个保存和加载数据的过程分自动保存/加载和手动保存/加载


本文来自论坛,点击查看完整帖子内容。

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

热门文章