STM32 —— UCOS 移植

完成这个实验首先我们需要在官网上下载 uc/os iii 这个系统,官网下载网址: Browse Example Projects for the µC/ Product Line

这里版本一定要下载正确,不然问题只会越来越多,版本如下:

注意: 这里,我查询了很多资料,并没有看到移植的版本,并且这里 STM32F1 对应的系统版本只有 F103ZE-SK 、F107 和 10B-EVAL ,所以这里找最相近的版本下载即可,这里选择下载 F107 版本,在下载之前需要进行注册,这里不能够使用腾讯和网易的邮箱,最好是使用 Google Mail

移植前准备

在移植前我们需要用 CubeMX 新建一个工程,需要将项目完全配置好之后才能够进行添加

然后我们需要解压我们所下载的 uc/os iii ,可以看到目录下内容如下:

我们需要新建两个目录如下:

在 uC-BSP 中新建如下两个文件:

然后将目录 Micrium\Software\EvalBoards\Micrium\uC-Eval-STM32F107\uCOS-III-FS-LIB 中的如下文件复制到 uC-CONFIG 目录下:

然后将我们的系统文件夹复制到我们的项目目录下就可以开始移植了

这里为了方便我直接把文件夹名称改成了 UCOS

我们点图片上的按钮进行添加文件:

首先添加目录如下:

然后我们分别给新增的目录下添加文件如下:

CPU 目录:

LIB 目录:

PORT 目录:

SOUCRCE 目录:

CONDFIG 目录:

BSP 目录:

添加完成的文件会在这里可以进行查看:

添加(导入)文件路径

在项目设置中的 C/C++ 页面点击按钮进行添加:

点击按钮进行添加,选择我们刚才拷贝文件的目录即可:

补充/修改代码

补充 bsp

我们刚刚新建了 bsp.c 和 bsp.h 文件,但是我们添加的是空白文件。这里需要向文件中添加代码

bsp.c :

// bsp.c
#include "includes.h"
#define  DWT_CR      *(CPU_REG32 *)0xE0001000
#define  DWT_CYCCNT  *(CPU_REG32 *)0xE0001004
#define  DEM_CR      *(CPU_REG32 *)0xE000EDFC
#define  DBGMCU_CR   *(CPU_REG32 *)0xE0042004
#define  DEM_CR_TRCENA                   (1 << 24)
#define  DWT_CR_CYCCNTENA                (1 <<  0)
CPU_INT32U  BSP_CPU_ClkFreq (void)
    return HAL_RCC_GetHCLKFreq();
void BSP_Tick_Init(void)
	CPU_INT32U cpu_clk_freq;
	CPU_INT32U cnts;
	cpu_clk_freq = BSP_CPU_ClkFreq();
	#if(OS_VERSION>=3000u)
		cnts = cpu_clk_freq/(CPU_INT32U)OSCfg_TickRate_Hz;
	#else
		cnts = cpu_clk_freq/(CPU_INT32U)OS_TICKS_PER_SEC;
	#endif
	OS_CPU_SysTickInit(cnts);
void BSP_Init(void)
	BSP_Tick_Init();
	MX_GPIO_Init();
#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
#if (CPU_CFG_TS_32_EN == DEF_ENABLED)
CPU_INT64U  CPU_TS32_to_uSec (CPU_TS32  ts_cnts)
	CPU_INT64U  ts_us;
  CPU_INT64U  fclk_freq;
  fclk_freq = BSP_CPU_ClkFreq();
  ts_us     = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);
  return (ts_us);
#endif
#if (CPU_CFG_TS_64_EN == DEF_ENABLED)
CPU_INT64U  CPU_TS64_to_uSec (CPU_TS64  ts_cnts)
	CPU_INT64U  ts_us;
	CPU_INT64U  fclk_freq;
  fclk_freq = BSP_CPU_ClkFreq();
  ts_us     = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);
  return (ts_us);
#endif

bsp.h :

// bsp.h
#ifndef  __BSP_H__
#define  __BSP_H__
#include "stm32f1xx_hal.h"
void BSP_Init(void);
#endif

修改启动项

修改启动文件代码,启动文件位置如下:

在以下位置处将 PendSV_Handler 和 SysTick_Handler 改为 OS_CPU_PendSVHandler 和 OS_CPU_SysTickHandler:

修改 app_cfg.h

找到 app_cfg.h 文件,位置如下:

补充 includes.h 文件

找到 includes.h 文件,添加对头文件 gpio.h 和 app_cfg.h 文件的引用,并将对头文件 stm32f10x_lib.h 的引用改为 对头文件 stm32f1xx_hal.h 的引用,具体如下:

这里原来是 stm32f10x_lib.h ,是一个标准库的头文件,这里只需要将其改为 HAL 中对应的头文件 stm32f1xx_hal.h 即可

找到 lib_cfg.h ,堆栈空间修改为5(该处宏定义设置堆空间的大小,STM32F103C8T6的RAM只有20K,所以要改小一点):

由于我们使用了 printf 函数,需要在 usart.c 或 main.c 文件中添加以下代码完成 printf 重定向,代码如下:

int fputc(int ch,FILE *f){
	HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xffff);
	return ch;

Keil 配置

配置主函数

主函数代码如下(仅实现配置功能):

代码过长已被折叠,点击查看
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
#include "usart.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <includes.h>
#include "stm32f1xx_hal.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* 任务优先级 */
#define START_TASK_PRIO		3
/* 任务堆栈大小	*/
#define START_STK_SIZE 		64
/* 任务栈 */	
CPU_STK START_TASK_STK[START_STK_SIZE];
/* 任务控制块 */
OS_TCB StartTaskTCB;
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
int fputc(int ch,FILE *f){
	HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xffff);
	return ch;
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* 任务函数定义 */
void start_task(void *p_arg);
static  void  AppTaskCreate(void);
static  void  AppObjCreate(void);
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
  * @brief System Clock Configuration
  * @retval None
void SystemClock_Config(void)
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  /**Initializes the CPU, AHB and APB busses clocks 
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    Error_Handler();
  /**Initializes the CPU, AHB and APB busses clocks 
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
    Error_Handler();
/* USER CODE END 0 */
  * @brief  The application entry point.
  * @retval int
int main(void)
	OS_ERR  err;
	OSInit(&err);
  HAL_Init();
	SystemClock_Config();
	//MX_GPIO_Init(); 这个在BSP的初始化里也会初始化
  MX_USART1_UART_Init();	
	/* 创建任务 */
	OSTaskCreate((OS_TCB     *)&StartTaskTCB,                /* Create the start task                                */
				 (CPU_CHAR   *)"start task",
				 (OS_TASK_PTR ) start_task,
				 (void       *) 0,
				 (OS_PRIO     ) START_TASK_PRIO,
				 (CPU_STK    *)&START_TASK_STK[0],
				 (CPU_STK_SIZE) START_STK_SIZE/10,
				 (CPU_STK_SIZE) START_STK_SIZE,
				 (OS_MSG_QTY  ) 0,
				 (OS_TICK     ) 0,
				 (void       *) 0,
				 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
				 (OS_ERR     *)&err);
	/* 启动多任务系统,控制权交给uC/OS-III */
	OSStart(&err);            /* Start multitasking (i.e. give control to uC/OS-III). */
void start_task(void *p_arg)
	OS_ERR err;
	CPU_SR_ALLOC();
	p_arg = p_arg;
	/* YangJie add 2021.05.20*/
  BSP_Init();                                                   /* Initialize BSP functions */
  //CPU_Init();
  //Mem_Init();                                                 /* Initialize Memory Management Module */
#if OS_CFG_STAT_TASK_EN > 0u
   OSStatTaskCPUUsageInit(&err);  		//统计任务                
#endif
#ifdef CPU_CFG_INT_DIS_MEAS_EN			//如果使能了测量中断关闭时间
    CPU_IntDisMeasMaxCurReset();	
#endif
#if	OS_CFG_SCHED_ROUND_ROBIN_EN  		//当使用时间片轮转的时候
	 //使能时间片轮转调度功能,时间片长度为1个系统时钟节拍,既1*5=5ms
	OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);  
#endif		
	OS_CRITICAL_ENTER();	//进入临界区
	OS_TaskSuspend((OS_TCB*)&StartTaskTCB,&err);		//挂起开始任务			 
	OS_CRITICAL_EXIT();	//进入临界区
  * 函数功能: 启动任务函数体。
  * 输入参数: p_arg 是在创建该任务时传递的形参
  * 返 回 值: 无
  * 说    明:无
/* USER CODE BEGIN 4 */
  * 函数功能: 创建应用任务
  * 输入参数: p_arg 是在创建该任务时传递的形参
  * 返 回 值: 无
  * 说    明:无
static  void  AppTaskCreate (void)
  * 函数功能: uCOSIII内核对象创建
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
static  void  AppObjCreate (void)
/* USER CODE END 4 */
  * @brief  This function is executed in case of error occurrence.
  * @retval None
void Error_Handler(void)
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  /* USER CODE END Error_Handler_Debug */
#ifdef  USE_FULL_ASSERT
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
void assert_failed(uint8_t *file, uint32_t line)
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

到此,我们的 UC/OS III 的全部移植过程就结束了,如果有报错,则需要检查是否有代码输入错误或者文件或函数重复添加的问题

错误解决方案

在新建目录和添加文件的时候要注意,不要新建重复目录或添加相同的文件到同一个目录下

文件或路径添加完成之后一定要点 ok 否则将前功尽弃,就需要重新再执行一遍,比较浪费时间: