单片机---STM8L移植ucosII系统

初次听说ucos还是在还大学即将毕业的时候,姐夫给我介绍他研发的产品,用的ucosII,还特别热心的给我准备了一套调试的东西和代码,当时也是没耐心,心思也没放在上面,后来也就没下文了,想起来当时还是挺无知的,有价值的东西放在面前,都没有发现,早点开始学习,没准现在也应该能在另一方面有点成就了。
在这里插入图片描述
不过学习这种事,对于普通人来说,很少是天生就能去接受,毕竟这是一件令人承受压力的过程,尤其是对于年轻人来说,就是需要一点挫折一点悔悟,才有一点积累,才能享受一点进步。我们都希望孩子从小热爱学习,其实都是那份成绩带来的虚荣在推动,很少去思考学习真正的目的。
在这里插入图片描述
直到我们进入了社会,才知道学习能够带来的巨大作用,原来,学习,是真的香,知识,真的有力量
在这里插入图片描述

言归正传
正好手里有一块STM8的单片机,前几天搭了开发环境,那就试一下移植个操作系统上去吧,想起了这个ucosII。

uC/OS II(Micro Control Operation System Two)是一个可以基于ROM运行的、可裁减的、抢占式、实时多任务内核,具有高度可移植性,特别适合于微处理器和控制器,是和很多商业操作系统性能相当的实时操作系统(RTOS)。

网上找了很多资料,大概把思路理清了。

如果用户理解了处理器和 C 编译器的技术细节,移植µC/OS-Ⅱ的工作实际上是非常简 单的。前提是您的处理器和编译器满足了µC/OS-Ⅱ的要求,并且已经有了必要工具。移植
工作包括以下几个内容: l 用#define 设置一个常量的值(OS_CPU.H)
l 声明 10 个数据类型(OS_CPU.H)
l 用#define 声明三个宏(OS_CPU.H)
l 用 C 语言编写六个简单的函数(OS_CPU_C.C)
l 编写四个汇编语言函数(OS_CPU_A.ASM)
根据处理器的不同,一个移植实例可能需要编写或改写 50 至 300 行的代码,需要的时
间从几个小时到一星期不等。
-----摘自《uCOS-II(邵贝贝).pdf》

万事俱备,开干
在这里插入图片描述

代码准备

首先创建好工程文件夹,里面定义好各个模块代码放置的文件夹,我是如下定义的
在这里插入图片描述
这里只是存放用,后续的工程,我们会在工程中建立对应的group,添加上对应的文件
然后把所用的文件拷贝过去,其中stm8l的标准库,ucosII的源码,都是官方提供的,无需修改,只需要放过去即可,俗称,拷贝。
在这里插入图片描述

下面是文件图
在这里插入图片描述
因为用到了定时器4做中断,所以这里用了clk和tim4,如果用到其他标准库,例如GPIO等,就还是放在这里就可以。
在这里插入图片描述在这里插入图片描述
这里,我们记得将源码中的os_cfg_r.h修改为os_cfg.h
在这里插入图片描述
stm8l15x_conf.h中注释掉其他头文件,只保留两个我们用到的c文件的头文件
在这里插入图片描述

其他文件,我们稍后再添加。
在这里插入图片描述

创建工程

然后我们打开IAR,创建一个新的工程,然后创建对应group,并且添加好对应的c文件。这里只需要添加c文件即可。
在这里插入图片描述
其中main文件为测试ucos创建任务写的,后面我们添加内容。
然后我们修改工程的芯片类型
在这里插入图片描述
增加头文件路径及宏定义
在这里插入图片描述
好了,准备开始接受error和warnnings的冲击吧
在这里插入图片描述

编译过程

其中,我们为移植工作做的修改,全部放在mywork文件下,这样就显得比较清楚

开始编译,

错误1

在这里插入图片描述
增加一个app_cfg.h放在mywork文件夹下。

错误2,(如果前面我们修改重命名之后,就不会在出现了)

在这里插入图片描述
重命名原有的os_cfg_r.h为os_cfg.h

错误3

在这里插入图片描述
新建一个空文件os_cpu.h放在mywork文件夹下

错误4

101个错误,显示大量宏定义缺失,
在这里插入图片描述
在os_cpu.h中增加宏定义


#ifndef  __OS_CPU_H
#define  __OS_CPU_H

#include <intrinsics.h>
#ifdef   OS_CPU_GLOBALS
#define  OS_CPU_EXT
#else
#define  OS_CPU_EXT  extern
#endif

/*********************************************************************************************************
  Date types(Compiler specific)  数据类型(和编译器相关)                
*********************************************************************************************************/
typedef unsigned char	BOOLEAN;                                        /*  Boolean 布尔变量            */
typedef unsigned char	INT8U;                                          /*  Unsigned  8 bit quantity    */                       
typedef signed   char	INT8S;                                          /*  Signed    8 bit quantity    */                         
typedef unsigned short	INT16U;                                         /*  Unsigned 16 bit quantity    */
typedef signed   short	INT16S;                                         /*  Signed   16 bit quantity    */
typedef unsigned long	INT32U;                                         /*  Unsigned 32 bit quantity    */
typedef signed   long	INT32S;                                         /*  Signed   32 bit quantity    */
typedef float           FP32;                                           /*  Single precision floating */
typedef double          FP64;                                           /*  Double precision floating */

typedef unsigned char	OS_STK;                                         /*  Each stack entry is 32-bit */
typedef unsigned char	OS_CPU_SR;                                      /*  Define size of CPU status   register (PSR = 32 bits)    */

typedef signed char		int8;
typedef unsigned char	uint8;
typedef signed short	int16;
typedef unsigned short	uint16;
typedef	signed long		int32;
typedef unsigned long	uint32;

/*********************************************************************************************************
  Other definitions  其他定义         
*********************************************************************************************************/
//栈指针增长方向
#define  OS_STK_GROWTH        1        
//任务切换 是在 uC/OS-II 从低优先级切换到高优先级任务,时调用的,通过引发一次中断来进行任务切换,所以这个宏定义是一条软中断指令   
#define  OS_TASK_SW()         OSCtxSw()
/*********************************************************************************************************
  Method of critical section management  临界区管理方法                
*********************************************************************************************************/
#define  OS_CRITICAL_METHOD  3

#if OS_CRITICAL_METHOD == 3
#define OS_ENTER_CRITICAL() cpu_sr=CriticalEnter()
#define OS_EXIT_CRITICAL()  CriticalExit(cpu_sr)
#endif   

//这里声明了几个函数,后续会定义
#if __CODE_MODEL__==__SMALL_CODE_MODEL__
void __near_OSCtxSw(void);
void __near_OSIntCtxSw(void);
void __near_OSStartHighRdy(void);
#define OSCtxSw          __near_OSCtxSw
#define OSIntCtxSw       __near_OSIntCtxSw
#define OSStartHighRdy   __near_OSStartHighRdy
#else
void __far_OSCtxSw(void);
void __far_OSIntCtxSw(void);
void __far_OSStartHighRdy(void);
#define OSCtxSw          __far_OSCtxSw
#define OSIntCtxSw       __far_OSIntCtxSw  
#define OSStartHighRdy   __far_OSStartHighRdy
#endif
                  
#endif

错误5

在这里插入图片描述
在app_cfg.h中增加

#ifndef APP_CFG_H 
#define APP_CFG_H

#define OS_TASK_TMR_PRIO (OS_LOWEST_PRIO - 2)
#endif

这几个问题才是小菜
在这里插入图片描述

关键步骤

到这一步,就需要我们自己实现(参考别人的代码实现)了
其中汇编函数:

函数含义
OSIntCtxSw中断服务程序切换准备
OSStartHighRdy这个函数由 OSStart()函数调用,作用是使就绪态任务中优先级最高的任务开始运行。
OSCtxSw中断服务程序切换
OSTickISR提供一个周期性的时钟源,来实现时间的延迟和超时功能。名字可以随意定,我们用的是_interrupt_27

C语言函数:

函数含义
OSSTaskStkInit由 OSTaskCreat 函数调用,作用是初始化任务的堆栈结构
关于CPU 钩子函数有关的函数

我们在mywork下创建如下文件
在这里插入图片描述
首先在os_cpu_c.c中,定义相关的C语言函数定义

#include    <intrinsics.h>
#include    "os_cpu.h"
#include    "os_cfg.h"
#include    "ucos_ii.h"
#include    "stm8l15x_conf.h"
#define     OS_CPU_GLOBALS
INT8U __zero_in_ram__=0;
/*********************************
  Local variables 局部变量
**********************************/
#if OS_TMR_EN > 0
    static INT16U OSTmrCtr;
#endif

#if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203
void OSInitHookBegin (void)
{
    #if OS_TMR_EN > 0
        OSTmrCtr = 0;
    #endif
}
#endif
#if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203
void OSInitHookEnd (void)
{
}
#endif
#if OS_CPU_HOOKS_EN > 0
void OSTaskCreateHook (OS_TCB  *ptcb)
{
    (void)ptcb; /*  Prevent compiler warning      防止编译警告                */
}
#endif

#if OS_CPU_HOOKS_EN > 0
void  OSTaskDelHook (OS_TCB  *ptcb)
{
    (void)ptcb;    /*  Prevent compiler warning      防止编译警告                */
}
#endif
#if OS_CPU_HOOKS_EN > 0 && OS_VERSION >= 251
void OSTaskIdleHook (void)
{
}
#endif
#if OS_CPU_HOOKS_EN > 0
void OSTaskStatHook (void)
{
}
#endif
OS_STK  *OSTaskStkInit (void (*task)(void *pd), void *p_arg, OS_STK *ptos, INT16U opt)
{
    INT8U  *psoft_stk;
    INT32U  tmp;

    (void)opt;                          
    psoft_stk     = (INT8U *)ptos;
    tmp           = (INT32U)task;
                                            
    *psoft_stk--  = (INT8U)(tmp & 0xFF);       //PCL
    tmp         >>= 8;
    
    *psoft_stk--  = (INT8U)(tmp & 0xFF);       //PCH
    tmp         >>= 8;
    
    *psoft_stk--  = (INT8U)(tmp & 0xFF);       //PCE
    tmp         >>= 8;
          
    *psoft_stk--  = (INT8U)0x01;               //YL
    *psoft_stk--  = (INT8U)0x02;               //YH
    
    *psoft_stk--  = ((INT16U)p_arg)&0XFF;       //XL
    *psoft_stk--  = (((INT16U)p_arg)>>8)&0XFF;  //XH
    
    *psoft_stk--  = (INT8U)0x05;                //A
    *psoft_stk--  = (INT8U)0x20;                //CC
    
    *psoft_stk--  = (INT8U)0x00;                //?B0
    *psoft_stk--  = (INT8U)0x01;                //?B0
    *psoft_stk--  = (INT8U)0x02;                //?B0
    *psoft_stk--  = (INT8U)0x03;                //?B0
    *psoft_stk--  = (INT8U)0x04;                //?B0
    *psoft_stk--  = (INT8U)0x05;                //?B0
    *psoft_stk--  = (INT8U)0x06;                //?B0
    *psoft_stk--  = (INT8U)0x07;                //?B0
    
    *psoft_stk--  = (INT8U)0x08;                //?B0
    *psoft_stk--  = (INT8U)0x09;                //?B0
    *psoft_stk--  = (INT8U)0x10;                //?B0
    *psoft_stk--  = (INT8U)0x11;                //?B0
    *psoft_stk--  = (INT8U)0x12;                //?B0
    *psoft_stk--  = (INT8U)0x13;                //?B0
    *psoft_stk--  = (INT8U)0x14;                //?B0
    *psoft_stk--  = (INT8U)0x15;                //?B0    
    
    return ((OS_STK *)psoft_stk);
}

void OSTaskSwHook (void)
{
}

#if (OS_CPU_HOOKS_EN > 0) && (OS_VERSION > 203)
void OSTCBInitHook (OS_TCB  *ptcb)
{
    (void)ptcb;       /*  Prevent compiler warning     防止编译警告                */
}
#endif

#if ((OS_CPU_HOOKS_EN > 0) && (OS_TIME_TICK_HOOK_EN > 0)) || (OS_VERSION < 283)
void OSTimeTickHook (void)
{
    #if OS_TMR_EN > 0
        OSTmrCtr++;
        if (OSTmrCtr >= (OS_TICKS_PER_SEC / OS_TMR_CFG_TICKS_PER_SEC)) {
            OSTmrCtr = 0;
            OSTmrSignal();
 }
    #endif
}
#endif

然后在os_cpu_a.s实现其汇编的三个函数,这里用到的汇编方式,根据__CODE_MODEL__不同定义了两组函数,最终只有一组起作用,根据你在IAR中的code model选项来决定的

#include "os_cpu_a.inc"
      
        EXTERN OSTaskSwHook
        EXTERN OSRunning
        EXTERN OSTCBHighRdy
        EXTERN OSTCBCur
        EXTERN OSPrioCur
        EXTERN OSPrioHighRdy
        EXTERN OSIntEnter
        EXTERN OSIntExit
        EXTERN OSTimeTick
        
        PUBLIC __far_OSStartHighRdy
        PUBLIC __far_OSCtxSw
        PUBLIC __far_OSIntCtxSw
        
        PUBLIC __near_OSStartHighRdy
        PUBLIC __near_OSCtxSw
        PUBLIC __near_OSIntCtxSw
        
        EXTERN __zero_in_ram__
            
        SECTION `.far_func.text`:CODE:ROOT(0)
__far_OSStartHighRdy:
         CALLX	OSTaskSwHook	           //OSTaskSwHook()
	 MOV	L:OSRunning,#1	           //OSRunning=1
       
         LOAD_NEW_STK_PTR
         RESTORE_REGS
         RETX
        
        SECTION `.far_func.text`:CODE:ROOT(0)
__far_OSCtxSw: 
	SAVE_REGS
        SAVE_OLD_STK_PTR

	CALLX	OSTaskSwHook		      //OSTaskSwHook()
        
        MOV     L:OSPrioCur,L:OSPrioHighRdy   //OSPrioCur=OSPrioHighRdy
        LDW     X, L:OSTCBHighRdy 
        LDW     L:OSTCBCur, X               //OSTCBCur=OSTCBHighRdy
             
        LOAD_NEW_STK_PTR
        RESTORE_REGS      
        RETX
 
        SECTION `.far_func.text`:CODE:ROOT(0)
__far_OSIntCtxSw:
	CALLX	  OSTaskSwHook			 //OSTaskSwHook()
        
        MOV    L:OSPrioCur,L:OSPrioHighRdy    //OSPrioCur=OSPrioHighRdy
        LDW    X, L:OSTCBHighRdy 
        LDW    L:OSTCBCur, X                  //OSTCBCur=OSTCBHighRdy
        
        LOAD_NEW_STK_PTR
        INT_RESTORE_REGS
        
        IRET
        
        SECTION `.near_func.text`:CODE:ROOT(0)
__near_OSStartHighRdy:
         CALLX	OSTaskSwHook	                 //OSTaskSwHook()
	 MOV	L:OSRunning,#1	                 //OSRunning=1
       
         LOAD_NEW_STK_PTR
         RESTORE_REGS
         RETX
        
        SECTION `.near_func.text`:CODE:ROOT(0)
__near_OSCtxSw: 
	SAVE_REGS
        SAVE_OLD_STK_PTR

	CALLX	OSTaskSwHook		          //OSTaskSwHook()
        
        MOV     L:OSPrioCur,L:OSPrioHighRdy       //OSPrioCur=OSPrioHighRdy
        LDW     X, L:OSTCBHighRdy 
        LDW     L:OSTCBCur, X                     //OSTCBCur=OSTCBHighRdy
             
        LOAD_NEW_STK_PTR
        RESTORE_REGS      
        RETX
 
         SECTION `.near_func.text`:CODE:ROOT(0)
__near_OSIntCtxSw:
	CALLX	OSTaskSwHook			   //OSTaskSwHook()
        
        MOV     L:OSPrioCur,L:OSPrioHighRdy      //OSPrioCur=OSPrioHighRdy
        LDW     X, L:OSTCBHighRdy 
        LDW     L:OSTCBCur, X                    //OSTCBCur=OSTCBHighRdy
        
        LOAD_NEW_STK_PTR
        INT_RESTORE_REGS 
        
        IRET        
        
        END
 

os_cpu_a.inc中定义了一组操作。
periph_ticks.s中定义了一个中断处理函数_interrupt_27。

最后,我们打开inline函数许可,这里调整为High。
在这里插入图片描述
如果遇到这个错误在这里插入图片描述
关闭debug,IS_DEBUG_EN改为0u
在这里插入图片描述
系统部分就编译通过。哈哈哈哈。
在这里插入图片描述

系统测试

然后我们写一个测试主函数,创建两个任务,看能否顺利切换。

void task0( void * pdata )
{
	int test=0;
	while(1)
	{    
		test++;
		OSTimeDly(LONG_DELAY_TICKS); 
        test++;
	}
}

void task1(void * pdata )
{
	int test=0;
	while(1)
	{    
		test++;
        OSTimeDly(LONG_DELAY_TICKS); 
		test++;
	}
}
int main()
{
	TIM4_Init();
	OSInit();
	OSTaskCreate(task0,(void *)OS_TASK_0_STK_SIZE, &Task0Stack[OS_TASK_0_STK_SIZE-1], OS_TASK_0_PRIO );
	OSTaskCreate(task1,(void *)OS_TASK_1_STK_SIZE, &Task1Stack[OS_TASK_1_STK_SIZE-1], OS_TASK_1_PRIO );
	OSStart();
	return	0;
}

我们开启stlink调试模式
在这里插入图片描述
连接好单片机,就可以下载程序进行调试了。设置两个断点,运行程序查看
在这里插入图片描述
在这里插入图片描述
发现能够顺利切换进程。
在这里插入图片描述

补充

内容大部分为实际操作结果,涉及汇编的部分,代码还在理解当中,如果有错误之处还请多多担待。后续还会补充说明。

所有代码均可下载
传送门

在这里插入图片描述

写在最后

最近有位老师,她质疑三十万。
在这里插入图片描述

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胖哥王老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值