1、准备工作
STM32开发板,我这里用的是STM32F103C8T6,各位小伙伴可以自行选择
Clion平台下的STM32开发环境,Clion的版本我的是2021.3.4,这个问题不大
uCos III 的源码,可以区官网自行下载,也可以用我准备好的,连接如下:
链接:https://pan.baidu.com/s/17cegS4sAAlm4LpjyH31J4w
提取码:7788
到这里准备工作就搞定了,下面开始创建基础工程,我们将在此工程的基础上移植uCos III
2、基础工程
打开CubeMx选择自己的目标芯片,我的是STM32F103C8T6
配置用于测试工程所需外部硬件,我这里是使用的LED以及串口,多嘴一句,LED的话无所谓,串口建议还是要开启。
然后再根据自己的芯片信号配置好晶振以及时钟分频就好了,这里就不演示了,生成工程后,测试一下工程有没有问题(一般都不会有问题),到这里就成功一半了,我就拿串口来做演示
printf( "Hello uC/os III\r\n" ); HAL_Delay( 1000 );
工程配置好了以后,就开始摘取我们所需要的 uCos III 的源码,也就是CV一下,具体看图吧!
3、源码的移植
首先创建如下文件夹
我们一个一个来,双击打开 uC_bsp 文件夹,创建两个文件,一个是 bsp_os.c 以及 bsp_os.h,如图
打开这两个文件夹将一下代码复制并粘贴到你自己创建的文件下
bsp_os.c
// bsp.c
#include "includes.h"
#include "usart.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 );
}
int _write(int fd, char *ptr, int len)
{
HAL_UART_Transmit(&huart1, (uint8_t*)ptr, len, 0xFFFF);
return len;
}
int __io_putchar(int ch)
{
uint8_t temp[1]={ch};
HAL_UART_Transmit(&huart1,temp,1,0xff);
return (ch);
}
void BSP_Init(void)
{
BSP_Tick_Init();
}
#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
/**
* @brief 初始化事件戳
* @param NONE
* @date 2023-11-17
*/
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);
}/* CPU_TS_TmrInit */
#endif
#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
/**
* @brief 读取当前时间戳
* @param NONE
* @return DWT_CYCCNT寄存器的值
* @date 2023-11-17
*/
CPU_TS_TMR CPU_TS_TmrRd (void)
{
return ( (CPU_TS_TMR)DWT_CYCCNT );
}/* CPU_TS_TmrRd */
#endif
/* Configure CPU timestamp features (see Note #1) : */
#if (CPU_CFG_TS_32_EN == DEF_ENABLED)
/**
* @brief uSec延时函数 ( 32bit )
* @param ts_cnts 延时时间 ( 32bit )
* @return
* @date 2023-11-17
*/
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 );
}/* CPU_TS32_to_uSec */
#endif
#if (CPU_CFG_TS_64_EN == DEF_ENABLED)
/**
* @brief uSec延时函数 ( 64bit )
* @param ts_cnts 延时时间 ( 64bit )
* @return
* @date 2023-11-17
*/
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);
}/* CPU_TS64_to_uSec */
#endif
bsp_os.h
// bsp.h
#ifndef __BSP_H__
#define __BSP_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stm32f1xx_hal.h"
#include "bsp_led.h"
#include "bsp_i2c.h"
#include "bsp_list.h"
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
/* USER CODE END ET */
/* Exported functions prototypes ---------------------------------------------*/
/* USER CODE BEGIN EFP */
void BSP_Init(void);
/* USER CODE END EFP */
#ifdef __cplusplus
}
#endif
#endif /* __BSP_H__ */
在bsp_os.c/.h中主要实现了 内核微妙延时以及串口的重定向,其他的先不管,接着往下走
打开 uC_cfg 文件夹,然后在uCos III的源码中找到以下文件复制并粘贴,如图
以下是 uC_cpu 文件夹的内容,注意 ARM-Cortex-M3 文件夹内只保留 GNU 文件及其内容,其他的全部删除,这是重点。
然后打开 uC_lib 文件夹接着复制粘贴,看图吧,同样的 <Ports->ARM-Cortex-M3>目录下,只保留 GNU 文件夹其他的全部删掉,这里就不贴图了
最后就是 uC_os3 文件夹了,如下图
这里是 Source 文件夹下的内容,与前面一样,<Ports->ARM-Cortex-M3->Generic>路径下只保留 GNU 文件夹,其他的全部删除
到这里文件就准备好了,下面开始移植
4、移植 uCos III
将文件复制到工程文件夹内,各位小伙伴可以像我一向,如图!
包含路径 ,打开 CMakeLists.txt 文件,跟我一样的话可以直接复制过去,代码在下面
include_directories(
User/include
User/uCos_III/uC_bsp/include
User/uCos_III/uC_cfg
User/uCos_III/uC_cpu
User/uCos_III/uC_cpu/ARM-Cortex-M3/GNU
User/uCos_III/uC_lib
User/uCos_III/uC_lib/Ports/ARM-Cortex-M3/GNU
User/uCos_III/uC_os3/Source
User/uCos_III/uC_os3/Ports/ARM-Cortex-M3/Generic/GNU
)
file(GLOB_RECURSE SOURCES "Core/*.*" "Drivers/*.*" "User/*.*")
然后使用 CMake 重新构建项目,并编译(点击 Reload Cmake Projrct)
此时编译因该是没有错误的
到这儿就差不多了,对工程做一些简单的更改就可以了,一个是改启动文件,一定不要忘记,不然 系统是无法运行的,找到启动文件,看图吧
做如下更改
.word OS_CPU_PendSVHandler
.word OS_CPU_SysTickHandler
.weak OS_CPU_PendSVHandler
.thumb_set OS_CPU_PendSVHandler,Default_Handler
.weak OS_CPU_SysTickHandler
.thumb_set OS_CPU_SysTickHandler,Default_Handler
搞定以后就可以测试 uCos III 是否移植成功了在工程下创建 appliance.c/.h 两个文件复制代码
appliance.c
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "includes.h"
#include "appliance.h"
/* USER CODE END Includes */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define START_TASK_PRIO 3 /* 起始任务的任务优先级 */
#define LED1_TASK_PRIO 4 /* LED1任务的任务优先级 */
#define START_STK_SIZE 96 /* 起始任务的任务堆栈大小 */
#define LED1_STK_SIZE 96 /* LED1任务的任务堆栈大小 */
/* USER CODE END PD */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
CPU_STK START_TASK_STK[ START_STK_SIZE ]; /* 起始任务,任务堆栈 */
CPU_STK LED1_TASK_STK[ LED1_STK_SIZE ]; /* LED1任务,任务堆栈 */
OS_TCB StartTaskTCB; /* 起始任务,任务控制块实例化 */
OS_TCB Led1TaskTCB; /* Led1任务,任务控制块实例化 */
OS_TMR BntScanTime; /* 软件定时器实例化 */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
void start_task( void *p_arg ); /* 起始任务函数 */
static void led_pa3( void *p_arg ); /* LED1任务函数 */
static void BtnScanTime_CallBack( void *p_tmr, void *p_arg ); /* 软件定时器回调函数 */
/* USER CODE END PFP */
/**
* @brief 应用层入口
* @param None
* @date 2023-11-16
*/
void Appliance( void )
{
OS_ERR err; /* 声明错误代码存储变量 */
OSInit(&err); /* 初始化 uC/OS */
CPU_SR_ALLOC(); /* 创建临界区变量 */
OS_CRITICAL_ENTER( ); /* 进入临界区 */
OSTaskCreate( (OS_TCB* ) &StartTaskTCB, /* 任务控制块 */
(CPU_CHAR* ) "start task", /* 任务名 */
(OS_TASK_PTR ) start_task, /* 任务函数 */
(void* ) NULL, /* 任务函数的入口参数 */
(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* ) NULL, /* 任务 TCB 内存拓展 */
(OS_OPT ) (OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR), /* 创建任务时的附加操作 */
(OS_ERR* ) &err); /* 返回错信息 */
OSTmrCreate( (OS_TMR* ) &BntScanTime, /* 软件定时器控制块 */
(CPU_CHAR* ) "BtnScanTime", /* 软件定时器的名字 */
(OS_TICK ) 5, /* 软件定时器的初始值 */
(OS_TICK ) 5, /* 软件定时器的重装载值 */
(OS_OPT ) OS_OPT_TMR_PERIODIC, /* 软件定时器的工作模式 */
(OS_TMR_CALLBACK_PTR ) BtnScanTime_CallBack, /* 软件定时器的回调函数 */
(void* ) NULL, /* 软件定时器的入口传入参数 */
(OS_ERR* ) &err ); /* 返回错误信息 */
OS_CRITICAL_EXIT( ); /* 退出临界区 */
OSTmrStart( (OS_TMR*) &BntScanTime, (OS_ERR*) &err ); /* 启动软件定时器 */
OSStart( &err ); /* 启动任务调度 */
}/* Appliance */
/**
* @brief 起始任务
* @param p_arg
* @date 2023-11-16
*/
void start_task( void *p_arg )
{
OS_ERR err;
(void)p_arg;
CPU_SR_ALLOC( ); /* 创建临界区变量 */
BSP_Init( ); /* Initialize BSP functions */
#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( ); /* 进入临界区 */
OSTaskCreate( (OS_TCB* ) &Led1TaskTCB, /* 任务控制块 */
(CPU_CHAR* ) "led_pa3", /* 任务名 */
(OS_TASK_PTR ) led_pa3, /* 任务函数 */
(void* ) NULL, /* 任务函数的入口参数 */
(OS_PRIO ) LED1_TASK_PRIO, /* 任务优先级 */
(CPU_STK* ) &LED1_TASK_STK[ 0 ], /* 任务堆栈基地址 */
(CPU_STK_SIZE ) LED1_STK_SIZE/10, /* 任务堆栈溢出最大值 */
(CPU_STK_SIZE ) LED1_STK_SIZE, /* 任务堆栈大小 */
(OS_MSG_QTY ) 0, /* 消息数量 */
(OS_TICK ) 0, /* 时间片数量 */
(void* ) NULL, /* 任务 TCB 内存拓展 */
(OS_OPT ) (OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR), /* 创建任务时的附加操作 */
(OS_ERR* ) &err); /* 返回错误码 */
OS_CRITICAL_EXIT( ); /* 退出临界区 */
OSTaskDel( (OS_TCB*) &StartTaskTCB, &err ); /* 删除起始任务 */
}/* start_task */
void MyPrintf( Data *pTemp )
{
printf( "%d\r\n", pTemp->Num );
}
/**
* @brief Led闪烁任务
* @param p_arg
* @date 2023-11-16
*/
static void led_pa3 ( void *p_arg )
{
OS_ERR err; /* 声明错误代码存储变量 */
Led_Typedef LED_G = { GPIOB, GPIO_PIN_8, 0 }; /* 注册一个LED灯 */
(void)p_arg; /* 消除编译器警告 */
BSP_Init( ); /* Initialize BSP functions */
CPU_Init( ); /* Initialize CPU module */
#if OS_CFG_STAT_TASK_EN > 0u /* 统计任务是否使能 */
OSStatTaskCPUUsageInit( &err ); /* Compute CPU capacity with no task running */
#endif
while ( DEF_TRUE )
{
LED.Flips( &LED_G ); /* 翻转LED灯 */
OSTimeDly( 100, OS_OPT_TIME_DLY, &err ); /* 延时500个时钟节拍 */
}
}/* led_pa3 */
/**
* @brief 按键扫描软件定时器回调函数
* @param p_tmr
* @param p_arg
* @date 2023-11-16
*/
static void BtnScanTime_CallBack( void *p_tmr, void *p_arg )
{
(void)p_arg; (void)p_tmr;
HAL_GPIO_TogglePin( GPIOA, GPIO_PIN_1 );
}/* BtnScanTime_CallBack */
appliance.h
#ifndef __APPLIANCE_H__
#define __APPLIANCE_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "includes.h"
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
/* USER CODE END ET */
/* Exported functions prototypes ---------------------------------------------*/
/* USER CODE BEGIN EFP */
void Appliance( void );
/* USER CODE END EFP */
#ifdef __cplusplus
}
#endif
#endif /* __APPLIANCE_H__ */
在主函数中添加一下代码,要记住声明头文件,大伙自行调用吧,这里就不贴代码了
其中有部分代码无关乎移植,删除就可以了,如下
void MyPrintf( Data *pTemp )
{
printf( "%d\r\n", pTemp->Num );
}
Led_Typedef LED_G = { GPIOB, GPIO_PIN_8, 0 }; /* 注册一个LED灯 */
LED.Flips( &LED_G ); /* 翻转LED灯 */
到这里就移植完了,添加测试代码,查看验证就可以了,找到 led_pa3 函数在主循环中添加代码
while ( DEF_TRUE )
{
LED.Flips( &LED_G ); /* 翻转LED灯 */
printf( "Task ---> Run\r\n" );
OSTimeDly( 100, OS_OPT_TIME_DLY, &err ); /* 延时500个时钟节拍 */
}
找到 BtnScanTime_CallBack 函数,添加一下代码
/**
* @brief 按键扫描软件定时器回调函数
* @param p_tmr
* @param p_arg
* @date 2023-11-16
*/
static void BtnScanTime_CallBack( void *p_tmr, void *p_arg )
{
(void)p_arg; (void)p_tmr;
printf( "BtnScanTime ---> Run\r\n" );
}/* BtnScanTime_CallBack */
下载验证就可以了,到此移植完成,结果就不贴图了,反正可看不出来,有问题评论区见吧,告辞