百为STM32开发板UCOSII移植步骤
一、准备源码
本例在百为 3.5固件库模版.rar和在ucos官网下载的Micrium_uC-Eval-STM32F107_uCOS-II.zip的基础上进行移植
这里采用Micrium_uC-Eval-STM32F107_uCOS-II.zip,是因为ucos官网上最新的源码ucos2.92在cortex-m3上的移植只提供了这个。
ucos移植到其他CPU只涉及到以下几个文件:
os_cpu.h
os_cpu_a.asm
os_cpu_c.c
我们百为开发板上用的CPU是STM32F103ZET6,和STM32F107上差不多的,所以这三个文件可以直接拿过来用
二、建立工程,并建立组,把相关文件添加到工程的组里,移植、编译工程
1、把Micrium_uC-Eval-STM32F107_uCOS-II.zip里面
Micrium_uC-Eval-STM32F107_uCOS-II\Micrium\Software\下面的uCOS-II目录拷贝到工程目录下,如下图示:
2、添加uCOS-II/Ports,uCOS-II/Source两个组,如下图示:
3、把Ports和Source目录下的文件添加到工程里,如下图示:
4、并把相关头文件路径加入到工程里,如下图示:
5、编译工程,发现还缺少os_cfg.h,includes.h等文件,在目录Micrium_uC-Eval-STM32F107_uCOS-II\Micrium\Software\uC-CPU\ARM-Cortex-M3\RealView下面找到这两个文件,
拷贝到工程目录下面。这里我新建了一个Cfg目录,存放这两个文件。并把这两个头文件所在路径加入到工程。
注释掉uCOS_II.H里的app_cfg.h
//#include <app_cfg.h>
编译出现错误
..\..\uCOS-II\Source\os_tmr.c(899): error: #20: identifier "OS_TASK_TMR_PRIO" is undefined
这个OS_TASK_TMR_PRIO在app_cfg.h里定义的,我们没加进去,所以报错。把os_cfg.h里的宏开关OS_TMR_EN关掉就可以了:
#define OS_TMR_EN 1 /* Enable (1) or Disable (0) code generation for TIMERS */
改为
#define OS_TMR_EN 0 /* Enable (1) or Disable (0) code generation for TIMERS */
继续编译出现下面错误:
表示很多xxxHook和OSDebugInit函数没有定义,同样我们把OS_APP_HOOKS_EN和OS_DEBUG_EN宏开关关掉。
#define OS_APP_HOOKS_EN 0 /* Application-defined hooks are called from the uC/OS-II hooks */
#define OS_DEBUG_EN 0 /* Enable(1) debug variables
然后再编译就可以通过了。
6、给系统增加时钟节拍,这里由STM32的systick定时器提供。
在os_cpu_c.c里面已经给我们提供好了接口,但是它对SysTick的初始化有点烦琐,这里我们用库函数只要一行代码就能实现。
初始化:
SysTick_Config(SystemCoreClock / 1000); //SysTick 1毫秒产生一次中断
systick中断服务函数:
void SysTick_Handler(void)
{
OS_CPU_SR cpu_sr;
OS_ENTER_CRITICAL(); /* Tell uC/OS-II that we are starting an ISR */
OSIntNesting++;
OS_EXIT_CRITICAL();
OSTimeTick(); /* Call uC/OS-II's OSTimeTick() */
OSIntExit(); /* Tell uC/OS-II that we are leaving the ISR */
}
另外,还要在启动代码startup_stm32f10x_hd.s里把PendSV_Handler替换成OS_CPU_PendSVHandler,提供系统调用接口。不然系统启动时会跑到OSStartHang,然后死循环在那里。
这步比较容易忽略,要注意。
至此,UCOSII移植已经完成了,下面开始编写UCOSII应用。
三、编写简单的UCOSII应用程序
1、UCOSII应用程序的组成
(1)必须先调用OSInit()对UCOSII进行初始化。
(2)调用OSTaskCreate或OSTaskCreateExt创建任务。(我们需要增加或修改的只有这部分)
(3)调用OSStart()启动任务调度。
我们来看下OSTaskCreate 函数的原型:
INT8U OSTaskCreate (void (*task)(void *p_arg),
void *p_arg,
OS_STK *ptos,
INT8U prio);
其中:
task是指向任务函数的指针
p_arg传递给任务函数的参数的指针,一般设为0
ptos是分配给任务的堆栈的栈顶指针
prio是任务的优先级
2、编写含有三个简单任务的UCOS应用程序
#define Task1_PRIO 15
#define Task2_PRIO 16
#define Task3_PRIO 17
#define TASK1_STACK_SIZE 64
#define TASK2_STACK_SIZE 64
#define TASK3_STACK_SIZE 64
static OS_STK Task1_Stack[TASK1_STACK_SIZE];
static OS_STK Task2_Stack[TASK2_STACK_SIZE];
static OS_STK Task3_Stack[TASK3_STACK_SIZE];
void Task1_Func(void *p_arg) //任务1代码
{
while(1)
{
printf("task1\n\r");
STM_EVAL_LEDOn(LED1); //点亮LED1
STM_EVAL_LEDOff(LED2);
STM_EVAL_LEDOff(LED3);
OSTimeDly(200); //延时200ms
}
}
void Task2_Func(void *p_arg) //任务2代码
{
while(1)
{
printf("**********task2\n\r");
STM_EVAL_LEDOn(LED2); //点亮LED2
STM_EVAL_LEDOff(LED1);
STM_EVAL_LEDOff(LED3);
OSTimeDly(400); //延时400ms
}
}
void Task3_Func(void *p_arg) //任务3代码
{
while(1)
{
printf("********************task3\n\r");
STM_EVAL_LEDOn(LED3); //点亮LED3
STM_EVAL_LEDOff(LED1);
STM_EVAL_LEDOff(LED2);
OSTimeDly(800); //延时800ms
}
}
void App_TaskStart(void)
{
OSInit();
SysTick_Config(SystemCoreClock / OS_TICKS_PER_SEC); //初始化SysTick系统时钟
OSTaskCreate(Task1_Func, (void *)0, (OS_STK *)&Task1_Stack[TASK1_STACK_SIZE-1], Task1_PRIO); //创建任务1
OSTaskCreate(Task2_Func, (void *)0, (OS_STK *)&Task2_Stack[TASK2_STACK_SIZE-1], Task2_PRIO); //创建任务2
OSTaskCreate(Task3_Func, (void *)0, (OS_STK *)&Task3_Stack[TASK3_STACK_SIZE-1], Task3_PRIO); //创建任务3
OSStart();
}
|