Chinaunix首页 | 论坛 | 博客
  • 博客访问: 18467
  • 博文数量: 6
  • 博客积分: 210
  • 博客等级: 二等列兵
  • 技术积分: 70
  • 用 户 组: 普通用户
  • 注册时间: 2009-05-13 18:21
文章分类

全部博文(6)

文章存档

2011年(1)

2009年(5)

我的朋友
最近访客

分类:

2009-11-17 23:04:29

                             uC/OS 的移植测试

                      

    原创文章,希望喜欢的朋友给在下宣传一下,涨涨人气

shichaog

调试思路

  一般相对处理器内存而言操作系统都比较大,为了使原本就比较复杂的问题不更加难于解决,对移植的代码,首先不加任何应用代码,只测试内核自身的运行状况;如果产生问题就可确信为是移植的自身问题而不是应用程序的问题,解决内核代码问题后;剩下的任务就是给内核添加用户任务代码,调试并使之通过测试。而对uC/OS而言主要是验证OSTaskStkInit()OSStartHighRdy()OSIntCtxSw()OSTickISR()OSCtxSw()这几个函数。

确保C编译器、汇编编译器及链接器的正常工作

对于MCS-51处理器而言,我们用比较流行的集C编译器、汇编编译器及链接器于一身的Keil公司产品Keil uVision3 编译器,它是功能强大的集成开发环境(IDE),所以先要确保集成开发环境没有问题,具体可以自己先写一些简单的程序,测试一下,这一步完成之后,就要做一个最小的测试,如图一中的测试程序;

图一:测试程序

Fig1:testing program

因为程序员经常使用keil 编写和调试51系列单片机的应用程序,所以一般keil是不会有问题的。从图一的输出窗口信息可以看出没有错误,但是有14个警告,并且从截图中也可以看出有未调用的代码段,这是因为为了检验系统移植是否正确,注释掉了串口初始化和中断函数及创建任务函数等的缘故;对于单片机序而言,能通过编译并不意味着生成的目标代码就能按照用户期望在单片机上运行,必须注重输出窗口给的提示信息,尤其不要忽视警告信息,这部分的提示可能就是问题的症结所在,这里图一中的警告是因为没有调用工程中所有函数所导致的,不妨碍验证keil的正确性。

3验证OSTaskStkInit()OSStartHighRdy()函数

做完第一步工作后,接着就要使keil调试uc/os 的内核函数了,首先修改OS_CFG.H文件,设置OS_TASK_EN0,以禁止统计任务。因为上一步的操作中并未添加任何应用程序,所以唯一的任务就是空闲任务,可以使用单步执行来调试该函数,直到该函数运行到OS_TaskIdle()

Keil支持单步执行的调试机制,也支持多步调试执行,并在调试同时可以查看各个寄存器以及各变量的值,单步执行main()函数。跳过(调试菜单中的step over选项)OSInit();单步进入OSStart()函数。一直单步该函数调用OSStartHighRdy()(这里是OSStart()函数的最后一句),然后单步进入step into选项)OSStartHighRdy()。这时keil会切换到宏汇编语言模式下,因为OSStartHighRdy()是用汇编语言实现的(见图三),继续单步执行,同时观察堆栈内容及CPU寄存器内容的变化、SP指针的指向,检查是否出

错,如果正确,OSStartHighRdy()会将OSTaskStkInit()推入堆栈的CPU寄存器按相反顺序弹出。如果不正确,堆栈指针会出错,应校正OSTaskStkInit()函数。

图二:测试OSStart()函数

Fig2:test OSStart() function

图三:切换到汇编模式下的调试界面

Fig3: switch to the window of assembly mode

同样我们也可以借助硬件资源进行调试,具体做法是利用LED来指示程序运行到的地方,具体做法是先关闭LED,如果OSTaskStkInit()OSStartHighRdy()函数工作工作正常,再由OS_TaskIdle()函数点亮LED。实际上,因为LED的亮灭速度特别快,用户只会看到LED是一直亮着的。这时用示波器观察应该可以看到大约是50%占空比的闪烁。但是为了进行这样的测试,应临时修改OS_CFG.H中,需设置OS_TASK_STAT_EN0同时在OS_Init() OSStart()插入关LED(如图一中被注释掉的那句),最后还要在OS_CPU_C.C中修改OSTaskIdleHook()函数,修改后如下:

图四: 修改的OSTaskIdleHook()函数

Fig4modified OSTaskIdleHook() function

这样如果系统正常则LED先被关掉,接着由OS_Init()会建立统计任务,这里统计任务代码已被我们修改了,变成了开关LED灯,如果程序正确,那么空闲统计任务会一直运行,则可以看出它将不断的执行开和关LED操作,由于51的主频达选12M,所以此时用示波器观察将看到LED两端的电平发生高低跳变并且占空比为50%,而用肉眼看到的将是LED一直亮着。如果缺少示波器,则需要根据图二的示意代码添加延时代码,但是这里我们的主要任务是调试内核,额外的代码将会增加复杂度,所以尽量避免使用这种方法。

4调试OSCtxSw()函数

在上一步的测试成功基础上,就知道OSTaskStkInit()正确了,由于51堆栈自低地址往高地址生长

:完整的OSCtxSw()函数测试代码

Fig5: whole codes for testing OSCtxSw() function

这里需要注意的是MCS-51系列是没有软中断指令的,其实现是靠程序员编写代码完成这一功能的,也就是说,这一函数也该在调试的内容之一,其编写是用汇编完成的。因为其调试是基于源码的,可以充分利用单步执行功能,验证其正确性,通过观察堆栈及寄存器的变化,查看是否出错。当执行中断返回指令时,应该是在OS_TaskIdle()中。

在这一步也可用硬件的一些资源来辅助调试,如LED;还是要借助其亮灭的指示作用,因为OSCtxSw()正确,就会使是循环很快,这就要求用示波器观察其闪烁频率,才可以判断该函数是否正确,当然u C 

基于源码的,没必要如此麻烦,因为代码越多意味着出错的概率越大。

验证 OSTickISR()OSInitCtxSw()函数

由于OSInitCtxSw()函数很像OSCtxSw()且比OSCtxSw()简单,所以调试相对较轻松,在次测试之前,因该保证时钟中断向量指向了时钟中断节拍中断服务子程序,然后初始化时钟节拍并开中断。这里OSTickISR()是用Timer 0 来产生该操作系统需要的时钟频率的。源码在图五中可以看出。

图六:测试OSTickISR()函数

Fig6test function of OSTickISR()

keil中是可以近似知道代码执行时间的,看这截下的keil调试环境的底部,有t1sec项,就可以知道运行的时间了,但是在运行时,是要把仿真的器晶振的频率选为具体硬件的外接晶振频率的;

图七:测试OSInitCtxSw()函数

Fig7test OSInitCtxSw() function

(注意:图一至图六给出的代码中,只有是用C语言编写测试程序才是完整的,汇编语言编写的并不是完整的。) 

当然这里也是可以修改前面的调试程序,利用硬件资源验证修改的正确性,此处也需要示波器进行观察,用LED的闪烁频率验证时序的正确性。至此内核调试结束,该操作系统已经可以正常工作了,可以添加应用任务了。

结束语:操作系统的调试并不是件简单的事,这不仅要求调试人员能熟练C语言、汇编语言编程和对硬件资源的充分了解,还要求程序员能正确分析编译器编译结果因为能通过编译并不意味着生成的代码符合程序员的期望,这一过程还需要反复结合硬件来综合调试,在这一过程中,遇到问题解决问题,提升能力,是一趣事;成功的通过测试才能加载用户的应用程序,为以后的发展奠定坚实的基础。

阅读(1083) | 评论(0) | 转发(0) |
0

上一篇:linux emial

下一篇: uC/OS 的移植测试

给主人留下些什么吧!~~