基于STM32单片机的uC/OS-II操作系统移植

2020-12-30 04:26张中前
机电元件 2020年6期
关键词:堆栈示意图中断

张中前

(贵州航天电器股份有限公司,贵州贵阳,550009)

1 引言

操作系统是裸机的第一层软件,操作系统直接运行在硬件上,上层软件通过提供应用程序接口(API函数),实现对底层硬件的访问,同时,通过操作系统实现对多个上层应用软件(任务)管理,实现对硬件CPU管理、存储管理、I/O接口管理及文件管理,如图1所示。

图1 操作系统功能组成示意图

STM32系列单片机以其优良的价格,大容量的FLASH及RAM存储空间,极易用于较为复杂的控制系统;在STM32单片机上进行uC/OS-II实时操作系统的移植,提高了产品的设计灵活性,实现较为复杂的系统功能;通过将开源的uC/OS-II移植在STM32单片机上,以其较为低廉的硬件成本获得较高的使用性能,具有良好的应用前景。

2 uC/OS-II操作系统

2.1 uC/OS-II操作系统的基本特征

uC/OS-II是一个完整的、可移植、可固化、可剪裁的基于优先级调度的抢占式实时多任务操作系统;它能够在外界事件或数据产生时,能够接收并以足够快的速度响应,其处理的结果又能够在规定的时间内输出,并控制所有实时任务协调、一致运行。它包含了基本的任务调度、时间管理、内存管理以及任务之间的通信和同步等功能。

图2 uC/OS-II文件结构示意图

uC/OS-II从结构上分为:应用软件、与软件处理器无关的代码、配置文件、与处理器有关的移植文件及实际硬件,uC/OS-II的文件结构如图2所示。

2.2 uC/OS-II任务及相关管理机制

任务是uC/OS-II操作系统的基本执行单位,是操作系统中的一次执行过程,如产品设计中的程序是静止的,存储在ROM、硬盘等设备中;任务主要由任务控制块、任务堆栈、任务程序代码等组成,如图3所示。

图3 uC/OS-II任务组成示意图

任务是动态的,存在于产品的RAM或闪存中,其运行状态可分为睡眠、运行、等待、中断等多个状态;每个任务可多次重复执行。在产品设计时,将产品的应用程序设计过程分解,得到多个任务,并依据实际的运行过程,赋予每个任务优先级,操作系统通过任务调度,实现产品的功能。在uC/OS-II操作系统中,多个任务通过任务控制块组成任务链表, CPU通过uC/OS-II操作系对多任务链表任务进行调度,通过读取任务控制块中的优先级,使高优先级的任务处于就绪状态,就绪状态的任务得到执行。任务状态切换如图4所示。

图4 uC/OS-II任务状态切换示意图

2.3 uC/OS-II任务优先级管理

uC/OS-II每个时间段执行的任务只有一个。通过调度,使高优先级任务得到执行,故任务优先级是CPU执行任务时选择的依据。uC/OS-II对任务的执行方式是优先级抢占式,在创建任务时,每个任务被分配一个唯一的优先级。uC/OS-II可以创建多达64个任务,采用优先级0~63表示,0为最高优先级。

2.4 uC/OS-II中断管理

中断是嵌入式实时操作系统中的重要机制,当CPU正在运行任务时,若有中断事件发射管,则CPU暂停当前的任务,转向执行中断事件,CPU执行完中断事件后,进行一次任务调度计算,若有比中断更高优先级的任务,则CPU转向执行高优先级任务,否则,继续执行被中断执行的任务。

2.5 uC/OS-II时间管理

是操作系统实现并发运行的关键,为了使操作系统在一定的时间内执行多个任务,通过硬件定时器产生一个周期性的中断,作为操作系统处理的系统时钟,两个时钟之间的中断一般称为时钟节拍。操作系统中,任务通过调用时钟节拍函数OSTimeTick();从而进入定时中断,通过操作系统中断管理,实现对多任务的调度执行。

2.6 uC/OS-II任务间同步与通信

在uC/OS-II操作系统在执行多任务时,需要多个任务按照一定的时间顺序配合,完成产品的给定功能,为此,任务间需要进行时间的同步与信息的交换。uC/OS-II操作系统中,通过信号量、邮箱(消息邮箱)和消息队列这些被称作事件的中间环节来实现任务间的同步与通信,如图5所示。

为了把描述事件的数据结构统一起来,uC/OS-II使用事件控制块ECB数据结构来描述诸如信号量、邮箱(消息邮箱)和消息队列这些事件。事件控制块中包含包括等待任务表在内的所有有关事件的数据。

图5 任务通过事件通信示意图

2.7 uC/OS-II内存管理

uC/OS-II通过对内存建立分区、申请及释放内存块、查询存储分区状态信息等方式,实现对内存的管理,μC/OS-II对内存进行两级管理,即把一个大片连续的内存空间分成了若干个分区,每个分区又分成了若干个大小相等的内存块来进行管理。操作系统以分区为单位来管理动态内存,而任务以内存块为单位来获得和释放动态内存。内存分区使用一个二维数组实现,然后将数组与内存控制块关联,通过内存控制块组成链表,实现对内存的动态管理,如图6、图7所示。

图6 内存的分区管理示意图

图7 内存控制块链表示意图

3 uC/OS-II操作系统在STM32F103单片机上的移植

所谓移植,就是使一个实时操作系统能够在某个微处理器平台上或微控制器平台上运行。在2.1节中介绍了uC/OS-II的文件结构,从图2可见,移植uC/OS-II操作系统时,需要将与CPU有关的文件进行修改,以适应在STM32单片机上的使用。与CPU有关的三个文件分别为OS_CPU.H、OS_CPU_C.C、OS_CPU_A.ASM。

3.1 OS_CPU.H文件移植说明

OS_CPU.H文件主要定义了与CPU相关的数控类型,主要为CPU的类型不同,所对应的操作系统中的数据类型占用的存储空间也不一样。为了保证可移植性,程序中没有直接使用C语言中的short、int和long等数据类型的定义,因为它们与处理器类型有关,隐含着不可移植性。程序中自己定义了一套数据类型,如INT16U表示16位无符号整型。对于ARM这样的32位内核,INT16U是unsigned short型;如果是16位处理器,则是unsingedint型。根据STM32中数据类型及uC/OS-II所需数据类型,同时对STM32进入临界区及堆栈方向进行定义,对OS_CPU.H文件修改如下图8所示。

图8 OS_CPU.H文件修改

3.2 OS_CPU_C.C文件移植说明

OS_CPU_C.C文件中包含了OSTaskStkInit()、OSTaskDelHook()、OSTaskSwHook()、OSTaskStartHook()及OSTimeHook()共计6个函数。这些函数中,基于STM32单片机必须移植的是任务堆栈初始化函数OSTaskStkInit()。这个函数在任务创建时被调用,负责初始化任务的堆栈结构并返回新堆栈的指针stk。主要对任务中需要用到的PC指针以及各个寄存器进行处理,堆栈初始化工作结束后,返回新的堆栈栈顶指针。该函数移植修改如图9所示。

图9 OS_CPU.H文件修改示意

3.3 OS_CPU_A.ASM文件移植说明

OS_CPU_A.ASM文件采用汇编语言编制,在移植时,主要对与CPU有关的函数进行修改,这些函数为:高优先级任务就绪函数OSStartHighRdy()、任务切换函数OSCtxSw()、中断任务切换函数OSIntCtxSw()及时钟节拍中断服务函数OSTickISR()函数。

OSStartHighRdy()高优先级任务就绪函数是在OSStart()多任务启动之后,负责从最高优先级任务的TCB控制块中获得该任务的堆栈指针SP,并通过SP依次将CPU现场恢复。这时系统就将控制权交给用户创建的任务进程,直到该任务被阻塞或都被其他更高优先级的任务抢占CPU。该函数仅仅在多任务启动时被执行一次,用来启动最高优先级的任务执行。移植该函数的原因是,它涉及将处理器寄存器保存到堆栈的操作。

OS_TASK_SW()任务切换函数由OSSched()函数调用,OSSched()函数负责任务之间的调度。OSCtxSw()函数的工作是,先将当前任务的CPU现场保存到该任务的堆栈中,然后获得最高优先级任务的堆栈指针,并从该堆栈中恢复此任务的CPU现场,使之继续执行,该函数就完了一次任切换。

OSIntCtxSw()中断任务切换函数由OSIntExit()调用。由于中断可能会使更高优先级的任务进入就绪态,因此,为了让更高优先级的任务能立即运行,在中断服务子程序的最后,OSInitExit()函数会调用OSInitCtxSw()做任务切换。这样做的目的主要是能够尽快地让高优先级的任务得到响应,保证系统的实时性能。 OSInitCtxSw()与OSCtxSw()都是用于任务切换函数,其区别在于,在OSIntCtxSw()中无需再保存CPU寄存器,因为在调用OSIntCtxSw()之前已发生了中断,OSIntCtxSw()已将默认的CPU寄存器保存到被中断的任务堆栈中。

OSTickISR()时钟节拍中断服务函数,是特定的周期性中断,是由硬件定时器产生的。时钟节拍式中断使得内核可将任务延时若干个整数时钟节拍,以及当任务等待事件发生时,提供等待超时的依据。时钟节拍频率越高,系统的额外开销越大。中断间的时间间隔取决于不同的应用。OSTickISR()首先将CPU寄存器的值保存在被中断任务的堆栈中,之后调用OSIntEnter()。随后,OSTickISR()调用OSTimeTick,检查所有处于延时等待状态的任务,判断是否有延时结束就绪的任务。OSTickISR()最后调用OSIntExit()。如果在中断中(或其他嵌套的中断)有更高优先级的任务就绪,并且当前中断为中断嵌套的最后一层,那么OSIntExit()将进行任务调度。

4 uC/OS-II在STM32上的应用实例

为验证uC/OS-II操作系统移植的成功与否,在STM32开发板上对uC/OS-II移植进行验证,创建任务为:

任务1:LED0灯闪烁点亮;

任务2:按键扫描;

任务3:任务2按键扫描值通过信号量的形式,传递给任务3,按下一次按键,实现LED1灯的一次闪烁点亮;

任务4:触摸屏任务,借用开发板已有程序,采用邮箱形式进行任务间信号传递;

任务5:主任务,实现对触摸屏的显示,清除等功能。

创建任务如图10所示,任务执行结果如图11所示。

图10 任务创建示意图

图11 uC/OS-II系统移植后程序执行结果示图

5 结论

本文介绍了uC/OS-II实时操作系统的基本原理,针对uC/OS-II操作系统在STM32单片机上的移植进行了详细说明,并对移植实例进行了分析,取得了良好的效果。本文对小型系统级别电子控制组件提供了一种可行的解决方案,对电子控制组件产品的设计具有一定的参考及指导作用。

猜你喜欢
堆栈示意图中断
基于行为监测的嵌入式操作系统堆栈溢出测试*
先画示意图再解答问题
黔西南州旅游示意图
基于FPGA的中断控制器设计*
Linux中断线程化分析及中断延时测试
跟踪导练(二)(5)
千里移防,卫勤保障不中断
基于堆栈自编码降维的武器装备体系效能预测
两张图读懂“青年之声”
一种用于分析MCS-51目标码堆栈深度的方法