UCOSIII学习笔记

μC/OS-II由Micrium公司提供,是一个可移植、可固化的、可裁剪的、占先式多任务实时内核,它适用于多种微处理器,微控制器和数字处理芯片(已经移植到超过100种以上的微处理器应用中)。同时,该系统源代码开放、整洁、一致,注释详尽,适合系统开发。 μC/OS-II已经通过联邦航空局(FAA)商用航行器认证,符合航空无线电技术委员会(RTCA)DO-178B标准。
首先,来附图,我相信只要刚刚认识ucosii的人,都见过这种类型的图了;而且版本不一
在这里插入图片描述

可能有人还不知道什么是BSP,Board Support Package,板级支持包;这样的话,一看我们的代码就可以分为四部分了;

为了有点逻辑,我从uC/OS-II Source开始说起;这部分代码大家都知道是不用修改的,但是我们至少要知道他依赖的外部头文件都有哪些;

1.配置文件修改
±-----------------------------------------
|core: os_core.c
| os: os_flag.c os_mbox.c
| os_mem.c os_mutex.c
| os_q.c os_sem.c
| os_task.c os_time.c
| os_tmr.c
|head: ucos_ii.h
±-----------------------------------------
理论上这几个文件我们完全不用修改!但是,他依赖外部的一些头文件;
app_cfg.h //应用程序的一些功能,目测这里是不需要的;但是他已经写了,那我们就保留吧;所以我们就要先建立一个空的app_cfg.h文件
os_cfg.h //做一些os功能的开关,我们可以由此来对系统进行一些裁剪;保留我们需要的功能;
os_cpu.h //为了适应os,我们必须把os与cpu之间建立一个桥梁;就是通过os_port来进行建立的;
2.cpu文件修改
os_ports 在uCOS-II\Ports\ARM-Cortex-M3\Generic\IAR
os_cpu_c.c //有两个地方要说下:1:在stm32的启动代码里面已经有一些功能函数了,所以我们要把他进行删除,以及他所附带的函数;并在os_cpu.h中注释点他们的外部声明;2:部分宏定义也删除了;(也可以不用修改删除)
#if 0
#define OS_CPU_CM3_NVIC_ST_CTRL (*((volatile INT32U )0xE000E010uL)) / SysTick Ctrl & Status Reg. /
#define OS_CPU_CM3_NVIC_ST_RELOAD (
((volatile INT32U )0xE000E014uL)) / SysTick Reload Value Reg. /
#define OS_CPU_CM3_NVIC_ST_CURRENT (
((volatile INT32U )0xE000E018uL)) / SysTick Current Value Reg. /
#define OS_CPU_CM3_NVIC_ST_CAL (
((volatile INT32U )0xE000E01CuL)) / SysTick Cal Value Reg. /
#define OS_CPU_CM3_NVIC_PRIO_ST (
((volatile INT8U )0xE000ED23uL)) / SysTick Handler Prio Reg. */

#define OS_CPU_CM3_NVIC_ST_CTRL_COUNT 0x00010000uL /* Count flag. /
#define OS_CPU_CM3_NVIC_ST_CTRL_CLK_SRC 0x00000004uL /
Clock Source. /
#define OS_CPU_CM3_NVIC_ST_CTRL_INTEN 0x00000002uL /
Interrupt enable. /
#define OS_CPU_CM3_NVIC_ST_CTRL_ENABLE 0x00000001uL /
Counter mode. /
#define OS_CPU_CM3_NVIC_PRIO_MIN 0xFFu /
Min handler prio. */
#endif
#if 0
void OS_CPU_SysTickHandler (void)
void OS_CPU_SysTickInit (INT32U cnts)
#endif

os_cpu.h 同样把下面几个外部声明的函数给去掉;
#if 0
/* See OS_CPU_C.C /
void OS_CPU_SysTickHandler(void); //系统定时中断处理函数,时钟节拍函数
/OS_CPU_SysTickHandler() 在 os_cpu_c.c 中定义,是 SysTick 中断的中断处理函 数,而在 stm32f10x_it.c 中已经有该中断函数的定义 SysTick_Handler(),这里也就不需要了。(没有就需要)/
void OS_CPU_SysTickInit(void); //系统 SysTick 定时器初始化
/OS_CPU_SysTickInit() 定义在 os_cpu_c.c 中,用于初始化 SysTick 定时器,它 依赖于 OS_CPU_SysTickClkFreq(),也要注释掉。不编写就不注释/
/
See BSP.C /
INT32U OS_CPU_SysTickClkFreq(void); //返回 SysTick 定时器的时钟频率
/OS_CPU_SysTickClkFreq() 定义在 BSP.C 中,此函数我们自己会编写,把它注释,不编写就不注释/
#endif
3.汇编文件修改
os_cpu_a.asm
这部分是汇编代码;由于他里面有部分指令集不适合stm32(匹配),所以我们要稍微改下:
1、将所有的PUBLIC 改为 EXPORT(由于编译器的原因)
2、把自己对齐部分也改下,也是因为指令集不匹配;
; RSEG CODE:CODE:NOROOT(2)
AREA |.text|, CODE, READONLY, ALIGN=2
THUMB
REQUIRE8
PRESERVE8
;CODE表示代码段,READONLY表示只读(缺省) 361. ;ALIGN=2 表示 4 字节对齐。若 ALIGN=n,这 2^n 对齐 THUMB ;Thumb REQUIRE8 ;指定当前文件要求堆栈八字节对齐 PRESERVE8 ;令指定当前文件保持堆栈八字节对齐
注:AREA 一点不能顶头写,这是规定,不然回编译出错;
os_dbg.c
#define OS_COMPILER_OPT __root
这个不兼容,需要把它改下;这个问题也是由编译器不同而产生的。
#define OS_COMPILER_OPT //__root
4. 将ST的官方库导进去即可;
5. 修改库文件
我们也必须要注意,因为我们的移植是使用标 准外设库 CMSIS 中 startup_stm32f10x_hd.s 作为启动文件的,还没有设置 OS_CPU_SysTickHandler。而 startup_stm32f10x_hd.s 文件中,PendSV 中断向量名为 PendSV_Handler,因此只需把所有出现 PendSV_Handler 的地方替换成 OS_CPU_PendSVHandler 即可
startup_stm32f10x_hd.s(系统一开始的启动文件,由此关联到内核)
将 PendSV_Handler 替换成 OS_CPU_PendSVHandler(使用内核的)
原因:SVC(系统服务调用,亦简称系统调用)和 PendSV(可悬起系统调用),它们多用 在上了操作系统的软件开发中。 SVC 用于产生系统函数的调用请求,SVC 异常是必须在执行 SVC 指令后立即得到响应 的。PendSV(可悬起的系统调用)则不同,它是可以像普通的中断一样被悬起的(不像 SVC 那样会上访)。OS 可以利用它“缓期执行”一个异常——直到其它重要的任务完成后才执 行动作。悬起 PendSV 的方法是:手工往 NVIC 的 PendSV 悬起寄存器中写 1。悬起后, 如果优先级不够高,则将缓期等待执行。 PendSV 的典型使用场合是在上下文切换时(在不同任务之间切换)。例如,一个系 统中有两个就绪的任务,上下文切换被触发的场合可以是: 执行一个系统调用l 系统滴答定时器(SysTick)中断。(轮转调度中需要)
stm32f10x_it.c
加头文件: ucos_ii.h,并添加如下代码(如果前面没有注释掉这个函数,这里就不用写,使用前面的):
/
*

  • @brief This function handles SysTick Handler.
  • @param None
  • @retval None
    */
    void SysTick_Handler(void)
    {
    OSIntEnter();
    OSTimeTick();
    OSIntExit();
    }
    原因:系统时钟(必须),当系统时钟节拍到了,就进入查询,查看延时的任务以及就绪的任务,主要用于任务切换
    os_cfg.h对部分功能进行剪裁(也可以不剪接);
    #define OS_FLAG_EN0
    #define OS_MBOX_EN 0
    #define OS_MEM_EN 0
    #define OS_MUTEX_EN 0
    #define OS_Q_EN 0
    #define OS_SEM_EN 0
    #define OS_TMR_EN 0
    #define OS_DEBUG_EN 0
    #define OS_APP_HOOKS_EN 0
    #define OS_EVENT_MULTI_EN 0
    这样算是简单系统以及移植完成了,下面就是写自己的app了;

这样算是简单系统以及移植完成了,下面就是写自己的app了;我直接附上自己的main.c代码;

main.c

#include “stm32f10x.h”
#include “stm32f10x_conf.h”
#include “ucos_ii.h”

#define ON 1
#define OFF 0
#define LED1(opt) ((opt) ? (GPIOD->BRR |= 1<<3):(GPIOD->BSRR |= 1<<3))
#define LED2(opt) ((opt) ? (GPIOD->BRR |= 1<<6):(GPIOD->BSRR |= 1<<6))
#define LED3(opt) ((opt) ? (GPIOB->BRR |= 1<<5):(GPIOB->BSRR |= 1<<5))

#define SystemFrequency 72000000
#define STARTUP_TASK_PRIO 4
#define STARTUP_TASK_STK_SIZE 80

void SysTick_init(void)
{
SysTick_Config(SystemFrequency/OS_TICKS_PER_SEC);
}

void LED_Init()
{
RCC->APB2ENR |= (1<<3)|(1<<5);
GPIOB->CRL &= ~(0xff<<20);
GPIOB->CRL |= 0x33<<(4*5);

GPIOD->CRL &= ~(0xff<<(4*3));
GPIOD->CRL &= ~(u32)((u32)0xff<<(4*6));
GPIOD->CRL |= 0x33<<(4*3);
GPIOD->CRL |= 0x33<<(4*6);LED1(OFF);
LED2(OFF);
LED3(OFF);

}
void TestLed1(void *p_arg)
{
SysTick_init();
while(1)
{
LED1(ON);
OSTimeDlyHMSM(0,0,1,0);
LED1(OFF);
OSTimeDlyHMSM(0,0,1,0);
}
}
void TestLed2(void *p_arg)
{
SysTick_init();
while(1)
{
LED2(ON);
OSTimeDlyHMSM(0,0,0,500);
LED2(OFF);
OSTimeDlyHMSM(0,0,0,500);
}
}
void TestLed3(void *p_arg)
{
SysTick_init();
while(1)
{
LED3(ON);
OSTimeDlyHMSM(0,0,0,100);
LED3(OFF);
OSTimeDlyHMSM(0,0,0,100);
}
}
static OS_STK task_testled1[STARTUP_TASK_STK_SIZE];
static OS_STK task_testled2[STARTUP_TASK_STK_SIZE];
static OS_STK task_testled3[STARTUP_TASK_STK_SIZE];
int main()
{
LED_Init();
OSInit();
OSTaskCreate(TestLed1,(void *)0,&task_testled1[STARTUP_TASK_STK_SIZE-1],STARTUP_TASK_PRIO);
OSTaskCreate(TestLed2,(void *)0,&task_testled2[STARTUP_TASK_STK_SIZE-1],STARTUP_TASK_PRIO-1);
OSTaskCreate(TestLed3,(void *)0,&task_testled3[STARTUP_TASK_STK_SIZE-1],STARTUP_TASK_PRIO-2);
OSStart();
return 0;
}

菜鸡儿的架构师之路.
原创文章 6获赞 8访问量 5488
关注私信
展开阅读全文