ucos ii 中断编程中的中断函数只能用汇编来写么

1099人阅读
& & & & & & & & & & & & & & &uCOS-II移植(Freescale &MPC5644A)
1、从官网上下载源码:
如果官网上有对应芯片移植好的源码,那么拿过来略微改动就可以用。
32位的MPC5644A支持两种汇编指令集--BookE(32位)和VLE(可变指令集,32位&16位),所以在新建工程或者导入工程时要统一选择其中的一种。
下载解压后会有这么一个文件夹,内部文件结构如下:
& &&EvalBoards
& & & &&&BSP&&
& & --&&Board Support Package 板级相关,(系统时钟,LED。。。)
& & & &&&uCOS-II&& &--& 应用程序(main在这里)& uC-II的配置(os_cfg.h)
& & uC-CPU &--& &芯片的CPU相关移植代码
& & uC-LIB & &--& micrium官网的一个库代码
& & uCOS-II
& & & & Ports & --&移植主要需要改动或者自己写的几个文件(os_dbg.c 可以忽略)
& & & & Source --&uC-II源代码
MPC5644A内部有一个e200的核,uC-CPU的部分也是针对这个核的相关代码,主要用到了内部减数器,来完成系统的OSTickISR周期调用。
在找到,详细介绍了如何将下载的工程导入CodeWarrior
导入后需要将BSP中板级相关的函数替换成自己板子的函数(可能还需要添加一些文件路径),这个时候操作系统就可以跑起来了!
下附一张CW10.6移植后的截图:
3、不那么简单的情况:
有的时候或许没有那么幸运,直接就可以下载到所需芯片(系列)已经移植好的工程;或者官网提供的工程与你所用的编译器不同(我就是这种情况),你无法import。这时就需要自己新建一个工程,自己来做一次移植。
第一种情况多数需要自己完成(或者是找相近的参考)Ports内部的几个文件,可以参考邵贝贝写的那本书中uC-II的移植那一章。
下面我们来说第二种情况:
官网提供的工程针对10.x编译器直接就可以用,而因为一些原因我必须使用CodeWarrior 2.8编译器,我先是在10.6上成功移植后,确认代码没有问题了,再在2.8上新建工程,一步步移植。
新建一个工程(指令集这里我选的BookE,中断选择的硬件中断!)
将uCOS-II的代码加载进来(这里我们不考虑需要自己写汇编的情况)
新建工程后在系统生成的Source文件夹下是没有ivor_branch_table.c的,需要手动添加进来,branch_table中用到了3个和系统相关的函数,这里直接替换并在上面extern
这里只是你的函数和branch_table建立了关系,还需要对应到Exceptions中(如果你新建工程时没有生成ivor_branch_table.c,很大可能你的Exceptions.c需要修改):
& & & & & & & & &
& & & & & & 修改前: & & & & & & & & & & & & & & & & & & & & & & & & & 修改后:&&
目录截图:
uCOS-II中系统的延时函数OSTimeDly(num)是通过周期调用OSTickISR实现的。先将减数器给定一个初始值(1个tick)后使能,在每一次减数器减到0时会产生一个Exception,也就会去执行branch_table中减数器的异常函数。
在Task中调用OSTimeDly(tick_num)时,会将当前任务挂起,当前任务让出CPU,在每次系统心跳中将挂起任务的时间tick_num--,减为0时则任务恢复,产生一次调度,根据优先级去选择要执行的任务。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:6256次
排名:千里之外您所在位置: &
&nbsp&&nbsp&nbsp&&nbsp
ucos-ii的中断_1.ppt29页
本文档一共被下载:
次 ,您可全文免费在线阅读后下载本文档。
文档加载中...广告还剩秒
需要金币:10 &&
ucos-ii的中断_1,ucos ii 中断,ucosii中外部中断,ucos ii 定时器中断,ucos中断,ucos串口中断,stm32 ucos 中断,ucos 定时器中断,ucos怎么关掉滴答中断,ucos 中断发送信号量
你可能关注的文档:
··········
··········
概述 从发展过程来看: 中断(interrupt)最初被用来替换I/O操作的轮询处理方式,以提高I/O处理的效率。 随后,中断又包含了自陷(trap,也称为内部中断或是软件中断)的功能。 后来,中断的概念得到进一步扩大,被定义为导致程序正常执行流程发生改变的事件(不包括程序的分支情况)。可把概念被扩大的中断称为广义中断。 概述 在实际应用中,广义的中断通常被分为中断、自陷和异常(exception)等类别。 中断是由于CPU外部的原因而改变程序执行流程的过程,属于异步事件,又称为硬件中断。自陷和异常则为同步事件;
自陷表示通过处理器所拥有的软件指令、可预期地使处理器正在执行的程序的执行流程发生变化,以执行特定的程序。自陷是显式的事件,需要无条件地执行; Motorola 68000系列中的Trap指令 ARM中的SWI指令 Intel 80x86中的INT指令?? 概述 异常为CPU自动产生的自陷,以处理异常事件。 如被0除、执行非法指令和内存保护故障等。 异常没有对应的处理器指令,当异常事件发生时,处理器也需要无条件地挂起当前运行的程序,执行特定的处理程序。 中断的分类 分类方式 硬件中断是否可以被屏蔽: 可屏蔽中断和不可屏蔽中断
中断源: 硬件中断和软件中断
中断信号的产生: 边缘触发中断和电平触发中断
中断服务程序的调用方式: 向量中断、直接中断和间接中断 可屏蔽中断和不可屏蔽中断 由于中断的发生是异步的,程序的正常执行流程随时有可能被中断服务程序打断。如果程序正在进行某些重要运算,中断服务程序的插入将有可能改变某些寄存器的数据,造成程序的运行发生错误。
可屏蔽中断:能够被屏蔽掉的中断。 外部设备的中断请求信号一般需要先通过CPU外部的中断控制器
正在加载中,请稍后...搜索关键字:
&&& 1.在uC/OS-II的帮助手册内,作者特地强调绝对不能在OSInit()或者OSStart()内调用初始化程序,那会破坏系统的可移植性同时带来性能上的损失。所以,一个折中的办法就是:在优先级最高的程序内调用,这样可以保证当OSStart()调用系统内部函数OSStartHighRdy()开始多任务后,首先执行的就是初始化程序。或者专门开一个优先级最高的任务,只做一件事情,那就是执行 初始化,之后通过调用OSSuspend()将自己挂起来,永远不再执行。不过这样会浪费一个TCB空间。对于那些RAM吃紧的系统来说,还是不用为好。
&&& 在uC/OS-II里,每个任务都有一个任务控制块(
),这是一个比较复杂的数据结构。在任务控制快的偏移为0的地方,存储着一个指针,它记录了所属任务的专用堆栈地址。事实上,再uC/OS-II内,每个任务都有自己的专用堆栈,彼此之间不能侵犯。这点要求程序员再他们的程序中保证。一般的做法是把他们申明成静态数组。而且要申明成OS_STK类型。当任务有了自己的堆栈,那么就可以将每一个任务堆栈再那里记录到前面谈到的任务控制快偏移为0的地方。以后每当发生任务切换,系统必然会先进入一个中断,这一般是通过软中断或者时钟中断实现。然后系统会先把当前任务的堆栈地址保存起来,仅接着恢复要切换的任务的堆栈地址。由于哪个任务的堆栈里一定也存的是地址(还记得我们前面说过的,每当发生任务切换,系统必然会先进入一个中断,而一旦中断CPU就会把地址压入堆栈),这样,就达到了修改PC为下一个任务的地址的目的。
&&& 2.(三) 一些重要的uC/OS-II API介绍
&&& &C/OS 和&C/OS-II 是专门为计算机的嵌入式应用设计的, 绝大部分代码是用C语言编写的。CPU 硬件相关部分是用汇编语言编写的、总量约200行的汇编语言部分被压缩到最低限度,为的是便于移植到任何一种其它的CPU 上。
&&& 任何一个操作系统都会提供大量的API供程序员使用,uC/OS-II也不例外。由于uC/OS-II面向的是嵌入式开发,并不要求大而全,所以内核提供的API也就大多和多任务息息相关。
&&& 主要的有以下几类:
&&& 1)任务类
&&& 2)消息类
&&& 3)同步类
&&& 4)时间类
&&& 5)临界区与事件类
&&& 我个人认为对于初级程序员而言,任务类和时间类是必须要首先掌握的两种类型的API.下面我就来介绍比较重要的:
&&& 1)OSCreate函数
&&& 这个函数应该至少再main函数内调用一次,在OSInit函数调用之后调用。作用就是创建一个任务。目前有四个参数,分别是任务的入口地址,任务的参数,然后将会根据用户给出参数初始化任务堆栈,并在内部的任务就绪表内标记该任务为就绪状态。最后返回,这样一个任务就创建成功了。
&&& 2)OSTaskSuspend函数
&&& 这个函数很简单,一看名字就该明白它的作用,它可以将指定的任务挂起。那为什么是优先级呢?事实上在系统内部,优先级除了表示一个任务执行的先后次序外,还起着分别每一个任务的作用,换句话说,优先级也就是任务的ID.所以uC/OS-II不允许出现相同优先级的任务。
&&& 3)OSTaskResume函数
&&& 这个函数和上面的函数正好相反,它用于将指定的已经挂起的函数恢复成就绪状态。其参数类似 OSTaskSuspend函数,为指定任务的优先级。需要特别说明是,本函数并不要求和OSTaskSuspend函数成对使用。
&&& 4)OS_ENTER_CRITICAL宏
&&& 很多人都以为它是个函数,其实不然,仔细分析一下OS_CPU.H文件,它和下面马上要谈到的OS_EXIT_CRITICAL都是宏。他们都是涉及特定 CPU的实现。由于系统希望向上层程序员隐藏内部实现,故而一般都宣称执行此条指令后系统进入临界区。这个宏能少用还是少用,因为它会破坏系统的一些服务,尤其是时间服务。并使系统对外界响应性能降低。
&&& 5)OS_EXIT_CRITICAL宏
&&& 这个是和上面介绍的宏配套使用另一个宏,它在系统手册里的说明是退出临界区。其实它就是重新开中断。需要注意的是,它必须和上面的宏成对出现,否则会带来意想不到的后果。最坏的情况下,系统会崩溃。我们推荐程序员们尽量少使用这两个宏调用,因为他们的确会破坏系统的多任务性能。
&&& 6)OSTimeDly函数
&&& 这应该程序员们调用最多的一个函数了,这个函数完成功能很简单,就是先挂起当起当前任务,然后进行任务切换,在指定的时间到来之后,将当前任务恢复为就绪状态,如果恢复后是优先级最高就绪任务的话,因为此时仅仅依靠时钟机制在进行任务切换。一个好的任务应该在完成一些操作主动放弃使用权,好东西要大家分享嘛!
&&& 3.我们推荐程序员们尽量少使用OS_ENTER_CRITICAL宏和 OS_EXIT_CRITICAL宏两个宏调用,因为他们的确会破坏系统的多任务性能。why??
&&& 4.在以uC/OS为操作系统的项目中,系统可能要处理各种不同的中断请求,如果某个中断处理程序需要调用uC/OS的各种函数向任务发出消息,那么uC/OS建议中断服务程序的写法是:
&&& 1、保存全部CPU寄存器
&&& 2、调用OSIntEnter或OSIntNesting直接加1
&&& 3、执行用户代码做中断服务
&&& 4、调用OSIntExit
&&& 5、恢复所有CPU寄存器
&&& 6、执行中断返回指令
&&& 暂且称为&标准中断&方式,这种方式实际上是将这个中断处理加入了任务调度系统,也就是说这个中断可以引起任务的切换。如果在中断处理中没有调用各种函数的话,则可以用一般的、象原来没有操作系统时的
&&& 写法:
&&& 1、保存中断处理程序需要用到的CPU寄存器
&&& 2、执行中断处理
&&& 3、恢复保存了的CPU寄存器
&&& 4、执行中断返回指令
&&& 暂且称为&快中断&方式,按照这种方法定义的中断永远不会引起任务切换。在uC/OS系统中,每个任务都要定义独立的栈空间,一个栈空间的使用包括5个部分:
&&& 1、任务包括的各个函数的调用返回地址
&&& 2、任务包括的各个函数中可能在栈上分配的局部变量
&&& 3、发生了&标准中断&方式定义的中断或任务被挂起时,所要保存的任务上下文
&&& 4、发生了&快中断&方式定义的中断时,中断处理程序所需要的栈空间
&&& 5、中断嵌套时,所要保存的中断嵌套上下文
&&& 在这些使用的部分中,1,2,3,4的内存占用量是比较容易估算的,最精确和保险的确定方法是:查看由C生成的asm文件,并计算各个函数的栈使用量。为每个任务都定义一个充分大的栈空间,这在某些内存稀缺的小项目中是非常痛苦的,
&&& 有时不得不增扩内存,这就会使成本增加。我深入研究了uC/OS后,这样将会大大的降低整个系统对内存的需求。C/OS的任务调度是靠OS_Sched和 OSIntExit来完成的,这两个函数中都要先判断一个叫OSIntNesting的系统变量,如果OSIntNesting不为0,则不进行任务切换。也就是说:在OSIntNesting为1时起,那么在所有嵌套的中断一层一层地都返回直到 OSIntNesting再次为1时止,任务栈是不会切换的。
&&& 据此,我们可以这样改动:设置一个缓冲区OSInterruptStk,作为嵌套中断的栈空间
&&& 由所有任务共享,中断服务程序改为:
&&& 1、保存全部CPU寄存器
&&& 2、调用OSIntEnter或OSIntNesting直接加1
&&& 增加:2.1、判断OSIntNesting是否等于1,如果不是则转到3
&&& 增加:2.2、将栈指针SP保存到OSTCBCur-&OSTCBStkPtr
&&& 增加:2.3、将SP指向OSInterruptStk的栈顶(注意栈增长的方向)。
&&& 3、执行用户代码做中断服务
&&& 4、调用OSIntExit
&&& 增加:4.1、判断OSIntNesting是否等于0,如果不是则转到5
&&& 增加:4.2、从OSTCBCur-&OSTCBStkPtr中恢复栈指针SP
&&& 5、恢复所有CPU寄存器
&&& 6、执行中断返回指令
&&& 并且要修改OSIntCtxSw函数,原始的OSIntCtxSw函数的写法是:
&&& 1、调整栈指针来去掉在调用:OSIntExit,OSIntCtxSw过程中入栈的多余内容
&&& 2、将当前任务栈指针保存到OSTCBCur中(OSTCBCur-&OSTCBStkPtr = __SP__)
&&& 3、如果需要则调用OSTaskSwHook
&&& 4、OSTCBCur = OSTCBHighRdy
&&& 5、OSPrio = OSPrioHighRdy
&&& 6、从OSTCBCur中恢复栈指针(__SP__ = OSTCBCur-&OSTCBStkPtr)
&&& 7、恢复保存了的CPU寄存器
&&& 8、执行中断返回指令
&&& 5.注意arm
for uCOSII for lpc213x 模板中的TargetInit()对于很多使用ZLG arm
for uCOSII for lpc213x 模板的初学者,常常会置疑使用该模板后自动生成的target.c文件,和在程序中调用的TargetInit()函数,我和 Zgpswh都是如此,这个问题当初困扰了很久:当用户程序中不调用TargetInit()时,发现内核能运行,但是等待机制失灵,调用 TargetInit(),很多硬件中断打不开,后来,在很多热心人的指点下解决了,现重新
&&& 总结如下:
&&& 请仔细察看ZLG模板里的target.c文件,这里的TargetInit()如下:
&&& void TargetInit(void)
&&& OS_ENTER_CRITICAL();
&&& srand((uint32)TargetInit);
&&& VICInit();
&&& Timer0Init();
&&& OS_EXIT_CRITICAL();
&&& 其中的Timer0Init();用于硬件器0的初始化,事实上,ZLG的移植代码的&C/OS-Ⅱ的时钟节拍是通过器0提供的,不在主程序里调用这个函数,&C/OS-Ⅱ的时钟源就无法打;没有开启时钟源的&C/OS-Ⅱ是同样能运行的,系统虽能将就运行,但因没调用TargetInit()而使内核功能不健全。请注意,TargetInit()中的另一个函数VICInit ()是用来中断的初始化,它其中含有对UART0中断的分配,在用户程序里需要根据使用的硬件中断修改这部分代码,否则,这些硬件中断无法开启;这也就是Zgpswh提到的现象:不调用TargetInit()内核运行异常,调用了却开不了UART0的中断。
&&& 解决的方法如下:
&&& 这在《arm嵌入式系统基础教程》的430页7.4.3节中论述的很清楚:&&关键在于把程序与芯片相关中断源挂接,使芯片在产生相应的中断后会调用相应的处理程序。这需要做两方面事情:
&&& 1. 增加汇编接口的支持。&&
&&& 2. 初始化向量中断控制器。&&
&&& 按照一下方法完成中断源的的挂接:
&&& 1、增加汇编接口的支持。方法是修改IRQ.s文件,在末尾添加本句代码:
&&& UART0_Handler HANDLER UART0_Exception
&&& 追加定义了通用串口0 中断句柄。
&&& 2、初始化向量中断控制器。将target.c文件中的VICInit()修改如下:
&&& void VICInit(void)
&&& { extern void IRQ_Handler(void);
&&& extern void Timer0_Handler(void);
&&& extern void UART0_Handler(void);
&&& VICIntEnClr = 0
&&& VICDefVectAddr =(uint32)IRQ_H
&&& VICVectAddr0 =(uint32)Timer0_H
&&& VICVectCntl0 =(0x20 | 0x04);
&&& VICIntEnable = 1《4;
&&& VICVectAddr14 =(uint32)UART0_H
&&& VICVectCntl14 =(0x20 | 0x06);
&&& VICIntEnable = 1《6;
&&& 此为初始化向量中断控制器。包括器0和串口0,特别要注意的是,一定不可以省略对定时器0的初始化中断里,不可以调用延时请注意,中断里面是不支持等待机制的。问题就可以解决了。中断源挂接正确是没问题的。
&&& void TargetInit(void)
&&& OS_ENTER_CRITICAL();
&&& srand((uint32)TargetInit);
&&& VICInit();
&&& Timer0Init();
&&& OS_EXIT_CRITICAL();
&&& 在此单独用srand()函数有什么作用(用了有什么好处,不用又会怎样),一般srand()用于给rand()设定种子(即srand给定rand运算式子的第一个值)。查了FAQ(P22)仅仅说明 seed的译文。
&&& 你说的没有错,他就是用来设置随机数的种子。
&&& 每次编译一次,void TargetInit(void)函数在Ram或者Flash中的地址都不一样(即种子也不一样)。如果你在程序中不用随机函数rand(),那么srand()在这里对你来说是没有意义的,如果你要用rand(),那么每次编译程序后你的rand()产生的随机数就不一样。当然,你也可以自己种种子咯。
&&& srand((uint32) TargetInit);是初始化uc/os-ii随机数函数rand();也就是说给随机数一个基值,以后调用相关随机数函数时,随机数就在此基值的基础上改变。只要不调用rand()函数,就可以去掉这句。
&&& 在arm上移植操作系统有一点需要注意:建立任务的任务,最好不要做复杂的工作。频繁的访问硬件或者做时序要求比较严的工作容易造成系统死机,希望大家多多注意。我的做法是:将建立任务的任务,闲置起来,但是不能进入死循环。方法
&&& 是:利用一个空邮箱,让任务无限期的等待,这样可以实现与任务的切换。
&&& 8.//定义与编译器无关的数据类型
&&& typedef unsigned char BOOLEAN;//布尔变量
&&& typedef unsigned char INT8U;//无符号8位整型变量
&&& typedef signed char INT8S;//有符号8位整型变量
&&& typedef unsigned short INT16U;//无符号16位整型变量
&&& typedef signed short INT16S;//有符号16位整型变量
&&& typedef unsigned int INT32U;//无符号32位整型变量
&&& typedef signed int INT32S;//有符号32位整型变量
&&& typedef float FP32;//单精度浮点数(32位长度)
&&& typedef double FP64;//双精度浮点数(64位长度)
&&& typedef INT32U OS_STK;//堆栈是32位宽度
&&& 注:这里为什么用typedef,因为如果用#define,那么代码中的每一个相应的类型都会被替代,很有可能会出现问题,毕竟他只是一个替代的关系,且编译时间会增加,而用typedef则不会,它就相当于我们C++里面的引用,一样的思维,在这里面就是说多了一个名称。还有要注意的是我们怎么知道unsigned char 就是无符号8位整型变量,可以arm公司里面下载ADS_CompilerGuide_D.PDF文件,或者在你所装的ADS1.2目录里面有一个文件夹叫PDF,打开它就可
IC快速检索:}

我要回帖

更多关于 ucos ii 中断函数 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信