stm32超轻量操作系统之抢占式内核

这一章比上一章内容多了不少。第一章完成了任务切换功能,这一章在任务切换功能上增加了以下几个功能。

1.改变特权级,加入SVC异常

2.增加优先级,使得内核可以抢占。

3.增加了滴答定时器中断功能,使得同优先级的任务以时间片方式调度。

4.增加延时函数。

接下来一项一项介绍。

1. 改变特权级

第一章中,所有的程序都是运行在特权级下。在中断中时切换到内核模式,在任务中切换到线程模式(Thread),但是权限都是特权级,意味着程序对内存中所有的数据都有修改的权限。此处加入两张图,通过修改寄存器,可以在退出中断后,在任务中运行即线程模式时权限是非特权级,这样在线程模式时就不能够更改内核模式下的数据了,程序的更具有健壮性。


图一.特权级与优先级运行状态说明

更改特权级只能在特权级下更改,所以通过在PendSV最后加入红色字体部分来更改了特权级。

__ASM void PendSVPopData()

{

extern PendSVFirst;

extern currTCB;

extern nextTCB;

PRESERVE8

LDR R0,=currTCB //R0=currTCB 

LDR R1,=nextTCB //R1=nextTCB

LDR R1,[R1] //R1=*R1

STR R1,[R0] //*R0=R1 currTCB=nextTCB完成了指向新的任务TCB的工作

LDR R0,[R1] //R0=*R1 R0保存了TCB堆栈栈顶的指针

LDMIA R0!,{R4-R11} //依次弹出R4-R11,完成后R0=R0+0x20

MSR PSP,R0 //PSP=R0

ORR LR,LR,#0x04 //LR=LR|0x04,表示函数返回后使用PSP指针

//使程序运行在非特权级,设置CONTROL[0]位为1,这样内核级和用户级就分开了,即是某个线程出现了问题也不会影响内核

LDR R1,=0x3

MSR CONTROL,R1

ISB

CPSIE I

BX LR

nop

}

同时要注意在非特权级(用户级)下只有触发异常才可以进入重新进入特权级,因此额外加入了SVC异常来主动触发中断。

还记得我们上一章讲过的发起任务调度的两种方式吗?

1.产生异常。

2.systick定时器中断。

其中第一条就是SVC异常中断。SVC异常用于产生系统调用,它的优先级最高,一经调用立刻进入此异常,因此,通过调用SVC异常,OS就进入了内核态(handler模式),在此就可以进行任务切换了。这种方式发起任务调度就不必等到systick定时器中断产生再发生任务调度了。

在任务中调用SvcTaskSwitch()就可以进行一次任务切换,这是自己定义的函数。SVC具体细节可以在网上查看相关资料。



2. 增加优先级功能

优先级功能参考了FreeRTOS的设计,通过列表和列表项的方式实现。

简单来讲,为了实现这个功能,我们设置了不同的列表,如果我们设置优先级共有8个,则新建8个优先级列表priorityReadyList[8]存储处于就绪态的任务,新建一个delayedList,存储处于延时的任务,新建一个pendList,存储处于挂起态的任务。所有的任务必然存在于这三种列表中。

列表又由列表项组成,列表中的列表项以双向链表的形式组合在一起,每一个列表项又存储了一个任务的TCB,这样就可以找到相应的任务。



图二.FreeRTOS列表结构说明

在任务切换时,首先找到一个目前优先级最高的任务,OSFindMaxPriorityTask()。如果找到的这个任务跟当前任务的优先级相同,那么就指向当前任务在列表中的下一个任务,来做切换,如果找到的任务优先级更高,那么直接切换高优先级的任务



3. 滴答定时器

滴答定时器的中断时间时1ms,也是时间片的时间。同优先级的任务每个运行1ms再切换。

systemTicks是任务运行的时间,系统初始化时赋值为0。在此我们不考虑溢出的问题,因为systemTicks是一个uint32_t的值,在此最大值代表约50天,因此在这个简易系统中不考虑溢出的情况。

其中需要注意的一点是判断任务的延时是否到达。其实很简单,如果有一个任务的延时时间到了,在延时列表中删除这个任务,在就绪列表中增加这个任务。我们怎么在延时列表中找到这个任务呢?因为列表中的列表项是按照readyTime升序排列的,因此通过我们前面在列表中特意设的最后列表的最后一项可以轻易的根据previous找到列表中的第一项。更新完任务后不要忘了更新下一项延时任务将要到达的时间。

在初始话列表的过程中我们给列表最后一项赋予了一个很大的值0x3ffffffff,因此可以任务永远不会到达这个时间。在列表中添加的项都会在它的前面。


4. 增加延时函数。

在第一章,我们时通过无意义的while(i--)来达到延时的目的,但这是阻塞运算,程序会卡在这个地方,满足不了实际的需要。OS中的延时函数会发生任务的调度,这样才不会浪费资源。

OSDelay的主要功能就是把当前任务挂起,在就绪列表中删除当前的任务,把任务加入到延时的列表中,更新其将要延时的时间,然后寻找下一个优先级最高的任务,进行切换。


最后设计了几个小实验,来验证程序是否正确运行。

设计了几个实验

1.两个小灯优先级相同,验证同优先级下的时间片调度。ok

void Task1()

{

int j = 0;

    while(1)

    {

          j=20000000;

         HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);

         while(j!=0)

         j--;

         HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);

         j=20000000;

         while(j!=0)

         j--;

   }

}

void Task2()

{

     int i = 0;

     while(1)

     {

        i=10000000;

        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);

        while(i!=0)

        i--;

        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET);

        i=10000000;

        while(i!=0)

        i--;

    }

}

2.两个任务优先级相同,验证延时功能是否有效 ok

void Task1()

{

     while(1)

     {

        OSDelay(2000);

        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);

        OSDelay(2000);

        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);

      }

}

void Task2()

{

      while(1)

     {

          OSDelay(1000);

          HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);

          OSDelay(1000);

          HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET);

     }

}

3.验证优先级不同,任务一优先级高,任务二优先级低,任务一一直运行,小灯暗灭切换,可以看到任务二不运行,小灯一直亮

void Task1()

{

      int i = 0;

      while(1)

      {

           i = 20000000;

          while(i!=0)

          i--;

          //OSDelay(2000);

         HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);

         i = 20000000;

         while(i!=0)

         i--;

         //OSDelay(2000);

        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);

     }

}

void Task2()

{

      while(1)

      {

          OSDelay(1000);

          HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);

          OSDelay(1000);

          HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET);

      }

}

4.任务一优先级高,任务二优先级低,任务一程序中有挂起3秒。可以看到在挂起的这段时间内任务二会切换,一但不挂起,任务二灯不会切换

void Task1()

{

     int i = 0;

     while(1)

     { 

          i = 100000000;

          while(i!=0)

          i--;

          //OSDelay(2000);

         HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);

         i = 100000000;

         while(i!=0)

         i--;

         OSDelay(5000);

         HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);

      }

}

void Task2()

{

    while(1)

    {

        OSDelay(1000);

        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);

       OSDelay(1000);

        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET);

    }

}

程序链接如下,实验用的是STM32F407的开发板

链接:https://pan.baidu.com/s/1my2HPG6shXB7QiwbR47Dnw

提取码:j5hw

stm32超轻量操作系统之任务调度

stm32超轻量操作系统之信号量与互斥量

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容