1.前言

随着计算机技术和微电子技术的迅速发展,嵌入式系统应用领域越来越广泛,尤其是其具备低功耗技术的特点得到人们的重视。随着工信部提出NB-IoT基站建设具体目标、三大运营商加速建设,即将迎来万物互联的新时代,这是信息产业继移动互联网之后的下一个万亿级市场,这些为实时操作系统的应用提供了广阔的前景。

嵌入式实时操作系统将会部署到越来越多的设备中,这就要求工程师深入地了解嵌入式实时操作系统。本系列文章将和大家一起从零开始构建一个嵌入式实时操作系统,我将用最简单直白的方式一步一步搭建,我将用一篇文章的方式来总结搭建中的每个节点阶段,并开源软件工程和源代码。

2.嵌入式实时操作系统

嵌入式实时操作系统是一个特殊的程序,是一个支持多任务的运行环境。嵌入式实时操作系统最大的特点就是“实时性”,如果有一个任务需要执行,实时操作系统会立即执行该任务,不会有较长的延时。典型的实时操作系统有uCOS ,RT-Thread,FreeRTOS ,VxWorks,WinCE等。

嵌入式实时操作系统是一个特殊的程序(通常称为内核),它可以创建和控制所有任务。嵌入式实时操作系统除了包含一个内核以外,还提供其他服务,如文件系统,协议栈,图形用户界面等。本文的重点在于了解嵌入式实时操作系统内核的工作原理和结构,因此文中提到的实时操作系统通常指的是操作系统内核。实时操作系统内核通常要占用5%左右的CPU运行时间,另外内核是一个软件代码,需要额外占用ROM空间和RAM空间。

嵌入式实时操作系主要由以下3个子系统组成:

1、任务调度子系统
2、任务通信子系统
3、内存管理子系统

3.实现目标

本文讲解构建嵌入式实时操作系统的第一个节点阶段:实现简单的任务切换功能。
由于代码区的数据是不变的,处理器寄存器的值和栈空间的值决定程序运行状态。让每个任务“独享”一个栈空间,当我们将任务运行时的处理器寄存器的值保存起来时,这样就实现保存任务的运行状态。同样的当我们把保存的任务运行时的处理器寄存器的值装载到处理的寄存器中时,这样就恢复了任务的运行状态,任务继续运行起来。

切换任务的原理是:每个任务有一个“独享”栈空间,通过保存和装载任务运行时的处理器寄存器的值,实现任务的暂停和恢复运行。暂停一个任务后再恢复另外一个任务就完成了一次任务切换。

任务代码,任务栈空间和处理器状态如下图:

4.实验环境

硬件是基于意法半导体的STM32F401(ARM公司的Cortex-M4内核),软件开发使用的是KEIL V5.2 开发工具。

软件工程如下:

软件工程中包含:main.c ,startup_stm32f401xc.s 和 readme三个文件。startup_stm32f401xc.s文件为STM32F401的启动文件,main.c文件实现任务切换功能,readme文件用于记录版本修改日志。

5.代码实现

切换任务的原理是让每个任务都有一个“独享”栈空间,通过保存和装载任务运行时的处理器寄存器的值,实现任务的暂停和恢复运行。暂停一个任务后再恢复另外一个任务就完成了一次任务切换。
因此需要实现:

1、每个任务的独立栈空间。
2、实现任务的暂停和恢复。
3、实现任务的调度。

5.1实现独立栈空间
栈空间代码如下:

为每个任务定义一个静态数组,当任务运行时将处理器的栈指针指向任务“自己的”静态数组,从而实现独立栈空间。栈空间用来存放局部变量,中断调用和函数调用时的处理器寄存器的值。任务切换时需要将处理器寄存器的值保存到任务的独立栈空间。

在保存任务运行状态时需要保存处理器寄存器值到栈空间,因此需要深入了解处理器寄存器的用途和出入栈顺序,Cortex-M4内核的寄存器和寄存器中断自动入栈的顺序图如下:

初始化栈空间的代码如下:

栈空间初始化后的状态如下:

栈是一中先入后出的数据结构,Cortex-M4内核的栈操作方式倍设置成了向下生长。psp_array用于保存任务栈指针,psp_array[0]任务0栈指针指向task0_stack[112],其中task0_stack[116]保存PC程序指针值,task0_stack[117]保存状态寄存器(符合Cortex-M4内核寄存器出栈顺序:手动出栈8个寄存器,硬件自动出栈8个寄存器)。

5.2实现任务的暂停和恢复
代码如下:

cortex-M4内核有一个PendSV(可挂起的系统调用)异常,其异常编号为14并且具有可编程的优先级。当软件将PendSV设置成挂起时,程序将进入PendSV异常(中断)。
将PendSV异常优先级设置为最低,其它中断函数都可以得到正常响应,不会受到PendSV异常影响,在PendSV异常中执行任务切换,时序框图如下:

PendSV_Handler为Cortex-M4内核中断服务函数,进入中断函数时处理器自动保存了R0,R1,R2,R3, R12,LR,PC,XPSR,在PendSV_Handler中断程序中完成R4~R11入栈保存工作,从而实现任务保存工作。

/* 读取当前进程栈指针数值 */
MRS R0,PSP
/* 保存R4-R11八个寄存器的值到当前任务栈中  同时将回写的地址写入R0 */
STMDB R0!,{R4-R11}

psp_array[0]为任务0的栈指针, psp_array[1]为任务1的栈指针。以下代码实现任务栈指针切换

/* 读取psp_array 地址 */
LDR R3, =__cpp(&psp_array)
/* 将当前进程PSP指针值 写入 相应的 PSP_array 位置  */
STR  R0,[R3,R2,LSL #2]
/* 获取下个进程序号 */
LDR R4,=__cpp(&next_task)
LDR R4,[R4]
/* R1为&curr_task   将下个进程序号写入curr_task中 */
STR R4,[R1]
/* psp_array读取更新后的curr_task的PSP指针数值 */
LDR R0,[R3,R4,LSL #2]

在PendSV_Handler中断程序中完成R4~R11寄存器出栈,PendSV_Handler中断程序返回时处理器自动出栈R0,R1,R2,R3, R12,LR,PC,XPSR,从而实现任务恢复工作。

/* 出栈 R4-R11八个寄存器 */
LDMIA R0!,{R4-R11}
/* 设置PSP指针 */
MSR PSP,R0
/* 中断返回 */
BX LR

5.3实现任务的调度
任务调度的代码如下:

SysTick_Handler为定时器中断程序,实现时间片轮流改变目标任务,并挂起PendSV_Handle中断,退出SysTick_Handler中断程序时进入PendSV_Handle中断程序。

6.运行结果

代码仿真运行如下:

task_num0和task_num1这两个变量依次自加,代码实现任务轮流切换功能。

希望获取源码的朋友们在评论区里留言。

未完待续…
实时操作系统系列将持续更新
创作不易希望朋友们点赞,转发,评论,关注。
您的点赞,转发,评论,关注将是我持续更新的动力
作者:李巍
Github:liyinuoman2017
CSDN:liyinuo2017
今日头条:程序猿李巍

从零开始构建嵌入式实时操作系统1——任务切换相关推荐

  1. 从零开始构建嵌入式实时操作系统2——重构

    1.前言 本人是一个普通的中年程序员,并不是圈内的大牛,写嵌入式操作系统这一系列的文章并不是要显示自己的技术,而是出于对嵌入式的热爱.非常幸运,本人毕业后的十几年一直从事嵌入式行业,遇到过各种坑,也收 ...

  2. 从零开始构建嵌入式实时操作系统3——任务状态切换

    1.前言 一个行者问老道长:"您得道前,做什么?"老道长:"砍柴担水做饭."行者问:"那得道后呢?"老道长:"砍柴担水做饭.&qu ...

  3. 从零开始构建嵌入式实时操作系统5——设计延时功能

    1.前言 人生只有三天,昨天.今天和明天.昨天已然成为过去,明天尚在未来,拥有的不过是今天. 每一个今天,终将成为昨天,每一个明天,也都会成为今天,如此往复,抓住现在,珍惜未来,才能过好这一生. 这段 ...

  4. 嵌入式实时操作系统11——操作系统内核运行原理

    先展示一个操作系统运行动态图 1.操作系统内核关键知识点 本文将用一个实际的工程例子来剖析操作系统内核运行原理.在此之前我们先回顾一下之前文章讲述的重点知识点. <嵌入式实时操作系统3--任务切 ...

  5. 嵌入式系统开发16——嵌入式实时操作系统uC/OS的简介及简单应用

    本文主要介绍嵌入式实时操作系统(RTOS),并且以uc/OS为例,将其移植到stm32F103C8T6上,构建3个任务:其中两个task分别以1s和3s周期对LED灯进行点亮-熄灭的控制:另外一个ta ...

  6. 嵌入式实时操作系统ucos-ii_「正点原子NANO STM32开发板资料连载」第三十六章 UCOSII 实验 1任务调度...

    1)实验平台:alientek NANO STM32F411 V1开发板2)摘自<正点原子STM32F4 开发指南(HAL 库版>关注官方微信号公众号,获取更多资料:正点原子 第三十六章 ...

  7. 嵌入式实时操作系统ucos-ii_「正点原子NANO STM32开发板资料连载」第三十八章 UCOSII 实验 3...

    1)实验平台:alientek NANO STM32F411 V1开发板2)摘自<正点原子STM32F4 开发指南(HAL 库版>关注官方微信号公众号,获取更多资料:正点原子 第三十八章 ...

  8. 嵌入式实时操作系统1——初识嵌入式实时操作系统

    嵌入式实时操作系统是什么 嵌入式实时操作系统是一个特殊的程序,是一个支持多任务的运行环境.嵌入式实时操作系统最大的特点就是"实时性",如果有一个任务需要执行,实时操作系统会立即执行 ...

  9. 嵌入式实时操作系统μC/OS-Ⅱ 在DSP芯片上的移植与测试

    [摘要]为了降低DSP 系统软件的开发难度,保证系统的实时性,缩短开发周期,将嵌入式实时操作系统μC/OS-Ⅱ移植到DSP 芯片中是目前比较常用的一种方法.本文介绍了嵌入式实时操作系统μC/OS-Ⅱ的 ...

  10. 《嵌入式实时操作系统 uc/OS-II 原理及应用》【任哲 主编】随书例程以及使用方法

    说明 uc/OS-II 是一款开源的实时操作系统,但是如果用于商业,是需要付费的.为了深入了解,找到任哲老师的<嵌入式实时操作系统 uc/OS-II 原理及应用>一书,总体还不错.但是书中 ...

最新文章

  1. C语言register关键字—最快的关键字
  2. 前端学习(3274):js中this的使用三
  3. js删除数组中的某个对象
  4. Memcache 中实现消息队列
  5. 利用Socketserver实现简单的文件上传
  6. 云计算机工作组,边缘云场景、需求与组网架构
  7. 如果Google统治世界[组图]
  8. C#中的常量、类型推断和作用域
  9. drools rule (二) LHS语法详解
  10. k8s部署mysql
  11. 科研狗的英语翻译小众软件
  12. 使用unity3d 接入anySDK的总结2
  13. 使用OneR算法进行分类(Python实现)
  14. linux寄存器位运算,位运算的一些操作
  15. websocket网络断开之后重连
  16. 防灾科技学院图书馆大数据分析,2018读书报告丨来看一下谁是全年的阅读之星?
  17. mysql download mysql各个版本下载地址
  18. 在ROS平台上标定普通摄像头与Kinect摄像头
  19. linux服务器 增量,CentOS 自动备份增量文件
  20. 易语言报错:无法定位链接器!请检查 tools\link.ini 中的配置是否正确。 静态连接失败...

热门文章

  1. Nginx面试题整理
  2. plc基础知识入门学习
  3. 【音乐拼接】mp3格式
  4. input框背景设置透明
  5. python分析财务报表
  6. 谷歌浏览器32位安装包_谷歌团队新作!只需下载3M安装包,就能让你的手机浏览器跟踪眼球运动...
  7. 【Nginx】Nginx 工作原理
  8. 模糊综合评价模型 ——第三部分,一级模糊综合评价模型应用:例题1,对员工进行年终综合评定
  9. 【2022最新Java面试宝典】—— Linux面试题(50道含答案)
  10. Java飞机大战 项目-源码