注意,这可能是你在全网找到的最完整,最妈妈级的教程!!!
说一下原因吧
自从用上cubemx之后,便一发不可收拾,研究来研究去,终于发现到了移植UCOS的时候了,可是网络上的移植教程基本上都是基于标准库的,怎么,瞧我HAL库不起还是咋地了,今天就带给大家最详细的移植教程,看完还移植不成功怎么办,不怕,工程文件给到你!
还请各位看官给个素质三。。对不起,串台了,给个赞再走呗!
移植os是个大工程,这篇文章注定要非常长,如果你能耐下心来看到最后,咱俩就是朋友。废话不多说,我们直接开锤
-----------------------------------------------------------------------------------------------------------------------------------
第一步,配置一个Hello world工程,跑起来先
这一步我在之前的教程中已经讲过了,可以移步到STM32 cubemx 开发系列文章(一)认识cubemx查看,本篇不再展开讨论。
第二步,下载UCOSIII源码
别的教程到这一步一般就要推荐你去官网下载107的包了,怎么说呢,也不是不行,但是由于各种心知肚明的原因,那个官网能不能打开全靠个人造化,翻墙的除外,所以我们应该怎么办呢,你可以先把这篇文章放到后台,去找官网下载,也可以直接用我提供的包。
这么一说,有的极客朋友可能心里过意不去了,用人家提供的包怎么能行,必须自己动手
可以,我非常赞赏这种思想,因为当初的我就是这样,但是我要说的是,我提供给你的包,里面的代码我可是丝毫没动过,我只是把移植需要的文件给复制出来了,到时候该怎么修改还是你自己的事啊!
好了不皮了,源码和我复制好的都挂到资源上,免费下载就是了。
第三步,将UCOSIII的源码添加到你的工程中
这一步只需要注意一个点,本篇文章中用到的编译器是MDK5,如果你使用IAR或者gcc,那你复制文件的时候记得不要选错了,是什么编译器就选什么文件,这里同样不再展开讨论。
首先你需要再cubemx生成的工程中新建一个文件夹,起名随便,为了好听,咱就叫她UCOSIII,然后在这个文件夹里新建这么六个文件夹,命名无所谓,但是推荐和我一样的命名。
- 进入源码文件夹,Micrium\Software\EvalBoards\Micrium\uC-Eval-STM32F107\uCOS-III,在这个文件夹下,你需要复制如图所示的文件到你的工程文件夹中,放在APP内,如图。
- 源码文件夹往上退一步,会发现有一个BSP文件夹,同样复制里面的两个文件到你工程的BSP文件夹,如图:
- 复制UCOS_CPU中的文件,你需要到源码文件夹中找到Micrium\Software\uC-CPU\ARM-Cortex-M3\RealView,将这里面的三个文件复制到工程的UCOS_CPU文件夹下,因为MDK编译器就是RealView,然后返回两级目录,将三个c文件也复制过去,复制完成后你的工程中UCOS_CPU应该长这样:
- 同理,工程的UCOS_LIB应该张这样:
- 继续复制文件,完善UCOS_PORT和UCOS_SOURCE,如图
如果对复制文件还有疑问的话,可以将资源中的源码和我复制好的文件夹一并下载下来比较一下,这里还是不再讨论了。
第四步,打开你的工程,不厌其烦的将文件都添加进去
这里就是简单的向工程中添加文件,我直接放出来添加好的目录,一定要耐心添加。
剩下那几个文件夹没展开,因为太多了,而且也和我对应的起名一致,添加进去即可。
第五步,回到cubemx配置你的时钟
这一步尤为重要,相信多少研究过嵌入式操作系统的同学们都知道,嵌入式系统运行的时候需要有一个时钟提供心跳,一般都是SysTick提供,但是到了HAL库中,有一个HAL_Delay函数专门用来延时,这个函数就使用了SysTick,显然与OS起了冲突,所以我们把他的时钟依赖设置为TIM1,这样就可以了。
第六步,修改app.c , bsp.c
走到这里,移植工程可以说进行了一多半,我们不妨先打开源码中的app.c,看看里面都写了什么。根据源码我们可以得知,app.c中默认写好了三个任务,一个初始化任务和两个空任务。
空任务不用我多说,是在座各位的发挥空间,我们只需要注意初始化任务中的关键几行,上代码
BSP_Init(); /* Initialize BSP functions */
CPU_Init();
cpu_clk_freq = BSP_CPU_ClkFreq(); /* Determine SysTick reference freq. */
cnts = cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz; /* Determine nbr SysTick increments */
OS_CPU_SysTickInit(cnts); /* Init uC/OS periodic time src (SysTick). */
Mem_Init(); /* Initialize Memory Management Module */
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err); /* Compute CPU capacity with no task running */
#endif
CPU_IntDisMeasMaxCurReset();
注意注意注意,重中之重,千万不能吧以上这几行代码给弄没了,这里涉及到初始化SysTick和OS的心跳,不写这几个初始化,你的OS是不能运行的
如果有能力的同学还是推荐仔细研究研究这几行初始化的代码,我在这里简单的提一下,首先,肯定是初始化板级驱动,初始化cpu,下面的三行是获得cpu的工作频率,初始化SysTick,并且用作os的心跳,再往下还是一些初始化的工作,能力有限,怕误导你们,还请各位自行研究把。
注意此处,我把app.c里面的main函数名字改成start了,注意,这也是重点,后面要用到
从上述的代码片段不难看出,和BSP有关的函数我们必须要进行修改,因为人家的开发板资源和自己手里的肯定是不一样的
所以我们打开bsp.c
注意,划重点了
- 找到BSP_Init函数,把里面东西统统删掉,因为资源肯定和我们自己的板子不一样,改成这样:
void BSP_Init (void)
{
}
- 找到CPU_INT32U BSP_CPU_ClkFreq (void)函数,这个函数用来返回系统的cpu频率,但是我们注意到他是根据标准库写的,这肯定不适用HAL库,所以我们做如下修改
CPU_INT32U BSP_CPU_ClkFreq (void)
{
return HAL_RCC_GetHCLKFreq();
}
剩下的没用的函数就全部删除即可,具体参考如下代码
/*
*********************************************************************************************************
* MICIRUM BOARD SUPPORT PACKAGE
*
* (c) Copyright 2013; Micrium, Inc.; Weston, FL
*
* All rights reserved. Protected by international copyright laws.
* Knowledge of the source code may NOT be used to develop a similar product.
* Please help us continue to provide the Embedded community with the finest
* software available. Your honesty is greatly appreciated.
*********************************************************************************************************
*/
/*
*********************************************************************************************************
*
* BOARD SUPPORT PACKAGE
*
* ST Microelectronics STM32
* on the
*
* Micrium uC-Eval-STM32F107
* Evaluation Board
*
* Filename : bsp.c
* Version : V1.00
* Programmer(s) : EHS
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* INCLUDE FILES
*********************************************************************************************************
*/
#define BSP_MODULE
#include <bsp.h>
#define DBGMCU_CR_TRACE_IOEN_MASK 0x10
#define DBGMCU_CR_TRACE_MODE_ASYNC 0x00
#define DBGMCU_CR_TRACE_MODE_SYNC_01 0x40
#define DBGMCU_CR_TRACE_MODE_SYNC_02 0x80
#define DBGMCU_CR_TRACE_MODE_SYNC_04 0xC0
#define DBGMCU_CR_TRACE_MODE_MASK 0xC0
#define DEM_CR_TRCENA (1 << 24)
#define DWT_CR_CYCCNTENA (1 << 0)
void BSP_Init (void)
{
}
/*
*********************************************************************************************************
* BSP_CPU_ClkFreq()
*
* Description : Read CPU registers to determine the CPU clock frequency of the chip.
*
* Argument(s) : none.
*
* Return(s) : The CPU clock frequency, in Hz.
*
* Caller(s) : Application.
*
* Note(s) : none.
*********************************************************************************************************
*/
CPU_INT32U BSP_CPU_ClkFreq (void)
{
return HAL_RCC_GetHCLKFreq();
}
/*
*********************************************************************************************************
* OSProbe_TmrInit()
*
* Description : Select & initialize a timer for use with the uC/Probe Plug-In for uC/OS-II.
*
* Argument(s) : none.
*
* Return(s) : none.
*
* Caller(s) : OSProbe_Init().
*
* Note(s) : none.
*********************************************************************************************************
*/
#if ((APP_CFG_PROBE_OS_PLUGIN_EN == DEF_ENABLED) && \
(OS_PROBE_HOOKS_EN == 1))
void OSProbe_TmrInit (void)
{
}
#endif
/*
*********************************************************************************************************
* OSProbe_TmrRd()
*
* Description : Read the current counts of a free running timer.
*
* Argument(s) : none.
*
* Return(s) : The 32-bit timer counts.
*
* Caller(s) : OSProbe_TimeGetCycles().
*
* Note(s) : none.
*********************************************************************************************************
*/
#if ((APP_CFG_PROBE_OS_PLUGIN_EN == DEF_ENABLED) && \
(OS_PROBE_HOOKS_EN == 1))
CPU_INT32U OSProbe_TmrRd (void)
{
return ((CPU_INT32U)DWT_CYCCNT);
}
#endif
#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
void CPU_TS_TmrInit (void)
{
CPU_INT32U cpu_clk_freq_hz;
DEM_CR |= (CPU_INT32U)DEM_CR_TRCENA; /* Enable Cortex-M3's DWT CYCCNT reg. */
DWT_CYCCNT = (CPU_INT32U)0u;
DWT_CR |= (CPU_INT32U)DWT_CR_CYCCNTENA;
cpu_clk_freq_hz = BSP_CPU_ClkFreq();
CPU_TS_TmrFreqSet(cpu_clk_freq_hz);
}
#endif
#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
CPU_TS_TMR CPU_TS_TmrRd (void)
{
return ((CPU_TS_TMR)DWT_CYCCNT);
}
#endif
第七步,打开启动文件,将汇编代码改为适配UCOS的启动方式
1.看到汇编代码的第七十行左右
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
将这两句改成如下代码:
DCD OS_CPU_PendSVHandler ; PendSV Handler
DCD OS_CPU_SysTickHandler ; SysTick Handler
这样就在启动的时候将各项管理的权限交给UCOS处理
上面改动了,下面调用的地方也学要做出相应的改动,来到代码的第190行左右,将上文提到的修改前的函数均替换为修改后的函数名,代码如下:
OS_CPU_PendSVHandler PROC
EXPORT OS_CPU_PendSVHandler [WEAK]
B .
ENDP
OS_CPU_SysTickHandler PROC
EXPORT OS_CPU_SysTickHandler [WEAK]
B .
ENDP
2.细心的小伙伴可能注意到了,我们既然不调用SysTick_Handler
和PendSV_Handler
这两个函数了,但是每次生成代码的时候总是在stm32f1xx_it.c会重新生成这两个函数,就显得非常不舒服,如下:
/**
* @brief This function handles Pendable request for system service.
*/
void PendSV_Handler(void)
{
/* USER CODE BEGIN PendSV_IRQn 0 */
/* USER CODE END PendSV_IRQn 0 */
/* USER CODE BEGIN PendSV_IRQn 1 */
/* USER CODE END PendSV_IRQn 1 */
}
/**
* @brief This function handles System tick timer.
*/
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
/* USER CODE END SysTick_IRQn 0 */
/* USER CODE BEGIN SysTick_IRQn 1 */
/* USER CODE END SysTick_IRQn 1 */
}
于是我们可以选择避开生成这两个函数,如图设置:
第八步,到main函数中添加对应的头文件,启动ucosiii,大功告成
能仔细看到这里的小伙伴,恭喜你,距离启动ucosiii只差临门一脚,让我们踹门而入。
- 在main.c 的指定位置添加头文件
#include <includes.h>
- 在while(1)的前面添加这么一行函数
start();
,还记得我前面修改app.c的时候提到的重点没有,就是在这里启动ucosiii用的。
第九步,到app.c里面去完善你想要的功能吧!!!
真不容易,移植工作到此算是正式结束了,有不懂的小伙伴可以私信我,当然,源码,工程我都会放到资源里面免费下载,祝各位成功!!!