【STM32】ucOS-III多任务程序

【STM32】uc/OS-III多任务程序

文章目录

STM32F103C8T6移植uC/OS-III基于HAL库超完整详细过程与相关实验

实验任务

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

实验过程

一、 uC/OS-III源码下载

uC/OSIII

二、 建立STM32CubeMX工程

打开stm32 cubeMX,选择芯片stm32f103c8,配置系统时钟为72M,作为移植测试,将与LED相连的两个端口PB0,PB1配置为GPIO_Output,可根据LED现象作为我们是否移植成功的依据。

点击GENERATE CODE,生成工程如下:

三、 复制uC/OS-III文件到工程文件夹
  • 在生成的工程文件目录下新建一个UCOSIII 文件夹,将我们下载的源代码中三个文件夹: uC-CPU、 uC-LIB、 uCOS-III 复制到我们新建的文件夹中:

  • 在**/Core/Src文件夹下新建一个OS**文件夹:

  • 将刚才下载源码打开,将路径:\EvalBoards\Micrium\uC-Eval-STM32F107\uCOS-III 下的文件:
    app.c 、 app_cfg.h 、 cpu_cfg.h 、 includes.h 、 lib_cfg.h 、 os_app_hooks.c 、os_app_hook.h、os_cfg.h、os_cfg_app.h 复制到上一步建立的OS文件夹中,同时新建三个空白文件: bsp.c、bsp.h、app.h

四、 添加工程组件和头文件路径
  1. 添加工程分组

    打开工程, 按照如图所示添加六个新的组: bsp、uCOSIII_CPU、 uCOSIII_LIB、 uCOSIII_Ports、 uCOSIII_Source、 OS_cfg:

  2. 添加文件到分组

    • 文件目录是 Src/OS ,将其中 bsp.cbsp.h 文件添加至 bsp 组中:

    • 选择 uCOSIII_CPU 组件, 点击 Add Files...按钮,将文件目录跳转至:UCOSIII/uC-CPU , 选择 ALL files 文件类型,将其中的三个文件点击 Add 添加, 然后再打开: ARM-Cortex-M3\RealView, 同样选择 ALL files 文件类型,将三个文件添加进 uCOSIII_CPU 组:

    • 添加 uCOSIII_LIB 组件文件:选择 uCOSIII_LIB 组,点击 Add Files...按钮, 将文件目录跳转至: UCOSIII/uCLIB ,选择 ALL files 文件类型,将其中的九个文件添加进 uCOSIII_LIB 组;然后继续打开: Ports/ARM-Cortex-M3/Realview , 添加 lib_mem_a.asm 文件:

    • 选择 uCOSIII_Ports 组,点击 Add Files...按钮, 将文件目录调整至: UCOSIII/UcosIII/Ports/RAM-Cortex-M3/Generic/RealView。选择 ALL files 文件类型, 将其中三个文件添加进 uCOSIII_Ports 组:

    • 选择 uCOSIII_Source 组,点击Add Files...按钮, 将文件目录调整至: UCOSIII/UcosIII/Source 。选择 ALL files 文件类型, 将其中二十个文件添加进 uCOSIII_Source 组:

    • 选择 OS_cfg 组,点击 Add Files...按钮, 将文件目录调整至: Src/OS。选择 ALLfiles 文件类型, 将图中的八个文件添加进 uCOSIII_Sourc 组:

    至此,全部组件文件添加完成。

  3. 添加头文件路径

五、修改文件内容
  1. 启动文件

  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>,修改为:

      c 复制代码
      #include <bsp.h>
      #include "gpio.h"
      #include "app_cfg.h"
      #include "app.h"
    • 找到 #include <stm32f10x_lib.h>,修改为:#include "stm32f1xx_hal.h"

  4. bsp.h 和 bsp.c

    • bsp.h:

      c 复制代码
      #ifndef  __BSP_H__
      #define  __BSP_H__
      
      #include "stm32f1xx_hal.h"
      
      void BSP_Init(void);
      
      #endif
    • bsp.c:

      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
  5. lib_cfg.h

    这个头文件中有一个宏定义:

    c 复制代码
    #define  LIB_MEM_CFG_HEAP_SIZE          27u * 1024u

    表示把堆的空间设置为27KB,但是stm32f103c8t6的RAM总共才20K,所以这里需要将堆空间改小一点,我改成了10K。

    c 复制代码
    #define  LIB_MEM_CFG_HEAP_SIZE          10u * 1024u  
  6. main.c

    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 \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****/
六、实验效果


总结

在本次实验中,我深入了解了嵌入式实时操作系统(RTOS)的移植及配置过程。通过实际操作,我成功实现了在同一环境下多个任务的并行执行,这不仅加深了我对RTOS机制的理解,还让我掌握了多任务管理的技能。虽然过程中遇到了不少步骤和细节,需要一丝不苟地操作,但只要认真跟随教程指导,便能顺利完成。学习这个系统对将来的嵌入式多任务开发大有裨益,可以显著提升开发的效能和便捷性。

相关推荐
国科安芯4 小时前
航天器多路并联大功率电源系统设计与ASP4644均流特性分析
单片机·嵌入式硬件·fpga开发·安全性测试
茯苓gao6 小时前
嵌入式开发笔记:CANopen相关移位运算与通信协议术语详解
网络·嵌入式硬件·学习·信息与通信
梁朝辉9 小时前
STM32H750VBT6中ADCINP与INN什么区别
stm32·单片机·嵌入式硬件
省四收割者10 小时前
一文详解信号完整性(1)
python·嵌入式硬件·数学建模·信息与通信·信号处理·智能硬件
崇山峻岭之间11 小时前
单片机无感FOC驱动之ADC
单片机·嵌入式硬件
Ligocious11 小时前
1.点亮一颗小小的LED
单片机·嵌入式硬件
KaifuZeng15 小时前
通信与接口协议面试八、CAN通信
单片机·嵌入式硬件·面试·通信与接口协议
智源单片机设计16 小时前
基于单片机的直流电机双闭环调速系统设计
单片机·嵌入式硬件
kebidaixu16 小时前
两轮车换电 BMS 的模拟前端中颖 SH367306 AFE 芯片详解
stm32
kebidaixu17 小时前
两轮车换电 BMS 的模拟前端中颖 SH367306 AFE 芯片调试实录:四个关键问题与解决方案
stm32