4013|9

1070

帖子

7

TA的资源

纯净的硅(中级)

 

扯扯任务切换 [复制链接]

 
                                                 扯扯任务切换
最近在玩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同理。):
VPGYJXKTWWCHB$BJ5OA~SNV.jpg
这两个栈各有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任务......
下面再上个图,这样可以比较形象点
_S)]E15RT}FZ16T]_5WUCD5.png
上图看不太清楚的文字是:
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是刚开始接触,学的不是很深,如果有说的不对的地方还请各位指正

最新回复

  详情 回复 发表于 2017-3-28 17:41

赞赏

1

查看全部赞赏

 

回复
举报

5977

帖子

8

TA的资源

版主

 
写的不错
最近的文章都很有水准啊
 
个人签名生活就是油盐酱醋再加一点糖,快活就是一天到晚乐呵呵的忙
===================================
做一个简单的人,踏实而务实,不沉溺幻想,不庸人自扰
 
 

回复

1070

帖子

7

TA的资源

纯净的硅(中级)

 
chenzhufly 发表于 2014-12-9 15:29
写的不错
最近的文章都很有水准啊



谢谢  
文笔不行,写点东西练练
 
 
 

回复

1

帖子

0

TA的资源

一粒金砂(初级)

 
谢谢楼主,学习了!
 
 
 

回复

72

帖子

0

TA的资源

一粒金砂(中级)

 
恩 虽然没全看懂,但是感觉很对的样子
 
 
 

回复

79

帖子

0

TA的资源

一粒金砂(中级)

 
越是理论的东西  越感觉很难一下说的清   支持个
 
 
 

回复

1070

帖子

7

TA的资源

纯净的硅(中级)

 
liuxiang5119 发表于 2015-3-12 18:09
越是理论的东西  越感觉很难一下说的清   支持个


恩,确实。特别是自己心里面的一些东西,有时候你明明感觉在自己脑子里面已经理得很顺,但是用语言表达的时候总感觉语言组织不起来

 
 
 

回复

7729

帖子

57

TA的资源

裸片初长成(中级)

 
dj狂人 发表于 2015-3-12 20:39
恩,确实。特别是自己心里面的一些东西,有时候你明明感觉在自己脑子里面已经理得很顺,但是用语言表达的时候总感觉语言组织不起来
分点写,每一个点都尽量简单,只说一个东西,短句.

把一个事情庖丁解牛.

我自己也写过很多很长的帖子,估计很多人都没心思看或者顺着看
"只是觉得很有道理,但完全不知道重点在哪"

我现在也在思索这个问题.
如何让发的贴更加有效


 
个人签名

强者为尊应让我

 
 

回复

1070

帖子

7

TA的资源

纯净的硅(中级)

 
辛昕 发表于 2015-3-16 17:01
分点写,每一个点都尽量简单,只说一个东西,短句.

把一个事情庖丁解牛.

我自己也写过很多很长的帖子,估计很多人都没心思看或者顺着看
"只是觉得很有道理,但完全不知道重点在哪"

我现在也在思索这个问题.
如何让发的贴更加有效



嗯嗯,学习了。确实,把想要把自己表达的的意思用文字写出来有讲究,不能你讲的顺畅就可以了。还的写的让人看得明白,总的来说就是把自己要表达的意思写明白来
 
 
 

回复

13

帖子

1

TA的资源

一粒金砂(初级)

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

猜你喜欢
随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表