STM32CubeMx+freeRTOS的使用

目录

第一步,利用CubeMx创建工程并修改一些必要设置

第二步,测试LED灯和HAL库延时

第三步,选择和配置freeRTOS选项

3.1、选择RTOSV1版本

3.2、配置内核参数

3.3、设置Task、SoftTimer

3.4、设置时基,生成代码

第四步,分析和使用生成的代码

4.1、先对比下与ucOSII有什么不同

4.2 freeRTOS生成的代码

5、结束


第一步,利用CubeMx创建工程并修改一些必要设置

牛逼的大佬,也可以直接做成脚本,我这里每次都是采用手动设置。

具体参考我上篇文章,里面讲述了详细步骤

移植和使用ucOSII_柿子风年的博客-CSDN博客

第二步,测试LED灯和HAL库延时

先不选择freeRTOS,只生成最基础的驱动代码,测试LED灯IO控制和延时能否正常运行。

这一步可以取消,但很有必要。

主要是为了测试板子能不能正常起来,如果LED灯无法正常闪烁,基本是硬件问题,抑或是芯片及芯片驱动有问题。

第三步,选择和配置freeRTOS选项

3.1、选择RTOSV1版本

V1和V2版本主要的区别在于,V2兼容支持的硬件更多,内存耗费更多;

对于常见的Cortex-M3、M4、M7芯片,选择V1即可。

STM32CubeMx+freeRTOS的使用_第1张图片

3.2、配置内核参数

见下图。 

核心参数1,tick中断频率,数值为1000时即1ms中断1次。

核心参数2,最大优先级数量,根据使用场景进行设置。

核心参数3,内存管理设置,默认采用堆内存方式进行管理。

STM32CubeMx+freeRTOS的使用_第2张图片

 这里只在内核参数中修改一个东西,就是软件定时器使能,如下图,

STM32CubeMx+freeRTOS的使用_第3张图片

3.3、设置Task、SoftTimer

1)首先是创建一个任务,我的习惯是将所有任务设置为weak方式。

这种方式的优点是,在后续改动CubeMx文件时,不影响现有的代码。

懂得weak关键字优点的自然懂。

2)其次是任务堆栈大小和优先级的设置

在实际应用中,堆栈大小根据栈内存和嵌套调用情况而定,实际大小需要进行测试和修改,防止浪费内存。

特别的,freeRTOS支持相同优先级任务,相同优先级任务之间的调度,采用的是轮询机制,每个任务分配一定的执行时间。

不同优先级任务之间的调度,执行的是抢占式调度。

3)最后是任务函数名和字符串名称

一般的习惯是,相同的字符串,函数名首字母大写,字符串名称小写。

STM32CubeMx+freeRTOS的使用_第4张图片

 类似地,再创建一个定时器任务,用作软件定时,如下图。

STM32CubeMx+freeRTOS的使用_第5张图片

3.4、设置时基,生成代码

此时点击生成代码,会弹出警告,在使用FreeRTOS时,必须为HAL设置一个非SysTick定时器作为HAL的基础时钟,SysTick将自动作为FreeRTOS的基础时钟。

这里选择TIM6作为HAL库的基础时钟。

STM32CubeMx+freeRTOS的使用_第6张图片

第四步,分析和使用生成的代码

4.1、先对比下与ucOSII有什么不同

一是SysTick_Handler中断专门用来触发系统信号;

二是HAL_IncTick中断用单独的定时器触发;

并且二者优先级都设置为最低。

//FreeRTOSConfig.h文件

/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names. */
#define vPortSVCHandler    SVC_Handler
#define xPortPendSVHandler PendSV_Handler

/* IMPORTANT: This define is commented when used with STM32Cube firmware, when the timebase source is SysTick,
              to prevent overwriting SysTick_Handler defined within STM32Cube HAL */

#define xPortSysTickHandler SysTick_Handler



//port.c文件

/*-----------------------------------------------------------*/

void xPortSysTickHandler( void )
{
	/* The SysTick runs at the lowest interrupt priority, so when this interrupt
	executes all interrupts must be unmasked.  There is therefore no need to
	save and then restore the interrupt mask value as its value is already
	known - therefore the slightly faster vPortRaiseBASEPRI() function is used
	in place of portSET_INTERRUPT_MASK_FROM_ISR(). */
	vPortRaiseBASEPRI();
	{
		/* Increment the RTOS tick. */
		if( xTaskIncrementTick() != pdFALSE )
		{
			/* A context switch is required.  Context switching is performed in
			the PendSV interrupt.  Pend the PendSV interrupt. */
			portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
		}
	}
	vPortClearBASEPRIFromISR();
}
/*-----------------------------------------------------------*/



//main.c文件

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* USER CODE BEGIN Callback 0 */

  /* USER CODE END Callback 0 */
  if (htim->Instance == TIM6) {
    HAL_IncTick();
  }
  /* USER CODE BEGIN Callback 1 */

  /* USER CODE END Callback 1 */
}

4.2 freeRTOS生成的代码

如下main函数,

先定义软件定时器任务,其次是起始任务,和测试任务,

然后调用内核启动函数。

  osTimerDef(testTimer, TestTimerCallback);
  testTimerHandle = osTimerCreate(osTimer(testTimer), osTimerPeriodic, NULL);

  /* Create the thread(s) */
  /* definition and creation of defaultTask */
  osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
  defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);

  /* definition and creation of testTask */
  osThreadDef(testTask, TestTask, osPriorityNormal, 0, 128);
  testTaskHandle = osThreadCreate(osThread(testTask), NULL);

  /* Start scheduler */
  osKernelStart();

  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  HAL_GPIO_TogglePin(LED_YELLOW_GPIO_Port, LED_YELLOW_Pin);
	  HAL_Delay(200);
  }


//********************************************************************************
//*********************************** 分隔符 **************************************
//********************************************************************************

__weak void TestTask(void const * argument)
{
  /* USER CODE BEGIN TestTask */
  /* Infinite loop */
  for(;;)
  {
    osDelay(1);
  }
  /* USER CODE END TestTask */
}

我们修改一下测试任务,测试LED闪烁。

注意__weak声明的函数,不能在同一个文件中同时进行弱定义和强定义,

需要放到另外一个文件中。

也是为了不修改CubeMx生成的代码,从而将应用代码隔离出来。

void TestTask(void const * argument)
{
  /* USER CODE BEGIN TestTask */
  /* Infinite loop */
  for(;;)
  {
    HAL_GPIO_TogglePin(LED_BLUE_GPIO_Port, LED_BLUE_Pin);
    osDelay(200);
  }
  /* USER CODE END TestTask */
}

运行之后,可以看到蓝灯开始闪烁。

5、结束

你可能感兴趣的:(RTOS,嵌入式硬件,c语言)