【STM32】STM32CubeMX使用FreeRTOS教程1----定时器学习

【STM32】STM32CubeMX使用FreeRTOS教程1----定时器学习

前言

本教程将对应外设原理,HAL库、STM32CubeMX和FreeRTOS结合在一起讲解,分析学习过程中遇到的问题和一些注意事项。

知识概括:

SMT32定时器原理
STM32CubeMX创建定时器例程
HAL库TIM定时器函数库
定时器中断的创建与使用
FreeRTOS中断级临界代码段理解

定时器简介

SMT32F1系列共有8个定时器:

高级定时器(TIM1、TIM8);通用定时器(TIM2、TIM3、TIM4、TIM5);基本定时器(TIM6、TIM7)。

SMT32F4系列共有15个定时器:

高级定时器(TIM1、TIM8);通用定时器(TIM2、TIM3、TIM4、TIM5、TIM9~TIM14);基本定时器(TIM6、TIM7)。

基本定时器功能(TIM6、TIM7):

1. 16位向上、向下、向上/下自动装载计数器
2. 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65535之间的任意数值
3. 触发DAC的同步电路 注:此项是TIM6/7独有功能.
4. 位于APB1总线上
**

通用定时器(TIM2~TIM5)的主要功能:

  1. 16位向上、向下、向上/下自动装载计数器

  2. 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65535之间的任意数值

  3. 4 个独立通道(TIMx_CH1~4)可以用作:
    测量输入信号的脉冲长度( 输入捕获)
    输出比较
    单脉冲模式输出
    PWM输出(边缘或中间对齐模式)

  4. 支持针对定位的增量(正交)编码器和霍尔传感器电路

  5. 如下事件发生时产生中断/DMA:
    更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
    触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
    输入捕获
    输出比较

  6. 位于APB1总线上

CubeMX创建freertos工程

CubeMX工程中我选的芯片为STM32F103C8T6

1、设置RCC

设置高速外部时钟HSE 选择外部时钟源
【STM32】STM32CubeMX使用FreeRTOS教程1----定时器学习_第1张图片

2、设置时钟

选择外部时钟为8MHz,在HCLK中直接输入72,CubeMX会自动配置好。
【STM32】STM32CubeMX使用FreeRTOS教程1----定时器学习_第2张图片
设置时钟后,需要选择系统时钟来源,当使用了FreeRtos的时候,强烈建议HAL库使用除了Systick以外的时钟源。也就是说当不使用FreeRtos的时候,HAL使用的是systick作为时钟源,现在使用了rtos,不建议hal库和rtos一起使用systick作为时钟源。在这里我选择了TIM1作为HAL库时钟。
【STM32】STM32CubeMX使用FreeRTOS教程1----定时器学习_第3张图片

3、设置定时器

定时器选择内部时钟
Prtscaler (定时器分频系数) : 7199
Counter Mode(计数模式) Up(向上计数模式)
Counter Period(自动重装载值) : 4999
CKD(时钟分频因子) : No Division 不分频
auto-reload-preload(自动重装载) : Enable 使能

在这里定时器溢出时间公式,根据公式溢出时间为500ms
在这里插入图片描述

在NVIC Settings中使能定时器中断
在这里插入图片描述

4、配置freeRTOS

在Middleware中选中FREERTOS

根据自己需要裁剪freertos,我一般选中系统默认配置。
【STM32】STM32CubeMX使用FreeRTOS教程1----定时器学习_第4张图片

编写定时器中断代码

在这里使用了两个定时器,定时器3每1s触发一次,优先级为4(优先级分组4),定时器4每0.5s触发一次,优先级为5,在FreeRTOS中优先级低于configMAX_SYSCALL_INTERRUPT_PRIORITY优先级的中断在临界代码段开启时会被屏蔽(这里优先级越高,数字越低)。如果使用FreeRTOS默认配置的话configMAX_SYSCALL_INTERRUPT_PRIORITY为5。在任务中会开启临界代码段观察定时器情况。

任务代码

在这里使用的HAL_Delay(5000);会用到TIM定时器1,他的优先级等于0,优先级最高!

void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
  /* Infinite loop */
  for(;;)
  {
		printf("close\r\n");
		portDISABLE_INTERRUPTS();
		HAL_Delay(5000);
		printf("open\r\n");
		portENABLE_INTERRUPTS();
        osDelay(2000);
  }
  /* USER CODE END StartDefaultTask */
}

定时器回调函数

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

  /* USER CODE END Callback 0 */
  if (htim->Instance == TIM1) {
    HAL_IncTick();
  }
  /* USER CODE BEGIN Callback 1 */
  if (htim->Instance == TIM3)
  {
			printf("time3\r\n");
  }
		
  if (htim->Instance == TIM4)
  {
			printf("time4\r\n");
  }
  /* USER CODE END Callback 1 */
}

定时器相关函数讲解:

  /* USER CODE BEGIN 2 */
    /*使能定时器3、4中断*/
    HAL_TIM_Base_Start_IT(&htim3);
    HAL_TIM_Base_Start_IT(&htim4);
  /* USER CODE END 2 */

打开定时器

HAL_TIM_IRQHandler(&htim2);

定时器中断处理函数在stm32f1xx_it.c中 ,定时器中断服务函数中这个函数的具体作用是判断中断是否正常,然后判断产生的是哪一类定时器中断(溢出中断/PWM中断…),然后进入相应的中断回调函数

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

在HAL库中,每进行完一个中断,并不会立刻退出,而是会进入到中断回调函数中,这里我们是使用定时器溢出中断回调函数
void TIM3_IRQHandler(void) 首先进入中断函数HAL_TIM_IRQHandler(&htim2);之后进入定时器中断处理函数判断产生的是哪一类定时器中断(溢出中断/PWM中断…) 和定时器通道void HAL_TIM_PeriodElapsedCallback(&htim2); 进入相对应中断回调函数(此处为溢出中断)
在中断回调函数中添加用户代码你也可以在在stm32f1xx_it.c中找到中断回调函数

__weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)   

现象

在开启临界保护时,优先级低于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断不会被触发,而time3定时器为4,所有可以一直触发。当关闭临界保护后,time4中断才能被触发。
【STM32】STM32CubeMX使用FreeRTOS教程1----定时器学习_第5张图片

你可能感兴趣的:(freertos,stm32,stm32)