准备资料:
Micrium官网上已经有官方移植版本。但这些版本具体是怎么移植出来的,现在来讲讲我的移植过程,希望对读者有帮助。 以下为链接地址:
http://micrium.com/downloadcenter/download-results/?searchterm=mp-uc-os-ii&supported=true
在该页面下找到如下:
下载后解压,可以看到该目录下的文件:
开始搭建:
说明:本工程是在上一篇文章:http://blog.csdn.net/ballack_linux/article/details/40003503的基础上继续搭建的.
资源下载地址是http://download.csdn.net/detail/ballack_linux/8028111。
下载后解压,如下图:
1、在STM32_TEST下建立一个子文件夹UCOS-II,在UCOS-II下再建立两个子文件夹Ports和Source。
将Micrium_STM32xxx_uCOS-II\Micrium\Software\uCOS-II\Ports\ARM-Cortex-M3\Generic\RealView下的文件拷贝到STM32_TEST\UCOS-II\Ports下,将Micrium_STM32xxx_uCOS-II\Micrium\Software\uCOS-II\Source下的文件拷贝到STM32_TEST\UCOS-II\Source下。如下图:
2、打开KEIL工程,将UCOS-II下面的源文件添加进工程中,如下图:
并且将UCOS-II头文件的路径添加到工程中,如下图:
点击OK后,编译,可以看到报错:
可以看到,由于工程中没有app_cfg.h这个文件,所以才报此错误,此文件是用来定义用户自己的任务栈大小和任务优先级等,那么我们可以直接在STM32_TEST\USER\下建一个新文件app_cfg.h,先不添加任何内容,再次编译,可以看到又报了一个错误:
问题是找不到文件os_cfg.h文件,该文件是用来给用户定制自己的系统功能模块的,用户可以选择是否需要消息邮箱、消息队列、信号量、互斥信号量等功能。那么此时将Micrium_STM32xxx_uCOS-II\Micrium\Software\EvalBoards\ST\STM3210B-EVAL\RVMDK\OS-Probe 路径下的os_cfg.h拷贝到STM32_TEST\USER\下。再次编译,还是报错,如下:
在工程中查找App_TCBInitHook,可以看到如下:
继续查找OS_APP_HOOKS_EN,可以在os_cfg.h文件中找到该宏的定义:
可以先将该宏OS_APP_HOOKS_EN定义为0,但此时你会发现改不了,这是为什么呢,因为该文件的属性为“只读”,如图:
将“只读”复选框的勾去掉即可修改。修改后如图:
继续编译,还是报错,这次是什么错误呢?
os_cpu_c.c文件中的OS_CPU_SysTickClkFreq()是在Micrium_STM32xxx_uCOS-II\Micrium\Software\EvalBoards\ST\STM3210B-EVAL\RVMDK\BSP中的bsp.c定义的,而本文移植中并未用到bsp.c,而OS_CPU_SysTickInit()函数是依赖于OS_CPU_SysTickClkFreq()的,此函数主要用来设置SysTick系统时钟的,后面我们会自己实现,所以直接将该函数注释掉即可。提醒一下,可以将STM32_TEST\UCOS-II\Ports下的所有文件的“只读”属性都去掉,以方便修改。注释后如下:
编译,通过了!!!谢天谢地,不容易啊~~~~~ 不过还有几个地方需要注意:
os_cpu_c.c文件中OS_CPU_SysTickHandler()是SysTick中断的处理函数,其实在STM32_TEST\USER\stm32f10x_it.c文件中已经有SysTick中断函数的定义SysTick_Handler(),在STM32_TEST\CORE\startup_stm32f10x_md.s下也是定义的SysTick_Handler,而且该函数经常会做修改,故在此把OS_CPU_SysTickHandler()函数也注释掉,后面我们在平台中自己实现SysTick_Handler()函数。注释后如下图:
3、在STM32中所有任务切换都被放到PendSV的中断处理函数中去做了,因此任务切换只需简单的触发PendSV中断即可。
在STM32_TEST\CORE\startup_stm32f10x_md.s中定义了PendSV_Handler,而在STM32_TEST\UCOS-II\Ports\os_cpu_a.asm中却定义的是OS_CPU_PendSVHandler,其实它们是同一个函数,因此将os_cpu_a.asm中的所有OS_CPU_PendSVHandler都替换成PendSV_Handler。并且将STM32_TEST\USER\stm32f10x_it.c中的PendSV_Handler定义体注释掉,如下图:
再次编译,通过!
4、接下来,就剩下两个函数没有实现了,一个是设置系统时钟SysTick的函数,一个是其中断处理函数SysTick_Handler()函数。在STM32_TEST.c中添加此函数:
static void SetSysTick()
{
RCC_ClocksTypeDef rcc_clocks;
RCC_GetClocksFreq(&rcc_clocks);
SysTick_Config(rcc_clocks.HCLK_Frequency/OS_TICKS_PER_SEC);
}
在STM32_TEST\USER\stm32f10x_it.c中仿照os_cpu_c.c文件中的OS_CPU_SysTickHandler()函数写:
#include "ucos_ii.h"
void SysTick_Handler(void)
{
OSIntEnter(); //进入中断,实际上就是执行了OSIntNesting++;
OSTimeTick(); //调用ucos的时钟服务程序,ucos的时钟滴答函数
OSIntExit(); //可能会触发中断级的任务切换
}
5、至此,移植完毕。可以在STM32_TEST.c和app_cfg.h中添加应用程序了。
app_cfg.h中添加如下代码:
#ifndef __APP_CFG_H__
#define __APP_CFG_H__
#define APP_TASK_START_PRIO 5
#define APP_TASK_USER_PRIO 6
#define APP_TASK_START_STK_SIZE 128
#define APP_TASK_USER_STK_SIZE 128
#endif
STM32_TEST.c中的代码如下:
#include "stm32f10x.h"
#include "ucos_ii.h"
static OS_STK App_TaskStartStk[APP_TASK_START_STK_SIZE];
static OS_STK App_TaskUserStk[APP_TASK_USER_STK_SIZE];
static void App_TaskStart (void *p_arg);
static void App_TaskUser (void *p_arg);
static void SetSysTick()
{
RCC_ClocksTypeDefrcc_clocks;
RCC_GetClocksFreq(&rcc_clocks);
SysTick_Config(rcc_clocks.HCLK_Frequency/OS_TICKS_PER_SEC);
}
static void LedInit()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能PA端口时钟
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_1; //LED端口配置
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_1); //PA1 输出高
}
int main (void)
{
LedInit();
OSInit(); /* Initialize "uC/OS-II, TheReal-Time Kernel". */
OSTaskCreate(App_TaskStart,(void* )0,(OS_STK*)&App_TaskStartStk[APP_TASK_START_STK_SIZE - 1],(INT8U)APP_TASK_START_PRIO);
OSStart(); /* Start multitasking (i.e. givecontrol to uC/OS-II). */
return (0);
}
static void App_TaskStart (void *p_arg)
{
SetSysTick();
OSTaskCreate(App_TaskUser,(void* )0,(OS_STK*)&App_TaskUserStk[APP_TASK_USER_STK_SIZE - 1],(INT8U) APP_TASK_USER_PRIO);
while (1)
{
GPIO_SetBits(GPIOA,GPIO_Pin_1); //PA1 输出高
OSTimeDly(200);
}
}
static void App_TaskUser (void *p_arg)
{
while(1)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_1); //PA1 输出低
OSTimeDly(400);
}
}
资源下载地址:http://download.csdn.net/detail/ballack_linux/8034799