uC/OS II是一个完整的、可移植、可裁减、源码公开的抢占式实时多任务操作系统。因此程序开发人员可以在嵌入式系统的开发过程中.灵活地改写其源代码.以满足用户特定的需求。PIC18F452是Microchip公司生产的单片机PICmicro家族中的中档微处理器产品.是一款含有丰富片上资源的8位MCU.广泛应用在家用电器、医疗设备、工业控制等领域。因此uC/OS II在该处理器上的成功移植.将大大提高复杂应用系统的开发效率.增强系统的可靠性,降低开发成本,提高经济效益。 1 uC/OS II移植方法 1.1 uC/OS II成功移植的条件 要把uC/OS II成功地移植到某一处理器上.该处理器必须满足以下要求: - 处理器的C编译器能产生可重入代码。
- 用C语言就可以打开和关闭中断。
- 处理器支持中断,并且能产生定时中断(通常在10至100Hz之间)。
- 处理器支持能够容纳一定量数据(可能是几千字节)的硬件堆栈。
- 处理器有将堆栈指针和其它CPU寄存器读出和存储到堆栈或内存中的指令。
而Microchip PIC18F452的体系结构可以满足移植uC/OS II的硬件需求.同时Microchip提供的C18编译器也能满足移植的需要。
1.2 uC/OS II移植的相关工作 uC/OS II的移植工作主要涉及与处理器相关的以下内容: - 与编译器相关的数据类型声明(OS_CPU.H)不同的处理器有不同的字长.所以必须定义一系列数据类型以确保移植的正确性。文件OS_CPU.H中声明了10个相关数据类型。
- 改写与任务管理相关的函数(OS_CPU_C.C)uC/OS II移植需要改写6个与任务管理相关的函数.它们是:OSTaskStkInit()、OSTaskCreatHook()、OSTaskDelHook()、OSTaskSwHook()、OSTaskStatHook()、OSTaskTickHook()
其中只需对OSTaskStkInit()编写代码,后5个函数必须声明,但是内部并没有代码。OSTaskCreate()和OsTaskCreateExt()通过调用OSTaskStkInit()来初始化任务的堆栈结构。 - 编写与任务切换相关的函数(OS_CPU_A.ASM)
uC/OS II的移植要求用户编写四个与处理器相关的汇编语言函数:OSStartHighRdy()、OSCtxSw()、OSIntCtxSw()、OSTickISR()。 如果用户的编译器支持插入汇编语言代码,可将所有与处理器相关的代码放到OS_CPU_C.C文件中,该文件便不再需要。 - 编写中断服务程序CPUhighInterruptHook() 数和CPUlwoInterruptHook()函数
2 uC/OS II在PIC18F452上的移植实现 2.1数据类型定义 在uC/OS II中,不使用c的short、int和long等数据类型。下面就是uC/OS II定义的一部分数据类型。 typedef unsigned char BOOLEAN; typedef unsigned char INT8U;/*无符号8位整数 */ typedef signed char INT8S; /*有符号8位整数 */ typedef unsigned int INT16U; /*无符号16位整数 */ typedef signed int INT16S; /*有符号16位整数 */ ……
2.2宏定义 包括开关中断的宏定义,以及进行任务切换的宏定义。 #define OS_CRITICAL_METHOD 3 …… #if OS_CRITICAL_METHOD==3 /*关开中断方式*/ #define OS_ENTER_CRITICAL() / cpu_sr=INTCON & 0b11000000;/ INTCON &=(0b00111111|(RCON&0b10000000)) #define OS_ENTER_CRITICAL_HIGH() / cpu_sr=INTCON & 0b11000000;/ INTCON &=0b00111111 #define OS_EXIT_CRITICAL() INTCON |=cpu_sr #endif …… void OSCtxSw(void); #define OS_TASK_SW() OSCtxSw() (1)开关中断宏 与其他实时系统一样,uC/OS II在进入系统临界代码区之前要关闭中断,等到退出临界区后再打开,从而保护核心数据不被多任务环境下的其他任务或中断破坏。uC/OS II定义了两个宏用来关闭/打开中断:OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()。uC/OS II中提供三种开关中断的方法。本移植中实现OS_ENTER_CRITICAL()用的是第3种方法,将CPU的状态字寄存器保存到局部变量中。而OS_EXIT_CRITICAL()从这个局部变量中恢复状态寄存器。该移植中使用的局部变量为OS_CPU_SR类型的cpu_sr。此方法还定义了一个关中断的宏OS_ENTER_CRITICAL_HIGH(),与OS_ENTER_CRITICAL()不同的是它不仅可以禁止低优先级中断,而且可以禁止高优先级中断。后者只能禁止低优先级中断。 (2)任务切换宏OS_TASK_SW() 上下文切换时可直接调用该宏,因为在PIC18中是没有软中断的。
2.3堆栈 uC/OS II是一个多任务的调度器,每个任务都有自己的堆栈。堆栈必须声明为OS_STK类型,并且由连续的内存空间组成。OS_STK数据类型和处理器的寄存器长度是一致的,PIC18F452的寄存器长度为8位,并定义堆栈由低地址向高地址增长,以便在调用任务建立函数OSTaskCreate()或OSTaskCreateExt()时,告知堆栈是增长方向: typedef INT8U OS_STK;/*栈类型(8位宽)*/ #define OS_STK_GROWTH 0 /*定义栈增长方向为由低到高*/
2.4时钟 PIC18F452有8种振荡器模式。设计中选用的是XT模式,故决定了时钟频率为4Mhz。
2.5任务切换 由于uC/OS II是一个抢占式的内核,所以它总是执行处于就绪态的优先级最高的任务。任务在执行时会调用uC/OS II提供的一个服务来等待时间过期,或者信号量的到来,或者另一个任务或中断服务例程的消息的到来。当内核发现有优先级更高的任务处于就绪态时,便进行任务间切换。其处理过程如下: - 任务调用uC/OS II提供的OSTimeDly()服务;
- OSTimeDly()将任务放到正在等待任务过期的一串任务里面;
- 因为任务不可能再被执行,系统会调用调度器(OSSched())找出下一个优先级最高的任务来运行;
- 上下文切换是通过调用OSCtxSw()来完成的。
OSCtxSw()是用内嵌汇编语言写的,因为它要直接操作PIC中的寄存器。 2.6中断服务例程 根据uC/OS II的要求,用户要编写自己的中断服务例程。所有的中断是在CPUhighInterruptHook()函数和CPUlowInterruptHook()函数中处理的.用户只需要提供处理中断的代码。时钟中断中的必须是一个低优先级的中断.并且需要定时调用OSTimeTick()。 在CPUlowInterruptHook()函数处理完中断服务子程序后,CPU相关代码开始退出中断。调用OSIntExit()使中断嵌套层数递减,当嵌套层数为0时,所有的中断嵌套结束,系统通过调用OSSched()判断CPU应该回到先前被中断的任务,还是运行高优先级的任务。如果有一个高优先级的任务,uC/OS II会通过任务切换使CPU运行此任务。 void CPUlowInterruptHook(void) { if(INTCONbits.TMROIF){ //检查TMR0是否溢出 INTCONbits.TMR0IF=0; //清除中断标志 TMR0H=0xD8; //设置时间常数10 ms.(at 4MHz) TMR0L=0xA0; OSTimeTick(); //调用OS时钟请求 } /*此处插入用户的中断程序*/ } #pragma interrupt CPUhighInterruptHook void CPUhighInterruptHook(void) { /*此处插入高优先级中断程序,但不能使用任何OS功能调用*/ } 3 用户实时任务编写 uC/OS II中的实时任务是在系统初始化(调用OSInit()和OSCtxSw())后,通过OSTaskCreateExt()调用创建的,实时任务创建完成后,调用OpenTimer0()设置时钟中断,最后调用OSStart(),系统开始运行并进行任务调度。 为了测试移植的结果,使用高奇ICD DEMO教学实验板并利用板上资源创建TempTask()、LEDTask()及通过RS232实现的Shell任务。其中,Shell任务接收并执行用户的Shell命令.并通过LCDTask()任务显示该命令.TempTask()则实现则周期性地采集与RA0-RA3相连接的温度。由于PIC的USART中只有2个字节的FIFO缓冲队列,快速的通信过程中很容易丢失数据.故除了通信的实现采用中断方式之外.还设计了一个30Byte的缓冲队列,存放接收到的数据,接收数据由设计在CPUlowInterruptHook()中的代码完成,主要代码如下: while((PIE1bits.RCIE)&&(PIR1bits.RCIF)) { c=RCREG; t=q.rear+1; if(t==MAX_LEN)//接收的数据存放到队列中 t=0; if(t==q.front) break; //溢出 q.rear=t; q.data[q.rear]=c; } 4 结束语 目前正在进行的水质控制系统中采用PIC MCU作为下位机负责数据采集、数据简单处理、控制执行机构以及与上位机的通信。该项目中引人uC/OS II后.系统开发效率明显提高。下一步考虑将其与已经设计完成的以太网控制器结合,实现嵌人式控制系统的TCP/IP互连。
|