前言
实时操作系统(RTOS) 是指当外界事件或数据产生时,能够接受并以足够快的速度予以处理,其处理的结果又能在规定的时间之内来控制生产过程或对处理系统做出快速响应,并控制所有实时任务协调一致运行的操作系统。提供及时响应和高可靠性是其主要特点。 实时操作系统是保证在一定时间限制内完成特定功能的操作系统。实时操作系统有硬实时和软实时之分,硬实时要求在规定的时间内必须完成操作,这是在操作系统设计时保证的;软实时则只要按照任务的优先级,尽可能快地完成操作即可。我们通常使用的操作系统在经过一定改变之后就可以变成实时操作系统。
一、μCOS简介
1.简介
uC/OS-III(Micro C OS Three 微型的C 语言编写的操作系统第3版) 是一个可升级的,可固化的,基于优先级的实时内核。它对任务的个数无限制。uC/OS-III 是一个第3 代的系统内核,支持现代的实时内核所期待的大部分功能。例如资源管理,同步,任务间的通信等等。
2.特点
1)优先级 μCOS-III是可以抢占的多任务内核,始终运行进入就绪态的最重要的任务。μC/OS-III支持无限数量的任务,并允许在运行时,监测堆栈增长的任务。它还支持无限数量的优先级。然而,通常情况下,对于大多数应用,32至256个不同的优先级是足够的。 2)多任务 uCOS-III允许有任意数量的任务,信号量,互斥信号量,事件标志,消息队列,定时器和内存分区(仅受限于处理器可用的RAM大小)。 3)中断极快 μC/OS-III提供接近零的中断停用时间。μC/OS-III有一些内部数据结构和变量,需要获得原子访问权(不能够被打断的)。这些关键区域的保护由锁调度,而不是由禁用中断实现。中断被禁用的时钟周期几乎为零,确保了实时操作系统将能够响应一些最快的中断源。
二、STM32F103C8T6移植uCOS
1.uCOS下载
STM32F107uCOS样例下载 下载完成后文件如下:
2.文件导入
1)项目创建 使用STM32CUBEMX创建空项目 2)项目管理 1、在新建项目中新建文件夹UCOSIII 2、将官网样例文件中的uC-CPU、uC-LIB、uCOS-III移动到新建的文件夹UCOSIII中,并新建文件夹uCOS-BSP、uCOS-CONFIG文件 3)文件添加 新建Groups:uCOS-BSP、uCOS-CPU、uCOS-LIB、uCOS-Core、uCOS-Port、uCOS-Config 1、uCOS-BSP中添加文件 完成后如下: 2、uCOS-CPU中添加文件 完成后如下: 3、uCOS-LIB中添加文件 完成后如下:
4、uCOS-Core中添加文件 共计20个文件 5、uCOS-Port中添加文件 完成后如下: 6、uCOS-Config中添加文件 7、keil总文件目录 4)头文件路径添加
3.文件修改
1、启动文件
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
改为
PendSV_Handler PROC
EXPORT PendSV_Handler [WEAK]
B .
ENDP
SysTick_Handler PROC
EXPORT SysTick_Handler [WEAK]
B .
ENDP
改为 2、app_cfg.h
#define APP_CFG_SERIAL_EN DEF_ENABLED 改为 #define APP_CFG_SERIAL_EN DEF_DISABLED
#define APP_TRACE BSP_Ser_Printf 改为 #define APP_TRACE (void)
3、includes.h
第一处修改: 添加相关头文件 #include <bsp.h> 修改为 #include <bsp.h> #include “gpio.h” #include “app_cfg.h” #include "app.h"
第二处修改: 添加HAL 库 #include <stm32f10x_lib.h> 修改为 #include "stm32f1xx_hal.h"
4、 bsp.c和bsp.h
#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();
}
#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;
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
###################################################################
#ifndef __BSP_H__
#define __BSP_H__
#include "stm32f1xx_hal.h"
void BSP_Init(void);
#endif
5、lib_cfg.h 这个头文件中有一个宏定义: #define LIB_MEM_CFG_HEAP_SIZE 27u * 1024u 表示把堆的空间设置为27KB,但是我使用的stm32f103c8t6的RAM总共才20K,所以这里需要将堆空间改小一点,我改成了10K #define LIB_MEM_CFG_HEAP_SIZE 10u * 1024u 此处的修改若是对于RAM空间较大的单片机是没有必要的,但是对于小容量的单片机则是必须的。
三、简单多任务实现
1、main.c
#include "main.h"
#include "usart.h"
#include "gpio.h"
#include <includes.h>
#include <stdio.h>
int fputc(int ch,FILE *f)
{
HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFF);
while(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_TC)!=SET){
}
return ch;
}
static OS_TCB AppTaskStartTCB;
OS_TCB LEDPB6TaskTCB;
OS_TCB LEDPB7TaskTCB;
OS_TCB USART1TaskTCB;
static CPU_STK AppTaskStartStk[APP_TASK_START_STK_SIZE];
static void AppTaskCreate(void);
static void AppObjCreate(void);
static void AppTaskStart(void *p_arg);
void LEDPB6_TASK(void *p_arg);
void LEDPB7_TASK(void *p_arg);
void USART1_TASK(void *p_arg);
#define LEDPB6_TASK_PRIO 3
#define LEDPB7_TASK_PRIO 3
#define USART1_TASK_PRIO 3
#define LEDPB6_STK_SIZE 128
#define LEDPB7_STK_SIZE 128
#define USART1_STK_SIZE 128
CPU_STK LEDPB6_TASK_STK[LEDPB6_STK_SIZE];
CPU_STK LEDPB7_TASK_STK[LEDPB7_STK_SIZE];
CPU_STK USART1_TASK_STK[USART1_STK_SIZE];
void SystemClock_Config(void);
int main(void)
{
OS_ERR err;
HAL_Init();
SystemClock_Config();
OSInit(&err);
MX_GPIO_Init();
MX_USART1_UART_Init();
OSTaskCreate((OS_TCB *)&AppTaskStartTCB,
(CPU_CHAR *)"App Task Start",
(OS_TASK_PTR ) AppTaskStart,
(void *) 0,
(OS_PRIO ) APP_TASK_START_PRIO,
(CPU_STK *)&AppTaskStartStk[0],
(CPU_STK_SIZE) APP_TASK_START_STK_SIZE / 10,
(CPU_STK_SIZE) APP_TASK_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);
OSStart(&err);
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
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_1) != HAL_OK)
{
Error_Handler();
}
}
static void AppTaskStart (void *p_arg)
{
OS_ERR err;
(void)p_arg;
BSP_Init();
CPU_Init();
Mem_Init();
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err);
#endif
CPU_IntDisMeasMaxCurReset();
AppTaskCreate();
AppObjCreate();
OSTaskCreate((OS_TCB * )&LEDPB6TaskTCB,
(CPU_CHAR * )"PB6 task",
(OS_TASK_PTR )LEDPB6_TASK,
(void * )0,
(OS_PRIO )LEDPB6_TASK_PRIO,
(CPU_STK * )&LEDPB6_TASK_STK[0],
(CPU_STK_SIZE)LEDPB6_STK_SIZE/10,
(CPU_STK_SIZE)LEDPB6_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 * )&LEDPB7TaskTCB,
(CPU_CHAR * )"PB7 task",
(OS_TASK_PTR )LEDPB7_TASK,
(void * )0,
(OS_PRIO )LEDPB7_TASK_PRIO,
(CPU_STK * )&LEDPB7_TASK_STK[0],
(CPU_STK_SIZE)LEDPB7_STK_SIZE/10,
(CPU_STK_SIZE)LEDPB7_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 * )&USART1TaskTCB,
(CPU_CHAR * )"usart1 task",
(OS_TASK_PTR )USART1_TASK,
(void * )0,
(OS_PRIO )USART1_TASK_PRIO,
(CPU_STK * )&USART1_TASK_STK[0],
(CPU_STK_SIZE)USART1_STK_SIZE/10,
(CPU_STK_SIZE)USART1_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*)&AppTaskStartTCB,&err);
}
void LEDPB6_TASK (void *p_arg)
{
OS_ERR err;
(void)p_arg;
BSP_Init();
CPU_Init();
Mem_Init();
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err);
#endif
CPU_IntDisMeasMaxCurReset();
AppTaskCreate();
AppObjCreate();
while (DEF_TRUE)
{
OSTimeDly(1000, OS_OPT_TIME_DLY, &err);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);
OSTimeDly(1000, OS_OPT_TIME_DLY, &err);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);
}
}
void LEDPB7_TASK (void *p_arg)
{
OS_ERR err;
(void)p_arg;
BSP_Init();
CPU_Init();
Mem_Init();
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err);
#endif
CPU_IntDisMeasMaxCurReset();
AppTaskCreate();
AppObjCreate();
while (DEF_TRUE)
{
OSTimeDly(1000, OS_OPT_TIME_DLY, &err);
OSTimeDly(1000, OS_OPT_TIME_DLY, &err);
OSTimeDly(1000, OS_OPT_TIME_DLY, &err);
OSTimeDly(1000, OS_OPT_TIME_DLY, &err);
OSTimeDly(1000, OS_OPT_TIME_DLY, &err);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);
OSTimeDly(1000, OS_OPT_TIME_DLY, &err);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);
}
}
void USART1_TASK (void *p_arg)
{
OS_ERR err;
(void)p_arg;
BSP_Init();
CPU_Init();
Mem_Init();
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err);
#endif
CPU_IntDisMeasMaxCurReset();
AppTaskCreate();
AppObjCreate();
while (DEF_TRUE)
{
printf("hello uc/OS! 欢迎来到RTOS多任务环境!");
OSTimeDly(1000, OS_OPT_TIME_DLY, &err);
OSTimeDly(1000, OS_OPT_TIME_DLY, &err);
}
}
static void AppTaskCreate (void)
{
}
static void AppObjCreate (void)
{
}
void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif
2、运行结果
3、注意事项
1)keil编译报错内存不足 .\Objects\ucos-led.axf: Error: L6406E: No space in execution regions with .ANY selector matching os_cfg_app.o(.bss). 参考解决方法: 将红框数据改大即可 2)重写输出函数后需要勾选 Use MicroLIB
参考
https://blog.csdn.net/weixin_43116606/article/details/105532222
|