【STM32Cubemx HAL库+STM32F4××+uCOSIII移植】


前言

本文介绍了基于STM32F405ZGT× HAL库的uCOSIII移植的详细过程,创建了三个任务,实现了LED闪烁、浮点数计算和串口打印等功能

一、uCOS源码获取

方法一:可以通过官网下载源码,官网链接:
https://www.silabs.com/developers/micrium
提示:在官网下载资源时需要注册账号。我注册的时候总是提示邮箱有误,不知道怎么解决,有了解的小伙伴欢迎把方法发在评论区


方法二:热心网友的分享:
https://download.csdn.net/download/fhdghfuiahfsdifbs/18909773
源码目录如下:
图片描述

补充几个UCOS源码下载的相关博客链接:

二、HAL工程建立

1.配置SYS,选择Serial Wire
在这里插入图片描述

2.配置RCC,选择高速外部时钟
在这里插入图片描述


在这里插入图片描述
3.配置GPIO(LED)和USART1,通过实现相关功能来测试uCOS移植效果
在这里插入图片描述


在这里插入图片描述
4.配置完成后,点击“GENERATE CODE”,生成工程代码。生成的keil工程如下
在这里插入图片描述

三、移植uCOS

3.1 工程文件夹的文件移植

1.在工程目录下新建文件夹UCOSIII,将源码内的uC-CPU、uC-LIB和uCOS-III这三个文件夹复制粘贴到UCOSIII文件夹下_
在这里插入图片描述


在这里插入图片描述
2.在UCOSIII目录下创建一个新的文件夹,命名为uCOS-CONFIG。接着,将源代码目录中的八个指定文件复制并粘贴到新创建的uCOS-CONFIG文件夹中。
在这里插入图片描述


在这里插入图片描述
3.在UCOSIII目录下创建一个新的文件夹,命名为uCOS-BSP,并新建两个空白文件bsp.c和bsp.h
在这里插入图片描述

3.2 keil工程目录文件添加

1.向keil工程中添加如下分组
在这里插入图片描述
2.向分组中添加文件

Image 1Image 2Image 3
Image 4Image 5Image 6

3.添加头文件路径
在这里插入图片描述

3.3 文件修改

1.在bsp.h中添加如下内容

#ifndef  __BSP_H__
#define  __BSP_H__

#include "stm32f4xx_hal.h"

void BSP_Init(void);

#endif

2.在bsp.c中添加如下内容

#include "includes.h"

#define  BSP_REG_DEM_CR                           (*(CPU_REG32 *)0xE000EDFC)	//DEMCR寄存器
#define  BSP_REG_DWT_CR                           (*(CPU_REG32 *)0xE0001000)    //DWT控制寄存器
#define  BSP_REG_DWT_CYCCNT                       (*(CPU_REG32 *)0xE0001004)	//DWT时钟计数寄存器	
#define  BSP_REG_DBGMCU_CR                        (*(CPU_REG32 *)0xE0042004)

//DEMCR寄存器的第24位,如果要使用DWT ETM ITM和TPIU的话DEMCR寄存器的第24位置1
#define  BSP_BIT_DEM_CR_TRCENA                    DEF_BIT_24			

//DWTCR寄存器的第0位,当为1的时候使能CYCCNT计数器,使用CYCCNT之前应当先初始化
#define  BSP_BIT_DWT_CR_CYCCNTENA                 DEF_BIT_00

/*
*********************************************************************************************************
*                                            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();//返回HCLK时钟频率
}

/*
*********************************************************************************************************
*                                            BSP_Tick_Init()
* Description : BSP_Tick_Init.
* Argument(s) : none.
* Return(s)   : none.
* Note(s)     : none.
*********************************************************************************************************
*/
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();//此函数会初始化OS系统时钟,如果移植了正点原子的delay文件,则与主函数中的delay_init(168)只需要调用一个即可
}

#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
void  CPU_TS_TmrInit (void)
{
    CPU_INT32U  cpu_clk_freq_hz;

    BSP_REG_DEM_CR     |= (CPU_INT32U)BSP_BIT_DEM_CR_TRCENA; 	//使用DWT  /* Enable Cortex-M4's DWT CYCCNT reg.*/
    BSP_REG_DWT_CYCCNT  = (CPU_INT32U)0u;					 	//初始化CYCCNT寄存器
    BSP_REG_DWT_CR     |= (CPU_INT32U)BSP_BIT_DWT_CR_CYCCNTENA;	//开启CYCCNT

    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)BSP_REG_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

3.修改启动文件startup_stm32f405xx.s

                DCD     PendSV_Handler             ; PendSV Handler
                DCD     SysTick_Handler            ; SysTick Handler

修改为

                DCD     OS_CPU_PendSVHandler             ; PendSV Handler
                DCD     OS_CPU_SysTickHandler            ; SysTick Handler

PendSV_Handler  PROC
                EXPORT  PendSV_Handler             [WEAK]
                B       .
                ENDP
SysTick_Handler PROC
                EXPORT  SysTick_Handler            [WEAK]
                B       .
                ENDP

修改为

OS_CPU_PendSVHandler  PROC
                EXPORT  OS_CPU_PendSVHandler             [WEAK]
                B       .
                ENDP
OS_CPU_SysTickHandler PROC
                EXPORT  OS_CPU_SysTickHandler            [WEAK]
                B       .
                ENDP

4.支持浮点运算
在startup_stm32f405xx.s 中添加如下汇编代码

				IF {FPU} != "SoftVFP"
				; Enable Floating Point Support at reset for FPU
				LDR.W   R0, =0xE000ED88         ; Load address of CPACR register
				LDR     R1, [R0]                ; Read value at CPACR
				ORR     R1,  R1, #(0xF <<20); Set bits 20-23 to enable CP10 and CP11 coprocessors
				; Write back the modified CPACR value
				STR     R1, [R0]                ; Wait for store to complete
				DSB

				; Disable automatic FP register content
				; Disable lazy context switch
				LDR.W   R0, =0xE000EF34         ; Load address to FPCCR register
				LDR     R1, [R0]
				AND     R1,  R1, #(0x3FFFFFFF)  ; Clear the LSPEN and ASPEN bits
				STR     R1, [R0]
				ISB                             ; Reset pipeline now the FPU is enabled
				ENDIF

添加完成后如图所示:
在这里插入图片描述

3.4 编译测试

完成上述步骤后,点击编译按钮,若提示无报错,则移植成功
在这里插入图片描述

四、功能实现

任务概述

  1. 创建一个名为start_task的初始化任务,负责执行系统启动过程以及创建后续任务。
  2. 创建一个名为led_task的任务,其功能是控制LED的开关状态。
  3. 创建一个名为float_task的任务,用于执行浮点数运算测试,并将结果通过串口输出

4.1 串口重定向

修改usart.c,添加如下代码

//******************其它代码************************//

/* USER CODE BEGIN 0 */
#include "stdio.h"
/* USER CODE END 0 */

//******************其它代码************************//

/* USER CODE BEGIN 1 */
/**
  * 函数功能: 重定向c库函数printf到DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
  return ch;
}
 
/**
  * 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
int fgetc(FILE *f)
{
  uint8_t ch = 0;
  HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
  return ch;
}
/* USER CODE END 1 */

//******************其它代码************************//

4.2 创建任务

修改main.c,添加如下代码

//******************其它代码************************//
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include <includes.h>
/* USER CODE END Includes */

//******************其它代码************************//

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* UCOSIII中以下优先级用户程序不能使用:
 * 将这些优先级分配给了UCOSIII的5个系统内部任务
 * 优先级0:中断服务服务管理任务 OS_IntQTask()
 * 优先级1:时钟节拍任务 OS_TickTask()
 * 优先级2:定时任务 OS_TmrTask()
 * 优先级OS_CFG_PRIO_MAX-2:统计任务 OS_StatTask()
 * 优先级OS_CFG_PRIO_MAX-1:空闲任务 OS_IdleTask()
 */

/* 任务优先级 */
#define START_TASK_PRIO		3
#define LED_TASK_PRIO		4
#define FLOAT_TASK_PRIO		5

/* 任务堆栈大小	*/
#define START_STK_SIZE 		512
#define LED_STK_SIZE 		128
#define FLOAT_STK_SIZE		128
/* USER CODE END PD */

//******************其它代码************************//

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
/* 任务控制块 */
OS_TCB StartTaskTCB;
OS_TCB LedTaskTCB;
OS_TCB FloatTaskTCB;

/* 任务栈 */	
CPU_STK START_TASK_STK[START_STK_SIZE];
CPU_STK LED_TASK_STK[LED_STK_SIZE];
__align(8) CPU_STK FLOAT_TASK_STK[FLOAT_STK_SIZE];
/* USER CODE END PV */

//******************其它代码************************//

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* 任务函数定义 */
void start_task(void *p_arg);
void led_task(void *p_arg);
void float_task(void *p_arg);
/* USER CODE END 0 */

//******************其它代码************************//

int main(void)
{
  /* USER CODE BEGIN 1 */
	OS_ERR err;
	CPU_SR_ALLOC();
  /* USER CODE END 1 */
  
  //******************其它代码************************//
  
  /* USER CODE BEGIN 2 */
    //delay_init(168);   //时钟初始化 如果移植了正点原子的delay文件且SYSTEM_SUPPORT_OS被定义,此函数会初始化OS系统时钟,与start_task任务中的BSP_Init()只需要调用一个即可
    OSInit(&err);				//初始化UCOSIII
    OS_CRITICAL_ENTER();//进入临界区
    //创建开始任务
    OSTaskCreate((OS_TCB 	* )&StartTaskTCB,				//任务控制块
                 (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,						//任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
                 (OS_TICK	  )0,						//当使能时间片轮转时的时间片长度,为0时为默认长度,
                 (void   	* )0,						//用户补充的存储区
                 (OS_OPT    )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
                 (OS_ERR 	* )&err);				//存放该函数错误时的返回值
    OS_CRITICAL_EXIT();	//退出临界区	

    OSStart(&err); //启动多任务系统,控制权交给uC/OS-III
  /* USER CODE END 2 */
  
  //******************其它代码************************//
}

/* USER CODE BEGIN 4 */
//开始任务函数
void start_task(void *p_arg)
{
	OS_ERR err;
	CPU_SR_ALLOC();
	p_arg = p_arg;
	
  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();	//进入临界区
	/* 创建LED任务 */
	OSTaskCreate((OS_TCB 	* )&LedTaskTCB,		
				 (CPU_CHAR	* )"led task", 		
                 (OS_TASK_PTR )led_task, 			
                 (void		* )0,					
                 (OS_PRIO	  )LED_TASK_PRIO,     
                 (CPU_STK   * )&LED_TASK_STK[0],	
                 (CPU_STK_SIZE)LED_STK_SIZE/10,	
                 (CPU_STK_SIZE)LED_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);
	/* 创建浮点测试任务 */
	OSTaskCreate((OS_TCB 	* )&FloatTaskTCB,		
				 (CPU_CHAR	* )"float test task", 		
                 (OS_TASK_PTR )float_task, 			
                 (void		* )0,					
                 (OS_PRIO	  )FLOAT_TASK_PRIO,     
                 (CPU_STK   * )&FLOAT_TASK_STK[0],	
                 (CPU_STK_SIZE)FLOAT_STK_SIZE/10,	
                 (CPU_STK_SIZE)FLOAT_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);
								 
	OS_TaskSuspend((OS_TCB*)&StartTaskTCB,&err);		//挂起开始任务			 
	OS_CRITICAL_EXIT();	//进入临界区
}

/* led任务函数 */
void led_task(void *p_arg)
{
	OS_ERR err;
	p_arg = p_arg;
	
	while(1)
	{
		HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
		OSTimeDly(500, OS_OPT_TIME_DLY, &err);
	}
}

/* 浮点测试任务 */
void float_task(void *p_arg)
{
	OS_ERR err;
	p_arg = p_arg;
	CPU_SR_ALLOC();
	static float float_num=0.01;
	
	while(1)
	{
		float_num+=0.01f;
		OS_CRITICAL_ENTER(); //进入临界区
		printf("float_num的值为:%.4f\r\n",float_num);
		OS_CRITICAL_EXIT();
		OSTimeDly(500, OS_OPT_TIME_DLY, &err);
	}
}
/* USER CODE END 4 */

  //******************其它代码************************//

五、编译测试

编译程序,将程序烧录到开发板上,可以观察到LED灯闪烁,串口打印浮点数据
在这里插入图片描述
在浮点计算处设置断点,全速运行,程序到达断点后查看汇编窗口,如下图所示:
在这里插入图片描述

在这里插入图片描述
可以看到有VLDR、VADD.F32等FPU指令,这说明STM32F405内部的FPU进行浮点运算成功


总结

本文章介绍了基于STM32F405ZGT× HAL库的uCOSIII移植的详细过程,实现了LED闪烁、浮点数计算和串口打印等功能,给出了实验验证。

  • 8
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值