基于C8051F015芯片在开发板上实现μC/OS-II的移植

发布时间:2023-08-02  

嵌入式应用中,使用RTOS的最主要原因是提高系统的可靠性,其次是提高开发效率、缩短开发周期。μC/OS-II 是一个基于优先级的抢占式实时内核,支持56 个用户任务,90%的代码使用标准的ANSI C语言书写,程序可读性强,移植性好,代码可固化,可裁剪,非常灵活。C8051F是美国Cygnal公司生产的与51系列兼容的微控制器,流水线指令结构70%的指令的执行时间为1个或2个系统时钟周期。当时钟频率为25MHz时,速度可达25MIPS,是一款不错的片上系统。


1 开发工具和运行环境

实现μC/OS-II的移植,要求所用的C编译器支持混合编程。KEIL C51可为众多的8051派生器件编程。我们选用的是KEIL7.02集成开发环境,仿真板基于C8051F015芯片。


2 移植中所需修改的文件

和CPU相关的文件主要有三个,分别是汇编文件OS_CPU_A.ASM、C语言文件 OS_CPU_C.C和头文件OS_CPU.H。


2.1 OS_CPU.H文件

OS_CPU.H文件中定义了数据类型及与硬件相关的基本信息。其中改动部分如下:

基于C8051F015芯片在开发板上实现μC/OS-II的移植

在C8051F中,堆栈都是按字节操作的,故数据类型OS_STK声明为8位。方向从低地址向高地址方向递增,所以OS_STK_GROWTH设置为 0。μC/OS-II在进入系统临界代码区之前要关中断,等到退出临界区后再打开,以保护核心数据不被多任务环境下的其它任务或中断破坏。开、关中断可通过设置SFR中的中断屏蔽位实现。在关中断时,先将IE的内容保存在全局变量IE_ SHADOW中,然后关中断;退出临界区时,还原IE_SHADOW的值。

OS_TASK_SW()用来实现任务切换。就绪任务的堆栈初始化应该模拟一次中断发生后的样子,堆栈中应该按入栈次序设置好各个寄存器。OS_TASK_SW()函数模拟一次中断过程,在中断返回的时候进行任务切换。由于 C8051F015没有软中断,故直接定义宏OS_TASK_SW()为函数OSCtxSw()。


2.2 OS_CPU_A.ASM文件

编译器将每个文件作为一个模块,编译模块以主名命名,称为编译模块名,用NAME 来声明。因此,应在文件头部声明NAME OS_CPU_A。


函数有程序部分和局部变量部分,它们分别放在独立的段中。在大模式下,段名声明的固定格式为 ?PR?函数名?模块名 SEGMENT CODE。因此需要将OSStartHighRdy()、OSCtxSw()、OSIntCtxSw()和OSTickISR()用上面的格式一一声明。如?PR?OSStartHighRdy?OS_CPU_A SEGMENT CODE,本模块实现的函数需要用PUBLIC声明,如PUBLIC OSStartHighRdy等。


C51将所有定义说明的数据标识符转换为大写字符,对函数则根据有无寄存器参数传送和函数是否可重入进行换名,如:void OSIntEnter(void) reentrant函数的名字OSIntEnter换成_?OSIntEnter。这些规则可从编译后的LST文件中看出。程序中声明引用的五个全局变量为OSTCBCur、OSTCBHighRdy、OSRunning、OSPrioCur、OSPrioHighRdy,声明格式是EXTRN IDATA (OSTCBCur)等。调用四个外部子程序OSTaskSwHook()、OSIntEnter()、OSIntExit()、 OSTimeTick(),固定格式为:EXTRN CODE (_?OSTaskSwHook)等。


由于C8051F的堆栈指针只有8位,只能指向内部数据区的256个字节,因此,当前运行的任务的堆栈在IDATA区,堆栈大小为40H(64字节),堆栈起点由KEIL决定。通过标号可以获得KEIL分配的SP起点,代码如下:

?STACK SEGMENT IDATA

RSEG ?STACK

OSStack:

DS 40H

OSStkStart IDATA OSStack-1

为简化子程序特定义压栈出栈宏。压栈的次序为PSW、ACC、B、DPL、DPH、R0~R7,出栈的次序与入栈相反。

PUSHALL MACRO

IRP REG, 《SW,ACC, B, DPL, DPH, 0, 1, 2, 3, 4, 5, 6, 7》

PUSH REG

ENDM

POPALL MACRO

IRP REG, 《7, 6, 5, 4, 3, 2, 1, 0, DPH, DPL, B, ACC, PSW》

POP REG

ENDM

具体函数的修改部分见本刊网络补充版(http://www.dpj.com.cn)。


2.3 OS_CPU_C.C文件

移植μC/OS-II 需要在OS_CPU_C.C中定义六个函数,而实际上需要定义的只有OSTaskStkInit()一个函数。该函数用来初始化任务的堆栈。初始状态的堆栈只须初始化?C_XBP (仿真堆栈指针)、任务地址及堆栈的长度。由于只有INC DPTR指令,故返回栈的最低地址,且最低地址处存放栈的长度,方便用汇编语言实现任务的切换。堆的大小可根据任务的实际情况自行确定,由参数 ppdata所指的值确定。

void *OSTaskStkInit (void (*task)(void *pd), void *ppdata,

void *ptos, INT16U opt) reentrant

{

OS_STK *stk;

INT8U HeapSize;

HeapSize=*(INT8U *)ppdata;

opt = opt;

stk = (OS_STK *)ptos+HeapSize+2;

*stk++ = 15;

*stk++ = (INT16U)task & 0xFF;

*stk++ = (INT16U)task 》》 8;

stk = (OS_STK *)ptos+HeapSize+2;

*--stk = (INT16U) (ptos+HeapSize-1) 》》 8;

*--stk = (INT16U) (ptos+HeapSize-1) & 0xFF;

return ((void *)stk);

}


3 可重入函数

因为51系列堆栈空间的限制, KEIL编译器没有像大系统那样使用调用堆栈。一般C语言调用过程中,会把过程的参数和使用的局部变量入栈。为了提高效率,编译器没有提供这种堆栈,而是提供一种压缩栈,每个过程被给定一个空间用于存放局部变量。过程中的每个变量都放在这个空间的固定位置,当递归调用这个过程时,会导致变量被覆盖。编译器允许将函数定义成可重入函数,由reentrant关键字指定,可重入函数可被单独保存。因为这些堆栈是模拟的,可重入函数一般都比较大,运行起来也比较慢。模拟栈不允许传递bit类型的变量,也不能定义局部位标量。移植中最好是将可能被多个任务使用的函数定义成可重入函数。


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>