1.单片机程序分类:轮询程序,前后台程序,多任务系统程序

2.多任务系统伪代码

1 int flag1 = 0;
2 int flag2 = 0;
3 int flag3 = 0;
4
5 int main(void)
6 {
7 /* 硬件相关初始化 */
8 HardWareInit();
9
10 /* OS 初始化 */
11 RTOSInit();
12
13 /* OS 启动,开始多任务调度,不再返回 */
14 RTOSStart();
15 }
16
17 void ISR1(void)
18 {
19 /* 置位标志位 */
20 flag1 = 1;
21 }
23 void ISR2(void)
24 {
25 /* 置位标志位 */
26 flag2 = 2;
27 }
28
29 void ISR3(void)
30 {
31 /* 置位标志位 */
32 flag3 = 1;
33 }
34
35 voidDoSomething1(void)
36 {
37 /* 无限循环,不能返回 */
38 for (;;)
39 {
40 /* 任务实体 */
41 if (flag1)
42 {
43 }
44 }
45 }
46
47 voidDoSomething2(void)
48 {
49 /* 无限循环,不能返回 */
50 for (;;)
51 {
52 /* 任务实体 */
53 if (flag2)
54 {
55 }
56 }
57 }
58
59 voidDoSomething3(void)
60 {
61 /* 无限循环,不能返回 */
62 for (;;)
63 {
64 /* 任务实体 */
65 if (flag3)
66 {
67 }
68 }
69 }

View Code

3.三类系统异同

4.任务是什么:

在裸机系统中,系统的主体就是 main 函数里面顺序执行的无限循环,这个无限循环里面 CPU 按
照顺序完成各种事情。在多任务系统中,我们根据功能的不同,把整个系统分割成一个个独立的
且无法返回的函数,这个函数我们称为任务。

5.多任务系统中,要为每一个任务分配独立的栈空间

#define TASK1_STK_SIZE 128 (1)
#define TASK2_STK_SIZE 128
static CPU_STK Task1Stk[TASK1_STK_SIZE];(2)
static CPU_STK Task2Stk[TASK2_STK_SIZE];

6.重要宏定义

1 #ifndef CPU_H
2 #define CPU_H
3
4 typedef unsigned short CPU_INT16U;
5 typedef unsigned int CPU_INT32U;
6 typedef unsigned char CPU_INT08U;
7
8 typedef CPU_INT32U CPU_ADDR;
9
10 /* 栈数据类型重定义 */
11 typedef CPU_INT32U CPU_STK;
12 typedef CPU_ADDR CPU_STK_SIZE;
13
14 typedef volatile CPU_INT32U CPU_REG32;
15
16 #endif/* CPU_H */

7.系统为了顺利的调度任务,为每个任务都额外定义了一个任务控制块 TCB(Task Con-

trolBlock),这个任务控制块就相当于任务的身份证,里面存有任务的所有信息,比如任务的栈,
任务名称,任务的形参等。有了这个任务控制块之后,以后系统对任务的全部操作都可以通过这个 TCB 来实现。TCB 是一个新的数据类型

1 /* 任务控制块重定义 */
2 typedefstruct os_tcb OS_TCB;(1)
3
4 /* 任务控制块数据类型声明 */
5 struct os_tcb {(2)
6 CPU_STK *StkPtr;
7 CPU_STK_SIZE StkSize;
8 };


1 static OS_TCB Task1TCB;
2 static OS_TCB Task2TCB;

8.任务的栈,任务的函数实体,任务的 TCB 最终需要联系起来才能由系统进行统一调度。那么这

个联系的工作就由任务创建函数 OSTaskCreate 来实现,该函数在 os_task.c

1 void OSTaskCreate (OS_TCB *p_tcb,(1)//任务控制块指针
2          OS_TASK_PTR p_task,(2)//p_task 是任务函数名,类型为 OS_TASK_PTR
3              void *p_arg,(3)//p_arg 是任务形参,用于传递任务参数
4        CPU_STK *p_stk_base, (4)//p_stk_base 用于指向任务栈的起始地址
5       CPU_STK_SIZE stk_size, (5)//stk_size 表示任务栈的大小
6            OS_ERR *p_err) (6)//p_err 用于存错误码
7 {
8   CPU_STK *p_sp;
9
10   p_sp = OSTaskStkInit (p_task,(7)
11   p_arg,
12   p_stk_base,
13   stk_size);
14   p_tcb->StkPtr = p_sp;(8)
15   p_tcb->StkSize = stk_size;(9)
16
17   *p_err = OS_ERR_NONE;(10)
18 }

9.OSTaskStkInit() 是任务栈初始化函数。当任务第一次运行的时候,

加载到 CPU 寄存器的参数就放在任务栈里面,在任务创建的时候,预先初始化好栈。

1 CPU_STK *OSTaskStkInit (OS_TASK_PTR p_task,(1)//p_task 是任务名,指示着任务的入口地址,在任务切换的时候,需要加载到 R15,即 PC 寄存器,这样 CPU 就可以找到要运行的任务
2 void *p_arg,(2)//p_arg 是任务的形参,用于传递参数,在任务切换的时候,需要加载到寄存器 R0。R0 寄存器通常用来传递参数。
3 CPU_STK *p_stk_base,(3)//p_stk_base 表示任务栈的起始地址
4 CPU_STK_SIZE stk_size)(4)
5 {
6   CPU_STK *p_stk;
7
8   p_stk = &p_stk_base[stk_size];(5)//获取任务栈的栈顶地址,ARMCM3 处理器的栈是由高地址向低地址生长的。所以初始化栈之前,要获取到栈顶地址,然后栈地址逐一递减即可。
9   /* 异常发生时自动保存的寄存器 */(6)
10   *--p_stk = (CPU_STK)0x01000000u; /* xPSR 的 bit24 必须置 1 */
11   *--p_stk = (CPU_STK)p_task; /* R15(PC) 任务的入口地址 */
12   *--p_stk = (CPU_STK)0x14141414u; /* R14 (LR) */
13   *--p_stk = (CPU_STK)0x12121212u; /* R12 */
14   *--p_stk = (CPU_STK)0x03030303u; /* R3 */
15   *--p_stk = (CPU_STK)0x02020202u; /* R2 */
16   *--p_stk = (CPU_STK)0x01010101u; /* R1 */
17   *--p_stk = (CPU_STK)p_arg; /* R0 : 任务形参 */
18   /* 异常发生时需手动保存的寄存器 */(7)
19   *--p_stk = (CPU_STK)0x11111111u; /* R11 */
20   *--p_stk = (CPU_STK)0x10101010u; /* R10 */
21   *--p_stk = (CPU_STK)0x09090909u; /* R9 */
22   *--p_stk = (CPU_STK)0x08080808u; /* R8 */
23   *--p_stk = (CPU_STK)0x07070707u; /* R7 */
24   *--p_stk = (CPU_STK)0x06060606u; /* R6 */
25   *--p_stk = (CPU_STK)0x05050505u; /* R5 */
26   *--p_stk = (CPU_STK)0x04040404u; /* R4 */
27
28   return (p_stk);(8) //返回栈指针 p_stk,这个时候 p_stk 指向剩余栈的栈顶
29 }

10.任务创建好之后,我们需要把任务添加到一个叫就绪列表的数组里面,表示任务已经就绪,系统随时可以调度。

1 typedef struct os_rdy_list OS_RDY_LIST;(1)
2
3 struct os_rdy_list {(2)
4 OS_TCB *HeadPtr;
5 OS_TCB *TailPtr;
6 };1 #ifdef OS_GLOBALS
2 #define OS_EXT
3 #else
4 #define OS_EXT extern
5 #endif#define OS_CFG_PRIO_MAX 32u
OS_EXT OS_RDY_LIST OSRdyList[OS_CFG_PRIO_MAX];1 /* 将任务加入到就绪列表 */
2 OSRdyList[0].HeadPtr = &Task1TCB;(1)
3 OSRdyList[1].HeadPtr = &Task2TCB;(2)

11.OS 系统初始化一般是在硬件初始化完成之后来做的,主要做的工作就是初始化 μC/OS-III 中定义的全局变量。

1 void OSInit (OS_ERR *p_err)
2 {
3   OSRunning = OS_STATE_OS_STOPPED;(1)//系统用一个全局变量 OSRunning 来指示系统的运行状态,刚开始系统初始化的时候,默认为停止状态,即 OS_STATE_OS_STOPPED
4
5   OSTCBCurPtr = (OS_TCB *)0;(2)//全局变量 OSTCBCurPtr 是系统用于指向当前正在运行的任务的TCB 指针,在任务切换的时候用得到
6   OSTCBHighRdyPtr = (OS_TCB *)0;(3)//全局变量 OSTCBHighRdyPtr 用于指向就绪任务中优先级最高的任务的 TCB,在任务切换的时候用得到
7
8   OS_RdyListInit();(4)
9
10   *p_err = OS_ERR_NONE;(5)
11 }

OS_RdyListInit() 用于初始化全局变量 OSRdyList[],即初始化就绪
列表


1 OS_EXT OS_TCB *OSTCBCurPtr;
2 OS_EXT OS_TCB *OSTCBHighRdyPtr;
3 OS_EXT OS_RDY_LIST OSRdyList[OS_CFG_PRIO_MAX];
4 OS_EXT OS_STATE OSRunning;


1 #define OS_STATE_OS_STOPPED (OS_STATE)(0u)
2 #define OS_STATE_OS_RUNNING (OS_STATE)(1u)



1 void OS_RdyListInit(void)
2 {
3     OS_PRIO i;
4     OS_RDY_LIST *p_rdy_list;
5
6     for ( i=0u; i<OS_CFG_PRIO_MAX; i++ )
7     {
8         p_rdy_list = &OSRdyList[i];
9         p_rdy_list->HeadPtr = (OS_TCB *)0;
10        p_rdy_list->TailPtr = (OS_TCB *)0;
11     }
12 }

12.任务创建好,系统初始化完毕之后,就可以开始启动系统了

1 void OSStart (OS_ERR *p_err)
2 {
3     if ( OSRunning == OS_STATE_OS_STOPPED ) {(1)
4         /* 手动配置任务 1 先运行 */
5         OSTCBHighRdyPtr = OSRdyList[0].HeadPtr;(2) //OSTCBHIghRdyPtr 指向第一个要运行的任务的 TCB
6
7         /* 启动任务切换,不会返回 */
8         OSStartHighRdy();(3)
9
10         /* 不会运行到这里,运行到这里表示发生了致命的错误 */
11         *p_err = OS_ERR_FATAL_RETURN;
12     }
13     else
14     {
15         *p_err = OS_STATE_OS_RUNNING;
16     }
17 }    

OSStartHighRdy() 用于启动任务切换,即配置 PendSV 的优先级
为最低,然后触发 PendSV 异常,在 PendSV 异常服务函数中进行任务切换

1 ;*******************************************************************
2 ; 开始第一次上下文切换
3 ; 1、配置 PendSV 异常的优先级为最低
4 ; 2、在开始第一次上下文切换之前,设置 psp=0
5 ; 3、触发 PendSV 异常,开始上下文切换
6 ;*******************************************************************
7 OSStartHighRdy
8 LDR R0, = NVIC_SYSPRI14 ; 设置 PendSV 异常优先级为最低(1)
9 LDR R1, = NVIC_PENDSV_PRI
10 STRB R1, [R0]
11
12 MOVS R0, #0 ; 设置 psp 的值为 0 ,开始第一次上下文切换 (2)
13 MSR PSP, R0
14
15 LDR R0, =NVIC_INT_CTRL ; 触发 PendSV 异常(3)
16 LDR R1, =NVIC_PENDSVSET
17 STR R1, [R0]
18
19 CPSIE I ; 启用总中断,NMI 和 HardFault 除外(4)
20
21 OSStartHang
22 B OSStartHang ; 程序应永远不会运行到这里5 ; 有关内核外设寄存器定义可参考官方文档:STM32F10xxx Cortex-M3 programming manual
6 ; 系统控制块外设 SCB 地址范围:0xE000ED00-0xE000ED3F
7 ;--------------------------------------------------------------------
8 NVIC_INT_CTRL EQU 0xE000ED04 ; 中断控制及状态寄存器 SCB_ICSR。
9 NVIC_SYSPRI14 EQU 0xE000ED22 ; 系统优先级寄存器 SCB_SHPR3:
10 ; bit16~23
11 NVIC_PENDSV_PRI EQU 0xFF ; PendSV 优先级的值(最低)。
12 NVIC_PENDSVSET EQU 0x10000000 ; 触发 PendSV 异常的值 Bit28:PENDSVSET

UCOS-III笔记相关推荐

  1. ucos iii学习笔记——为什么选择ucos iii

    首先我们得先讨论前后台系统和RTOS(Real Time OS)的区别.前后台系统,也即是我们所说的裸机程序,它的结构通常包括一个死循环和若干个中断服务程序,直接上图,我们有一个直观认识: 假如Tas ...

  2. UCOS III 任务堆栈理解

    UCOS III在创建任务时,调用OSTaskStkInit函数,以初始化正在创建的任务的堆栈框架. 1:堆栈就是一段连续的空间.用于存储数据的,在c计算机中有很多应用,比如发生中断时保存现场,c语言 ...

  3. stm32单片机应用ucOS III ,操作浮点数导致死机解决方法

    ucOS III 的浮点数导致死机 解决方法: 1.启动文件Reset_Handler修改成: Reset_Handler PROCEXPORT Reset_Handler [WEAK]IMPORT ...

  4. 嵌入式软件设计(ucos iii使用)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 很多人都知道ucos ii,因为邵贝贝翻译的那本书<嵌入式实时操作系统-ucos ii&g ...

  5. 实时操作系统UCOS学习笔记1----UCOSII简介

    前面我们所有的实验都是跑的裸机程序(裸奔),从本章开始,我们开始介绍UCOSII(实时多任务操作系统内核). UCOSII简介 UCOSII的前身是UCOS,最早出自于1992年美国嵌入式系统专家Je ...

  6. 实时操作系统UCOS学习笔记5----UCOSIII移植

    在2009年Micrium公司推出了UCOSIII,相对于UCOSII性能有了进一步的提升,支持时间片轮转调度,极短的关中断事件等.本章讲解如何在STM32F103开发板上移植UCOSIII操作系统. ...

  7. UCOS 杂项 笔记

    1.  建立任务和建立数据队列  哪个先建立? 经过试验得知,数据队列和任务的建立先后没有顺序,都可以正常运行. 2.关于主函数的面试问题. 主函数写法有:   int  main()    和voi ...

  8. ucos II与ucos III的区别

    邵贝贝:嵌入式操作系统μC/OS-III 作者:邵贝贝 来源:嵌入式系统联谊会 邵老师长期从事单片机和嵌入式系统教学和应用工作,并负责清华大学飞思卡尔实验室工作.邵老师与大家分享了μC/OS的发展经历 ...

  9. uCOS III 和 uCOS II的区别

    邵贝贝:嵌入式操作系统μC/OS-III 作者:邵贝贝 来源:嵌入式系统联谊会 邵老师长期从事单片机和嵌入式系统教学和应用工作,并负责清华大学飞思卡尔实验室工作.邵老师与大家分享了μC/OS的发展经历 ...

  10. UCOS学习(一)——前后台系统、RTOS系统

    ⏩ 大家好哇!我是小光,嵌入式爱好者,一个想要成为系统架构师的大二学生. ⏩最近开始学习UCOS操作系统,后面会更新一些关于UCOS学习笔记. ⏩今天了解了UCOS操作系统,总结一下知识点. ⏩感谢你 ...

最新文章

  1. 精通spring——深入java ee开发核心技术 pdf_2019精通Spring Boot 42讲 高清pdf完整版
  2. opengl如何画出一个球_少儿美术绘画教程:毛线球
  3. idea搭建可运行Servlet的Web项目[maven]
  4. zynq中mgtx应用_【干货分享】ZYNQ常用外设设计 (上)
  5. vs2015打开慢的解决方法
  6. 【java】swing构件的操作
  7. Python chardet模块
  8. win10记得pin码 重置密码登录
  9. java method方法_java入门(六) | 方法(Method)的定义和使用
  10. 为 “超级大脑”构建支撑能力,腾讯云聚焦AI技术落地
  11. Python初级项目之随机漫步的Matplotlib实现
  12. SpringMVC:视图解析器(ViewResolver)
  13. RabbitMQ消息队列详细教程
  14. 前端发起接口请求时报错:405 Method Not Allowed
  15. 20221208英语学习
  16. -bash: /home/alex: 是一个目录
  17. PDManer安装教程
  18. android的亮屏幕的锁和键盘锁
  19. 数位DP POJ3208 Apocalypse Someday
  20. 彼得蒂尔《从0到1》阅读笔记

热门文章

  1. Mysql主从复制,级联复制(重点,重点,重点)命令,参数
  2. perl脚本提取后仿中的notimingcheck路径
  3. 终于搞定Paypal了
  4. SSH远程ubuntu【无公网IP、内网穿透】 1-3
  5. MySQL安装2出现Typical_Mysql安装 - osc_c7lpn2ge的个人空间 - OSCHINA - 中文开源技术交流社区...
  6. 个人永久性免费-Excel催化剂功能第60波-数据有效性验证增强版,补足Excel天生不足...
  7. 搭建kinect for windows开发平台
  8. 蹦蹦鸟游戏代码-JavaSE版本
  9. java解析xlsx表格,写入xlsx表格实例
  10. 移动端某些网络下域名无法解析的DNS问题