第一篇:基于UCOS嵌入式实时操作系统的单任务和多任务LED显示总结----娄...
基于uCOSII的单任务和多任务LED显示
一、uCOSII简介
uCOS II是一个微型的实时操作系统,包括了一个操作系统最基本的一些特性,如任务调度、任务通信、内存管理、中断管理、定时管理等。而且这是一个代码完全开放的实时操作系统,简单明了的结构和严谨的代码风格,非常适合初涉嵌入式操作系统的人士学习。
二、设计目的
通过实验,学习在uC/OSII操作系统中单任务控制LED闪烁和多个任务控制LED之间的切换和同步,以及多任务控制程序的编写方法。
三、裸机程序和uCOSII 的运行流程对比
3.1 裸机程序的运行流程
裸机主函数的运行流程:
这个是我们写一般的单片机程序的流程,就是在主函数中用死循环执行功能函数,然后加上中断。3.2 uCOSII 的运行流程
uCOSII是一个操作系统,但是说到底也是一个支持任务切换的裸机程序。在初始化变量OSInit函数中,初始化所有全局变量,数据结构,创建最低优先级空闲任务OSTaskIde,并创建6个空数据链表:空任务控制块链表,空事件控制块链表,空列队控制块链表,空标志组链表,空内存控制块链表,空闲定时器控制块链表
创建任务 OSTaskCreate函数,一般创建一个最高优先级任务TaskStart任务,任务调度后,在这个任务中再创建其他的任务,初始化硬件,并打开中断。
进入多任务管理阶段OSStart函数,将就绪表中最高优先级任务的栈指针加载到SP中,并强制中断返回。
任务调度工作就是查找就绪表中优先级最高的任务,实现任务的切换。简单来说,裸机程序在主函数中通过死循环执行各种函数,最终达到实现各种功能函数的目的。而uCOSII系统,通过不断的产生定时中断,或则任务主动放弃CPU,然后进行任务之间的调度,相当于不断循环执行不同的任务,最终实现各种任务。
四、工作原理
4.1uCOSII 的内核管理
4.1.1 ucos的文件结构:
应用软件Ucos(与处理器无关的代码)OS_CORE.COS_FLAG.COS_MBOX.COS_MEM.COS_MUTEX.COS_Q.COS_SEM.COS_TASK.COS_TIME.CUCOS_11.CUCOS_11.HUCOS-11配置(与应用相关)OS_CFG.HINCLUDE.HUCOS移植(与处理器相关代码)OS_CPU.H,OS_CPU_A.ASM,OS_CPU_C.C硬件4.1.2 临界段:
OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()。它们可以用不同的方法去实现,用定义(#define)常数OS_CRITICAL_METHOD(1,2,3)来选择用哪种方法来实现。
当OS_CRITICAL_METHOD=1时,表示用处理器指令关中断,完成OS_ENTER_CRITIACL,用开中断完成OS_EXIT_CRITICAL.利用这种方法有点小问题,即是调用UCOS功能函数之前,中断是关掉的,从UCOS返回后,中断就打开了。
当OS_CRITICAL_METHOD=2时,这种方法是在堆栈中保存中断的开关状态,然后再关中断。在实现OS_EXIT_CRITICAL时,只需简单的从堆栈中弹出原来中断的开关状态。利用这种方法,不论用户在调用函数之前中断是开着的还是关着的,函数的进入和返回状态都得到了保护。
当OS_CRITICAL_METHOD=3时,一些编译器提供了扩展功能,用户可以得到当前处理器的状态字,并保存在C函数的局部变量中,这个变量可以用于恢复PSW。在STM32中,我们一般都是用第三种模式。4.1.3 任务的状态:
任务状态之间的转换如下图:
特别值得注意的是,在任务执行的过程中可以被中断打断。4.1.4任务控制快:
系统必须为每个任务创建一个保存与该任务有关的相关信息的数据结构,这个数据结构就叫做该任务的任务控制块(TCB)。当任务的CPU使用权被剥夺时UCOS利用它来保存任务的状态。4.1.5就绪表:
每个就绪的任务都放在就绪表中,就绪表中有两个变量,OSRdyGRP和OSRdyTbl。OSRdyGrp中每一位表示8组任务中每一组是否有进入就绪态的任务。当有任务进入就绪态时,就绪表OSRdyTbl[]中相应元素的相应位也置为1。4.1.6任务调度OS_SCHED():
Ucos总是进行进入就绪态任务中优先级最高的任务,确定哪个任务优先级最高,这一工作就是有调度器完成的。4.1.7任务切换OS_TASK_SW():
需恢复该任务在CPU使用权被剥夺时保存下来的全部寄存器的值,之后,运行被切换的任务。
4.1.8给调度器上锁和开锁:
给调度器上锁函数OSSchedlock()用于禁止任务调度,直到任务完成后,调用调度器开锁函数OSSchedUnlock()为止。这两函数必须成对使用。4.1.9空闲任务OS_TaskIdle():
每个程序必须在初始化时建立一个空闲任务,这个任务没有其他任务进入就绪态时,投入运行,空闲任务永远处于就绪态。空闲任务始终设为最低优先级。OSTaskIdle()可以调用OSTaskIdleHook()让CPU进入STOP指令,从而进入低功耗模式。当应用系统有电池供电时,这种方式特别有用。
4.2uCOSII 的任务管理
4.2.1建立任务OSTaskCreat(): 如果想让UCOS管理用户的任务,必须先建立任务。可以通过将任务的地址和其他参数传递到以下两个函数之一来建立任务。当调用OSTaskCreat()时,需要四个OSTaskCreate(void(*task)(void*pd),void*pdata,OS_STK*ptos,INTU prio)Task:是指向任务代码的指针,pdata:是任务开始执行是,传递给任务的参数的指针,ptos:是分配给任务的堆栈的栈顶指针,prio是分配给任务的优先级。
4.2.2任务堆栈OS_STK(): 每个任务都有自己的堆栈,堆栈必须申明为OS_STK类型,并且由连续的内存空间组成。可以静态分配堆栈空间,也可以动态分配堆栈空间。但是一般我们都是分配静态堆栈空间。4.2.3删除任务OSTaskDel():
有时需要删除任务,删除任务,是说任务返回并处于休眠态,并不是说任务的代码被删除了。4.3时间管理
4.3.1任务延迟函数OSTimeDly():
Ucos提供一个可以被任务调用而将任务延时一段特定时间的功能函数,即OSTimeDly().任务调用OSTimeDly()后,一旦规定的时间期满或者有其他的任务通过调用OSTimeDlyResume()取消了延时,他就会进入就绪状态。只有当该任务在所有就绪态任务中具有最高的优先级,它才会立即运行。4.3.2按时,分,秒延时函数OSRimeDLyHMSM():
OSTimeDly()一样,调用OSRimeDlyHMSM()函数也会是UCOS进行一次任务调度,并且执行下一个优先级最高的就绪任务。当OSTimeDlyHMSM()后,一旦规定的时间期满,或者有OSTimeDlyResume(),它就会马上处于就绪态。同样,只有当该任务在所有就绪态任务中具有最高的优先级,他才开始运行。
五、设计方案:
5.1单任务
在stm32的平台上移植ucosII,并且建立一个单任务,任务控制LED1以10HZ的频率闪烁。5.2多任务
在stm32的平台上移植ucosII,并且建立三个任务,三个任务分别控制LED1,LED2,LED3以10HZ,20HZ,50HZ的的频率闪烁。
六、程序流程图
多任务控制LED闪烁:
七、遇到的问题
7.1编译器报错,显示PUBLIC未定义
由于我们移植的核心代码用IAR编译的,由于编译器的不同,所以要把PUBLIC改成EXPORT。
7.2编译报错,显示,栈未定义
由于每个任务都要有独立的栈来保存局部变量,从本质上讲也就是将CPU寄存器的值保存到RAM中。在uCOS中,每一个任务都有一个独立的任务堆栈。
八、主要代码 8.1主函数
#include “includes.h” //包含所有头文件
OS_STK startup_task_stk[STARTUP_TASK_STK_SIZE];//定义起始任务堆栈
int main(void){
BSP_Init();//板级初始化
OSInit();//系统初始化,创建空闲任务
OSTaskCreate(Task_Start,(void *)0,&startup_task_stk[STARTUP_TASK_STK_SIZE-1], STARTUP_TASK_PRIO);
OS_ENTER_CRITICAL();OSStart();
//把控制权交给操作系统,进行任务调度
return 0;} 8.2用户应用函数
#include “includes.h”
OS_STK task_led2_stk[TASK_LED2_STK_SIZE];
//任务2堆栈 OS_STK task_led3_stk[TASK_LED3_STK_SIZE];
//任务3堆栈 OS_STK task_led4_stk[TASK_LED4_STK_SIZE];
//任务4堆栈
void Task_Start(void *p_arg)
//task1 {
(void)p_arg;
//未用到传递参数,防止编译器报错
SysTick_init();
OSTaskCreate(Task_LED2,(void *)0,//
&task_led2_stk[TASK_LED2_STK_SIZE-1], TASK_LED2_PRIO);OSTaskCreate(Task_LED3,(void *)0,//
&task_led3_stk[TASK_LED3_STK_SIZE-1], TASK_LED3_PRIO);
OSTaskCreate(Task_LED4,(void *)0,//
&task_led4_stk[TASK_LED4_STK_SIZE-1], TASK_LED4_PRIO);
while(1)
{
LED1(ON);
OSTimeDlyHMSM(0, 0,0,100);
LED1(OFF);
OSTimeDlyHMSM(0, 0,0,100);
} } //任务2 void Task_LED2(void *p_arg){
(void)p_arg;
SysTick_init();
while(1)
{
LED2(ON);
OSTimeDlyHMSM(0, 0,0,200);
LED2(OFF);
OSTimeDlyHMSM(0, 0,0,200);
} }
//任务3 void Task_LED3(void *p_arg){
(void)p_arg;
SysTick_init();
while(1)
{
//LED3(ON);
OSTimeDlyHMSM(0, 0,0,300);
//LED3(OFF);
OSTimeDlyHMSM(0, 0,0,300);
} }
//任务4 void Task_LED4(void *p_arg){
(void)p_arg;
SysTick_init();
while(1)
{
LED3(ON);
OSTimeDlyHMSM(0, 0,0,40);
LED3(OFF);
OSTimeDlyHMSM(0, 0,0,40);
} }
娄宇庭
2014年5月5 日
第二篇:嵌入式Linux实时操作系统习题总结
第1章
1.嵌入式系统是指操作系统和功能软件集成于计算机硬件系统之中。嵌入式系统一般有3个主要的组成部分:硬件、实时操作系统以及应用软件。
2.嵌入式系统的三要素是嵌入、专用、计算机;即以应用为中心、以计算机技术为基础、软件硬件可裁剪、适应应用系统对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。
3.目前国际较为知名的有:VxWorks、NeutrinoRTOS、Nucleus Plus、OS/
9、VRTX、LynuxOS,RTLinux、BlueCat RT等。
4.嵌入式系统一般由硬件层、中间层、软件层和功能层组成。其作用分别如下:
(1)硬件层 :由嵌入式微处理器、外围电路和外设组成。操作系统和应用程序都可以固化在ROM或者Flash中。为方便使用,有的模块在此基础上增加了LCD、键盘、USB接口,以及其他一些功能的扩展电路。
(2)中间层 :硬件层与软件层之间为中间层,其作用将系统软件与底层硬件部分隔离,使得系统的底层设备驱动程序与硬件无关;
(3)软件层 :主要是操作系统,有的还包括文件系统、图形用户接口和网络系统等。操作系统是一个标准的内核,将中断、I/O、定时器等资源都封装起来,以方便用户使用。(4)功能层 :由基于操作系统开发的应用程序组成,用来完成对被控对象的控制功能。5.非占先式调度法也称作合作型多任务(cooperative multitasking),各个任务彼此合作共享一个CPU。中断服务可以使一个高优先级的任务由挂起状态变为就绪状态。但中断服务以后控制权还是回到原来被中断了的那个任务,直到该任务主动放弃CPU的使用权时,那个高优先级的任务才能获得CPU的使用权。当系统响应时间很重要时,要使用占先式(preemptive)内核。最高优先级的任务一旦就绪,总能得到CPU的控制权。当一个运行着的任务使一个比它优先级高的任务进入了就绪态,当前任务的CPU使用权就被剥夺了。6.在实时系统中,如果系统在指定的时间内未能实现某个确定的任务,会导致系统的全面失败,这样的系统被称硬实时系统。在弱实时系统中,超时却不会发生致命的错误。其实时性的要求比硬实时系统要差一些。
7.嵌入式系统的设计步骤及各部分的主要工作如下。(1)需求分析阶段,罗列出用户的需求;
(2)体系结构设计阶段,描述系统的功能如何实现;
(3)详细设计阶段,进行硬件系统与软件系统的分类划分,以决定哪些功能用硬件实现,哪些用软件实现;
(4)系统集成,把系统的软件、硬件和执行装置集成在一起,进行调试,发现并改进在设计过程中的错误;
(5)系统测试,对设计好的系统进行测试,看其是否满足给定的要求。8.Linux作为嵌入式操作系统的优势主要有以下几点:
(1)可应用于多种硬件平台。
(2)Linux的高度模块化使添加部件非常容易。
(3)Linux是一个和Unix相似、以内核为基础的、具有完全的内存访问控制,支持大量硬件的一种通用操作系统。
(4)Linux可以随意地配置,不需要任何的许可证或商家的合作关系。
(5)Linux带有Unix用户熟悉的完善的开发工具。其强大的语言编译器GCC,C++等也可以很容易得到,不但成熟完善,而且使用方便。9. Linux执行进程调度一般是在以下情况发生的:(1)正在执行的进程运行完毕;
(2)正在执行的进程调用阻塞原语将自己阻塞起来进入等待状态;(3)正在执行的进程调用了P原语操作,从而因资源不足而被阻塞;(4)执行中的进程提出I/O请求后被阻塞;(5)系统分配的时间片已经用完;
(6)就绪队列中的某个进程的优先级变得高于当前运行进程的优先级。
第4章
1、Linux 内核的编译菜单有好几个版本,运行:
(1)make config:进入命令行,可以一行一行的配置,但使用不十分方便。
(2)make menuconfig:大多数开发人员使用的Linux 内核编译菜单,使用方便。
(3)make xconfig:在2.4.X 以及以前版本中xconfig 菜单是基于TCL/TK 的图形库的。
2、在完成内核的裁减之后,内核的编译就只要执行以下几条命令: make clean
编译内核之前先把环境给清理干净。make dep
编译相关依赖文件 make zImage
创建内核镜像文件 make modules 创建内核模块。
make install
把相关文件拷贝到默认的目录。
3、此命令是装载压缩映像文件zImage到flash存储器中,地址是kernel分区,并采用xmodem传输协议。
4、此命令是设置网卡1的地址192.168.1.1,掩码为255.255.255.0,不写netmask参数则默认为255.255.255.0。
5、此命令将nfs服务的共享目录sharedir加载到/mnt/nfs。
6、此命令是装载根文件系统root.cramfs到flash存储器中,地址是根文件系统分区,并采用xmodem传输协议。
7、这个命令的操作同时进行了分区和格式化,0~128K存放vivi,128K~192K存放VIVI控制台指令,192K~1216K存放kernel,1216K~4288K存放root,其余部分存放应用程序。
第6章
1.使用虚拟地址寻址整个系统的主存和辅存的方式在现代操作系统中被称为虚拟内存。虚拟内存的管理方法使系统既可以运行体积比物理内存还要大的应用程序,也可以实现“按需调页”策略,既满足了程序的运行速度,又节约了物理内存空间。2.进程内存区域涉及到5种数据段,即:
①代码段:代码段是用来存放可执行文件的操作指令。
②数据段:数据段用来存放可执行文件中已初始化全局变量。③BSS段:BSS段包含了程序中未初始化的全局变量。④堆(heap):用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。
⑤栈:栈是用户存放程序临时创建的局部变量。3.在Linux系统中,内核在最高级执行,也称为“系统态”,在这一级任何操作都可以执行。而应用程序则执行在最低级,即所谓的“用户态”。在这一级处理器禁止对硬件的直接访问和对内存的未授权访问。模块是在所谓的“内核空间”中运行的,而应用程序则是在“用户空间”中运行的。它们分别引用不同的内存映射,也就是程序代码使用不同的“地址空间”。4.共享内存区域是被多个进程共享的一部分物理内存。如果多个进程都把该内存区域映射到自己的虚拟地址空间,则这些进程就都可以直接访问该共享内存区域,从而可以通过该区域进行通信。共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容。5.内存管理利用虚拟文件系统支持交换,交换进程(swapd)定期由调度程序调度,这也是内存管理依赖于进程调度的唯一原因。当一个进程存取的内存映射被换出时,内存管理向文件系统发出请求,同时,挂起当前正在运行的进程。
第9章
1.参考答案:
Mutex互斥量,用于操作某个临界资源时对该资源上锁,以实现互斥地对独占资源的使用。Semophore信号灯,信号灯内有一计数器,可以用于对多个同类资源的分配。
Condition条件变量,条件变量用于等待信号。当一个线程需要等待某个信号时,就可到条件变量上等待,当信号具备时,系统会唤醒该线程继续运行。2.参考答案:
本地:共享内存+信号量,适合于大量数据传输。Linux支持系统V和POSIX的共享内存和信号量。(5分)
远程:Socket+应用协议。适合于跨网络的(大量)数据传输。Linux支持BSD的socket。应用层协议需要自行设计。(5分)
3.答案要点:程序是编译后形成的可执行代码,是静止的。进程是程序的一次执行,是活动的。线程是进程的可执行单元,同一进程的不同线程共享进程的资源和地址空间。4.两种实现方法,一种是继承Thread,另外一种是实现接口Runnable。
同步的实现方法有两种,分别是synchronized, wait与notify。用synchronized可以对一段代码、一个对象及一个方法进行加锁。用wait与notify可以使对象处于等待及唤醒方式导致同步,因为每个对象都直接或间接的继承了Object类。
5、什么是BootLoader?主要有几种工作模式及主要功能是什么? 答:
Bootloader就是操作系统内核运行的一段小程序,完成进行初始化系统硬件设置的任务,(2分)
分为启动加载模式和下载模式。(1启动加载模式
启动加载(Boot laoding)模式是指 Bootloader 从目标机上的某个固态存储设备上将操作系统加载到 RAM 中运行,整个过程并没有用户的介入。(2分)(2)下载模式
在下载模式下,目标机上的 Bootloader 将先通过串口连接或网络连接等通信手段从宿主机下载文件。(2分)
6、简述Bootloader有何作用?
答案要点:(1)首先,bootloader是在特定硬件平台运行的程序,严重依赖于硬件平台,需要移植;(2)是系统上电之后,第一个运行的程序,系统在上电或复位时通常都从地址 0x0 处开始执行,而在这个地址处安排的通常就是系统的 Boot Loader 程序;(3)bootloader程序的设计目标是启动嵌入式操作系统,嵌入式操作系统的启动需要一定的条件,这些条件由bootloader来满足;(4)Bootloader一般具有对存储器和网络接口操作的功能;如擦除、读写Flash,通过USB、串口下载文件等