文章目录
前言
本文介绍了基于STM32F405ZGT× HAL库的uCOSIII移植的详细过程,创建了三个任务,实现了LED闪烁、浮点数计算和串口打印等功能
一、uCOS源码获取
方法一:可以通过官网下载源码,官网链接:
https://www.silabs.com/developers/micrium
提示:在官网下载资源时需要注册账号。我注册的时候总是提示邮箱有误,不知道怎么解决,有了解的小伙伴欢迎把方法发在评论区
方法二:热心网友的分享:
https://download.csdn.net/download/fhdghfuiahfsdifbs/18909773
源码目录如下:
补充几个UCOS源码下载的相关博客链接:
- https://blog.csdn.net/DZRYWYBL/article/details/123153091
- https://blog.csdn.net/weixin_44388614/article/details/121076842
二、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
4.在Src和Inc文件夹下分别新建空白文件myucos.c和myucos.h
3.2 keil工程目录文件添加
1.向keil工程中添加如下分组
2.向分组中添加文件(添加.c文件和.asm文件)
![]() | ![]() | ![]() |
![]() | ![]() | ![]() |
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 编译测试
完成上述步骤后,点击编译按钮,若提示无报错,则移植成功
四、功能实现
任务概述
- 创建一个名为led_task的任务,其功能是控制LED的开关状态。
- 创建一个名为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 创建任务
1.在myucos.h中添加如下内容
#ifndef __MYUCOS_H__
#define __MYUCOS_H__
void MY_UCOS_Init(void);
void CreateTasks(void);
void led_task(void *p_arg);
void float_task(void *p_arg);
#endif
2.在myucos.c中添加如下内容
#include "myucos.h"
#include "main.h"
#include <includes.h>
/* Defines ------------------------------------------------------------------*/
/* Task Priority */
#define LED_TASK_PRIO 4
#define FLOAT_TASK_PRIO 4
/* Task Stacks Size */
#define LED_STK_SIZE 128
#define FLOAT_STK_SIZE 128
/* Task Stacks --------------------------------------------------------------*/
CPU_STK LED_TASK_STK[LED_STK_SIZE];
CPU_STK FLOAT_TASK_STK[FLOAT_STK_SIZE];
/* Task Control Blocks -----------------------------------------------------*/
OS_TCB LEDTaskTCB;
OS_TCB FLOATTaskTCB;
void MY_UCOS_Init(void)
{
BSP_Init(); /* Initialize BSP functions 不要忘记辣!!!*/
CPU_SR_ALLOC(); // 声明一个用于保存中断状态的变量
OS_CRITICAL_ENTER();//进入临界区,保存当前中断状态
CreateTasks();
OS_CRITICAL_EXIT(); // 退出临界区,恢复中断状态
}
void CreateTasks(void)
{
OS_ERR err; //err(OS_ERR类型)是一个用于存储错误代码的数据类型
OSInit(&err); //初始化UCOSIII
/* 创建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 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);
}
/* 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;
static float float_num=0.01;
while(1)
{
float_num+=0.01f;
printf("float_num的值为:%.4f\r\n",float_num);
OSTimeDly(500, OS_OPT_TIME_DLY, &err);
}
}
3.在main.c中添加如下内容
/*
其它代码
*/
int main(void)
{
/*
其它代码
*/
/* USER CODE BEGIN 2 */
MY_UCOS_Init(); //UCOS初始化,创建任务等
OS_ERR err;
OSStart(&err); //启动多任务系统,控制权交给uC/OS-III
/* USER CODE END 2 */
/*
其它代码
*/
}
/*
其它代码
*/
五、编译测试
编译程序,将程序烧录到开发板上,可以观察到LED灯闪烁,串口打印浮点数据
在浮点计算处设置断点,全速运行,程序到达断点后查看汇编窗口,如下图所示:
可以看到有VLDR、VADD.F32等FPU指令,这说明STM32F405内部的FPU进行浮点运算成功
总结
本文章介绍了基于STM32F405ZGT× HAL库的uCOSIII移植的详细过程,实现了LED闪烁、浮点数计算和串口打印等功能,给出了实验验证。