12周嵌入式RTOS多任务程序设计

一实验目的


理解RTOS的概念、特点和作用,包括任务调度、资源管理等基本原理。
掌握uc/OS-III作为RTOS的具体应用,并了解其在嵌入式系统中的应用场景。
移植RTOS到STM32F103上
学习如何将uc/OS-III移植到指定硬件平台上,理解移植的基本步骤和方法。
熟悉硬件抽象层(HAL)与RTOS之间的交互关系,包括时钟配置、中断处理、GPIO控制等方面的配置和使用。
理解任务(task)的概念和创建方法,包括任务初始化、任务优先级设置等基本概念。
设计并创建两个任务,分别以不同的周期对LED进行点亮-熄灭的控制,从而加深对任务调度和任务间通信的理解。
创建第三个任务,通过串口发送“hello uc/OS! 欢迎来到RTOS多任务环境!”,以加深对任务间协作和串口通信的理解。
记录详细的移植过程
锻炼对实际操作的记录和总结能力,包括对配置文件修改、任务初始化、优先级设置等关键步骤的记录和详细说明。
在整个移植过程中,培养对问题排查和解决的能力,包括对任务调度不准确、硬件驱动配置错误等各种问题的解决过程记录。

二实验任务


学习嵌入式实时操作系统(RTOS),以uc/OS-III为例,将其移植到stm32F103上,构建至少3个任务(task):其中两个task分别以1s和3s周期对LED等进行点亮-熄灭的控制;另外一个task以2s周期通过串口发送“hello uc/OS! 欢迎来到RTOS多任务环境!”。记录详细的移植过程。

三实验相关知识


RTOS中的基本概念
OS(操作系统,operating system),是嵌入式系统中的灵魂,是其软件系统中的重要组成部分,嵌入式系统的智能化程度与其密不可分。

从嵌入式系统的应用领域来看,嵌入式操作系统可以分为实时操作系统(RTOS)和非实时操作系统(NRTOS)。
uC/OS-II
uC/OS-II ,一个实时多任务的微内核,为 Jean J. Labrosse 在 1992 年编写的一个开源代码。由于内核小(仅由十几个 C 语言和汇编文件构成),应用范围宽,目前可应用在许多工业控制器、通信设备和交换机中。它既是实时多任务的微内核,又是开源的代码。

uCOS-II系统设置了两个系统任务,空闲任务和统计任务。Cpu空闲状态下执行空闲任务。目前任务必须存在。统计任务就是统计一下在单位时间内CPU的使用时间,也叫CPU占用率。统计任务可以通过设置使它不存在。
在这里插入图片描述

任务的状态:睡眠状态、就绪状态、运行状态、等待状态、中断服务状态。


四所需工具


1、芯片: STM32F103C8T6
2、STM32CubeMx软件
3、IDE: MDK-Keil软件
4、STM32F1xx/STM32F4xxHAL库
5、LED灯


五实验内容


学习嵌入式实时操作系统(RTOS),以uc/OS-III为例,将其移植到stm32F103上,构建至少3个任务(task):其中两个task分别以1s和3s周期对LED等进行点亮-熄灭的控制;另外一个task以2s周期通过串口发送“hello uc/OS! 欢迎来到RTOS多任务环境!”。记录详细的移植过程。

1工程新创
🎈 点击ACCESS TO MCU SELECTOR

在这里插入图片描述

选择STM32F103C8T6芯片
在这里插入图片描述

2.引脚排列和配置
2.1 配置RCC与SYS
2.1.1 配置RCC
🎈 点System Cor,选择RCC,在右侧弹出的菜单栏中选Crystal/Ceramic Resonator:
在这里插入图片描述

发现部分引脚高亮。

在这里插入图片描述

2.1.1 配置SYS
🎈 选择调试接口,点System Cor,选择SYS。在右侧弹出的菜单栏中选Serial Wire:

在这里插入图片描述

3.配置USART1
🎈 配置串口USART1:
在这里插入图片描述

4.设置LED端口
🎈 设置PA3、PC13作为两个LED灯的端口:
在这里插入图片描述

5.生成工程
🎈 配置如下:

在这里插入图片描述

四)准备uCOSIII源码
🎈进入官网下载:http://micrium.com/downloadcenter/
🎈或链接:https://pan.baidu.com/s/10RqsDRecbmVteWmDv2oUNQ
🎈提取码:1234
网盘下载,打开目录如下(文件夹uC-BSP和uC-CONFIG是自己新建的两个文件夹)

网盘下载,打开目录如下(文件夹uC-BSP和uC-CONFIG是自己新建的两个文件夹)

在这里插入图片描述

(五)移植前准备
1.文件内部移植
🎈 为uC-BSP文件夹新建bsp.c和bsp.h文件。
在这里插入图片描述

给文件夹uC-CONFIG添加以下文件(从以下路径复制过来)
在这里插入图片描述

粘贴
在这里插入图片描述

2.将uCOS相关文件复制到HAL工程的MDK-ARM文件夹下
🎈 操作如下:

在这里插入图片描述
在这里插入图片描述

(六)开始移植
回到Keil打开的HAL工程

1.将uCOS文件添加到项目
点击Manage Project Items:
在这里插入图片描述

为项目新建文件夹如下:
在这里插入图片描述
在这里插入图片描述

再打开MDK-ARM\uC-CPU\ARM-Cortex-M3\RealView路径,选中以下文件,Add添加
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

点击PORT–>Add Files…,打开MDK-ARM\uCOS-III\Ports\ARM-Cortex-M3\Generic\RealView路径,

在这里插入图片描述

点击SOURCE–>Add Files…,MDK-ARM\uCOS-III\Source路径下选中以下全部.c .h文件,Add添加:
在这里插入图片描述

点击CONFIG–>Add Files…,MDK-ARM\uC-CONFIG路径下选中以下全部文件,Add添加
在这里插入图片描述

点击BSP–>Add Files…,LMDK-ARM\uC-BSP路径下选中以下全部文件,Add添加:
在这里插入图片描述

点击OK,项目结构如图

在这里插入图片描述

2.导入文件路径
🎈 导入文件路径:
在这里插入图片描述

项目路径下寻找:
在这里插入图片描述

3.为bsp.c和bsp.h添加代码
🎈 为bsp.c和bsp.h添加代码

3.1 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

2 bsp.h代码
🎈 bsp.h代码:

#ifndef  __BSP_H__
#define  __BSP_H__

#include "stm32f1xx_hal.h"

void BSP_Init(void);

#endif

.修改startup_stm32f103xb.s文件代码
🎈 在以下位置处:

PendSV_Handler改为OS_CPU_PendSVHandler,
SysTick_Handler改为OS_CPU_SysTickHandler

5.修改app_cfg.h文件代码
🎈 DEF_ENABLED 改为 DEF_DISABLED

#define APP_TRACE BSP_Ser_Printf 改为 #define APP_TRACE(void)

6.修改includes.h文件代码
🎈 在#include <bsp.h>下面添加 #include “gpio.h” 和 #include “app_cfg.h”
🎈 将#include <stm32f10x_lib.h> 改为 #include “stm32f1xx_hal.h”

7.修改lib_cfg.h文件代码
🎈 修改为5u:

8.修改usart.c文件代码

🎈 添加代码完成printf重定向:
/* USER CODE BEGIN 1 */

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

/* USER CODE END 1 */

9.修改usart.h文件代码
🎈 添加定义代码:

typedef struct __FILE FILE;

10.初始化管脚
🎈 在gpio.c文件中修改代码:

void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);


  /*Configure GPIO pin : PC13|PA3 */
  GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_3;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	
}

(七)撰写代码与效果实现
1.撰写主函数
🎈 修改main.c文件代码:

/* 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 LED0_TASK_PRIO		4
#define MSG_TASK_PRIO		5
#define LED1_TASK_PRIO		6

/* 任务堆栈大小	*/
#define START_STK_SIZE 		96
#define LED0_STK_SIZE 		64
#define MSG_STK_SIZE 		64
#define LED1_STK_SIZE 		64

/* 任务栈 */	
CPU_STK START_TASK_STK[START_STK_SIZE];
CPU_STK LED0_TASK_STK[LED0_STK_SIZE];
CPU_STK MSG_TASK_STK[MSG_STK_SIZE];
CPU_STK LED1_TASK_STK[LED1_STK_SIZE];

/* 任务控制块 */
OS_TCB StartTaskTCB;
OS_TCB Led0TaskTCB;
OS_TCB MsgTaskTCB;
OS_TCB Led1TaskTCB;

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

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

/* USER CODE BEGIN PV */

/* 任务函数定义 */
void start_task(void *p_arg);
static  void  AppTaskCreate(void);
static  void  AppObjCreate(void);
static  void  led_pc13(void *p_arg);
static  void  send_msg(void *p_arg);
static  void  led_pa3(void *p_arg);
/* 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();	//进入临界区
	/* 创建LED0任务 */
	OSTaskCreate((OS_TCB 	* )&Led0TaskTCB,		
				 (CPU_CHAR	* )"led_pc13", 		
                 (OS_TASK_PTR )led_pc13, 			
                 (void		* )0,					
                 (OS_PRIO	  )LED0_TASK_PRIO,     
                 (CPU_STK   * )&LED0_TASK_STK[0],	
                 (CPU_STK_SIZE)LED0_STK_SIZE/10,	
                 (CPU_STK_SIZE)LED0_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);		

/* 创建LED1任务 */
	OSTaskCreate((OS_TCB 	* )&Led1TaskTCB,		
				 (CPU_CHAR	* )"led_pa3", 		
                 (OS_TASK_PTR )led_pa3, 			
                 (void		* )0,					
                 (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   	* )0,					
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                 (OS_ERR 	* )&err);										 
				 
	/* 创建MSG任务 */
	OSTaskCreate((OS_TCB 	* )&MsgTaskTCB,		
				 (CPU_CHAR	* )"send_msg", 		
                 (OS_TASK_PTR )send_msg, 			
                 (void		* )0,					
                 (OS_PRIO	  )MSG_TASK_PRIO,     	
                 (CPU_STK   * )&MSG_TASK_STK[0],	
                 (CPU_STK_SIZE)MSG_STK_SIZE/10,	
                 (CPU_STK_SIZE)MSG_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();	//进入临界区
}
/**
  * 函数功能: 启动任务函数体。
  * 输入参数: p_arg 是在创建该任务时传递的形参
  * 返 回 值: 无
  * 说    明:无
  */
static  void  led_pc13 (void *p_arg)
{
  OS_ERR      err;

  (void)p_arg;

  BSP_Init();                                                 /* Initialize BSP functions                             */
  CPU_Init();

  Mem_Init();                                                 /* Initialize Memory Management Module                  */

#if OS_CFG_STAT_TASK_EN > 0u
  OSStatTaskCPUUsageInit(&err);                               /* Compute CPU capacity with no task running            */
#endif

  CPU_IntDisMeasMaxCurReset();

  AppTaskCreate();                                            /* Create Application Tasks                             */

  AppObjCreate();                                             /* Create Application Objects                           */

  while (DEF_TRUE)
  {
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
		OSTimeDlyHMSM(0, 0, 1, 0,OS_OPT_TIME_HMSM_STRICT,&err);
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
		OSTimeDlyHMSM(0, 0, 1, 0,OS_OPT_TIME_HMSM_STRICT,&err);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

static  void  led_pa3 (void *p_arg)
{
  OS_ERR      err;

  (void)p_arg;

  BSP_Init();                                                 /* Initialize BSP functions                             */
  CPU_Init();

  Mem_Init();                                                 /* Initialize Memory Management Module                  */

#if OS_CFG_STAT_TASK_EN > 0u
  OSStatTaskCPUUsageInit(&err);                               /* Compute CPU capacity with no task running            */
#endif

  CPU_IntDisMeasMaxCurReset();

  AppTaskCreate();                                            /* Create Application Tasks                             */

  AppObjCreate();                                             /* Create Application Objects                           */

  while (DEF_TRUE)
  {
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_RESET);
		OSTimeDlyHMSM(0, 0, 3, 0,OS_OPT_TIME_HMSM_STRICT,&err);
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET);
		OSTimeDlyHMSM(0, 0, 3, 0,OS_OPT_TIME_HMSM_STRICT,&err);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

static  void  send_msg (void *p_arg)
{
  OS_ERR      err;

  (void)p_arg;

  BSP_Init();                                                 /* Initialize BSP functions                             */
  CPU_Init();

  Mem_Init();                                                 /* Initialize Memory Management Module                  */

#if OS_CFG_STAT_TASK_EN > 0u
  OSStatTaskCPUUsageInit(&err);                               /* Compute CPU capacity with no task running            */
#endif

  CPU_IntDisMeasMaxCurReset();

  AppTaskCreate();                                            /* Create Application Tasks                             */

  AppObjCreate();                                             /* Create Application Objects                           */

  while (DEF_TRUE)
  {
			printf("hello uc/OS!欢迎来到RTOS多任务环境! \r\n");
		OSTimeDlyHMSM(0, 0, 2, 0,OS_OPT_TIME_HMSM_STRICT,&err);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}


/* 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****/

2.环境配置
🎈 如图所示:

在这里插入图片描述

3.电路搭建
4.效果实现如下

在这里插入图片描述
在这里插入图片描述

六实验总结


在这个项目中,我们系统地学习了嵌入式实时操作系统(RTOS),并以uc/OS-III为例进行了移植到STM32F103上的实际操作。移植过程让我们更深入地了解了RTOS的内部机制和与特定硬件平台的适配。
我们成功地构建了至少3个任务(task),其中两个任务分别以1秒和3秒周期对LED进行控制,另一个任务以2秒周期通过串口发送特定的消息。这一步让我们深入了解了任务调度、任务优先级和任务间通信等概念。
在移植过程中,我们深入理解了硬件抽象层(HAL)与RTOS之间的交互关系,包括对时钟、中断处理、GPIO控制等方面的配置和使用。这一过程让我们更加深入地了解了嵌入式系统的底层硬件操作。
在整个实验过程中,我们遇到了各种问题,如任务调度不准确、硬件驱动配置错误等。通过仔细的调试和问题解决,我们不断提高了对RTOS的理解,并将其稳定地移植到目标硬件上。
我们详细地记录了移植过程的每一个关键步骤,包括配置文件的修改、任务初始化、优先级设置等。这样的文档记录不仅对我们自己的学习有帮助,也能够为其他人提供参考。
通过这次实验,我们不仅仅学到了关于RTOS的知识和移植技术,更重要的是,我们深刻认识到了对嵌入式系统的深入理解和掌握能力对于解决实际问题的重要性。这次实验让我们更加深入地理解了RTOS对于多任务处理和资源管理的重要性,也让我们在未来的嵌入式系统开发中更加得心应手。

  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
选择嵌入式RTOS需要考虑以下几个方面: 1. 任务调度算法:嵌入式RTOS的任务调度算法对系统的响应速度、资源利用率和稳定性等方面都有很大影响。一般来说,常用的任务调度算法有时间片轮转、优先级调度、最短作业优先等。选择嵌入式RTOS时需要根据具体应用场景来选择合适的任务调度算法。 2. 支持的处理器架构:不同的嵌入式处理器架构需要不同的RTOS支持。例如,ARM Cortex-M处理器可以选择FreeRTOS、uC/OS-II、ThreadX等RTOS。而对于其他处理器架构,需要选择对应的RTOS。 3. 功能和性能:不同的嵌入式RTOS提供的功能和性能也不同。例如,FreeRTOS提供了完整的任务管理、内存管理、信号量和消息队列等功能,而uC/OS-II则提供了更加轻量级的任务管理和内存管理。选择嵌入式RTOS时需要根据具体应用场景来选择合适的功能和性能。 4. 社区支持和文档资料:嵌入式RTOS的社区支持和文档资料对于开发和调试都非常重要。选择一个有活跃社区和丰富文档资料的RTOS可以更加方便地解决问题和进行开发。 5. 商业支持:一些嵌入式RTOS提供商业支持,例如提供付费技术支持、培训课程等。如果需要商业支持的话,可以考虑选择这些RTOS。 综上所述,选择嵌入式RTOS需要根据具体应用场景来选择。可以根据以上几个方面来进行筛选和比较,最终选择一个适合自己的嵌入式RTOS

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值