【嵌入式系统—实时操作系统】uC/OS-II 及其STM32F103移植
背景
踏入嵌入式领域,我们往往首先接触的都是单片机编程,而51也往往成为了入门首选。
而这种单片机编程通常都是指裸机编程(轮询系统/前后台系统),即没有加入 RTOS (多任务的实时操作系统)。
常用的 RTOS 有国外的 FreeRTOS、μC/OS、RTX 和国内的 Huawei LiteOS、和 RT-Thread 等。其中,开源且免费的 FreeRTOS 的 市场占有率最高,历史悠久的 μC/OS 则屈居第二。
学习目的
一、项目需要。单纯的裸机系统不能完美地解决问题,反而会使编程变得更加复杂,RTOS多任务管理的优势恰恰降低了编程的难度;
二、学习的需要。要想嵌入式学得更好,就必须学习更高级的东西,这样才可以实现更好的职业规划,为将来走向人生巅峰迎娶白富美做准备,而不是一味的在裸机编程上面死磕。
那为什么不选择实时性更高一筹的μC/OS-III而选择老一版本的μC/OS-II来学习μC/OS呢?
两者原理都差不多,学习的话建议学习uC/OS-II,uC/OS-II 资料相对较多些,uC/OS-II 经过长时间的检验,非常稳定可靠。可以先学II,等使用比较熟了后,再学III。
☞ STM32F107——μC/OS-II 源码包的快捷下载传送口
如果想自己亲身去官网下载源码包,我这里有详细指南☞☞ Micrium官网下载μC/OS II源码
文章目录
一、uC/OS-II内核结构的详细分析
二、微内核 uC/OS-II 中的任务
1、那在 uC/OS-II中,任务是什么呢?
2、关于任务的数据结构?
三、微内核 uC/OS-II 的移植
一、uC/OS-II内核结构的详细分析
实时微内核 uC/OS-II ,由 Jean J. Labrosse 在 1992 年编写发行,代码开源,如下图所示。
第一部分 (1):与硬件无关的高层的操作系统部分
大部分是关于任务的创建、信号量的创建、邮箱和队列的创建,以及它们所使用的函数库。另外,该部分还提供内存和实时时钟管理。
OS_Mbox.c | 消息邮箱(Mailbox)服务模块文件 |
---|---|
OS_MEM.c | 存储管理服务模块文件 |
OS_Q.c | 队列(Queue)服务模块文件 |
OS_SEM.c | 信号量(Semaphore)服务模块文件 |
OS_Task.c | 任务管理服务模块文件 |
OS_Time.c | 时间管理服务模块文件 |
第二部分 (2):与用户应用相关的配置头文件
主要定义了应用程序中的最大任务数、最低优先级、邮箱、信号量及钩子函数的使用情况等。
例如STM32F107评估板,其OS_CFG.H 配置头文件中的代码片段如下:
#ifndef OS_CFG_H
#define OS_CFG_H···#define OS_MAX_QS 4 /* Max. number of queue control blocks in your application */
#define OS_MAX_TASKS 20 /* Max. number of tasks in your application, MUST be >= 2 */···/* --------------------- TASK STACK SIZE ---------------------- */
#define OS_TASK_TMR_STK_SIZE 128 /* Timer task stack size (# of OS_STK wide entries) */···/* --------------------- TASK MANAGEMENT ---------------------- */
#define OS_TASK_CHANGE_PRIO_EN 1 /* Include code for OSTaskChangePrio() */
#define OS_TASK_CREATE_EN 1 /* Include code for OSTaskCreate()
···/* ----------------------- EVENT FLAGS ------------------------ */
#define OS_FLAG_EN 1 /* Enable (1) or Disable (0) code generation for EVENT FLAGS */
#define OS_FLAG_ACCEPT_EN 1 /* Include code for OSFlagAccept() */
···/* -------------------- MESSAGE MAILBOXES --------------------- */
#define OS_MBOX_EN 1 /* Enable (1) or Disable (0) code generation for MAILBOXES */
#define OS_MBOX_ACCEPT_EN 1 /* Include code for OSMboxAccept() */ ···/* --------------------- MEMORY MANAGEMENT -------------------- */
#define OS_MEM_EN 1 /* Enable (1) or Disable (0) code generation for MEMORY MANAGER */···
···/* ------------------------ SEMAPHORES ------------------------ */
#define OS_SEM_EN 1 /* Enable (1) or Disable (0) code generation for SEMAPHORES */
#define OS_SEM_ACCEPT_EN 1 /* Include code for OSSemAccept() */ ... #endif
第三部分 (3):与硬件处理器相关的代码
由 OS_CPU.H 、 OS_CPU_A.ASM 和 OS_CPU_C.C 构 成 。
其中,OS_CPU_A.ASM文件由三个汇编函数组成,,如下表。
OsStartHighRdy( ) | 运行优先级最高的就绪任务。 |
---|---|
Os_Task_Sw( ) | 任务切换函数 |
OsIntCtxSw( ) | 中断级的任务切换函数 |
这三个汇编函数非常重要(uC/OS-II 的移植工作大部分都基于这三个汇编函数,均与处理器硬件直接相关)
而 OS_CPU_C.C 主要包括任务堆栈的初始化函数、若干C语言的钩子函数(可以不加任何代码)。
二、微内核 uC/OS-II 中的任务
μC/OS-II 操作系统内核的主要工作——对任务进行管理和调度。
1、那在 uC/OS-II中,什么是任务呢?
“自顶向下,分而治之”的设计范型下,一 个大型的任务会被分解成一个个独立的且不能再分解的若干小任务(无法返回的函数),而与上述小任务对应的程序实体就叫做“任务”,也有人称之为线程。任务的大概形式具体如下。
void Task (void *parg)
{/* 任务主体,无限循环且不能返回 */for (;;) {/* 任务主体代码 */}
}
从代码级别上看,uC/OS-II 中的任务就是一个函数,由三个部分组成:任务程序代码、任务堆栈和任务控制块。
2、关于任务的数据结构?
N 个任务用双向链表串连起来,其中每个任务的数据结构由任务控制块(Task Control Block-TCB)和任务堆栈组成。
① 任务控制块:关联了任务代码的程序控制块(主要由指向任务堆栈的指针、指向前一个任务控制块的指针、指向后一个任务控制块的指针及任务的优先级等构成)。
任务控制块TCB的部分代码片段(在/uCOS-II/.../source/ucos_ii. h中),如下:
typedef struct os_tcb {OS_STK *OSTCBStkPtr; /* Pointer to current top of stack */···struct os_tcb *OSTCBNext; /* Pointer to next TCB in the TCB list */struct os_tcb *OSTCBPrev; /* Pointer to previous TCB in the TCB list */···void *OSTCBMsg; /* Message received from OSMboxPost() or OSQPost() */···INT32U OSTCBDly; /* Nbr ticks to delay task or, timeout waiting for event */INT8U OSTCBStat; /* Task status */INT8U OSTCBStatPend; /* Task PEND status */INT8U OSTCBPrio; /* Task priority (0 == highest) */INT8U OSTCBX; /* Bit position in group corresponding to task priority */INT8U OSTCBY; /* Index into ready table corresponding to task priority */···INT8U OSTCBDelReq; /* Indicates whether a task needs to delete itself */INT32U OSTCBCtxSwCtr; /* Number of time the task was switched in */INT32U OSTCBCyclesTot; /* Total number of clock cycles the task has been running */INT32U OSTCBCyclesStart; /* Snapshot of cycle counter at start of task resumption */OS_STK *OSTCBStkBase; /* Pointer to the beginning of the task stack */INT32U OSTCBStkUsed; /* Number of bytes used from the stack */INT8U *OSTCBTaskName;INT32U OSTCBRegTbl[OS_TASK_REG_TBL_SIZE];
} OS_TCB;
② 任务堆栈:保存任务的工作环境(主要用来保存任务断点的寄存器的状态值,在ARM处理器中则用于保存 PC、LR、 R0-R12、CPSR、SPSR 的状态值。任务堆栈在文件 os_cpu_c.c 中进行初始化)。
其堆栈初始化代码(在/Ports/.../RealView/os_cpu_c.c中),如下:
OS_STK *OSTaskStkInit (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt)
{OS_STK *stk;(void)opt; /* 'opt' is not used, prevent warning */stk = ptos; /* Load stack pointer *//* Registers stacked as if auto-saved on exception */*(stk) = (INT32U)0x01000000uL; /* xPSR */*(--stk) = (INT32U)task; /* Entry Point */*(--stk) = (INT32U)OS_TaskReturn; /* R14 (LR) */*(--stk) = (INT32U)0x12121212uL; /* R12 */*(--stk) = (INT32U)0x03030303uL; /* R3 */*(--stk) = (INT32U)0x02020202uL; /* R2 */*(--stk) = (INT32U)0x01010101uL; /* R1 */*(--stk) = (INT32U)p_arg; /* R0 : argument *//* Remaining registers saved on process stack */*(--stk) = (INT32U)0x11111111uL; /* R11 */*(--stk) = (INT32U)0x10101010uL; /* R10 */*(--stk) = (INT32U)0x09090909uL; /* R9 */*(--stk) = (INT32U)0x08080808uL; /* R8 */*(--stk) = (INT32U)0x07070707uL; /* R7 */*(--stk) = (INT32U)0x06060606uL; /* R6 */*(--stk) = (INT32U)0x05050505uL; /* R5 */*(--stk) = (INT32U)0x04040404uL; /* R4 */return (stk);
}
③ 任务程序代码:任务的执行部分。
三、微内核 uC/OS-II 的移植
1、在原有的STM32工程添加相应目录
原有SMT32工程文件夹下,新建一个目录uCOS-II,并在该目录下新建两个子目录:Ports和Source;
MDK工程目录下,新建uCOS-II_Source组、uCOS-II_Ports组。
2、添加源码文件到刚刚新建的目录下
(1)添加文件到本地工程文件夹
① /uCOS-II/Source文件下除os_cfg_c.h和os_dbg_r.c全部复制到移植工程目录下的Source子目录下
② /uCOS-II/Ports/ARM-Cortex-M3/Generic/RealView下的全部文件拷贝到移植目录的Ports子目录下
③ EvalBoards/Micrium/uC-Eval-STM32F107/uCOS-II下的app_cfg.h、includes.h 、 os_cfg.h和app_hooks.c(主要定义了一些钩子函数)这四个文件拷贝到移植工程的APP目录下。
(2)添加文件到MDK工程目录
分别在uCOS-II_Source组、uCOS-II_Ports组、APP组导入相应的本地工程文件。
3、修改includes.h
/*
*********************************************************************************************************
* EXAMPLE CODE
*
* (c) Copyright 2003-2013; Micrium, Inc.; Weston, FL
*
* All rights reserved. Protected by international copyright laws.
* Knowledge of the source code may NOT be used to develop a similar product.
* Please help us continue to provide the Embedded community with the finest
* software available. Your honesty is greatly appreciated.
*********************************************************************************************************
*//*
*********************************************************************************************************
*
* MASTER INCLUDES
*
* ST Microelectronics STM32
* on the
*
* Micrium uC-Eval-STM32F107
* Evaluation Board
*
* Filename : includes.h
* Version : V1.00
* Programmer(s) : EHS
*********************************************************************************************************
*/#ifndef INCLUDES_PRESENT
#define INCLUDES_PRESENT/*
*********************************************************************************************************
* STANDARD LIBRARIES
*********************************************************************************************************
*/#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>/*
*********************************************************************************************************
* LIBRARIES
*********************************************************************************************************
*///#include <cpu.h>
//#include <lib_def.h>
//#include <lib_ascii.h>
//#include <lib_math.h>
//#include <lib_mem.h>
//#include <lib_str.h>/*
*********************************************************************************************************
* APP / BSP
*********************************************************************************************************
*/#include "bsp.h"/*
*********************************************************************************************************
* OS
*********************************************************************************************************
*/#include <ucos_ii.h>/*
*********************************************************************************************************
* ST
*********************************************************************************************************
*//*
*********************************************************************************************************
* INCLUDES END
*********************************************************************************************************
*/#endif
4、修改main.c
/******************************************************************************
* File : main.c
* Function : 主文件
* Description: None
* Version : V1.00
* Author : WXP
* Date :
* History :
******************************************************************************/#include "includes.h"//START 任务
//设置任务优先级
#define START_TASK_PRIO 10 //开始任务的优先级设置为最低
//设置任务堆栈大小
#define START_STK_SIZE 64
//任务堆栈
OS_STK START_TASK_STK[START_STK_SIZE];
//任务函数
void start_task(void *pdata);//LED0任务
//设置任务优先级
#define LED0_TASK_PRIO 7
//设置任务堆栈大小
#define LED0_STK_SIZE 64
//任务堆栈
OS_STK LED0_TASK_STK[LED0_STK_SIZE];
//任务函数
void led0_task(void *pdata);//LED1任务
//设置任务优先级
#define LED1_TASK_PRIO 6
//设置任务堆栈大小
#define LED1_STK_SIZE 64
//任务堆栈
OS_STK LED1_TASK_STK[LED1_STK_SIZE];
//任务函数
void led1_task(void *pdata);int main(void)
{Bsp_Init();OSInit(); OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO );//创建起始任务OSStart(); while(1){}
}//开始任务
void start_task(void *pdata)
{OS_CPU_SR cpu_sr=0;pdata = pdata;OS_ENTER_CRITICAL(); //进入临界区(无法被中断打断) OSTaskCreate(led0_task,(void *)0,(OS_STK*)&LED0_TASK_STK[LED0_STK_SIZE-1],LED0_TASK_PRIO); OSTaskCreate(led1_task,(void *)0,(OS_STK*)&LED1_TASK_STK[LED1_STK_SIZE-1],LED1_TASK_PRIO); OSTaskSuspend(START_TASK_PRIO); //挂起起始任务.OS_EXIT_CRITICAL(); //退出临界区(可以被中断打断)
}//LED0任务
void led0_task(void *pdata)
{ while(1){LED2(ON);OSTimeDlyHMSM(0,0,0,200);LED2(OFF);OSTimeDlyHMSM(0,0,0,200);}
}//LED1任务
void led1_task(void *pdata)
{ while(1){LED3(ON);OSTimeDlyHMSM(0,0,0,500);LED3(OFF);OSTimeDlyHMSM(0,0,0,500);}
}
5、修改uCOS-II_Ports下的os_cpu_a.asm
① 第一处
EXPORT OS_CPU_PendSVHandler 改为 EXPORT PendSVHandler。
② 第二处
③ 第三个要改的:
将stm32f10x_it.c中的PendSV_Handler函数注释掉
6、修改bsp_systick.c
① 添加代码,如下
#include "includes.h"
② 在void SysTick_Init (void)函数中,修改为Syslick_Config(SystemCoreCIock OS_TICKS_PER_SEC//滴答时钟定时周期为1ms。
③ 第三处
7、修改uCOS-II_Ports文件夹下的os_cpu_c.c中的关于systick的配置初始化及中断处理部分
更新中···
8、uCOS-II_Ports文件夹下的os_cpu.h,注释掉我们刚才修改过的函数部分
更新中···
【嵌入式系统—实时操作系统】uC/OS-II 及其STM32F103移植相关推荐
- 关于任哲的《嵌入式实时操作系统uC/OS II原理及应用(第二版)》开发环境搭建和第一个例子
第一步 需要下载一个BC3.1精简版搭配书上的开发环境 .下载地址:云盘链接 提取码 0a44.这儿下载下来的bc文件夹可以 放在任何位置,楼主将其放在了C盘的根目录下. 第二步 就是文件的代码了,代 ...
- 嵌入式系统开发16——嵌入式实时操作系统uC/OS的简介及简单应用
本文主要介绍嵌入式实时操作系统(RTOS),并且以uc/OS为例,将其移植到stm32F103C8T6上,构建3个任务:其中两个task分别以1s和3s周期对LED灯进行点亮-熄灭的控制:另外一个ta ...
- 【嵌入式系统基础第九周作业】--嵌入式实时操作系统uc/OS
文章目录 1.CubeMX建立项目 1.1配置RCC(打开外部时钟),SYS(选择调试接口) 1.2配置GPIO(PC13用于点亮LED灯) 1.3配置USART1(串口输出) 1.4保存,生成项目文 ...
- 【嵌入式系统—实时操作系统】uC/OS II源码的官网下载
要下载源码为:STM32F107-uC/OS-II源码包 Micrium官网的下载地址:Micrium_uC-Eval-STM32F107_uCOS-II 怎么找? 到官网的产品专区目录入口查找STM ...
- 嵌入式系统 操作系统 uC/OS uClinux
摘要:嵌入式操作系统是嵌入式系统应用的核心软件.本文通过对两种典型的开源嵌入式操作系统的对比,分析和总结嵌入式操作系统应用中的若干问题,归纳嵌入式操作系统的选型依据. 关键词:嵌入式系统 操作系统 u ...
- 任哲《嵌入式实时操作系统uC/OS-II》 预备工具
进入工作后,白天负责公司项目开发,晚上蹭加班绩效在公司学点别的东西.虽说待在嵌入式部门,但基本上负责的项目都是微控制器类方面的开发,所以要加强学习真正的嵌入式方面的学习.第一个坑uC/OS-II.我学 ...
- 《嵌入式实时操作系统 uc/OS-II 原理及应用》【任哲 主编】随书例程以及使用方法
说明 uc/OS-II 是一款开源的实时操作系统,但是如果用于商业,是需要付费的.为了深入了解,找到任哲老师的<嵌入式实时操作系统 uc/OS-II 原理及应用>一书,总体还不错.但是书中 ...
- 任哲《嵌入式实时操作系统uC/OS-II》 基本概念与预备知识
爬坑系列第二讲:这两天手腕实在疼,以后再也不喝这么多酒了. 这两天看了第三章后面的知识,发现PC下的ucos学习真的很不方便,因为之前有简单地学习过LINUX,书上面的很多概念也都接触过,只不过学的不 ...
- UART0串口编程(四):UART0串口编程之在UC/OS—II中遭遇的危机
UART0串口编程之在UC/OS-II中遭遇的危机 一.潜在的危机 1.在uc/os操作系统中设计串口编程时,由于ISR和多个任务并发执行,情况比较复杂.尤其是接收状态为被动状态时,只能靠串行口中断来 ...
最新文章
- 信息安全系统设计基础家庭作业
- 目标检测--R-FCN: Object Detection via Region-based Fully Convolutional Networks
- Android事件机制:事件传递和消费
- php5.3+ 安装(mysqlnd )
- randn--创建正态分布随机矩阵
- P1121 环状最大两段子段和
- 嘉年华回顾丨阿里云吕漫漪带你一览POLARDB整体架构设计...
- python渐变色代码_如何在Python中创建颜色渐变?
- 亿佰特物联网开关电源模块:压电发声器驱动器
- 我的爹,我的娘(2006-02-22 21:39:07)(新浪)
- HackRF 无线门铃信号录制与重放
- python和java选择哪个-python和java哪个学起来更简单
- java基础学习(7)浅析final,private,public,protected,static等关键以及它们的区别的联系
- 华为命令 hybird实验
- 《二十世纪西方思想文化潮流》笔记--导论5--理性的后果1
- python语音库_python音频库dejavu原理浅析
- 微信公众平台开发教程Java版(一)环境准备篇
- alsa 麦克风采集音频
- Docker基础实战教程一:入门
- 判定覆盖 与 条件覆盖 的区别
热门文章
- ubuntu-budgine安装Fliqlo /gluqlo屏幕保护
- DIV CSS网页布局 让搜索引擎蜘蛛不再累
- 医疗护士专用PPT模板
- dell主板40针开机针脚_戴尔 OptiPlex 390 790 990主板34针前置 面板针脚 接口定义
- 「信息架构」EA874:信息架构基本组件
- java 数学公式解析框架有哪些_java程序员该如何进阶?这份java中高级核心知识全面解析请收好...
- 利用keil完成ARM汇编语言编程入门实践
- nvidia:成功解决Windows10右键没有NVIDIA控制面板图文教程之详细攻略
- Window11环境变量配置
- Caysn打印机IOS平台打印开发包及示例程序_20170610