玩转X-CTR100 l STM32F4 l UCOS-III移植
我造轮子,你造车,创客一起造起来!塔克创新资讯【塔克社区 www.xtark.cn 】【塔克博客 www.cnblogs.com/xtark/ 】
概述
前后台系统
简单的小型系统设计一般是基于前后台的或者无限循环的系统。包含一个无限循环的模块实现需要的操作(后台)。中断处理程序实现异步事件(前台)。前台也叫做中断级,后台也叫作任务级。临界操作应该在任务级中被执行,不可避免地必须在中断处理程序中执行也要确保是在很短的时间内完成。因为这会导致ISR 占用更长的时间。通常的,ISR 中使能相关的信息而在后台程序中执行相应的操作。这叫做任务级响应。任务级响应的时间依赖于后台循环一次所需的时间,通常这不是一个固定常量。另外,如果其中的代码稍有改动,那么循环一次所用的时间也将有所变化。
大多数高产量低成本微控制器的应用软件(例如微波炉,电话玩具等)都是基于前后台系统的。
实时内核系统
实时内核是一个能管理MPU、MCU、DSP 时间和资源的软件。实时内核的应用包括迅速地响应,可靠地完成工作的各个部分。任务(也叫做线程)是一段简单的程序,运行时完全地占用CPU。
在单CPU 中,任何时候只有1 个任务被执行。内核的责任是管理任务,也做多任务处理。多任务处理的作用是协调和切换多个任务依次享用CPU。多任务处理最大化CPU 的功能同时会让我们感觉是多个CPU 在同时运行。多任务处理也有利于处理模块化的应用。多任务处理一个最重要的方面在于它允许程序员管理复杂的实时应用。在多任务处理中程序员可以简单的维护和升级产品。
uC/OS-III 是一个抢占式内核,这意味着uC/OS-III 总是执行最重要的就绪任务,如下图。
uC/OS-III系统
uC/OS-III是一个可扩展的,可固化的,抢占式的实时内核,它管理的任务个数不受限制。它是第三代内核,提供了现代实时内核所期望的所有功能包括资源管理、同步、内部任务交流等。uC/OS-III 也提供了很多特性是在其他实时内核中所没有的。比如能在运行时测量运行性能,直接得发送信号或消息给任务,任务能同时等待多个信号量和消息队列。以下列出uC/OS-III 的特点:
源代码:uC/OS-III 完全根据ANSI-C 标准写的。代码的规范是Micrium 团队的一种文化。虽然很多商业内核供应商提供他们产品的源代码,但是这些产品很有可能是笨重且难以利用的。除非代码严格地遵循标准并且产品有完整的带例子的说明书以展示代码是怎样工作的。通过这本书,你将会对uC/OS-III 内部的工作情况有一个很深的了解。
应用程序接口(API):uC/OS-III 是很直观的。如果你熟悉类似的编码规范,你能轻松地知道函数名所对应的服务,以及需要怎样的参数。例如:指向对象的指针通常是第一个参数,指向错误代码的指针通常是最后一个参数。
抢占式多任务处理:uC/OS-III 是一个抢占式多任务处理内核,因此,uC/OS-III 正在运行的经常是最重要的就绪任务。
时间片轮转调度:uC/OS-III 允许多个任务拥有相同的优先级。当多个相同优先级的任务就绪时,并且这个优先级是目前最高的。uC/OS-III 会分配用户定义的时间片给每个任务去运行。每个任务可以定义不同的时间片。当任务用不完时间片时可以让出CPU 给另一个任务。
快速响应中断: uC/OS-III 有一些内部的数据结构和变量。uC/OS-III 保护临界段可以通过锁定调度器代替关中断。因此关中断的时间会非常少。这样就使uC/OS-III 可以响应一些非常快的中断源了。
确定性的:uC/OS-III 的中断响应时间是可确定的,uC/OS-III 提供的大部分服务的执行时间也是可确定的。
可扩展的:根据应用的需求,代码大小可以被调整。编译时通过调整uC/OS-III 源代码中的大约40 个#define(见OS_CFG.H)可以在添加或移除一些功能。uC/OS-III 的服务还提供一些实时检查功能。特别的,uC/OS-III 能检传递的参数是否为NULL 指针,ISR 是否就绪了任务级服务。参数有允许范围,指定选项都是有用的。检测功能可以被关闭(在编译时)以提供更好的性能和缩减代码大小。实际上,可扩展的uC/OS-III 支持更广泛的应用和项目。
易移植的:uC/OS-III 可以被移植到大部分的CPU 架构中。大部分的支持uC/OS-II 的器件通过改动就能支持uC/OS-III。而uC/OS-II已经移植到45 种CPU 架构中了。
可固化的:uC/OS-III 专为嵌入式系统设计,它可以跟应用程序代码一起被固化。
可实时配置的:uC/OS-III 允许用户在运行时配置内核。特别的,所有的内核对象如任务、堆栈、信号量、事件标志组、消息队列、消息、互斥信号量、内存分区、软件定时器等都是在运行时分配的,以免在编译时的过度分配。
任务数无限制:uC/OS-III 对任务数量无限制。实际上,任务的数量限制于处理器能提供的内存大小。每一个任务需要有自己的堆栈空间,uC/OS-III 在运行时监控任务堆栈的生长。uC/OS-III 对任务的大小无限制。
优先级数无限制:uC/OS-III 对优先级的数量无限制。然而,配置uC/OS-III 的优先级在32 到256 之间已经满足大多数的应用了。
内核对象数无限制:uC/OS-III 支持任何数量的任务、信号量、互斥信号量、事件标志组、消息队列、软件定时器、内存分区。用户在运行时分配所有的内核对象。
服务:uC/OS-III 提供了高档实时内核所需要的所有功能,例如任务管理、时间管理、信号量、事件标志组、互斥信号量、消息队列、软件定时器、内存分区等。
互斥信号量(Mutexes):互斥信号量用于资源管理。它是一个内置优先级的特殊类型信号量,用于消除优先级反转。互斥信号量可以被嵌套,因此,任务可申请同一个互斥信号量多达250 次。当然,互斥信号量的占有者需要释放同等次数。
嵌套的任务停止:uC/OS-III 允许任务停止自身或者停止另外的任务。停止一个任务意味着这个任务将不再执行直到被其他的任务恢复。停止可以被嵌套到250 级。换句话说,一个任务可以停止另外的任务多达250 次。当然,这个任务必须被恢复同等次数才有资格再次获得CPU。
软件定时器:可以定义任意数量的一次性的、周期性的、或者两者兼有的定时器。定时器是倒计时的,执行用户定义的行为一直到计数减为0。每一个定时器可以有自己的行为,如果一个定时器是周期性的,计数减为0 时会自动重装计数值并执行用户定义的行为。
挂起多个对象:uC/OS-III 允许任务等待多个事件的发生。特别的,任务可以同时等待多个信号量和消息队列被提交。等待中的任务在事件发生的时候被唤醒。
任务信号量:uC/OS-III 允许ISR 或者任务直接地发送信号量给其它任务。这样就避免了必须产生一个中间级内核对象如一个信号量或者事件标志组只为了标记一个任务。提高了内核性能。
任务消息:uC/OS-III 允许ISR 或者任务直接发送消息到另一个任务。这样就避免产生一个消息队列,提高了内核性能。
任务寄存器:每一个任务可以拥有用户可定义的任务寄存器,不同于CPU 寄存器。
错误检测:uC/OS-III 能检测指针是否为NULL、在ISR 中调用的任务级服务是否允许、参数在允许范围内、配置选项的有效性、函数的执行结果等。每一个uC/OS-III 的API 函数返回一个对应于函数调用结果的错误代号。
内置的性能测量:uC/OS-III 有内置性能测量功能。能测量每一个任务的执行时间,每个任务的堆栈使用情况,任务的执行次数,CPU的使用情况,ISR 到任务的切换时间,任务到任务的切换时间,列表中的峰值数,关中断、锁调度器平均时间等。
可优化: uC/OS-III 被设计于能够根据CPU 的架构被优化。uC/OS-III 所用的大部分数据类型能够被改变,以更好地适应CPU 固有的字大小。优先级调度法则可以通过编写一些汇编语言而获益于一些特殊的指令如位设置、位清除、计数清零指令(CLZ),find-first-one(FF1)指令。
死锁预防:uC/OS-III 中所有的挂起服务都可以有时间限制,预防死锁。
任务级的时基处理:uC/OS-III 有时基任务,时基ISR 触发时基任务。uC/OS-III 使用了哈希列表结构,可以大大减少处理延时和任务超时所产生的开支。
用户可定义的钩子函数:uC/OS-III 允许程序员定义hook 函数,hook 函数被uC/OS-III 调用。hook 函数允许用户扩展uC/OS-III 的功能。有的hook 函数在任务切换的时候被调用,有的在任务创建的时候被调用,有的在任务删除的时候被调用。
时间戳:为了测量时间,uC/OS-III 需要一个16 位或者32 位的时时间戳计数器。这个计数器值可以在运行时被读取以测量时间。例如:当ISR 提交消息到任务时,时间戳计数器自动读取并保存作为消息。当接收者接收到这条消息,时间戳被提供在消息内。通过读取现在的时间戳,消息的响应时间可以被确定。
嵌入的内核调试器:这个功能允许内核调试器查看uC/OS-III 的变量和数据结构通过一个用户定义的通道。(但是只能在调试器遇到断点的时候查看)。uC/OS-III 内核也支持uC/Probe(探针)在运行时显示信息。
对象名称:每个uC/OS-III 的内核对象有一个相关联的名字。这样就能很容易的识别出对象所指定的作用。分配一个ASCII 码的名字给任务、信号量、互斥信号量、事件标志组、消息队列、内存块、软件定时器。对象的名字长度没有限制,但是必须以空字符结束。
各版本对比
uC/OS-III的源码已经跟前面版本的源码相差很大,很多方面都做了更加规范的修改,建议没有了解过uC/OS的用户直接上手uC/OS-III,不要再学习uC/OS-II。
现在市面上讲解uC/OS-III的书籍或资料大都基于《嵌入式实时操作系统 uC/OS-III》修改,想系统学习uC/OS-III的用户,了解更多uC/OS-III细节,建议直接阅读该书,讲解非常全面。
教程说明
uC/OS-III细节内容较多,需要一般专著讲解,本教程旨在引导用户使用uC/OS-III系统,包括将uC/OS-III移植X-CTR100控制器,并通过A、B、C三个任务设计经典RTOS应用例程,通过简单的例程使用户更容易学习uC/OS-III的使用。
移植
本小节讲解将uC/OS-III移植到X工程模板的过程。
uC/OS-III文件说明
uC/OS-III文件结构如下图
①配置文件,通过定义这些文件里宏的值可以轻易地裁剪uC/OS-III 的功能。
②用户应用文件,定义和声明应用任务。
③内核服务文件,其代码与 CPU 无关,可以不做任何修改移植到任何CPU。
④底层函数库,比如字符串的常规操作,常用的数学计算等等。
⑤CPU移植文件,用户如果想要移植uC/OS-III到不同平台上,需要修改这部分代码。
⑥CPU 配置文件,主要是CPU的一些工作模式和服务函数。
⑦其他CPU 相关文件。
配置文件
文件名 | 作用 |
lib_cfg.h | uC/LIB配置文件,如果使用uC/LIB调用函数Mem_Init()初始化 |
os_cfg.h | uC/OS相关函数配置 |
os_cfg.h | 内核任务配置(中断管理,空闲/统计任务,定时器) |
app_cfg.h | 用户任务配置 |
cpu_cfg.h | uC/CPU相关配置 |
os_type.h | 变量类型定义 |
移植步骤说明
下载源码
登陆Micrium公司官方网站(http://micrium.com/),下载源码,本文使用uC/OS-III V3.04.04版本,资料里面下载好的源码,目录结构如下图,移植过程将从该源码向X工程拷贝文件。
步骤一:创建文件夹,复制官方源码对应文件夹到移植工程。
复制文件夹到移植工程uC-CPU、uC-LIB、uCOS-III文件夹
删除不用的编译器文件夹
复制如下文件到uCOS-APP
复制文件到uCOS-BSP
步骤二:修改工程配置。
如下图添加工程目录和文件,具体文件位置可根据文件名称对应目录查找。
添加时注意选择All file,添加.h和.asm文件。
添加工程路径
步骤三:修改工程文件
首先修改工程的启动文件" startup_stm32f40xx.s"。
其中将PendSV_Handler 和SysTick_Handler 分别改为OS_CPU_PendSVHandler 和OS_CPU_SysTickHandler,共有两处修改位置两处。
初始化时,使能硬件浮点。
修改bsp.h,头文件包括ax_basis.h基础板载资源文件。
保留三个函数名称。
修改bsp.c文件,BSP_Init()函数,调用AX_Init()初始化函数。
修改ax_basis.c文件,删除滴答时钟及延时函数部分内容,保留LED、BEEP、拨码开关、串口操作内容,具体查看源文件。
修改app_cfg.h,该文件为app配置文件,做如下修改。
修改app.c文件,该文件是应用程序文件,main()函数位于该文件,包括uC/OS-III系统初始化和初始任务创建。
int main(void) { OS_ERR err;
OSInit(&err); /* Init uC/OS-III. */
OSTaskCreate((OS_TCB *)&AppTaskStartTCB, /* Create the start task */ (CPU_CHAR *)"App Task Start", (OS_TASK_PTR)AppTaskStart, (void *)0, (OS_PRIO)APP_TASK_START_PRIO, (CPU_STK *)&AppTaskStartStk[0], (CPU_STK_SIZE)APP_TASK_START_STK_SIZE / 10, (CPU_STK_SIZE)APP_TASK_START_STK_SIZE, (OS_MSG_QTY)5u, (OS_TICK)0u, (void *)0, (OS_OPT)(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), (OS_ERR *)&err);
OSStart(&err); /* Start multitasking (i.e. give control to uC/OS-III). */
}
static void AppTaskStart(void *p_arg) { OS_ERR err;
(void)p_arg;
CPU_Init();
/* Initialize BSP functions */ BSP_Init(); BSP_Tick_Init(); //Configure and Initialize the OS Tick Services (SysTick).
Mem_Init(); //Initialize Memory Management Module
#if OS_CFG_STAT_TASK_EN > 0u OSStatTaskCPUUsageInit(&err); /* Compute CPU capacity with no task running */ #endif
#ifdef CPU_CFG_INT_DIS_MEAS_EN CPU_IntDisMeasMaxCurReset(); #endif
/* Task body, always written as an infinite loop. */ while (1) { AX_LEDG_Toggle(); OSTimeDly(500, OS_OPT_TIME_DLY, &err); } } |
开始任务循环体,每隔0.5S翻转绿色LED灯,以便观察系统启动情况。
至此,移植完成,编译后下载到X-CTR100,系统运行正常,绿色LED灯闪烁。
参考
曾鸣等,《嵌入式实时操作系统 uC/OS-III》
秉火《uCOS-III 应用开发指南》
正点原子《STM32F4 UCOS开发手册_V3.0》
屈环宇 译《uC/OS-III手册中文翻译》