实时嵌入式操作系统在单片机的应用研究解析.docx
- 文档编号:25667784
- 上传时间:2023-06-11
- 格式:DOCX
- 页数:43
- 大小:416.11KB
实时嵌入式操作系统在单片机的应用研究解析.docx
《实时嵌入式操作系统在单片机的应用研究解析.docx》由会员分享,可在线阅读,更多相关《实时嵌入式操作系统在单片机的应用研究解析.docx(43页珍藏版)》请在冰豆网上搜索。
实时嵌入式操作系统在单片机的应用研究解析
湖南文理学院
课程设计报告
课程名称:
嵌入式系统课程设计
专业班级:
通信工程12101班学号(11)
学生姓名:
刘洁仪
指导教师:
侯清莲
完成时间:
2015年6月7日
报告成绩:
评阅意见:
评阅教师日期
湖南文理学院制
摘要
现如今科技大发展已经进入了快车道,当然单片机处理器的发展也是非常迅速的,甚至已经进入了多任务多线程的时代。
许多公司都退出自己的操作系统,包括大型的liunx、UCliunx、freeRTOS,RTOS以及UCOSII等等,由于UCOSII可裁剪、源码开放、结构小巧、抢先式的实时多任务内核,主要面向中小型嵌入式系统,具有执行效率高、占用空间小、可移植性强、实时性能优良和可扩张性强等特点,因而在51系列单片机这种内存较小的单片机中具有相当大的市场前景,本设计基于这样的时代背景,讨论研究关于UCOSII在51单片机上的单片机上移植为题,具体讲述了内核结构、移植步骤以及相关实例情况,通过对内核的分析说明需要修改的移植内容,同时为了在感官上体现多任务的实现情况,还设计了一个简单的显示系统,能够看到系统任务的执行情况,此外因为51单片机的片内内存较小还需要进行内存扩展,通过Protues对实验的仿真可以表明,本设计实验效果良好,达到成功移植UCOSII到51单片机上的目的。
关键字:
UCOSII51单片机内存扩展多任务
Abstract
Nowthegreatdevelopmentofscienceandtechnologyhasenteredthefastlane,ofcourse,thedevelopmentofsingle-chipprocessorisveryfast,andevenhasenteredtheeraofmulti-taskingmulti-threaded.Manycompaniesareoutofyouroperatingsystem,includinglargeliunx,UCliunx,freeRTOS,RTOSandUCOSIIetc.,sinceUCOSIIcanbecut,opensource,compact,preemptivereal-timemultitaskingkernel,mainlyforsmallandmediumsizedembeddedsystemswithhighefficiency,smallfootprint,portability,excellentreal-timeperformanceandstrongexpansioncharacteristics,whichhaveconsiderablemarketpotentialin51seriesthislow-memorymicrocontroller,thedesignisbasedonbackground,discussionsonresearchon51single-chipmicrocontrollerUCOSIItransplanttitle,specificallyaboutthecorestructure,transplantprocedures,andrelevantexamples,theanalysisbytheneedtomodifythekernelportingcontent,andinordertoreflectonthesensestheachievementofmulti-tasking,alsodesignedasimpledisplaysystem,toseetheimplementationofthesystemtasks,inadditionto51single-chipbecausewithinlessmemoryrequiredformemoryexpansion,throughsimulationexperimentsProtuescanshowthatthedesignexperimentstogoodeffect,tosuccessfullytransplantedto51SCMUCOSIIpurposes.
Keywords:
UCOSII51microcontrollermemoryexpansionmultitasking
第一章绪论
大多数的操作系统只注重平均性能,如对于整个系统来说,所有任务的平均响应时间是关键,而不关心单个任务的响应时间。
而嵌入式实时操作系统最主要的特征是性能上的实时性,从这个角度上看,可以把嵌入式实时操作系统定义为“当外界事件或数据产生时,能够接受并以足够快的速度予以处理,其处理的结果又能在规定的时间之内来控制生产过程或对处理系统作出快速响应,并控制所有实时任务协调一致运行的嵌入式操作系统”。
1.1嵌入式实时操作系统
目前大多数嵌入式操作系统提供以下管理功能:
1.任务管理
所有嵌入式操作系统都是多任务的,目前所说的多任务大都是指多线程方式或多进程方式,两者的运行机制不完全一样。
以多进程为例,调度程序的好坏直接影响到系统的性能。
和一般的操作系统一样,嵌入式操作系统的作用也是决定在特定的某一时刻系统应该运行哪一个进程,对嵌入式系统中的运行软件进行描述和管理,并完成处理机资源的分配与调度。
2.存储管理
在嵌入式系统中,一般不采用虚拟内存管理,而采用动态内存管理方式,即当程序的某一部分需要使用内存时,利用操作系统提供的分配函数来处理,一旦使用完,可通过释放函数来释放所占用的内存,这样内存就可以重复使用,这样提高了内存的利用率,方便了用户的使用,并提供了足够的存储空间。
3.周边资源管理
在操作系统中必须提供周边资源的驱动程序,以方便资源管理和应用程序使用。
4.中断管理
嵌入式操作系统和一般操作系统一样,一般都是用中断方式来处理外部事件和I/O请求。
中断管理负责中断的初始化安装、现场的保存和恢复、中断栈的嵌套管理等。
1.2μC/OS-Ⅱ嵌入式操作系统
μC/OS-Ⅱ是一个可裁剪、源码开放、结构小巧、抢先式的实时多任务内核,主要面向中小型嵌入式系统,具有执行效率高、占用空间小、可移植性强、实时性能优良和可扩张性强等特点。
μC/OS-Ⅱ结构小巧,即使包含全部功能如信号量、消息邮箱、消息队列以及相关函数等,编译后的μC/OS-Ⅱ内核也仅有6~10KB,所以它比较适用于小型控制系统,μC/OS-Ⅱ也具有良好的扩展性能。
1.3μC/OS-II原理
μC/OS-II包括任务调度、时间管理、内存管理、资源管理四大部分。
它的移植只与4个文件相关:
汇编文件(OS_CPU_A.ASM)、处理器相关C文件(OS_CPU.H、OS_CPU_C.C)和配置文件(OS_CFG.H)。
有64个优先级,系统占用8个,用户可创建56个任务,不支持时间片轮转。
它的基本思路就是“近似地每时每刻总是让优先级最高的就绪任务处于运行状态”。
为了保证这一点,它在调用系统API函数、中断结束、定时中断结束时总是执行调度算法。
任务的切换是通过模拟一次中断实现的。
μC/OS-II工作核心原理是:
近似地让最高优先级的就绪任务处于运行状态。
第二章μC/OS-Ⅱ内核结构
2.1临界区
一个任务在某些时候可能会访问共享内存、共享文件或其他共享资源,这些对共享内存进行访问的程序片断称作临界区。
为了防止不同的任务同时处于临界区,必须使用一定互斥的方法来避免这种情况的发生,因此μC/OS-Ⅱ在处理临界区代码时需要关中断,处理完毕后再开中断。
μC/OS-Ⅱ定义两个宏来开关中断,μC/OS-Ⅱ中的这两个宏调用分别是:
OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()。
2.2任务及任务控制块
在μC/OS-Ⅱ中,一个任务看起来像其它C的函数一样,有函数返回类型,有形式参数变量,但是任务是不会返回的,所以返回参数要定义成void类型,下面这个程序就是一个任务函数:
voidTask(void*pdata)
{
for(;;)
{
/*用户代码*/
/*调用μC/OS-Ⅱ的各种服务*/
/*用户代码*/
}
}
当任务完成以后,任务函数可以调用OSTaskDel()来实现自我删除。
任务想要再次进入内核可以调用OSTaskCreat()或者OSTaskCreatExt()。
任务函数的形式参数变量是由用户代码在第一次执行时带入的,将变量定义成void指针是为了允许用户应用程序传递任何类型的数据给任务。
用户也可以建立许多相同的任务,且所有都使用同一个任务函数,但可以向这个任务传入不同的数据,就可以达到不同的任务使用同一个任务函数的目的,大大节省了代码的存储空间.
μC/OS-Ⅱ可以管理多达64个任务,但作者保留了优先级为0、1、2、3、OS_LOWEST_PRIO-3、OS_LOWEST_PRI0-2,OS_LOWEST_PRI0-1以及OS_LOWEST_PRI-0这8个任务以被将来使用。
必须给每个任务赋以不同的优先级,优先级号越低,任务的优先级越高。
μC/OS-Ⅱ总是运行进入就绪态的优先级最高的任务。
任务控制块(OS_TCB)是一个数据结构,是用来描述任务的一些属性。
当一个任务建立时,任务控制块将被初始化。
当任务的CPU使用权被剥夺时,μC/OS-Ⅱ用任务控制块来保存改任务的状态,当任务重新得到CPU使用权时,任务控制块能确保任务从中断的那一点继续执行下去。
2.3任务状态
每个任务都处在以下5种状态里:
休眠态、就绪态、运行态、挂起态和被中断态。
在任何时刻,任务的状态一定是这5种状态之一。
休眠态指任务在程序空间之中,还没有交给μC/OS-Ⅱ管理,可以通过调用OSTaskCreate()或OSTaskCreateExt()函数来把任务交给μC/OS-Ⅱ。
当任务一旦建立,这个任务就进入就绪态准备运行。
一个任务可以通过调用OSTaskDel()函数再返回到休眠态,或通过调用该函数让另一个任务进入休眠态。
调用OSStart()可以启动多任务。
OSStart()函数运行进入就绪态的优先级最高的任务。
只有当所有优先级高于它的任务转为等待状态,或者是被删除了,就绪的任务才能进入运行态。
正在运行的任务可以通过调用OSTimeDly()或OSTimeDlyHMSM()这两个函数将自身延迟一段时间,此时这个任务就进入了等待状态,等待这段时间过去,下一个优先级最高的、并进入了就绪态的任务立刻被赋予了CPU的控制权。
等待的时间过去以后,系统服务函数OSTimeTick()使延迟了的任务进入就绪态。
正在运行的任务期待某一事件的发生也要等待,手段是调用以下3个函数之一:
OSSemPend()、OSMboxPend()或OSQPend()。
调用后任务进入了等待状态。
当任务因等待事件被挂起,下一个优先级最高的任务立即得到了CPU的控制权。
当事件发生了,被挂起的任务进入就绪态。
正在运行的任务是可以被中断的,除非该任务或者μC/OS-Ⅱ关中断。
被中断了的任务就进入了中断服务子程序。
响应中断时,正在执行的任务被挂起,中断服务子程序控制了CPU的使用权。
中断服务子程序可能会报告一个或多个事件的发生,而使一个或多个任务进入就绪态。
在这种情况下,从中断服务子程序返回之前,μC/OS-Ⅱ要判定,被中断的任务是否还是就绪态任务中优先级最高的任务。
如果中断服务子程序使一个优先级更高的任务进入了就绪态,则新进入就绪态的这个优先级更高的任务将得以运行,否则原来被中断了的任务还会继续运行。
当所有的任务都处在等待事件发生或等待延迟时间结束的状态时,μC/OS-Ⅱ执行空闲任务。
2.4任务调度
μC/OS-Ⅱ总是运行进入就绪态任务中优先级最高的那个任务。
每个任务的就绪态标志都放入就绪表中,就绪表中有两个变量OSRdyGrp和OSRdyTbl[]。
通过这两个变量和优先级判定表OSUnMapTbl[256]来确定哪个任务运行。
所谓任务切换,其实要做的就是CPU寄存器内容切换。
当多任务内核决定运行另外的任务时,它保存正在运行任务的当前状态,即CPU寄存器中的全部内容。
这些内容保存在任务的当前状况保存区,也就是任务自己的栈区之中。
入栈工作完成以后,就是把下一个将要运行的任务的当前状况从该任务的栈中重新装入CPU的寄存器,并开始下一个任务的运行。
任务切换由以下两步完成:
(1)将被挂起任务的微处理器寄存器推入堆栈;
(2)将较高优先级的任务的寄存器值从栈中恢复到寄存器中。
2.5中断处理
μC/OS-II中的中断服务程序最好用汇编语言来写,以减少时间上的开销。
中断服务程序的示意代码如下。
用户中断服务子程序:
保存全部CPU寄存器;
(1)
调用OSIntEnter或OSIntNesting直接加1;
(2)
执行用户代码做中断服务;(3)
调用OSIntExit();(4)
恢复所有CPU寄存器;(5)
执行中断返回指令;(6)
用户代码应该将全部CPU寄存器推入当前任务栈
(1)。
μC/OS-Ⅱ需要了解用户在做中断服务,故用户应该调用OSIntEnter(),或者将全程变量OSIntNesting
(2)直接加1。
直接给OSIntNesting加1比调用OSIntEnter()快得多,可能时,直接加1更好。
上述两步完成以后,用户可以开始服务于叫中断的设备了(3)。
调用脱离中断函数OSIntExit()(4)标志着中断服务子程序的结束,OSIntExit()将中断嵌套层数计数器减1。
当嵌套计数器减到零时,所有中断,包括嵌套的中断就都完成了,此时μC/OS-Ⅱ要判定有没有优先级较高的任务被中断服务子程序唤醒了。
如果有优先级高的任务进入了就绪态,μC/OS-Ⅱ就返回到那个高优先级的任务,OSIntExit()返回到调用点(5)。
保存的寄存器的值是在这时恢复的,然后是执行中断返回指令(6)。
2.6时钟节拍
μC/OS-Ⅱ需要用户提供周期性的信号源,用于实现时间延时和确认超时。
节拍率应在每秒10次到100次之间,也就是每l0ms到l00ms响应一次。
51单片机有两个16位的定时器,可以作为时钟节拍的定时源。
用户必须在多任务系统启动之后再启动时钟节拍源开始计时,也就是在调用OSStart()之后。
2.7μC/OS-Ⅱ初始化与启动
μC/OS-Ⅱ的初始化是通过调用系统初始化函数OSInit()实现的。
OSInit()初始化内核所需要的所有变量和数据结构。
OSInit()还建立了空闲任务,使这个任务始终处于就绪态。
空闲任务OSTaskIdle()的优先级总是被设置成所有任务中最低的。
OSInit()初始化变量主要是一些系统的全局变量,还初始化了4个空的数据结构空间。
这4个结构都是单向链表,允许μC/OS-Ⅱ从缓冲区中迅速得到或释放一个其中的元素。
在空缓冲区中空任务控制块的数目取决于最多任务OS_MAX_TASKS,最多任务数在OS_CFG.H文件中定义的。
然后OSInit()将会建立两个任务,并将这两个任务的任务控制块OS_TCB用双向链表链接在一起。
OSTCBList指向这个链表的起始处。
当建立一个任务时,这个任务总是被放在这个链表的起始处。
换句话说,OSTCBList总是指向最后建立的那个任务。
因为两个任务都处于就绪态,在就绪任务表OSRdyTbl[]中的相应位也要设为1。
μC/OS-Ⅱ多任务的启动是用户通过调用OSStart()实现的,在启动之前,用户至少要建立一个应用任务。
OSStart()是从任务就绪表中构造出优先级最高的任务,然后调用高优先级就绪任务启动函数OSStartHighRdy()。
第三章μC/OS-Ⅱ在51单片机上的移植
所谓移植,就是使一个实时内核能在某个微处理器或微控制器上运行。
要使μC/OS-Ⅱ正常运行,处理器必须满足以下要求:
1.处理器的C编译器能产生可重入代码。
2.用C语言就可以打开和关闭中断。
3.处理器支持中断,并且能产生定时中断(通常在10至100Hz之间)。
4.处理器支持能够容纳一定量数据(可能是几千字节)的硬件堆栈。
5.处理器有将堆栈指针和其它CPU寄存器读出和存储到堆栈或内存中的指令。
移植工作主要包括以下几个内容:
1、用#define设置一个常量的值(OS_CPU.H)
2、声明10个数据类型(OS_CPU.H)
3、用#define声明三个宏(OS_CPU.H)
4、用C语言编写六个简单的函数(OS_CPU_C.C)
5、编写四个汇编语言函数(OS_CPU_A.ASM)
下面分别从这几个方面谈一下。
3.1OS_CPU.H文件的移植
OS_CPU.H包括了用#defines定义的与处理器相关的常量、宏和类型定义。
OS_CPU.H的大体结构如下所示:
#ifdefOS_CPU_GLOBALS
#defineOS_CPU_EXT
#else
#defineOS_CPU_EXTextern
#endif
typedefunsignedcharBOOLEAN;
(1)
typedefunsignedcharINT8U;/*无符号8位整数*/
typedefsignedcharINT8S;/*有符号8位整数*/
typedefunsignedintINT16U;/*无符号16位整数*/
typedefsignedintINT16S;/*有符号16位整数*/
typedefunsignedlongINT32U;/*无符号32位整数*/
typedefsignedlongINT32S;/*有符号32位整数*/
typedeffloatFP32;/*单精度浮点数*/
(2)
typedefdoubleFP64;/*双精度浮点数*/
typedefunsignedcharOS_STK;/*堆栈入口宽度为8位*/(3)
#defineOS_ENTER_CRITICAL()EA=0/*禁止中断*/(4)
#defineOS_EXIT_CRITICAL()EA=1/*允许中断*/
#defineOS_STK_GROWTH0/*定义堆栈的增长方向*/(5)
#defineOS_TASK_SW()OSCtxSw()(6)
3.1.1与编译器相关的数据类型
因为不同的微处理器有不同的字长,所以μC/OS-Ⅱ的移植包括了一系列的类型定义以确保其可移植性。
μC/OS-Ⅱ代码从不使用C的short,int和long等数据类型,因为它们是与编译器相关的,不可移植,因此将其定义成整型数据结构
(1)。
μC/OS-Ⅱ还定义了浮点数据类型
(2)。
用户必须将任务堆栈的数据类型告知μC/OS-Ⅱ,这个过程是通过为OS_STK声明正确的C数据类型来完成的。
51单片机的堆栈成员是8位的,并且用户的编译文件指定字符型为8位数,所以应将OS_STK声明为无符号字符型数据类型(3)。
所有的任务堆栈都必须用OS_STK来声明数据类型。
3.1.2OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()
与所有的实时内核一样,μC/OS-Ⅱ需要先禁止中断再访问代码的临界段,并且在访问完毕后重新允许中断,这就使得μC/OS-Ⅱ能够保护临界段代码免受多任务或中断服务例程的破坏。
μC/OS-Ⅱ定义了两个宏来禁止和允许中断:
OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()(4)。
OS_ENTER_CRITICAL()用来关中断,OS_EXIT_CRITICAL()用来开中断。
执行这两个宏的最简单的方法是在OS_ENTER_CRITICAL()中调用处理器指令来禁止中断,以及在OS_EXIT_CRITICAL()中调用允许中断指令。
本移植过程就是通过这种方法来禁止允许中断的,在51单片机中是通过中断允许寄存器来控制中断的,当EA=0时为关中断,当EA=1时为开中断。
3.1.3OS_STK_GROWTH
只要在结构常量OS_STK_GROWTH中指定堆栈的生长方式就可以了。
1、置OS_STK_GROWTH为0表示堆栈从低地址向高地址增长。
2、置OS_STK_GROWTH为1表示堆栈从高地址向低地址增长。
由于51单片机的堆栈是从低地址向高地址增长的,因此将OS_STK_GROWTH设置成0(5)。
3.1.4OS_TASK_SW()
OS_TASK_SW()(6)是一个宏,它是在μC/OS-Ⅱ从低优先级任务切换到最高优先级任务时被调用的。
OS_TASK_SW()总是在任务级代码中被调用的。
另一个函数OSIntExit()被用来在ISR使得更高优先级任务处于就绪状态时,执行任务切换功能。
任务切换只是简单的将处理器寄存器保存到将被挂起的任务的堆栈中,并且将更高优先级的任务从堆栈中恢复出来。
μC/OS-Ⅱ要运行处于就绪状态的任务必须要做的事就是将所有处理器寄存器从任务堆栈中恢复出来,并且执行中断返回。
为了切换任务可以通过执行OS_TASK_SW()来产生中断。
大部分的处理器会提供软中断或是陷阱指令来完成这个功能。
ISR或是陷阱处理函数的向量地址必须指向汇编语言函数OSCtxSw()。
然而51单片机并不提供软中断机制,因此需要尽自己的所能将堆栈结构设置成与中断堆栈结构一样。
OS_TASK_SW()只会简单的调用OSCtxSw()而不是将某个向量指向OSCtxSw()。
而?
C_XBP指针能做到这点。
?
C_XBP是外部可重入栈的堆栈指针。
51由于内部RAM容量的限制,可重入栈没有使用硬件堆栈(堆栈指针SP),而是在外部RAM中模拟的可重入栈,其堆栈指针即为?
C_XBP,不过它是用软件模拟的。
3.2OS_CPU_A.ASM文件的移植
OS_CPU_A.ASM的移植需要编写四个简单的汇编语言函数:
1、OSStartHighRdy()
2、OSCtxSw()
3、OSIntCtxSw()
4、OSTickISR()
3.2.1准备工作
要对所要移植的函数定义重定位段,声明引用的变量,分配堆栈空间,定义必要的宏等,如下面的程序所示:
;定义重定位段
?
PR?
OSStartHighRdy?
OS_CPU_ASEGMENTCODE
(1)
?
PR?
OSCtxSw?
OS_CPU_ASEGMENTCODE
?
PR?
OSIntCtxSw?
OS_CPU_ASEGMENTCODE
?
PR?
OSTickISR?
OS_CPU_ASEGMENTCODE
;声明引用全局变量和外部子程序
EXTRNIDATA(?
C_XBP);仿真堆栈指针用于重入局部变量保存
(2)
EXTRNIDATA(OSTCBCur)
EXTRNIDATA(OSTCBHighRdy)
EXTRNI
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 实时 嵌入式 操作系统 单片机 应用 研究 解析