移植UCOS之前,你首先应该做好三件事:

1.弄懂UCOS,这是谁都知道的哦 ^_^

2. 弄懂你想要移植到的硬件平台

3. 清楚你使用的编译器是如何处理函数的局部变量和怎么样处理函数间的参数传递

这里多废话几句第三点:在UCOS里面,所有函数都要求具有重入性(除了OSSTAR()外,只有这个函数我觉得是不需要的,它仅仅使用了一次);重入性是多任务的基础,而所谓重入性从函数而言就是它的变量的保存问题,在中断这个函数的执行时它使用的变量需要得到保存,以便返回后的执行是正确的,就我使用的编译器而言,它通过堆栈传递函数参数,

重入性问题就很容易解决拉,在中断任务时,它的参数已经在堆栈里面了,只要你保存好CPU寄存器和堆栈指针SP就好

而如果你使用的是KEIL的话就比较复杂拉,首先KEIL是51单片机的东西,51只有很少的存储空间,KEIL的重入性是通过设立模拟栈实现的,当任务中断执行时,你不仅需要保存CPU寄存器,还要保存模拟栈的内容,特别是51的SP寻址能力不强,只有8位,不能在64K的空间自移动,而UCOS比较大,KEIL编译时只能用大规模方式,这就意味着所有的全局变量都会保存在片外空间,而SP无法访问到,你需要设立一个公共的系统栈,保存正在运行的任务的数据,在任务切换时把这个系统栈的内容拷贝到它的任务栈里,操作比较繁琐

注意系统的初始化问题,我在第一个任务里调用了系统初始化函数,在里面开中断允许.

任务可以是关中断时被挂起,也可以是开中断时被挂起,那么在任务切换回来后如何保证它的中断状况呢?问题可以通过给每个任务设置一个中断计数器解决,并初始化为 0,记录每个任务的开关中断次数,关一次中断加 1,开一次中断减 1, 在任务调度的时候保存当前任务的中断计数器,切换到新任务时查看新任务的中断计数器,如果为 0就开中断返回,不然就直接返回(任务级切换是在关中断下进行的);而对于中断级任务调度,肯定是发生在开中断情况下的,就要查看是否需要关中断处理

现在开始说我的移植:我移植到的平台是凌阳公司的SPCE061A 16位单片机,它有2K的RAM,32K的ROM空间,基本上够用,但不能有太多功能,我在研究了这款片子的资料后,才开始自己的移植,主要是学了一下它的汇编语言和混合编程以及CPU得硬件方面;在堆栈的问题上我发现凌阳的SP是16位的,可以寻址64K的空间,不需要设立系统栈. 在OS_CPU_C.C中注意堆栈的初始化,一定要在任务切换时严格遵守你的初始化时假定的寄存器顺序.

下面开始移植最重要的三个文件:

OS_CPU_C.C:

OSTaskStkInit():

stk=(OS_STK *)ptos;

*stk--=*((INT16U*)task+1);            /*任务首地址 (PC)*/

*stk--=0x0000;                        /*SR(R6) */

*stk--=0x0000;                        /*BP(R5) */

*stk--=0x0000;                        /*R4    */

*stk--=0x0000;                        /*R3    */

*stk--=0x0000;                        /*R2    */

*stk--=0x0000;                        /*R1    */

*stk--=0x0000;                        /*该任务的中断状况计数器*/

return((void *)stk);

别的就是空函数,比较简单,这里略去

这个文件比较简单,唯一要注意的是堆栈初始化函数,像刚刚说到的,你假定的堆栈内容必须在任务切换时严格遵守.还有就是定义几个空函数

OS_CPU_A.ASM:

这个文件呢是移植的关键,需要用汇编语言编写,(我有个同学很能喷,认为汇编语言纯属没用,像这种话千万不要相信!),在这个文件里,你需要完成UCOS的核心代码!

首先是OSStartHighRdy():

该函数在系统开始时使最高优先级任务运行,代码如下:

_OSStartHighRdy:

CALL  _OSTaskSwHook

R1=0x0001

[_OSRunning]=R1

R1=[_OSTCBCur]

SP=[R1]

POP R1 FROM [SP]

[_InterruptC]=R1      //弹出任务中断状况计数器

POP R1,R5 FROM [SP]

RETI

接着是OSCtxSw():

完成任务切换,代码如下:

_OSCtxSw:

PUSH R1,R5 TO [SP]

R1=[_InterruptC]

PUSH R1 TO [SP]              //保存任务中断状况

R2=[_OSTCBCur]

[R2]=SP

CALL _OSTaskSwHook

//OSUCBCur=OSTCBHighRdy

R1=_OSTCBCur

R2=[_OSTCBHighRdy]

[R1]=R2

//OSPrioCur=OSPrioHighRdy

R1=[_OSPrioHighRdy]

[_OSPrioCur]=R1

R1=[_OSTCBHighRdy]

SP=[R1]

POP R1 FROM [SP]

[_InterruptC]=R1              //弹出任务中断状况

CMP R1,0                    //查看是否需要开中断

JNE KAI

INT IRQ

KAI: POP R1,R5 FROM [SP]

RETI

然后是OSIntCtxSw():完成中断级任务切换,大部分和上一个函数一样

_OSIntCtxSw:

CALL _OSTaskSwHook

//OSUCBCur=OSTCBHighRdy

R1=_OSTCBCur

R2=[_OSTCBHighRdy]

[R1]=R2

//OSPrioCur=OSPrioHighRdy

R1=[_OSPrioHighRdy]

[_OSPrioCur]=R1

R1=[_OSTCBHighRdy]

SP=[R1]

POP R1 FROM [SP]

[_InterruptC]=R1

CMP R1,0                      //查看是否需要关中断处理

JE KAI1                        //如果不需要则直接返回

IRQ OFF                      //需要就关中断

KAI1:      POP R1,R5 FROM [SP]

RETI

还有一个是OSTickISR():

这个函数其实不是必须叫这个名字,可以根据具体情况改变的,在uCOS_II.h里面关于函数原型的部分可以看到,它的原型是条件编译的,只要你定义一个OS_ISR_PROTO_EXT,编译器就不会再去编译这个原型了,定义OS_ISR_PROTO_EXT意味着你告诉编译器你将自己另写中断函数的,不再使用OSTickISR(),同时由于OSCtxSw()和OSTickISR()使用相同的

条件编译,你还必须再自己在    OS_CPU.H里面写一条语句:#define  OS_TASK_SW()        OSCtxSw();这样的话,就在任务切换时将调用你编写的函数(不过我开始没有定义那个OS_ISR_PROTO_EXT时也没有出现问题,所以这块我也不太肯定)

我自己写的中断函数是针对凌阳的,代码如下:

_IRQ6:

PUSH R1,R5 TO [SP]

R1=0x0002

[P_INT_Clear]=R1  //清中断标志

CALL _Clear_Dog    //俗称喂狗

R1=[_OSIntNesting]

R1+=1

[_OSIntNesting]=R1

CMP R1,1

JNE TCB            //查看是否发生中断嵌套,

R1=[_InterruptC]      //如果没有嵌套,则保存当前任务的中断计数器

PUSH R1 TO [SP]      //及任务堆栈地址

R2=[_OSTCBCur]

[R2]=SP

TCB:      CALL _OSTimeTick

CALL _OSIntExit

R1=[_OSIntNesting]    //如果能执行到此,则说明不需要任务切换

CMP R1,0            //查看是否发生过中断嵌套

JNE TCB1            //如果发生过,则没有保存中断计数器

POP R1 FROM [SP]    //否则需要弹出中断计数器调整堆栈指针

[_InterruptC]=R1

TCB1:    POP  R1,R5 FROM [SP]

RETI

OS_CPU.H:

在这个文件里面主要就是定义数据类型,一样的数据不同的CPU有不同的位数,在这里就是要定义移植过程中的数据位数问题,还有就是定义堆栈的生长方式,及OS_ENTER_CRITICAL( ),OS_EXIT_CRITICAL( ),OS_TASK_SW( ),也都是比较简单的问题,比较容易处理,不多废话

虽然说编译器有时候出些莫名其妙的问题,但我还是要说用好你的IDE真的是太重要了,象我在开始时老有问题,我不知道到底哪有毛病,怀疑是在保存堆栈指针时有问题,因为那一块尽是一堆的指针操作,我开始不知道怎么用那个变量查看窗口,就没办法确定我是否操作正确,最后比不得已,弄了半天学会了,通过那个窗口查看变量后,才确定自己真的是错在那了……

再有一个小小的经验就是像这种比较大的东西你要step调试真的很晕,我是自己搭了个小小的测试平台(其实就是8个发光二极管),连到B口,建立任务直接看结果,很简单,但真的很管用!移植UCOS之前,你首先应该做好三件事:

1.弄懂UCOS,这是谁都知道的哦 ^_^

2. 弄懂你想要移植到的硬件平台

3. 清楚你使用的编译器是如何处理函数的局部变量和怎么样处理函数间的参数传递

这里多废话几句第三点:在UCOS里面,所有函数都要求具有重入性(除了OSSTAR()外,只有这个函数我觉得是不需要的,它仅仅使用了一次);重入性是多任务的基础,而所谓重入性从函数而言就是它的变量的保存问题,在中断这个函数的执行时它使用的变量需要得到保存,以便返回后的执行是正确的,就我使用的编译器而言,它通过堆栈传递函数参数,

重入性问题就很容易解决拉,在中断任务时,它的参数已经在堆栈里面了,只要你保存好CPU寄存器和堆栈指针SP就好

而如果你使用的是KEIL的话就比较复杂拉,首先KEIL是51单片机的东西,51只有很少的存储空间,KEIL的重入性是通过设立模拟栈实现的,当任务中断执行时,你不仅需要保存CPU寄存器,还要保存模拟栈的内容,特别是51的SP寻址能力不强,只有8位,不能在64K的空间自移动,而UCOS比较大,KEIL编译时只能用大规模方式,这就意味着所有的全局变量都会保存在片外空间,而SP无法访问到,你需要设立一个公共的系统栈,保存正在运行的任务的数据,在任务切换时把这个系统栈的内容拷贝到它的任务栈里,操作比较繁琐

注意系统的初始化问题,我在第一个任务里调用了系统初始化函数,在里面开中断允许.

任务可以是关中断时被挂起,也可以是开中断时被挂起,那么在任务切换回来后如何保证它的中断状况呢?问题可以通过给每个任务设置一个中断计数器解决,并初始化为 0,记录每个任务的开关中断次数,关一次中断加 1,开一次中断减 1, 在任务调度的时候保存当前任务的中断计数器,切换到新任务时查看新任务的中断计数器,如果为 0就开中断返回,不然就直接返回(任务级切换是在关中断下进行的);而对于中断级任务调度,肯定是发生在开中断情况下的,就要查看是否需要关中断处理

现在开始说我的移植:我移植到的平台是凌阳公司的SPCE061A 16位单片机,它有2K的RAM,32K的ROM空间,基本上够用,但不能有太多功能,我在研究了这款片子的资料后,才开始自己的移植,主要是学了一下它的汇编语言和混合编程以及CPU得硬件方面;在堆栈的问题上我发现凌阳的SP是16位的,可以寻址64K的空间,不需要设立系统栈. 在OS_CPU_C.C中注意堆栈的初始化,一定要在任务切换时严格遵守你的初始化时假定的寄存器顺序.

下面开始移植最重要的三个文件:

OS_CPU_C.C:

OSTaskStkInit():

stk=(OS_STK *)ptos;

*stk--=*((INT16U*)task+1);            /*任务首地址 (PC)*/

*stk--=0x0000;                        /*SR(R6) */

*stk--=0x0000;                        /*BP(R5) */

*stk--=0x0000;                        /*R4    */

*stk--=0x0000;                        /*R3    */

*stk--=0x0000;                        /*R2    */

*stk--=0x0000;                        /*R1    */

*stk--=0x0000;                        /*该任务的中断状况计数器*/

return((void *)stk);

别的就是空函数,比较简单,这里略去

这个文件比较简单,唯一要注意的是堆栈初始化函数,像刚刚说到的,你假定的堆栈内容必须在任务切换时严格遵守.还有就是定义几个空函数

OS_CPU_A.ASM:

这个文件呢是移植的关键,需要用汇编语言编写,(我有个同学很能喷,认为汇编语言纯属没用,像这种话千万不要相信!),在这个文件里,你需要完成UCOS的核心代码!

首先是OSStartHighRdy():

该函数在系统开始时使最高优先级任务运行,代码如下:

_OSStartHighRdy:

CALL  _OSTaskSwHook

R1=0x0001

[_OSRunning]=R1

R1=[_OSTCBCur]

SP=[R1]

POP R1 FROM [SP]

[_InterruptC]=R1      //弹出任务中断状况计数器

POP R1,R5 FROM [SP]

RETI

接着是OSCtxSw():

完成任务切换,代码如下:

_OSCtxSw:

PUSH R1,R5 TO [SP]

R1=[_InterruptC]

PUSH R1 TO [SP]              //保存任务中断状况

R2=[_OSTCBCur]

[R2]=SP

CALL _OSTaskSwHook

//OSUCBCur=OSTCBHighRdy

R1=_OSTCBCur

R2=[_OSTCBHighRdy]

[R1]=R2

//OSPrioCur=OSPrioHighRdy

R1=[_OSPrioHighRdy]

[_OSPrioCur]=R1

R1=[_OSTCBHighRdy]

SP=[R1]

POP R1 FROM [SP]

[_InterruptC]=R1              //弹出任务中断状况

CMP R1,0                    //查看是否需要开中断

JNE KAI

INT IRQ

KAI: POP R1,R5 FROM [SP]

RETI

然后是OSIntCtxSw():完成中断级任务切换,大部分和上一个函数一样

_OSIntCtxSw:

CALL _OSTaskSwHook

//OSUCBCur=OSTCBHighRdy

R1=_OSTCBCur

R2=[_OSTCBHighRdy]

[R1]=R2

//OSPrioCur=OSPrioHighRdy

R1=[_OSPrioHighRdy]

[_OSPrioCur]=R1

R1=[_OSTCBHighRdy]

SP=[R1]

POP R1 FROM [SP]

[_InterruptC]=R1

CMP R1,0                      //查看是否需要关中断处理

JE KAI1                        //如果不需要则直接返回

IRQ OFF                      //需要就关中断

KAI1:      POP R1,R5 FROM [SP]

RETI

还有一个是OSTickISR():

这个函数其实不是必须叫这个名字,可以根据具体情况改变的,在uCOS_II.h里面关于函数原型的部分可以看到,它的原型是条件编译的,只要你定义一个OS_ISR_PROTO_EXT,编译器就不会再去编译这个原型了,定义OS_ISR_PROTO_EXT意味着你告诉编译器你将自己另写中断函数的,不再使用OSTickISR(),同时由于OSCtxSw()和OSTickISR()使用相同的

条件编译,你还必须再自己在    OS_CPU.H里面写一条语句:#define  OS_TASK_SW()        OSCtxSw();这样的话,就在任务切换时将调用你编写的函数(不过我开始没有定义那个OS_ISR_PROTO_EXT时也没有出现问题,所以这块我也不太肯定)

我自己写的中断函数是针对凌阳的,代码如下:

_IRQ6:

PUSH R1,R5 TO [SP]

R1=0x0002

[P_INT_Clear]=R1  //清中断标志

CALL _Clear_Dog    //俗称喂狗

R1=[_OSIntNesting]

R1+=1

[_OSIntNesting]=R1

CMP R1,1

JNE TCB            //查看是否发生中断嵌套,

R1=[_InterruptC]      //如果没有嵌套,则保存当前任务的中断计数器

PUSH R1 TO [SP]      //及任务堆栈地址

R2=[_OSTCBCur]

[R2]=SP

TCB:      CALL _OSTimeTick

CALL _OSIntExit

R1=[_OSIntNesting]    //如果能执行到此,则说明不需要任务切换

CMP R1,0            //查看是否发生过中断嵌套

JNE TCB1            //如果发生过,则没有保存中断计数器

POP R1 FROM [SP]    //否则需要弹出中断计数器调整堆栈指针

[_InterruptC]=R1

TCB1:    POP  R1,R5 FROM [SP]

RETI

OS_CPU.H:

在这个文件里面主要就是定义数据类型,一样的数据不同的CPU有不同的位数,在这里就是要定义移植过程中的数据位数问题,还有就是定义堆栈的生长方式,及OS_ENTER_CRITICAL( ),OS_EXIT_CRITICAL( ),OS_TASK_SW( ),也都是比较简单的问题,比较容易处理,不多废话

虽然说编译器有时候出些莫名其妙的问题,但我还是要说用好你的IDE真的是太重要了,象我在开始时老有问题,我不知道到底哪有毛病,怀疑是在保存堆栈指针时有问题,因为那一块尽是一堆的指针操作,我开始不知道怎么用那个变量查看窗口,就没办法确定我是否操作正确,最后比不得已,弄了半天学会了,通过那个窗口查看变量后,才确定自己真的是错在那了……

再有一个小小的经验就是像这种比较大的东西你要step调试真的很晕,我是自己搭了个小小的测试平台(其实就是8个发光二极管),连到B口,建立任务直接看结果,很简单,但真的很管用!

UCOS移植心得(的更多相关文章

  1. ucos移植指南

    指定堆栈数据类型(宽度) typedef unsigned int OS_STK; 指定Ucos移植方法3中保存cpu状态寄存器的变量的宽度 typedef unsigned int OS_CPU_S ...

  2. ANSIC程序到KeilC51的移植心得

    摘要:本文讲述了将ANSIC程序移植到KeilC51上应该注意的事项.文章讲述了存储类型.指针类型.重入函数.根据目标系统RAM的分布的段定位和仿真栈设置.函数指针.NULL指针问题.字节顺序.交叉汇 ...

  3. android4.0.3源码之USB wifi移植心得

    http://blog.csdn.net/eastmoon502136/article/details/7850157 http://forum.cubietech.com/forum.php?mod ...

  4. STM32固件库3.5+uCOS2.86移植(转自暴走的工程师)

    考了很多移植的资料和代码,终于移植好了...应该是完美移植吧~~哈哈哈~~ 编译环境是IAR 工程适用于STM32F10X大容量产品,如果不是,请自行修改启动文件和工程配置 编译器优化等级最高...这 ...

  5. UCOS2_STM32F1移植详细过程(四)

    Ⅰ.概述 上一篇文章是讲述uC/OS-II Ports下面os_cpu_a.asm.os_cpu_c.c和os_cpu.h文件底层端口代码的移植(修改)和说明,接着上一篇文章来讲述关于UCOS移植应用 ...

  6. UCOS2_STM32F1移植详细过程(三)

    Ⅰ.概述 上一篇文章是讲述ST芯片相关的配置和OS裁剪相关的配置,接着上一篇文章来讲述关于UCOS的移植,该文主要针对uC/OS-II Ports下面os_cpu_a.asm.os_cpu_c.c和o ...

  7. UCOS2_STM32F1移植详细过程(二)

    Ⅰ.概述 打开上一篇文章新建的工程,是提取的ST标准库里面源代码文件和UCOS工程包源代码文件.下载过的朋友可能会知道,直接编译那个工程会有大片的错误和警告,原因在于那个工程是没有经过修改源代码的工程 ...

  8. UCOS2_STM32F1移植详细过程(一)

    Ⅰ.概述 该文写针对初学µC/OS的朋友,基于以下平台来一步一步移植µC/OS嵌入式操作系统.UCOS移植相关平台: 系统平台:µC/OS-II  (最新V2.92版) 硬件平台:STM32F1    ...

  9. UCOS 堆栈大小 计算 (堆栈的决定性因素)

    决定栈空间的大小,不仅需要计算任务本身的需求(局部变量.函数调用等),还要计算最多中断嵌套层数(保存寄存器.中断服务程序中局部变量等) 原文地址:uCOS任务堆栈的深入分析.作者:jiecou 堆栈作 ...

随机推荐

  1. CVE-2012-0003 Microsoft Windows Media Player ‘winmm.dll’ MIDI文件解析远程代码执行漏洞 分析

    [CNNVD]Microsoft Windows Media Player ‘winmm.dll’ MIDI文件解析远程代码执行漏洞(CNNVD-201201-110)    Microsoft Wi ...

  2. 判断一个字符是否为数字的两种方法(C/C++)

    在平时,我们经常遇见判断字符是否为数字这种题目,虽然感觉还是很简单,不过我是个更喜欢用函数的人,因为我觉得这样更便捷,所以我更推荐第二种方式. 1.直接判断 #include <stdio.h& ...

  3. JDBC连接池和DBUtils

    本节内容: JDBC连接池 DBUtils 一.JDBC连接池 实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程,为了解决此类性能问题,通常情况我们采取连接池技术,来共享连接Conne ...

  4. 【LOJ】#2027. 「SHOI2016」黑暗前的幻想乡

    题解 我一开始写的最小表示法写的插头dp,愉快地TLE成60分 然后我觉得我就去看正解了! 发现是容斥 + 矩阵树定理 矩阵树定理对于有重边的图只要邻接矩阵的边数设置a[u][v]表示u,v之间有几条 ...

  5. 学习Nodejs的第一步

    最近看了几本关于Node.js的书,本来个人技术分享网站http://yuanbo88.com/是打算用Node.js作为服务器端语言来处理后台的,后来又改成了PHP(也是自己研究,毕竟网上DEMO多 ...

  6. Docker简介与安装(一)

    Docker简介 Docker 是 Docker.Inc 公司开源的一个基于 LXC技术之上构建的Container容器引擎, 源代码托管在 GitHub 上, 基于Go语言并遵从Apache2.0协 ...

  7. 安装 Git

    是时候动手尝试下 Git 了,不过得先安装好它.有许多种安装方式,主要分为两种,一种是通过编译源代码来安装:另一种是使用为特定平台预编译好的安装包. 从源代码安装 若是条件允许,从源代码安装有很多好处 ...

  8. Hadoop整理五(基于Hadoop的数据仓库Hive)

    数据仓库,是为企业所有级别的决策制定过程,提供所有类型数据支持的战略集合.它是单个数据存储,出于分析性报告和决策支持目的而创建. 为需要业务智能的企业,提供指导业务流程改进.监视时间.成本.质量以及控 ...

  9. MVP模型

    MVP模型一般要创建三个文件夹:View.Interactor(Model).Presenter 每个部分都有其接口和实现类,就是为了方便回调 这里做一个登陆界面为例子: 接口: Interactor ...

  10. CSUOJ 1217 奇数个的那个数 位运算

    Description 给定些数字,这些数中只有一个数出现了奇数次,找出这个数. Input 每组数据第一行n表示数字个数,1 <= n <= 2 ^ 18 且 n % 2 == 1. 接 ...