一、UCOSIII 简介
UCOSIII 是一个可裁剪、可固化、可剥夺的多任务系统,没有任务数目的限制,是 UCOS
的第三代内核,UCOSIII 有以下几个重要的特性:
可剥夺多任务管理:UCOSIII 和 UCOSII 一样都属于可剥夺的多任务内核,总是执行当前
就绪的最高优先级任务。
同优先级任务的时间片轮转调度:这个是 UCOSIII 和 UCOSII 一个比较大的区别,UCOSIII
允许一个任务优先级被多个任务使用,当这个优先级处于最高就绪态的时候,UCOSIII 就会轮
流调度处于这个优先级的所有任务,让每个任务运行一段由用户指定的时间长度,叫做时间片。
极短的关中断时间:UCOSIII 可以采用锁定内核调度的方式而不是关中断的方式来保护临
界段代码,这样就可以将关中断的时间降到最低,使得 UCOSIII 能够非常快速的响应中断请求。
任务数目不受限制:UCOSIII 本身是没有任务数目限制的,但是从实际应用角度考虑,任
务数目会受到 CPU 所使用的存储空间的限制,包括代码空间和数据空间。
优先级数量不受限制:UCOSIII 支持无限多的任务优先级。
内核对象数目不受限制:UCOSIII 允许定义任意数目的内核对象。内核对象指任务、信号
量、互斥信号量、事件标志组、消息队列、定时器和存储快等。
软件定时器:用户可以任意定义“单次”和“周期”型定时器,定时器是一个递减计数器,
递减到零就会执行预先定义好的操作。每个定时器都可以指定所需操作,周期型定时器在递减
到零时会执行指定操作,并自动重置计数器值。
同时等待多个内核对象:UCOSIII 允许一个任务同时等待多个事件。也就是说,一个任务
能够挂起在多个信号量或消息队列上,当其中任何一个等待的事件发生时,等待任务就会被唤
醒。
直接向任务发送信号:UCOSIII 允许中断或任务直接给另一个任务发送信号,避免创建和
使用诸如信号量或事件标志等内核对象作为向其他任务发送信号的中介,该特性有效地提高了
系统性能。
直接向任务发送消息:UCOSIII 允许中断或任务直接给另一个任务发送消息,避免创建和
使用消息队列作为中介。
任务寄存器:每个任务都可以设定若干个“任务寄存器”,任务寄存器和 CPU 硬件寄存器
是不同的,主要用来保存各个任务的错误信息,ID 识别信息,中断关闭时间的测量结果等。
任务级时钟节拍处理:UCOSIII 的时钟节拍是通过一个专门任务完成的,定时中断仅触发
该任务。将延迟处理和超时判断放在任务级代码完成,能极大地减少中断延迟时间。
防止死锁:所有 UCOSIII 的“等待”功能都提供了超时检测机制,有效地避免了死锁。
时间戳:UCOSIII 需要一个 16 位或 32 位的自由运行计数器(时基计数器)来实现时间测
量,在系统运行时,可以通过读取该计数器来测量某一个事件的时间信息。例如,当 ISR 给任
务发送消息时,会自动读取该计数器的数值并将其附加在消息中。当任务读取消息时,可得到
该消息携带的时标,这样,再通过读取当前的时标,并计算两个时标的差值,就可以确定传递
这条消息所花费的确切时间。
二、移植文件
2.1.滴答定时器 Systick
滴答定时器是一个 24 位的倒计数定时器,当计到 0 时,将从 RELOAD 寄存器中自动重装
载定时器初值,只要不把它在 SysTick 控制以及状态寄存器中的使能位清零,就将永久不息。SysTick 的最大使命,就是定期地产生异常请求作为系统的时基。OS 都需要这种“滴答”来推动任务和时间的管理。
//初始化延迟函数
//当使用 ucos 的时候,此函数会初始化 ucos 的时钟节拍
//SYSTICK 的时钟固定为 HCLK 时钟的 1/8
//SYSCLK:系统时钟
void delay_init(u8 SYSCLK)
{
#if SYSTEM_SUPPORT_UCOS//如果需要支持 OS.u32 reload;
#endifSysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//选择外部时钟 HCLK/8fac_us=SYSCLK/8;//为系统时钟的 1/8
#if SYSTEM_SUPPORT_UCOS//如果需要支持 OS.reload=SYSCLK/8;//每秒钟的计数次数 单位为 Kreload*=1000000/delay_tickspersec;//根据 OS_TICKS_PER_SEC 设定溢出时间//reload 为 24 位寄存器,最大值:16777216,在//72M 下,约合 1.86s 左右fac_ms=1000/delay_tickspersec;//代表 ucos 可以延时的最少单位SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;//开启 SYSTICK 中断SysTick->LOAD=reload;//每 1/OS_TICKS_PER_SEC 秒中断一次SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启 SYSTICK
#elsefac_ms=(u16)fac_us*1000;//非 ucos 下,代表每个 ms 需要的 systick 时钟数
#endif
SysTick 的中断服务函数 SysTick_Handler()
//systick 中断服务函数,使用 ucos 时用到
void SysTick_Handler(void)
{if(delay_osrunning==1)//OS 开始跑了,才执行正常的调度处理{OSIntEnter();//进入中断OSTimeTick();//调用 ucos 的时钟服务程序OSIntExit();//触发任务切换软中断}
}
2.2os_cpu_a.asm 文件详解(暂且跳过,粗略看了一下)
IMPORT OSRunning
IMPORT OSPrioCur
IMPORT OSPrioHighRdy
IMPORT OSTCBCur
IMPORT OSTCBHighRdy
IMPORT OSIntNesting
IMPORT OSIntExit
IMPORT OSTaskSwHookEXPORT OSStartHighRdy
EXPORT OSCtxSw
EXPORT OSIntCtxSw
EXPORT OS_CPU_SR_Save
EXPORT OS_CPU_SR_Restore
EXPORT PendSV_Handler
2.3os_cpu.h 文件详解
typedef unsigned char BOOLEAN;
typedef unsigned char INT8U; //无符号 8 位数
typedef signed char INT8S; //有符号 8 位数
typedef unsigned short INT16U; //无符号 16 位数
typedef signed short INT16S; //有符号 16 位数
typedef unsigned int INT32U; //无符号 32 位数
typedef signed int INT32S; //有符号 32 位数
typedef float FP32; //单精度浮点数
typedef double FP64; //双精度浮点数//STM32 是 32 位位宽的,这里 OS_STK 和 OS_CPU_SR 都应该为 32 位数据类型
typedef unsigned int OS_STK; //OS_STK 为 32 位数据,也就是 4 字节
typedef unsigned int OS_CPU_SR; //默认的 CPU 状态寄存器大小 32 位
//定义栈的增长方向.
//CM3 中,栈是由高地址向低地址增长的,所以 OS_STK_GROWTH 设置为 1
#define OS_STK_GROWTH 1 //堆栈增长方向
//任务切换宏,由汇编实现.
#define OS_TASK_SW() OSCtxSw()
//OS_CRITICAL_METHOD = 1 :直接使用处理器的开关中断指令来实现宏
//OS_CRITICAL_METHOD = 2 :利用堆栈保存和恢复 CPU 的状态
//OS_CRITICAL_METHOD = 3 :利用编译器扩展功能获得程序状态字,保存在局部变量 cpu_sr
#define OS_CRITICAL_METHOD 3
//进入临界段的方法#if OS_CRITICAL_METHOD == 3#define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();}#define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);}
#endif
2.4os_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 未使用stk = ptos;// Load stack pointer*(stk) = (INT32U)0x01000000L;//xPSP*(--stk) = (INT32U)task;//PC*(--stk) = (INT32U)OS_TaskReturn; //R14*(--stk) =(INT32U)0x12121212L; //R12*(--stk) = (INT32U)0x03030303L;//R3*(--stk) = (INT32U)0x02020202L;//R2*(--stk) = (INT32U)0x01010101L;//R1*(--stk) = (INT32U)p_arg;//R0*(--stk) = (INT32U)0x11111111L; //R11*(--stk) = (INT32U)0x10101010L;//R10*(--stk) = (INT32U)0x09090909L; //R9*(--stk) = (INT32U)0x08080808L; //R8*(--stk) = (INT32U)0x07070707L; //R7*(--stk) = (INT32U)0x06060606L; //R6*(--stk) = (INT32U)0x05050505L; //R5*(--stk) = (INT32U)0x04040404L; //R4return (stk);
}
总结
简单的系统移植下载验证