首页 VC环境下UCOS-II移植

VC环境下UCOS-II移植

举报
开通vip

VC环境下UCOS-II移植1 VC下时钟的获得 《嵌入式实时操作系统uC/OS-II》这本书已经安排了大量篇幅来专门讲解uC/OS-II的移植:第13章移植uC/OS-II,第14章uC/OS-II在80x86上的移植,第15章uC/OS-II在带有硬件浮点运算单元的80x86上的移植。所以本文只是重点讲解移植到VC下和其他处理器上的不同地方,更详细的介绍读者可以参考《嵌入式实时操作系统uC/OS-II》这本书。和所有其他的移植一样,本文所做的移植也只需要修改uC/OS-II处理器相关代码,一共包括3个文件:OS_CPU.H,OS_CPU...

VC环境下UCOS-II移植
1 VC下时钟的获得 《嵌入式实时操作系统uC/OS-II》这本 关于书的成语关于读书的排比句社区图书漂流公约怎么写关于读书的小报汉书pdf 已经安排了大量篇幅来专门讲解uC/OS-II的移植:第13章移植uC/OS-II,第14章uC/OS-II在80x86上的移植,第15章uC/OS-II在带有硬件浮点运算单元的80x86上的移植。所以本文只是重点讲解移植到VC下和其他处理器上的不同地方,更详细的介绍读者可以参考《嵌入式实时操作系统uC/OS-II》这本书。和所有其他的移植一样,本文所做的移植也只需要修改uC/OS-II处理器相关代码,一共包括3个文件:OS_CPU.H,OS_CPU_A.ASM,OS_CPU_C.C。考虑到VC可以嵌入汇编代码,并不需要专门的汇编代码文件,所以OS_CPU_A.ASM是多余的,最终只有OS_CPU.H和OS_CPU_C.C两个文件。所以这两个文件成了移植的关键,首先要解决的问题就是时钟“滴答”的获得。 移植到BC下的uC/OS-II是通过修改DOS下的硬件时钟中断来得到时钟滴答的,VC下时钟滴答从哪里来呢?这是移植uC/OS-II到VC下第一个要考虑的问题。在windows的保护模式下不能像DOS下面那么容易,直接通过一个函数调用就能够修改中断。windows下要修改中断涉及到驱动程序,这样就加大了移植的困难度与复杂度,但好处是只有真正硬件时钟的“滴答”才能够保证uC/OS-II的实时性。另外一种解决方法是采用windows下的软件定时器,通过定时器来产生模拟时钟“滴答”。考虑到本移植只是为了教学和学习,并没有应用到对实时性要求高的产品,所以最终决定采用软件定时器来模拟时钟中断。Windows下软件定时器种类很多,下面分别简要介绍一下这些定时器: 1.SetTimer()函数 有windows下编程经验的最先想到的应该是SetTimer这个API函数,但本文采用的移植程序是基于控制台的,也就是说最开始建立VC工程的时候选择的是创建win32 console application,控制台下的程序是没有消息循环的,所以要使用SetTimer函数则必须再创建一个线程来专门处理消息循环,这样一来事情就复杂了,而且这个函数定时精度非常不高。所以这种方法不是特别合适。 2.timeSetEvent()函数 这个函数很简单,不需要消息循环,定时精度为ms级,主要应用在多媒体定时方面,能够在非常精确的时间间隔内完成一个事件、函数或过程的调用。函数原型:MMRESULT timeSetEvent(UINT uDelay, UINT uResolution,LPTIMECALLBACK lpTimeProc,WORD dwUser,UINT fuEvent ),可以通过调用timeSetEvent()函数,将需要周期性执行的任务定义在LpTimeProc回调函数中,从而完成所需处理的事件。调用这个函数后会增加一个线程,时间一到则在这个线程中调用回调函数,对于主线程来说,非常类似外部中断调用,我们需要的正是这样的效果,所以本文最终选择这个函数来产生时钟“滴答”。 3.QueryPerformanceFrequency()和 QueryPerformanceCounter()函数 这两个函数可以实现更高精度的定时,误差不超过1微秒,进行定时之前,先调用QueryPerformanceFrequency()函数获得机器内部定时器的时钟频率, 然后在需要严格定时的事件发生之前和发生之后分别调用QueryPerformanceCounter()函数,利用两次获得的计数之差及时钟频率,计算出事件经 历的精确时间。可见,这两个函数主要是应用在计算时间方面,并没有设置回调函数机制,如果我们要使用这个函数的话,则需要首先创建一个线程,然后在这个线程中计算时间调用我们要定时处理的函数,等于需要手动实现定时函数回调机制,远比timeSetEvent()函数来得复杂。 当然还有更多的定时器函数,这里不一一介绍,读者可以自行参考相关书籍。本文选择的是timeSetEvent函数,调用这个函数后uC/OS-II就已经开始它的脉搏了。 2 模拟时钟中断的产生 中断指的是中止当前的事务,处理别的更要紧的事情。我们通过软件定时器来模拟产生uC/OS-II的时钟中断,但timeSetEvent()函数调用定时回调函数是和主线程同时被windows操作系统调度的,并没有起到中断的作用。所以在调用定时回调函数的时候必须停止主线程的运行,退出回调函数则恢复主线程的运行,自然这些事情可以都放在定时回调函数,也就是uC/OS-II的时钟中断处理函数中完成。Windows下要挂起一个线程的运行,首先要得到这个线程的句柄,然后调用SuspendThread(hangdler)和ResumeThread(handler)就可以挂起和继续执行线程。如图1所示。 图1 模拟中断 在我们的程序中刚开始只有一个线程,调用timeSetEvent则产生了定时器线程,定时器线程会按我们预定的时间周期调用uC/OS-II的中断处理函数OSTickISR,如果uC/OS-II没有屏蔽中断,OSTickISR则挂起主线程,然后才做它改做的事情:调度任务执行。 在main函数的的OSInit()前,我们加入了一个VCInit()函数,主要初始化VC环境,包括获得主线程的句柄,设置上下文环境标志位,特别要注意的是,句柄的获得是要通过伪句柄转换的,如程序 清单 安全隐患排查清单下载最新工程量清单计量规则下载程序清单下载家私清单下载送货清单下载 L1所示 程序清单 L1 初始化VC环境 void main (void) { VCInit(); //在此加入我们的VCInit函数 OSInit(); // 初始化uC/OS-II // 安装uC/OS-II的任务切换向量 // 创建用户起始任务(为了方便讨论,这里以TaskStart()作为起始任务) OSStart(); // 开始多任务调度 } HANDLE mainhandle; //增加的全局变量:主线程句柄 CONTEXT Context; //增加的全局变量:主线程切换上下文 void VCInit(void) { HANDLE cp,ct; Context.ContextFlags = CONTEXT_CONTROL; cp = GetCurrentProcess(); //得到当前进程句柄 Ct = GetCurrentThread(); //得到当前线程伪句柄 DuplicateHandle(cp, ct, cp, &mainhandle, 0, TRUE, 2); // 伪句柄转换,得到线程真句柄   }   时钟中断处理子程序OSTickISR将在调用timeSetEvent后,被定时器线程周期调用,其代码如程序清单 L2所示 程序清单 L2 时钟节拍ISR Void CALLBACK OSTickISR(unsigned int a,unsigned int b,unsigned long c,unsigned long d,unsigned long e) { if(!FlagEn) //通过一个全局变量 关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf 示是否屏蔽中断 return; //如果当前中断被屏蔽则返回 SuspendThread(mainhandle); //中止主线程的运行,模拟中断产生.但没有保存寄存器 GetThreadContext(mainhandle, &Context); //得到主线程上下文,为切换任务做准备 OSIntNesting++; if (OSIntNesting == 1) { OSTCBCur->OSTCBStkPtr = (OS_STK *)Context.Esp; //保存当前esp } OSTimeTick(); //ucos内部定时 OSIntExit(); //由于不能使用中断返回指令,所以此函数是要返回的 ResumeThread(mainhandle); //模拟中断返回,主线程得以继续执行 }   开关中断我们通过设置一个全局变量来解决,代码如下: #define  OS_ENTER_CRITICAL()  FlagEn=0            //禁止定时器 调度  #define  OS_EXIT_CRITICAL()  FlagEn=1        //容许定时器调度 因此在中断处理程序中首先判断当前是否容许中断,如果容许才挂起主线程,模拟中断产生,完成进一步的工作。 3 任务切换 任务切换,其实做的是任务的上下文切换,在其他CPU上非常容易分辨出任务的上下文,一般就是CPU上的相应寄存器,那么在VC下呢?从简单考虑,我们选择了不带浮点运算的上下文环境,因此任务的上下文和uC/OS-II在80x86上移植的上下文很相近,不同点只是段寄存器不用保存,因为在VC下任务其实只是在同一个线程中切换,而且在保护模式下段寄存器的概念已变,其值在同一个线程中是不会变的。任务切换压栈时如图2所示 低端地址 EDI ESI EBP ESP EBX EDX ECX EAX PSW OFF task 0 OFF pdata 高端地址   图2 任务切换压栈后状态 手动任务切换代码如程序清单L3所示,主要涉及VC中嵌入汇编的编写,请读者自行分析 程序清单L3 手动任务切换 void OSCtxSw(void) { _asm{ lea eax, nextstart ;任务切换回来后从nextstart开始 push eax pushfd ;标志寄存器的值 pushad ;保存EAX -- EDI mov ebx, [OSTCBCur] mov [ebx], esp ;把堆栈入口的地址保存到当前TCB结构中 } OSTaskSwHook(); OSTCBCur = OSTCBHighRdy; OSPrioCur = OSPrioHighRdy; _asm{ mov ebx, [OSTCBCur] mov esp, [ebx] ;得到OSTCBHighRdy的esp popad ;恢复所有通用寄存器,共8个 popfd ;恢复标志寄存器 ret ;跳转到指定任务运行 } nextstart: //任务切换回来的运行地址 return; }   至此,其他VC下的移植方法与普通的移植无异,不必再深究下去,请读者自行分析
本文档为【VC环境下UCOS-II移植】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_614050
暂无简介~
格式:doc
大小:73KB
软件:Word
页数:7
分类:互联网
上传时间:2019-01-20
浏览量:22