uCOS II内核调度分析

合集下载

ucosII多核移植和扩展的原理以及注意事项

ucosII多核移植和扩展的原理以及注意事项

uC/OS-II是源码开放、可固化、可移植、可裁剪、可剥夺的实时多任务OS 内核,适用于任务多、对实时性要求较高的场合。

uC/OS-II适合小型系统,具有执行效率高、占用空间小、实时性优良和可扩展性等特点,最小内核可编译至2K。

uC/OS-II内核提供任务调度与管理、时间管理、任务间同步与通信、内存管理和中断服务等功能。

所谓RTOS移植,就是使一个实时内核能在某个微处理器或微控制器上运行。

大部分的uC/OS-II代码试用C写的,但仍需要用C和ASM写一些与处理器相关的代码,这是因为uC/OS-II在读写处理器寄存器时只能通过ASM实现。

要是uC/OS-II正常运行,处理器必须满足一定的条件:处理器的C编译器能产生可重入代码;用C语言就可以打开和关闭中断;处理器支持中断,并能产生定时中断;处理器支持能够容纳一定量数据的硬件堆栈;处理器有将SP和其他CPU reg读出和存储到堆栈或内存中的指令;uC/OS-II移植工作主要包括以下三个方面的内容:(1)修改与处理器核编译器相关的代码:主要在includes.h中,修改数据类型定义说明,OS_ENTER_CRITICAL()、OS_EXIT_CRITICAL()和堆栈增长方向定义OS_STK_GROWTH。

(2)用C语言编写10个移植相关的函数:主要在OS_CPU_C.C中,包括堆栈初始化OSTaskStkInit()和各种回调函数。

(3)编写4个汇编语言函数:主要在OS_CPU_A.ASM中,包括:_OSTickISR //时钟中断处理函数_OSIntCtxSW //从ISR中调用的任务切换函数_OSCtxSW //从任务中调用的任务切换函数_OSStartHighRdy //启动最高优先级的任务uC/OS-II移植的关键问题:(1)临界区访问:uC/OS-II需要先禁止中断再访问代码临界段,并且在访问完毕后重新允许中断,这就使得uC/OS-II能够保护临界段代码免受多任务或ISR的破坏。

UCOS-II-II、FreeRTOS、RTX四大RTOS系统性能对比

UCOS-II-II、FreeRTOS、RTX四大RTOS系统性能对比

UCOS-II/II、FreeRTOS、RTX四大RTOS系统性能对比大家好,感谢社区提供的板卡。

这次的使用对象是安富莱的STM32-V6板卡。

由于之前用过安富莱的V4板卡,所以安富莱给我留下了很深的印象,他们开发板的资料很过硬,售后完善,线上QQ技术支持也很给力,作为学习,确实是一款很不错的板卡。

唯一的是,安富莱很少出视频,其主要是编写PDF教学手册和程序例程。

另外他们的按键检测代码,很紧凑,有单发、连发、长按、短按、上升沿触发、下降沿触发等功能,是我见到最棒的按键检测代码。

STM32-V6是一款基于STM32F429单片机的开发板,整板采用4层板设计,本次选择它的目的,除了测试其能做常用外设开发驱动,安富莱还对它做了一个示波器的例程。

虽然示波器的性能不强,但是去十分有意思。

另外其支持VNC虚拟屏幕功能。

开发者可以不用LCD显示屏幕,直接使用PC屏幕作为自己的开发板屏幕,十分方便。

所以这个板子真的很强大。

拿到板子,在我查看他们的网络示波器例程后,发现安富莱只做了基于RTX的例程,并没有做基于uCOS、FreeRTOS的例程,这样我感到很奇怪。

因为安富莱的每个例程都会做三个OS版本,唯独这个例程却只制作了一个基于RTX的。

他们的技术支持回复是:“FreeRTOS的性能不行,所以对这个网络示波器的的应用来说,没有制作这方面的例程”,这让我感到很疑惑,FreeRTOS作为一款开源RTOS,性能真有这么差么?到底他们之间的差距又有多大?所以才有这次做UCOS-II、UCOS-III、FreeRTOS、RTX系统性能对比测试,本次我只是站在一个使用者的角度,测试四个RTOS单一的系统调度性能。

尽量使4个RTOS处在同一水平上测试:l 使用相同的硬件平台和相同的资源l 单片机都使用相同的主频,只是单片机的Uart资源。

uCOS-II

uCOS-II

实验一、任务创建与删除1、uC/OS-II介绍对于操作系统的学习,创建任务和删除任务是最为基础的工作,uC/OS-II以源代码的形式发布,是开源软件, 但并不意味着它是免费软件。

可以将其用于教学和私下研究;但是如果将其用于商业用途,那么必须通过Micrium获得商用许可。

uC/OS-II属于抢占式内核,最多可以支持64个任务,分别对应优先级0~63,每个任务只能对应唯一的优先级,其中0为最高优先级。

63为最低级,系统保留了4个最高优先级的任务和4个最低优先级的任务,所有用户可以使用的任务数有56个。

uC/OS-II提供了任务管理的各种函数调用,包括创建任务,删除任务,改变任务的优先级,任务挂起和恢复等。

系统初始化时会自动产生两个任务:一个是空闲任务,它的优先级最低,该任务仅给一个整型变量做累加运算;另一个是系统任务,它的优先级为次低,该任务负责统计当前cpu的利用率。

μC/OS-II可管理多达63个应用任务,并可以提供如下服务,本章将针对以下服务分别以例程的方式来介绍1)信号量2)互斥信号量3)事件标识4)消息邮箱5)消息队列6)任务管理7)固定大小内存块管理8)时间管理2、任务创建与删除想让uC/OS-II管理用户的任务,用户必须要先建立任务,在开始多任务调度(即调用OSStart())前,用户必须建立至少一个任务。

uC/OS-II提供了两个函数来创建任务:OSTask Create()或OSTaskCreateExt()。

可以使用其中任意一个即可,其函数原型如下:INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U pri o)INT8U OSTaskCreateExt (void(*task)(void *pd),void *pdata,SD_STK *ptos,INT8U prio, INT16U id,OS_STK *pbos,INT32U stk_size, void *pext,INT16U opt)task:任务代码指针pdata:任务的参数指针ptos:任务的堆栈的栈顶指针prio:任务优先级id:任务特殊的标识符(uC/OS-II中还未使用)pbos:任务的堆栈栈底的指针(用于堆栈检验)stk_size:堆栈成员数目的容量(宽度为4字节)pext:指向用户附加的数据域的指针opt:是否允许堆栈检验,是否将堆栈清零,任务是否要进行浮点操作等等删除任务,是说任务将返回并处于休眠状态,任务的代码不再被uC/OS-II调用,而不是删除任务代码。

北航ARM9实验报告:实验3uCOS-II实验

北航ARM9实验报告:实验3uCOS-II实验

北航ARM9实验报告:实验3uCOS-II实验北航 ARM9 实验报告:实验 3uCOSII 实验一、实验目的本次实验的主要目的是深入了解和掌握 uCOSII 实时操作系统在ARM9 平台上的移植和应用。

通过实际操作,熟悉 uCOSII 的任务管理、内存管理、中断处理等核心机制,提高对实时操作系统的理解和应用能力,为后续的嵌入式系统开发打下坚实的基础。

二、实验环境1、硬件环境:ARM9 开发板、PC 机。

2、软件环境:Keil MDK 集成开发环境、uCOSII 源代码。

三、实验原理uCOSII 是一个可裁剪、可剥夺型的多任务实时内核,具有执行效率高、占用空间小、实时性能优良和可扩展性强等特点。

其基本原理包括任务管理、任务调度、时间管理、内存管理和中断管理等。

任务管理:uCOSII 中的任务是一个独立的执行流,每个任务都有自己的堆栈空间和任务控制块(TCB)。

任务可以处于就绪、运行、等待、挂起等状态。

任务调度:采用基于优先级的抢占式调度算法,始终让优先级最高的就绪任务运行。

时间管理:通过系统时钟节拍来实现任务的延时和定时功能。

内存管理:提供了简单的内存分区管理和内存块管理机制。

中断管理:支持中断嵌套,在中断服务程序中可以进行任务切换。

四、实验步骤1、建立工程在 Keil MDK 中创建一个新的工程,选择对应的 ARM9 芯片型号,并配置相关的编译选项。

2、导入 uCOSII 源代码将 uCOSII 的源代码导入到工程中,并对相关的文件进行配置,如设置任务堆栈大小、系统时钟节拍频率等。

3、编写任务函数根据实验要求,编写多个任务函数,每个任务实现不同的功能。

4、创建任务在主函数中使用 uCOSII 提供的 API 函数创建任务,并设置任务的优先级。

5、启动操作系统调用 uCOSII 的启动函数,使操作系统开始运行,进行任务调度。

6、调试与测试通过单步调试、查看变量值和输出信息等方式,对系统的运行情况进行调试和测试,确保任务的执行符合预期。

UCOS-II调试心得

UCOS-II调试心得

B. ARM_PC存放P
C.c, PC.h 文件, C. Ex1存放Uc/OS-II的工程,注意在工程与Ex1文件之间不应该再一层文件夹,
工程名.mcp文件.
D. Source文件夹存放Uc/OS-II源文件,可以是V2.80版本或V2.51版本。

Ucos-II调试心得
1. 工程下必须有4个文件夹,分别为: ARM,ARM_PC,Ex1,Source.
其中: A. ARM目录存放Uc/OS-II在ARM上的移植代码,包括OS_cpu_a.S, OS_cpu_c.c, IRQ.inc, OS_CPU.H等4个文件;
2. 如果不需要使用Easyarm.exe进行上位机显示,则可以不用文件PC.c和PC.h,当然也可以 不需要ARM_PC文件夹. 但是需先将 "工程\Ex1\Src\Config.h中将最后一条指令 #include "..\..\Arm_Pc\pc.h"删掉,然后就可以删掉整个ARM_PC文件夹。

删掉这一语句后,
就可以删掉整个ARM_PC文件夹。

例如Ex1下通常有如下3个文件: 工程名_data文件夹,Src文件夹,
3. 如果用V2.80 UC/OS-II软件,那么在工程中须删掉本来的文件OS_CFG.H,增加Source目 录下的os_cfg.h,如下图:
删掉工程\Ex1\Src\下的os_cfg.h,
因为默认的此文件只能调用V2.51版本的uc/OS-II系统文件。

增加工程\Source\下的os_cfg.h文件。

4. 增加文件os_dbg_r.C到工程中。

如下图:
将工程\Source\下的os_dbg_r.C文件添加到工程。

a。

小议UCOSⅡ操作系统优先级判定方法

小议UCOSⅡ操作系统优先级判定方法

小议UCOSⅡ操作系统优先级判定方法不知不觉工作三个月了,这三个月一直在学习使用移植在STM32芯片上的UC/OSⅡ操作系统,磕磕绊绊的走了过来总会存在一些一直搞不明白但又不影响使用的问题,其中最高优先级的判定是其中一个,国庆节对于我这用没什么钱的菜鸟只有呆在宿舍里闭关修炼,今天下午研究了一下,略有小成,在此总结一下。

解决这个问题要从任务就续表和就绪组的相关代码说起:#define OS_RDY_TBL_SIZE ((OS_LOWEST_PRIO) / 8 + 1)INT8U OSRdyGrp;INT8U OSRdyTbl[OS_RDY_TBL_SIZE];其中OS_RDY_TBL_SIZE是最低优先级任务的优先级,为了论述方便此值取为63,其实可以直接在上代码里写63的,这么写只是为了节省内存空间用的。

OSRdyGrp就是就绪组,而且是无符号字符型的,而就续表其实就是代码中的数组OSRdyTbl[OS_RDY_TBL_SIZE],而且数组中的每一个为都是无符号字符型的,与就续表的关系可以用下图表示:OSRdyGrp位:在操作系统没有建立任务时就绪组和就续表如上图所示,全是0,如果建立了任务,对应为就会置1,一般操作系统都会有一个空闲任务和一个统计任务,其优先级分别是63、62,就续表和就绪组就变成了下面的样子:OSRdyGrp位:由此应该可以看出来,当某一优先级prio的任务就绪后,就需要将就续表中的对应为置1,同时将该优先级对应的行也置1,也就是说将OSRdyGrp的对应为置1。

现在的问题就是这个置1如何用代码实现呢,代码如下:OSRdyGrp |= OSMapTbl [prio>>3];OSRdyTbl[prio>>3] |= OSMapTbl[prio & 0x07]这样就搞定了,但是OSMapTbl怎么回事呢,其实这也是一个无符号字符型的一维数组,代码如下:INT8U const OSMapTbl[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };如果分配一个任务优先级为25的优先级,那么就续表中应该第4行第1位置1(由右至左),而OSRdyGrp的第3位置1。

ucos多任务调度的基本原理

ucos多任务调度的基本原理

ucos多任务调度的基本原理题目:ucos多任务调度的基本原理引言:在嵌入式系统中,任务调度是一个重要而复杂的问题。

为了实现多任务的并发执行,实时操作系统(RTOS)ucos提供了一种成熟而高效的多任务调度方案。

本文将介绍ucos多任务调度的基本原理,包括任务管理、任务优先级、时间片轮转和中断处理等方面,以帮助读者更好地理解和应用ucos。

一、任务管理在ucos中,任务是系统中最基本的执行单位。

ucos的任务管理分为任务创建、任务删除和任务切换几个步骤。

1. 任务创建:ucos通过函数OSTaskCreate来创建任务。

该函数包括了任务的入口函数、任务的堆栈大小和任务的优先级等参数。

在任务创建过程中,ucos为任务分配堆栈空间,并把任务插入到任务就绪表中。

2. 任务删除:当任务完成了它的工作或者不再需要执行时,可以通过函数OSTaskDel来删除任务。

任务删除时,ucos会释放任务占用的资源,并将任务从任务就绪表中移除。

二、任务优先级ucos支持任务的优先级调度,即不同优先级的任务有不同的执行顺序。

优先级越高的任务会先于优先级较低的任务执行。

1. 任务优先级范围:ucos的任务优先级范围是0到ucos最大任务数减1(通常为256)。

优先级为0的任务为最高优先级任务,优先级为ucos 最大任务数减1的任务为最低优先级任务。

2. 任务的优先级设置:任务的优先级可以在任务创建的时候通过函数OSTaskCreate来设置,也可以在运行时通过函数OSTaskChangePrio来修改。

3. 任务的优先级比较和切换:ucos将优先级比较和任务切换过程放在了任务调度中,当有多个任务就绪时,ucos会选择优先级最高的任务执行。

任务调度过程是由ucos内核中的调度器负责的。

三、时间片轮转在ucos中,为了保证不同优先级任务的公平性和实时性,采用了时间片轮转的调度算法。

1. 时间片:时间片是指任务在一次调度中执行的时间。

μCOS-II微小内核分析

μCOS-II微小内核分析

概述| μC/OS-II微小内核分析
3、配置文件
μC/OS-II微小内核简介
配置文件是每个μC/OS-II程序必备的文件,而且不同的程序 一般不一样,但大小基本上相同。配置文件范例位于H目录下, 分别为INCLUDES.H和OS_CFG.H文件。
(1) INCLUDES.H:内核需要的头文件,对于特定的移植,一般 不需要改变; (2)OS_CFG.H:内核配置的头文件,一般需要根据程序的需求 修改其常量的内容。
OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL() 所属文件 移植代码 函数名称 OSTimeTick OSIntEnter 所属文件 OS_CORE.C OSTaskCreate OSSemCreate OSIntExit OSTaskDel OSStart OS_TASK.C 函数名称 OSSemDel 函数名称 OSSemPend OS_TIME.C OSInit OS_CORE.C OS_SEM.C 所属文件 OS_SEM.C 函数名称 OSSemPost 函数名称 OSTimeDly 由移植代码决定 (INT8U prio) 函数原型 void OSTimeTick(void) void OSIntExit(void) OS_EVENT *OSSemCreate (INT16U *pd), INT8U opt, INT8U *err) INT8U *OSSemDel OSStart(void) 函数原型 OS_EVENTOSTaskDel (void (*task)(voidINT16U timeout, INT8U *err) 函数原型 void OSSemPend (INT16U ticks) *pevent) OSTimeDly (OS_EVENT *pevent, cnt) void OSTaskCreate OSInit(void) 函数原型 INT8U OSSemPost (void)(OS_EVENT *pevent,void *pdata, OS_STK *ptos, INT8U prio) 函数原型 INT8U OSIntEnter (OS_EVENT 一般来说,OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()为定义的宏,用来 通知μC/OS-Ⅱ一个中断服务已开始执行,这有助于μC/OS-Ⅱ掌握中断嵌套的情 功能描述 删除信号量:在删除信号量之前,应当删除可能会使用这个信号量的任务 在每次时钟节拍中断服务程序中被调用,无函数参数和返回值。OSTimeTick()检查 建立并初始化一个信号量 通知μC/OS-Ⅱ一个中断服务已执行完毕,这有助于μC/OS-Ⅱ掌握中断嵌套的情 启动μC/OS-II的多任务环境,无函数参数和返回值 功能描述 发送信号量:如果指定的信号量是零或大于零,OSSemPost()函数递增该信号量 建立一个新任务。既可以在多任务环境启动之前,也可以在正在运行的任务中创建 删除一个指定优先级的任务。被删除的任务将回到休眠状态,任务被删除后可 初始化μC/OS-Ⅱ,无函数参数和返回值 功能描述 将一个任务延时若干个时钟节拍,无函数返回值。延时时间的长度可从0到65535个 功能描述 等待信号量:当任务调用OSSemPend()函数时,如果信号量的值大于零,那么 功能描述 功能描述 禁止、打开CPU的中断,无函数参数和返回值 况。通常OSIntExit()和OSIntEnter()联合使用,无函数参数和返回值 处于延时状态的任务是否达到延时时间,或正在等待事件的任务是否超时 任务 况。通常OSIntExit()和OSIntEnter()联合使用。当最后一层嵌套的中断执行完毕 以用函数OSTaskCreate()重新建立 时钟节拍,延时时间0表示不进行延时,函数将立即返回调用者,延时的具体时间 并返回。如果有任务在等待信号量,则最高优先级的任务将得到信号量并进入就绪 功能描述 pevent :指向信号量的指针,OSSemCreate()的返回值 cnt :建立的信号量的初始值,可以取0到65535之间的任何值 在调用OSStart( )之前必须先调用OSInit ( )。在用户程序中OSStart( )只能被调用 函数参数 OSSemPend()函数对该值减一并返回:如果调用时信号量等于零,那么OSSemPend() 必须在调用OSStart()函数之前调用OSInit(),而只有在调用OSStart()函数之后, 功能描述 特殊说明 函数将任务加入该信号量的等待列表,任务将等待直到获得信号量或超时 后,如果有更高优先级的任务准备就绪,μC/OS-Ⅱ会调用任务调度函数,在这 功能描述 opt OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()必须成对使用 依赖于系统每秒钟有多少时钟节拍(由文件OS_CFG..H中的常量 状态。然后进行任务调度,决定当前运行的任务是否仍然为处于最高优先级的就绪 特殊说明 OSTimeTick()的运行时间和系统中的任务数直接相关,在任务或中断中都可以调用。 在中断服务程序中,如果保证直接递增OSIntNesting“原子操作”,中断服务 prio :指定要删除任务的优先级,如果为OS_PRIO_SELF则删除自身 一次,第二次调用OSStart( )将不执行任何操作 :指向任务代码的指针(函数指针) 函数参数 task:定义信号量删除条件 μC/OS-Ⅱ才真正开始运行多任务 正常 : 态的任务 指向分配给所建立的信号量的事件控制块的指针 OS_TICKS_PER_SEC设定) 种情况下,中断返回到更高优先级的任务而不是被中断了的任务。无函数参数 函数参数 -OS_DEL_NO_PEND:没有任何任务等待信号量才删除 特殊说明 如果在任务中调用,任务的优先级应该很高(优先级数字很小),这是因为 函数返回值 pevent:传递给任务的参数(一个变量指针) 程序使用直接递增OSIntNesting的方法而不调用OSIntEnter()函数。 pdata :指向信号量的指针,OSSemCreate()的返回值 OS_NO_ERR:函数调用成功 和返回值 NULL :没有可用的事件控制块 特殊说明 pevent :指向信号量的指针,OSSemCreate()的返回值 函数参数 -OS_DEL_ALWAYS:立即删除 函数参数 timeout:最多等待的时间(超时时间),以时钟节拍为单位 OSTimeTick()负责所有任务的延时操作 ticks:要延时的时钟节拍数 函数参数 ptos :指向任务堆栈栈顶的指针 何为原子操作?在一个任务的执行过程中,如果有某些操作不希望在执行 OS_TASK_DEL_IDLE:错误,试图删除空闲任务(Idle task) :用于返回错误码 特殊说明 err 在任务级不能调用该函数。即使中断服务程序使用直接递增OSIntNesting的 OS_NO_ERR :发送信号量成功 延时时间0表示不进行延时操作,而立即返回调用者。为了确保设定的延时时间, err 必须先建立信号量,然后使用 过程中被别的任务或中断打断,那么这些不希望被打断的操作就是原子操作 :任务的优先级 特殊说明 prio :用于返回错误码 OS_TASK_DEL_ ERR:错误,指定要删除的任务不存在 函数返回值 方法(没有调用OSIntEnter()),也必须调用OSIntExit()函数 特殊说明 *err可能为以下值: 建议用户设定的时钟节拍数加1。例如,希望延时10个时钟节拍,可设定参数为11 OS_SEM_OVF :信号量的值溢出 函数返回 OS_NO_ERR :成功删除信号量 *err可能为以下值: OS_NO_ERR:函数调用成功 OS_PRIO_INVALID:参数指定的优先级大于OS_LOWEST_PRIO 值 OS_ERR_EVENT_TYPE :pevent 不是指向信号量的指针 OS_PRIO_EXIST:具有该优先级的任务已经存在 OS_TASK_DEL_ISR:错误,试图在中断处理程序中删除任务 函数返回 OS_ERR_DEL_ISR :在中断中删除信号量所引起的错误 函数返回 OS_NO_ERR :调用成功,得到信号量 OS_ERR_INVALID_OPT :错误,opt值非法 OS_ERR_PEVENT_NULL :错误,pevent为NULL OS_TIMEOUT :超过等待时间 值 值 OS_PRIO_INVALID:参数指定的优先级大于OS_LOWEST_PRIO 函数返回 OS_ERR_TASK_WAITING :有一个或多个任务在等待信号量 值 必须先建立信号量,然后使用 特殊说明 OS_ERR_EVENT_TYPE :错误,pevent不是指向信号量的指针 OS_ERR_PEND_ISR :在中断中调用该函数所引起的错误 OS_NO_MORE_TCB:系统中没有OS_TCB可以分配给任务了 OS_ERR_PEVENT_NULL :错误,pevent为NULL OS_ERR_EVENT_TYPE :错误,pevent 不是指向信号量的指针 任务堆栈必须声明为OS_STK类型。注意:在中断处理程序中不能建立任务。在任 (1)使用这个函数调用时,必须特别小心,因为其它任务可能还要用这个信号量 务中必须调用μC/OS提供的下述过程之一:延时等待、任务挂起、等待事件发生 特殊说明 OS_ERR_PEVENT_NULL :错误,pevent为NULL 特殊说明 (2)当挂起任务就绪时,中断关闭时间与挂起任务数目有关 (等待信号量,消息邮箱、消息队列),以便其它任务也能获得CPU的使用权 特殊说明 必须先建立信号量,然后使用,不允许在中断中调用该函数,因为中断不能被挂起

uCOS-II内核详解

uCOS-II内核详解

UC/OS-II内核详解一.内核概述:多任务系统中,内核负责管理各个任务,或者说为每个任务分配CPU时间,并且负责任务之间的通讯。

内核提供的基本服务是任务切换。

之所以使用实时内核可以大大简化应用系统的设计,是因为实时内核允许将应用分成若干个任务,由实时内核来管理它们。

内核本身也增加了应用程序的额外负荷,代码空间增加ROM的用量,内核本身的数据结构增加了RAM的用量。

但更主要的是,每个任务要有自己的栈空间,这一块吃起内存来是相当厉害的。

内核本身对CPU的占用时间一般在2到5个百分点之间。

UC/OS-II有一个精巧的内核调度算法,实时内核精小,执行效率高,算法巧妙,代码空间很少。

UC/OS-II的内核还可以被裁剪,Hmax中RTOS的就是一个被高度裁剪过的UC/OS-II。

二.任务控制块 OS_TCB:uC/OS-II的TCB数据结构简单,内容容易理解,保存最基本的任务信息,同时还支持裁减来减小内存消耗,TCB是事先根据用户配置,静态分配内存的结构数组,通过优先级序号进行添加,查找,删除等功能。

减少动态内存分配和释放。

因为依靠优先级进行TCB分配,每个任务必须有自己的优先级,不能和其他任务具有相同的优先级。

typedef struct os_tcb{OS_STK *OSTCBStkPtr;#if OS_TASK_CREATE_EXT_ENvoid *OSTCBExtPtr;OS_STK *OSTCBStkBottom;INT32U OSTCBStkSize;INT16U OSTCBOpt;INT16U OSTCBId;#endifstruct os_tcb *OSTCBNext;struct os_tcb *OSTCBPrev;#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN || OS_SEM_ENOS_EVENT *OSTCBEventPtr;#endif#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_ENvoid *OSTCBMsg;#endifINT16U OSTCBDly;INT8U OSTCBStat;INT8U OSTCBPrio;INT8U OSTCBX;INT8U OSTCBY;INT8U OSTCBBitX;INT8U OSTCBBitY;#if OS_TASK_DEL_ENBOOLEAN OSTCBDelReq;#endif} OS_TCB;.OSTCBStkPtr是指向当前任务栈顶的指针。

UCOSII实验1-任务调度

UCOSII实验1-任务调度

UCOSII实验1-任务调度 ·UCOSII 是⼀个可以基于 ROM 运⾏的、可裁减的、抢占式、实时多任务内核,具有⾼度可移植性,特别适合于微处理器和控制器。

·为了提供最好的移植性能, UCOSII 最⼤程度上使⽤ ANSI C 语⾔进⾏开发,并且已经移植到近 40 多种处理器体系上,涵盖了从 8 位到 64 位各种 CPU(包括 DSP)。

·UCOSII 具有执⾏效率⾼、占⽤空间⼩、实时性能优良和可扩展性强等特点,最⼩内核可编译⾄ 2KB 。

UCOSII 已经移植到了⼏乎所有知名的 CPU 上。

UCOSII体系结构图:UCOSII 的移植,我们只需要修改: os_cpu.h、 os_cpu_a.asm 和 os_cpu.c等三个⽂件即可: ① os_cpu.h,进⾏数据类型的定义,以及处理器相关代码和⼏个函数原型; ② os_cpu_a.asm,是移植过程中需要汇编完成的⼀些函数,主要就是任务切换函数; ③ os_cpu.c,定义⼀些⽤户 HOOK 函数。

图中定时器的作⽤是为 UCOSII 提供系统时钟节拍,实现任务切换和任务延时等功能。

这个时钟节拍由 OS_TICKS_PER_SEC(在os_cfg.h 中定义)设置,⼀般我们设置 UCOSII 的系统时钟节拍为 1ms~100ms,具体根据你所⽤处理器和使⽤需要来设置。

对于STM32的单⽚机⼀般⽤其 SYSTICK 定时器来为 UCOSII 提供时钟节拍。

UCOSII的任务优先级 · UCOSII 保留了最⾼ 4 个优先级和最低 4 个优先级的总共 8 个任务,⽤于拓展使⽤; · UCOSII ⼀般只占⽤了最低 2 个优先级,分别⽤于空闲任务(倒数第⼀)和统计任务(倒数第⼆),所以剩下给我们使⽤的任务最多可达 255-2=253 个(V2.91)。

任务 · 所谓的任务,其实就是⼀个死循环函数,该函数实现⼀定的功能,⼀个⼯程可以有很多这样的任务(最多 255 个), UCOSII 对这些任务进⾏调度管理,让这些任务可以并发⼯作(注意不是同时⼯作!!,并发只是各任务轮流占⽤ CPU,⽽不是同时占⽤,任何时候还是只有 1 个任务能够占⽤ CPU),这就是 UCOSII 最基本的功能。

嵌入式实时操作系统ucosii

嵌入式实时操作系统ucosii

医疗电子
ucosii在医疗电子领域 中应用于医疗设备、监
护仪、分析仪等。
物联网
ucosii在物联网领域中 应用于传感器节点、网
关、路由器等设备。
02
ucosii的体系结构与内核
任务管理
任务创建
ucosii提供了创建新任务的函数,如 OSTaskCreate(),用于创建新任务。
任务删除
ucosii提供了删除任务的函数,如 OSTaskDelete(),用于删除不再需要的任 务。
时间管理
01
02
03
时间节拍
ucosii通过定时器产生固 定时间间隔的节拍信号, 用于任务调度和时间管理 。
超时处理
ucosii支持超时机制,当 某个任务等待时间超过预 定阈值时触发相应的处理 函数。
时间函数
ucosii提供了一系列时间 函数,如OSTimeDly()、 OSTimeTick()等,用于时 间相关的操作和控制。
智能家居
ucosii适用于智能家居领域,可应用于 智能家电控制、家庭安全监控等场景。
02
03
医疗电子
ucosii适用于医疗电子领域,如医疗设 备控制、病人监控等,其可靠性和实 时性为医疗系统提供了有力保障。
THANKS。
应用软件的开发
任务管理
在UCOSII中,任务是用来实现应用程序功能的。在进行应用软件的开发时,需要创建和管理任务。这包括任务的创 建、删除、挂起和恢复等操作。
任务间通信
为了实现任务间的协同工作,需要进行任务间通信。UCOSII提供了信号量、消息队列、互斥量等机制来实现任务间 通信。在进行应用软件的开发时,需要利用这些机制来实现任务间的同步和数据交换。

Uc-OS II就绪表(Ready List)分析

Uc-OS II就绪表(Ready List)分析

Uc/OS II 就绪表(Ready List)分析就绪表(Ready List)每个任务被赋予不同的优先级等级,从0 级到最低优先级OS_LOWEST_PR1O,包括0 和OS_LOWEST_PR1O 在内(见文件OS_CFG.H)。

当uCOS II 初始化的时候,最低优先级OS_LOWEST_PR1O 总是被赋给空闲任务idle task。

注意,最多任务数目OS_MAX_TASKS 和最低优先级数是没有关系的。

用户应用程序可以只有10 个任务,而仍然可以有32 个优先级的级别(如果用户将最低优先级数设为31 的话)。

每个任务的就绪态标志都放入就绪表中的,就绪表中有两个变量OSRedyGrp和OSRdyTbl[]。

在OSRdyGrp 中,任务按优先级分组,8 个任务为一组。

OSRdyGrp 中的每一位表示8 组任务中每一组中是否有进入就绪态的任务。

任务进入就绪态时,就绪表OSRdyTbl[]中的相应元素的相应位也置位。

就绪表OSRdyTbl[]数组的大小取决于OS_LOWEST_PR1O(见文件OS_CFG.H)。

当用户的应用程序中任务数目比较少时,减少OS_LOWEST_PR1O 的值可以降低uCOS II 对RAM(数据空间)的需求量。

为确定下次该哪个优先级的任务运行了,内核调度器总是将OS_LOWEST_PR1O 在就绪表中相应字节的相应位置1。

OSRdyGrp 和OSRdyTbl[]之间的关系见图3.3,是按以下规则给出的:当OSRdyTbl[0]中的任何一位是1 时,OSRdyGrp 的第0 位置1,当OSRdyTbl[1]中的任何一位是1 时,OSRdyGrp 的第1 位置1,当OSRdyTbl[2]中的任何一位是1 时,OSRdyGrp 的第2 位置1,当OSRdyTbl[3]中的任何一位是1 时,OSRdyGrp 的第3 位置1,当OSRdyTbl[4]中的任何一位是1 时,OSRdyGrp 的第4 位置1,。

uCOSII原理及应用

uCOSII原理及应用
通过任务函数实现特定的功能,每个任务函数 对应一个独立的执行线程。
任务控制块
用于存储任务的运行状态和控制信息,包括任 务的优先级、状态、堆栈指针等。
任务切换函数
用于实现任务之间的切换,包括保存当前任务的上下文和恢复下一个任务的上 下文。
ucosii的任务管理
创建任务
通过调用ucosii提供的函数, 创建新的任务并分配相应的 资源。
在物联网应用中,ucosii能够为各种智能硬件提供统一的操 作系统平台,实现设备的互联互通和智能化管理。同时, ucosii还提供了丰富的中间件和驱动程序,方便开发者快速 开发出各种智能硬件和应用软件。
ucosii在嵌入式系统中的应用
嵌入式系统是指嵌入到硬件中的计算机系统,具有特定的功能和性能要求。ucosii作为一种实时操作 系统,在嵌入式系统中也有着广泛的应用。
调试工具
使用JTAG、SWD等调试工具,通过串口、网络等方式与目标板进行通信,实现程序的 下载、运行、断点设置等操作。
调试步骤
首先确认硬件连接正确,然后通过调试工具将程序下载到目标板中,设置断点并运行程 序,观察程序运行过程中变量的变化和程序的执行流程。
常见问题
硬件连接问题、调试工具配置问题、程序编译错误等。
ucosii的性能分析
性能指标
响应时间、吞吐量、资源利用率等。
分析方法
通过代码审查、性能测试、瓶颈分析等方法,找出影响性能的 关键因素,如算法复杂度、内存访问模式、IO性能等。
优化建议
针对分析结果,提出优化建议,如改进算法、优化数据结 构、减少IO操作等。
ucosii的优化建议
算法优化
通过改进算法,减少计算量和复杂度,提高程序执行效率。
易用性

uCOS-II源码分析

uCOS-II源码分析

uC/OS-II源码分析(一)下载地址:/它的特点:1)开源,2)可移植性,绝大部分代码用C写,硬件相关部分用汇编写,3可固化,4)可剪裁,这通过条件编译实现,使用#define语句定义所需要的功能。

5)可剥夺性(总是运行就绪条件下优先级最高的任务),6)多任务(可以管理64个任务,其中保留8个给uC/OS-II,因此用户最多可有56个任务,每个任务优先级不同,也就意味着不支持时间片轮转调度法,因为这种方法适合于优先级平等的任务)。

7)可确定性。

函数调度和服务执行时间具有确定性,除了OSTimeTick()和某些事件标志服务,系统服务执行时间不依赖用户应用程序任务数目的多少。

8)任务栈。

允许每个任务自己单独的栈空间不同,可以使用栈空间检验函数确定所需要的栈空间大小。

9)系统服务。

提供信号量,互斥型信号量,事件标志,消息邮箱,消息队列,块大小固定的内存申请与释放,时间管理函数等服务。

10)中断管理。

中断嵌套层数最多可达到255层。

11)稳定性和可靠性。

OSInit()函数用来初始化内核,必须首先调用。

建立两个任务:空闲任务(其他任务都未就绪时运行),统计任务(计算CPU的利用率).****************************************************************** Description: This function is used to initialize the internals of uC/OS-II and MUST be called prior to creating any uC/OS-II object and, prior to calling OSStart().*****************************************************************void OSInit (void){OSInitHookBegin();/* 调用用户特定的初始化代码(通过一个接口函数实现用户要求的插件式进入系统中)*/OS_InitMisc();/* 初始化变量*/OS_InitRdyList();/* 初始化就绪列表*/OS_InitTCBList();/* 初始化OS_TCB空闲列表*/OS_InitEventList();/* 初始化OS_EVENT空闲列表*/#if(OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)//允许事件标志OS_FlagInit();/* 初始化事件标志结构*/#endif#if(OS_MEM_EN > 0) && (OS_MAX_MEM_PART > 0)//允许内存管理OS_MemInit();/* 初始化内存管理器*/#endif#if(OS_Q_EN > 0) && (OS_MAX_QS > 0)//允许消息队列OS_QInit();/* 初始化消息队列结构*/#endifOS_InitTaskIdle();/*创建空闲任务*/#if OS_TASK_STAT_EN > 0OS_InitTaskStat();/* 创建统计任务*/#endif#if OS_TMR_EN > 0//允许时间管理OSTmr_Init();/* 初始化时间管理器*/#endifOSInitHookEnd();/*调用用户特定的初始化代码(参考OSInitHookBegin())*/#if OS_DEBUG_EN > 0//允许DebugOSDebugInit();//初始化调试器#endif}******************************************************************************************** * Description: This function is called by OSInit() to initialize miscellaneous variables.********************************************************************************************static void OS_InitMisc (void){#if OS_TIME_GET_SET_EN > 0OSTime = 0L; /* 32位的系统时钟清零*/#endifOSIntNesting = 0; /* 中断嵌套层数计数器清零*/OSLockNesting = 0; /* 调度器锁的嵌套层数计数器清零*/ OSTaskCtr = 0; /* 任务数清零*/OSRunning = OS_FALSE; /*指明多任务未开始*/OSCtxSwCtr = 0; /* 任务切换次数计数器清零*/OSIdleCtr = 0L; /*32位空闲计数器清零*/#if OS_TASK_STAT_EN > 0 /*运行统计任务*/OSIdleCtrRun = 0L;OSIdleCtrMax = 0L;OSStatRdy = OS_FALSE; /* 统计任务未就绪*/#endif}空闲任务和统计任务建立的代码基本一样,只是统计任务的优先级比空闲任务大1,******************************************************************************************** * Description: This function creates the Idle Task.********************************************************************************************static void OS_InitTaskIdle (void){#if OS_TASK_NAME_SIZE > 7 //INT8U err;#endif#if OS_TASK_CREATE_EXT_EN > 0 //使用扩展的OSTaskCreateExt来创建#if OS_STK_GROWTH == 1 //任务堆栈从底部向顶部增长的方向有两种:表示从大到小,表示从小到大(void)OSTaskCreateExt(OS_TaskIdle,(void *)0, /* 没有参数传给OS_TaskIdle() */&OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE - 1], /*设置堆栈顶*/OS_TASK_IDLE_PRIO, /* 优先级设置为最低*/OS_TASK_IDLE_ID, //设置ID&OSTaskIdleStk[0], /* 设置栈底*/OS_TASK_IDLE_STK_SIZE, //设置栈大小(void *)0, /* 没有TCB扩展数据结构OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);/* 允许堆栈检测和清空堆栈*/#else(void)OSTaskCreateExt(OS_TaskIdle,(void *)0, /* No arguments passed to OS_TaskIdle() */&OSTaskIdleStk[0], /* Set Top-Of-StackOS_TASK_IDLE_PRIO, /* Lowest priority levelOS_TASK_IDLE_ID,&OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE - 1], /* Set Bottom-Of-Stack */OS_TASK_IDLE_STK_SIZE,(void *)0, /* No TCB extensionOS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);/* Enable stack check ing + clear stack */#endif#else//使用不带扩展性的OSTaskCreate创建#if OS_STK_GROWTH == 1(void)OSTaskCreate(OS_TaskIdle,(void *)0,&OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE - 1],OS_TASK_IDLE_PRIO);#else(void)OSTaskCreate(OS_TaskIdle,(void *)0,&OSTaskIdleStk[0],OS_TASK_IDLE_PRIO);#endif#endif//设置任务名称#if OS_TASK_NAME_SIZE > 14OSTaskNameSet(OS_TASK_IDLE_PRIO, (INT8U *)"uC/OS-II Idle", &err); #else#if OS_TASK_NAME_SIZE > 7OSTaskNameSet(OS_TASK_IDLE_PRIO, (INT8U *)"OS-Idle", &err);#endif#endif}uC/OS-II源码分析(二)在真正开始分析源代码前,先来看使用uC/OS-II的三个例子1)使用信号量#define TASK_STK_SIZE 512 /* 每个任务堆栈的大小(以字计算)*/ #define N_TASKS 10 /* 任务数*/OS_STK TaskStk[N_TASKS][TASK_STK_SIZE]; /*任务堆栈*/OS_STK TaskStartStk[TASK_STK_SIZE]; //开始任务的堆栈char TaskData[N_TASKS]; /*传给每个任务的数据*/OS_EVENT *RandomSem; //互斥型信号量void main (void){PC_DispClrScr(DISP_FGND_WHITE + DISP_BGND_BLACK); /*清空屏幕*/OSInit(); /* 初始化uC/OS-II*/PC_DOSSaveReturn(); /* 保存环境以便稍后可以返回DOS 环境*/PC_VectSet(uCOS, OSCtxSw); /*设置uC/OS-II的切换处理函数*/RandomSem = OSSemCreate(1); /* 建立一个信号量*/OSTaskCreate(TaskStart, (void *)0, &TaskStartStk[TASK_STK_SIZE - 1], 0);//创建第一个任务,优先级设置为最大值OSStart(); /* 开始多任务*/}void TaskStart (void *pdata){#if OS_CRITICAL_METHOD == 3 /* 为CPU的状态寄存器分配内存*/OS_CPU_SR cpu_sr;#endifchar s[100];INT16S key;pdata = pdata; /* 这步是为了防止编译错误*/TaskStartDispInit(); /* 初始化显示屏*/OS_ENTER_CRITICAL();PC_VectSet(0x08, OSTickISR); /*替换机器的时钟中断函数为uC/OS-II所需要的中断函数*/PC_SetTickRate(OS_TICKS_PER_SEC); /* 调整时钟频率*/OS_EXIT_CRITICAL();OSStatInit(); /* 初始化统计任务*/TaskStartCreateTasks(); /*创建其他任务*/ for (;;) {TaskStartDisp();if (PC_GetKey(&key) == TRUE) { /* 是否按键*/if (key == 0x1B) { /* ESCAPE按下了*/PC_DOSReturn(); /* 返回DOS*/}}OSCtxSwCtr = 0; /* 切换次数计数器清零*/OSTimeDlyHMSM(0, 0, 1, 0); /*挂起秒,让给其他任务运行*/ }}static void TaskStartCreateTasks (void){INT8U i;for (i = 0; i < N_TASKS; i++) { /* 创建N_TASKS个任务*/TaskData[i] = '0' + i; /* 每个任务显示其数据*/OSTaskCreate(Task, (void *)&TaskData[i], &TaskStk[i][TASK_STK_SIZE - 1 ], i + 1);}}void Task (void *pdata){INT8U x;INT8U y;INT8U err;for (;;) {OSSemPend(RandomSem, 0, &err); /* 获取信号量*/x = random(80); /* 计算X坐标*/y = random(16); /* 计算Y坐标*/OSSemPost(RandomSem); /* 释放信号量*//* Display the task number on the screen */PC_DispChar(x, y + 5, *(char *)pdata, DISP_FGND_BLACK + DISP_BGND_ LIGHT_GRAY);OSTimeDly(1); /* 挂起秒,让给其他任务运行*/}}2)使用消息邮箱#define TASK_STK_SIZE 512#define TASK_START_ID 0 /* 任务ID*/#define TASK_CLK_ID 1#define TASK_1_ID 2#define TASK_2_ID 3#define TASK_3_ID 4#define TASK_4_ID 5#define TASK_5_ID 6#define TASK_START_PRIO 10 /* 任务优先级*/#define TASK_CLK_PRIO 11#define TASK_1_PRIO 12#define TASK_2_PRIO 13#define TASK_3_PRIO 14#define TASK_4_PRIO 15#define TASK_5_PRIO 16OS_STK TaskStartStk[TASK_STK_SIZE];OS_STK TaskClkStk[TASK_STK_SIZE];OS_STK Task1Stk[TASK_STK_SIZE];OS_STK Task2Stk[TASK_STK_SIZE];OS_STK Task3Stk[TASK_STK_SIZE];OS_STK Task4Stk[TASK_STK_SIZE];OS_STK Task5Stk[TASK_STK_SIZE];OS_EVENT *AckMbox; /* 任务和使用的消息邮箱*/ OS_EVENT *TxMbox;void main (void){OS_STK *ptos;OS_STK *pbos;INT32U size;PC_DispClrScr(DISP_FGND_WHITE);OSInit();PC_DOSSaveReturn();PC_VectSet(uCOS, OSCtxSw);PC_ElapsedInit();ptos = &TaskStartStk[TASK_STK_SIZE - 1]; pbos = &TaskStartStk[0];size = TASK_STK_SIZE;OSTaskStkInit_FPE_x86(&ptos, &pbos, &size); OSTaskCreateExt(TaskStart,(void *)0,ptos,TASK_START_PRIO,TASK_START_ID,pbos,size,(void *)0,OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); OSStart();}void TaskStart (void *pdata){#if OS_CRITICAL_METHOD == 3OS_CPU_SR cpu_sr;#endifINT16S key;pdata = pdata;TaskStartDispInit();OS_ENTER_CRITICAL();PC_VectSet(0x08, OSTickISR);PC_SetTickRate(OS_TICKS_PER_SEC);OS_EXIT_CRITICAL();OSStatInit();AckMbox = OSMboxCreate((void *)0); /* 创建两个消息邮箱*/ TxMbox = OSMboxCreate((void *)0);TaskStartCreateTasks();for (;;) {TaskStartDisp();if (PC_GetKey(&key)) {if (key == 0x1B) {PC_DOSReturn();}}OSCtxSwCtr = 0;OSTimeDly(OS_TICKS_PER_SEC);}}void Task1 (void *pdata){INT8U err;OS_STK_DATA data; /* 任务堆栈数据*/INT16U time;INT8U i;char s[80];pdata = pdata;for (;;) {for (i = 0; i < 7; i++) {PC_ElapsedStart();err = OSTaskStkChk(TASK_START_PRIO + i, &data);//执行堆栈检查time = PC_ElapsedStop();if (err == OS_NO_ERR) {sprintf(s, "%4ld %4ld %4ld %6d",data.OSFree + data.OSUsed,data.OSFree,data.OSUsed,time);PC_DispStr(19, 12 + i, s, DISP_FGND_BLACK + DISP_BGND_LIGHT_G RAY);}}OSTimeDlyHMSM(0, 0, 0, 100); /* 挂起mS*/}}void Task4 (void *data){char txmsg;INT8U err;data = data;txmsg = 'A';for (;;) {OSMboxPost(TxMbox, (void *)&txmsg); /* 发消息给Task #5*/OSMboxPend(AckMbox, 0, &err); /* 等待Task #5的应答消息*/txmsg++; /*下一个要发的消息数据*/if (txmsg == 'Z') {txmsg = 'A'; /* 循环发送A-Z*/}}}void Task5 (void *data){char *rxmsg;INT8U err;data = data;for (;;) {rxmsg = (char *)OSMboxPend(TxMbox, 0, &err); /* 等待来自Task #4的数据*/PC_DispChar(70, 18, *rxmsg, DISP_FGND_YELLOW + DISP_BGND_BLUE); OSTimeDlyHMSM(0, 0, 1, 0); /* 挂起秒,让给其他任务运行*/OSMboxPost(AckMbox, (void *)1); /*发送接收到数据的应答消息*/}}运行结果:3)使用消息队列#define TASK_STK_SIZE 512#define TASK_START_ID 0#define TASK_CLK_ID 1#define TASK_1_ID 2#define TASK_2_ID 3#define TASK_3_ID 4#define TASK_4_ID 5#define TASK_5_ID 6#define TASK_START_PRIO 10#define TASK_CLK_PRIO 11#define TASK_1_PRIO 12#define TASK_2_PRIO 13#define TASK_3_PRIO 14#define TASK_4_PRIO 15#define TASK_5_PRIO 16#define MSG_QUEUE_SIZE 20 /* 消息队列大小*/ typedef struct {char TaskName[30];INT16U TaskCtr;INT16U TaskExecTime;INT32U TaskTotExecTime;} TASK_USER_DATA;OS_STK TaskStartStk[TASK_STK_SIZE];OS_STK TaskClkStk[TASK_STK_SIZE];OS_STK Task1Stk[TASK_STK_SIZE];OS_STK Task2Stk[TASK_STK_SIZE];OS_STK Task3Stk[TASK_STK_SIZE];OS_STK Task4Stk[TASK_STK_SIZE];OS_STK Task5Stk[TASK_STK_SIZE];TASK_USER_DATA TaskUserData[7];OS_EVENT *MsgQueue; /*消息队列指针*/ void *MsgQueueTbl[20]; /*消息存储*/void main (void){PC_DispClrScr(DISP_BGND_BLACK);OSInit();PC_DOSSaveReturn();PC_VectSet(uCOS, OSCtxSw);PC_ElapsedInit();strcpy(TaskUserData[TASK_START_ID].TaskName, "StartTask"); OSTaskCreateExt(TaskStart,(void *)0,&TaskStartStk[TASK_STK_SIZE - 1],TASK_START_PRIO,TASK_START_ID,&TaskStartStk[0],TASK_STK_SIZE,&TaskUserData[TASK_START_ID],0);OSStart();}void TaskStart (void *pdata){#if OS_CRITICAL_METHOD == 3OS_CPU_SR cpu_sr;#endifINT16S key;pdata = pdata;TaskStartDispInit();OS_ENTER_CRITICAL();PC_VectSet(0x08, OSTickISR);PC_SetTickRate(OS_TICKS_PER_SEC);OS_EXIT_CRITICAL();OSStatInit();MsgQueue = OSQCreate(&MsgQueueTbl[0], MSG_QUEUE_SIZE); /*创建消息队列,大小为*/TaskStartCreateTasks();for (;;) {TaskStartDisp();if (PC_GetKey(&key)) {if (key == 0x1B) {PC_DOSReturn();}}OSCtxSwCtr = 0;OSTimeDly(OS_TICKS_PER_SEC);}}void Task1 (void *pdata){char *msg;INT8U err;pdata = pdata;for (;;) {msg = (char *)OSQPend(MsgQueue, 0, &err);//从消息队列中取消息PC_DispStr(70, 13, msg, DISP_FGND_YELLOW + DISP_BGND_BLUE);OSTimeDlyHMSM(0, 0, 0, 100);}}void Task2 (void *pdata)char msg[20];pdata = pdata;strcpy(&msg[0], "Task 2");for (;;) {OSQPost(MsgQueue, (void *)&msg[0]);//发送消息到队列中 OSTimeDlyHMSM(0, 0, 0, 500);}}void Task3 (void *pdata){char msg[20];pdata = pdata;strcpy(&msg[0], "Task 3");for (;;) {OSQPost(MsgQueue, (void *)&msg[0]);//发送消息到队列中 OSTimeDlyHMSM(0, 0, 0, 500);}}void Task4 (void *pdata){char msg[20];pdata = pdata;strcpy(&msg[0], "Task 4");for (;;) {OSQPost(MsgQueue, (void *)&msg[0]);//发送消息到队列中 OSTimeDlyHMSM(0, 0, 0, 500);}}void OSTaskStatHook (void)char s[80];INT8U i;INT32U total;INT8U pct;total = 0L; /* Totalize TOT. EXEC. TIME for each t askfor (i = 0; i < 7; i++) {total += TaskUserData[i].TaskTotExecTime;DispTaskStat(i); /* Display task data }if (total > 0) {for (i = 0; i < 7; i++) { /* Derive percentage of each task */pct = 100 * TaskUserData[i].TaskTotExecTime / total;sprintf(s, "%3d %%", pct);PC_DispStr(62, i + 11, s, DISP_FGND_BLACK + DISP_BGND_LIGHT_GRA Y);}}if (total > 1000000000L) { /* Reset total time counters at 1 billionfor (i = 0; i < 7; i++) {TaskUserData[i].TaskTotExecTime = 0L;}}}void OSTaskSwHook (void){INT16U time;TASK_USER_DATA *puser;time = PC_ElapsedStop(); /* This task is donePC_ElapsedStart(); /* Start for next task puser = OSTCBCur->OSTCBExtPtr; /* Point to used dataif (puser != (TASK_USER_DATA *)0) {puser->TaskCtr++; /* Increment task counter puser->TaskExecTime = time; /* Update the task's execution timepuser->TaskTotExecTime += time; /* Update the task's total executi on time}}运行结果:uC/OS-II源码分析(三)首先来了解下实时系统的基本概念:1)临界区,共享资源,任务(类似于进程),任务切换,任务调度,可剥夺型内核,可重入函数,动态优先级调度,2)如何处理优先级反转问题。

uCOS-II嵌入式操作系统介绍与移植

uCOS-II嵌入式操作系统介绍与移植

OSStartHighRd
1、该函数是在OSStart函数中调用 2、负责从最高优先级任务的TCB中获得该任务的堆
栈指针sp,并依次将cpu现场恢复,这时系统就将 控制权交给用户创建的该任务进程,直到该任务被 阻塞或者被其他更高优先级的任务抢占cpu 3、该函数仅在多任务启动时被执行一次,用来启 动之前创建的第一个,也就是最高优先级的任务执 行
3、可从网站上获 得全部源码及其在各种体系结构平 台上的移植范例。
uC/OS-II特点
1、uC/OS-II内核具有可抢占的实时 多任务调度功能
2、提供了许多系统服务,如信号量、 消息队列、邮箱、内存管理、时间 函数等
3、这些功能可以根据不同的需求进 行裁减。
uC/OS-II的移植
ARM处理器相关宏定义
1、退出临界区
#defineOS_ENTER_CRITICAL() ARMDisableInt()
2、进入临界区
#defineOS_EXIT_CRITICAL() ARMEnableInt()
堆栈增长方向
1、堆栈由高地址向低地址增长,这个也 是和编译器有关的,当进行函数调用时, 入口参数和返回地址一般都会保存在当 前任务的堆栈中,编译器的编译选项和 由此生成的堆栈指令就会决定堆栈的增 长方向。
#define OS_STK_GROWTH 1
OS_CPU.c的移植
1、任务堆栈初始化 2、系统hook函数 3、中断级任务切换函数
任务堆栈初始化OSTaskStkInit
1、由OSTaskCreate或OSTaskCreateExt调用 2、用来初始化任务的堆栈并返回新的堆栈指针stk。
退出/进入临界区函数 ARMDisableInt/ARMEnableInt

嵌入式实时操作系统ucosII

嵌入式实时操作系统ucosII

嵌入式实时操作系统ucosIIucosII是一款源代码公开、可免费使用的嵌入式实时操作系统。

它是由德国嵌入式系统专家brosse于1992年编写完成的,主要适用于嵌入式系统的开发。

ucosII具有源代码短小精悍、可移植性好、稳定性高等优点,被广泛应用于各种嵌入式系统中。

源代码短小精悍:ucosII的源代码只有几百KB,相对于其他RTOS来说,其代码量较小,易于理解和修改。

可移植性好:ucosII采用了可移植性的设计方法,可以在不同的处理器和编译器上进行移植和优化。

稳定性高:ucosII在各种嵌入式系统中得到了广泛应用,其稳定性和可靠性得到了充分的验证。

支持多任务:ucosII支持多任务处理,可以同时运行多个任务,提高系统的效率和响应速度。

实时性:ucosII具有较高的实时性,可以满足各种实时性要求高的应用场景。

可扩展性:ucosII具有较好的可扩展性,可以根据需要进行功能扩展和优化。

系统内核:包括任务调度、任务管理、时间管理、内存管理等核心功能。

中断处理程序:处理各种中断请求,包括硬件中断、软件中断等。

系统API:提供了一套完善的API函数,方便应用程序的开发和调试。

调试和测试工具:包括各种调试和测试工具,如内存检查工具、性能分析工具等。

ucosII被广泛应用于各种嵌入式系统中,如工业控制、智能家居、智能交通、航空航天等。

其应用场景涵盖了消费类电子产品、医疗设备、通信设备、汽车电子等领域。

ucosII作为一款源代码公开、可免费使用的嵌入式实时操作系统,具有短小精悍、可移植性好、稳定性高等优点。

它广泛应用于各种嵌入式系统中,为应用程序的开发提供了便利和支持。

其可扩展性和实时性也使得它在各种领域中具有广泛的应用前景。

随着嵌入式系统的广泛应用,对嵌入式操作系统的需求也日益增长。

uCOSII是一种流行的实时嵌入式操作系统,具有轻量级、实时性、可扩展性等优点。

本文将介绍如何在AT91平台上实现uCOSII的移植。

uCOS-II简介

uCOS-II简介

4.1OC/OS-II简介UC/OS-II 是一种基于优先级的可抢先的硬实时内核。

自从92 年发布以来,在世界各地都获得了广泛的应用,它是一种专门为嵌入式设备设计的内核,目前已经被移植到40 多种不同结构的CPU 上,运行在从8 位到64 位的各种系统之上。

尤其值得一提的是,该系统自从2.51版本之后,就通过了美国FAA 认证,可以运行在诸如航天器等对安全要求极为苛刻的系统之上。

鉴于UC/OS-II 可以免费获得代码,对于嵌入式RTOS 而言,选择UC/OS 无疑是最经济的选择。

需要说明的是,UC/OS-II 作为一个实时操作系统只提供了多任务调度等基本功能,这在实际应用中显然是不够的。

除了移植好的操作系统内核部分,还必须有文件系统,全部硬件的驱动程序,图形API,控件函数,综合提高的消息函数以及几个系统必须的基本任务,象键盘,触摸屏,LCD 刷新等。

有了这些,UC/OS-II 才能实现复杂的功能。

特殊需求的地方还需要像USB通信协议,TCP/IP 协议等更复杂的软件模块。

博创提供的UC/OS-II 库文件中包含了上述大部分功能,基于库的开发变的非常简单,在基本的程序框架下应用我们提供的丰富API 函数即可。

实际开发中,用户的工程中无需包括UC/OS-II 的源代码,只需要包括库文件即可。

当然,用户也可以了解库中部分代码的源文件,可以根据自己的需求就行重新编译,也可以对自己的一系列源文件生成一个专门的库,方便自己后续工作。

UC/OS-II 的开发中,应用程序和操作系统是绑在一起编译的,所生成的system.bin 文件是唯一的可执行文件,其中包括了所需要的UC/OS-II 代码和被用到的驱动程序等函数代码,以及应用程序的代码。

system.bin 文件是存放在平台的16M FLASH 中的,在系统启动时由BIOS依靠文件系统从FLASH 中读入到SDRAM 中,然后把控制转移到该代码上,完成所谓的引导。

ucos-ii工作原理

ucos-ii工作原理

ucos-ii工作原理uC/OS-II(Micro C/Operating System-II)是一种用于嵌入式系统的实时操作系统。

它的工作原理可以简单归纳为以下几个步骤:1. 任务管理:uC/OS-II使用优先级调度算法管理多个任务。

每个任务都有一个优先级,高优先级的任务会优先执行。

uC/OS-II通过一个任务控制块(TCB)来管理每个任务的信息,包括任务的状态、堆栈信息、优先级等。

2. 中断处理:uC/OS-II可以处理多种类型的中断。

当发生中断时,uC/OS-II会根据中断类型进行相应的处理,并且可以自动切换到中断服务程序(ISR)进行执行。

中断服务程序中的代码通常是短小且高效的,用于处理特定的中断事件。

3. 任务切换:uC/OS-II使用抢占式的任务调度方式,因此任务切换可以发生在任何时刻。

当一个任务的时间片用尽或者有更高优先级的任务需要执行时,uC/OS-II会保存当前任务的上下文信息,并切换到下一个任务的执行。

任务切换时,uC/OS-II会保存当前任务的栈指针等信息,并从下一个任务的栈指针中恢复相应的上下文,以使下一个任务继续执行。

4. 事件同步:uC/OS-II提供了多种事件同步机制,如信号量、事件标志、消息邮箱等,用于任务之间的同步和通信。

这些机制可以帮助任务之间按照一定的顺序进行执行,实现数据共享和互斥访问等功能。

5. 内存管理:uC/OS-II提供了内存管理功能,可以动态分配和释放内存块。

这种内存管理机制可以帮助节省内存空间,提高系统的效率。

总而言之,uC/OS-II通过任务管理、中断处理、任务切换、事件同步和内存管理等机制,实现了对嵌入式系统的实时调度和资源管理,以提供稳定、可靠的操作系统支持。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

内核概述: 一. 内核概述: 多任务系统中, 内核负责管理各个任务, 或者说为每个任务分配 CPU 时间, 并且负责任务之间的通讯。

内核提供的基本服务是任务切换。

之所以使用实时内核可以大大简化应用系统的设计,是因为实时内核允 许将应用分成若干个任务,由实时内核来管理它们。

内核本身也增加了应用程序的额外负荷,代码空间增 加 ROM 的用量,内核本身的数据结构增加了 RAM 的用量。

但更主要的是,每个任务要有自己的栈空间, 这一块吃起内存来是相当厉害的。

内核本身对 CPU 的占用时间一般在 2 到 5 个百分点之间。

uCOS II 有一 个精巧的内核调度算法,实时内核精小,执行效率高,算法巧妙,代码空间很少。

内核调度特点: 二. uCOS II 内核调度特点: 1. 只支持基于优先级的抢占式调度算法,不支持时间片轮训; 2. 64 个优先级,只能创建 64 个任务,用户只能创建 56 个任务; 3. 每个任务优先级都不相同。

4. 不支持优先级逆转; 5. READY 队列通过内存映射表实现快速查询。

效率非常高; 6. 支持时钟节拍; 7. 支持信号量,消息队列,事件控制块,事件标志组,消息邮箱任务通讯机制; 8. 支持中断嵌套,中断嵌套层数可达 255 层,中断使用当前任务的堆栈保存上下文; 9. 每个任务有自己的堆栈,堆栈大小用户自己设定; 10. 支持动态修改任务优先级; 11. 任务 TCB 为静态数组,建立任务只是从中获得一个 TCB,不用动态分配,释放内存; 12. 任务堆栈为用户静态或者动态创建,在任务创建外完成,任务创建本身不进行动态内存分配; 13. 任务的总个数(OS_MAX_TASKS)由用户决定; 14. 0 优先级最高,63 优先级最低; 15. 有一个优先级最低的空闲任务,在没有用户任务运行的时候运行.描述: 三. 任务控制块 OS_TCB 描述 uCOS II 的 TCB 数据结构简单,内容容易理解,保存最基本的任务信息,同时还支持裁减来减小内存消 耗, TCB 是事先根据用户配置, 静态分配内存的结构数组, 通过优先级序号进行添加, 查找, 删除等功能。

减少动态内存分配和释放。

因为依靠优先级进行 TCB 分配,每个任务必须有自己的优先级,不能和其他任 务具有相同的优先级。

typedef struct os_tcb { OS_STK *OSTCBStkPtr;#if OS_TASK_CREATE_EXT_EN void OS_STK INT32U *OSTCBExtPtr; *OSTCBStkBottom; OSTCBStkSize;INT16U INT16U #endifOSTCBOpt; OSTCBId;struct os_tcb *OSTCBNext; struct os_tcb *OSTCBPrev; #if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN || OS_SEM_EN OS_EVENT #endif #if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN void #endif INT16U INT8U INT8U INT8U INT8U INT8U INT8U OSTCBDly; OSTCBStat; OSTCBPrio; OSTCBX; OSTCBY; OSTCBBitX; OSTCBBitY; *OSTCBMsg; *OSTCBEventPtr;#if OS_TASK_DEL_EN BOOLEAN #endif } OS_TCB; .OSTCBStkPtr 是指向当前任务栈顶的指针。

.*OSTCBExtPtr;:任务扩展模块使用; .*OSTCBStkBottom; .OSTCBStkSize; . .OSTCBOpt; .OSTCBId; .OSTCBNext 和.OSTCBPrev 用于任务控制块 OS_TCBs 的双重链接, .OSTCBEventPtr 是指向事件控制块的指针 .OSTCBMsg 是指向传给任务的消息的指针。

.OSTCBDly 当需要把任务延时若干时钟节拍时要用到这个变量, 或者需要把任务挂起一段时间以等待某事 件的发生, .OSTCBStat 是任务的状态字。

.OSTCBPrio 是任务优先级。

.OSTCBX, .OSTCBY, .OSTCBBitX 和 .OSTCBBitY 用于加速任务进入就绪态的过程或进入等待事件发生 状态的过程 OSTCBDelReq;OSTCBY = priority >> 3; OSTCBBitY = OSMapTbl[priority >> 3]; OSTCBX = priority & 0x07; OSTCBBitX = OSMapTbl[priority & 0x07]; .OSTCBDelReq 是一个布尔量,用于表示该任务是否需要删除就绪表( 四. 就绪表(Ready List): ): uCOS II 采用内存映射的方式来实现 READY 队列的加入,查找,删除功能,效率非常高。

但是也因此 只能支持 64 个任务,每个任务都有自己的优先级,不能和其他任务优先级相同。

每个任务的就绪态标志都放入就绪表中的,就绪表中有两个变量 OSRdyGrp 和 OSRdyTbl[]。

在 OSRdyGrp 中,任务按优先级分组,8 个任务为一组。

OSRdyGrp 中的每一位表示 8 组任务中每一组中是 否有进入就绪态的任务。

任务进入就绪态时,就绪表 OSRdyTbl[]中的相应元素的相应位也置位。

就绪表 OSRdyTbl[]数组的大小取决于 OS_LOWEST_PRIO(见文件 OS_CFG.H)。

为确定下次该哪个优先级的任务运行了,内核调度器总是将 OS_LOWEST_PRIO 在就绪表中相应字节 的相应位置 1。

OSRdyGrp 和 OSRdyTbl[]的关系见图 3.3,是按以下规则给出的: 当 OSRdyTbl[0]中的任何一位是 1 时,OSRdyGrp 的第 0 位置 1, 当 OSRdyTbl[1]中的任何一位是 1 时,OSRdyGrp 的第 1 位置 1, 当 OSRdyTbl[2]中的任何一位是 1 时,OSRdyGrp 的第 2 位置 1, 当 OSRdyTbl[3]中的任何一位是 1 时,OSRdyGrp 的第 3 位置 1, 当 OSRdyTbl[4]中的任何一位是 1 时,OSRdyGrp 的第 4 位置 1, 当 OSRdyTbl[5]中的任何一位是 1 时,OSRdyGrp 的第 5 位置 1,当 OSRdyTbl[6]中的任何一位是 1 时,OSRdyGrp 的第 6 位置 1, 当 OSRdyTbl[7]中的任何一位是 1 时,OSRdyGrp 的第 7 位置 1,程序清单 3.5 中的代码用于将任务放入就绪表。

Prio 是任务的优先级。

程序清单 L3.5 使任务进入就绪态 (这两行代码简直是神来之笔啊!!!)/* 这行代码功能是找到列, 把列上的值置为 1 不妨假设 prio 的值为 13, 即优先级为 13. prio>>3 右移 3 位后值为 1, 可以查表 T3.1 找出 OSMapTbl[1] 的值为 0000 0010. 再用 0000 0010 和 OSRdyGrp 进行异或运算 */ OSRdyGrp |= OSMapTbl[prio >> 3]; /**/ OSRdyTbl[prio >> 3] |= OSMapTbl[prio & 0x07];任务优先级的低三位用于确定任务在总就绪表 OSRdyTbl[]中的所在位。

接下去的三位用于确定是在 OSRdyTbl[]数组的第几个元素。

OSMapTbl[]是在 ROM 中的(见文件 OS_CORE.C)屏蔽字,用于限制 OSRdyTbl[]数组的元素下标在 0 到 7 之间,见表 3.1 Index 0 1 2 3 4 5 6 7 Bit Mask (Binary) 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000如果一个任务被删除了,则用程序清单 3.6 中的代码做求反处理。

程序清单 L3.6 从就绪表中删除一个任务if ((OSRdyTbl[prio >> 3] &= ~OSMapTbl[prio & 0x07]) == 0) OSRdyGrp &= ~OSMapTbl[prio >> 3];以上代码将就绪任务表数组 OSRdyTbl[]中相应元素的相应位清零, 而对于 OSRdyGrp, 只有当被删除任务 所在任务组中全组任务一个都没有进入就绪态时,才将相应位清零。

也就是说 OSRdyTbl[prio>>3]所有的 位都是零时,OSRdyGrp 的相应位才清零。

为了找到那个进入就绪态的优先级最高的任务,并不需要从 OSRdyTbl[0]开始扫描整个就绪任务表,只需要查另外一张表,即优先级判定表 OSUnMapTbl ([256])(见文 件 OS_CORE.C)。

OSRdyTbl[]中每个字节的 8 位代表这一组的 8 个任务哪些进入就绪态了,低位的优先 级高于高位。

利用这个字节为下标来查 OSUnMapTbl 这张表,返回的字节就是该组任务中就绪态任务中优 先级最高的那个任务所在的位置。

这个返回值在 0 到 7 之间。

确定进入就绪态的优先级最高的任务是用以 下代码完成的。

找出进入就绪态的优先级最高的任务y x= OSUnMapTbl[OSRdyGrp]; = OSUnMapTbl[OSRdyTbl[y]];prio = (y << 3) + x;例如,如果 OSRdyGrp 的值为二进制 01101000,查 OSUnMapTbl[OSRdyGrp]得到的值是 3,它相应 于 OSRdyGrp 中的第 3 位 bit3,这里假设最右边的一位是第 0 位 bit0。

类似地,如果 OSRdyTbl[3]的值是 二进制 11100100,则 OSUnMapTbl [OSRdyTbc[3]]的值是 2, 即第 2 位。

于是任务的优先级 Prio 就等于 26 (3*8+2)。

利用这个优先级的值。

查任务控制块优先级表 OSTCBPrioTbl[],得到指向相应任务的任务控 制块 OS_TCB 的工作就完成了。

相关文档
最新文档