STM32F103RCT6学习之四:定时器

1.基础

定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断

16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时

不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能

根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型

 2.定时器中断--1秒

控制LED0闪烁,周期为1S

 1)基本配置

 因为T_{out}=\frac{((ARR+1)X(PSR+1)}{T_{clk}},有Tclk=72MHz,选择arr=9999,psc=7199,则溢出时间为Tout=1S

 2)编辑代码

触发中断时系统会调用定义于stm32f1xx_it.c的void TIM2_IRQHandler(void);可以看到该中断服务函数又调用定义于stm32f1xx_hal_tim.c中的HAL_TIM_IRQHandler(&htim2);函数HAL_TIM_IRQHandler(&htim2)又调用回调函数PeriodElapsedCallback(htim)

重定义void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)   //定时器溢出中断
{
    if (htim== &htim2)  //确定是否是定时器2触发中断
    {
			HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
    }
}

需要在主函数中启动定时器,用函数HAL_TIM_Base_Start_IT(&htim2);

int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM2_Init();
  /* USER CODE BEGIN 2 */
	HAL_TIM_Base_Start_IT(&htim2);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

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

3)分析

3.输出PWM波--呼吸灯

PWM即脉冲宽度调制,在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域

1)进行基本配置

2)进行编码

int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM1_Init();
  /* USER CODE BEGIN 2 */
	HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);//启动PWM输出
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */

  uint16_t pwmVal=0;   //PWM占空比  
  while (1)
  {
    /* USER CODE END WHILE */
	  while (pwmVal< 1000)
	  {
		  pwmVal++;
		  __HAL_TIM_SetCompare(&htim1, TIM_CHANNEL_1, pwmVal);    //修改比较值,修改占空比
		  HAL_Delay(1);
	  }
	  while (pwmVal > 0)
	  {
		  pwmVal--;
		  __HAL_TIM_SetCompare(&htim1, TIM_CHANNEL_1, pwmVal);    //修改比较值,修改占空比
		  HAL_Delay(1);
	  }
	  HAL_Delay(200); //完全熄灭后,等待200ms
  }

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

3)分析

4.测量PWM信号的频率及占空比

  • 在定时计数器的输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数

  • 每个高级定时器和通用定时器都拥有4个输入捕获通道 可配置为PWMI模式,同时测量频率和占空比

  • 可配合主从触发模式,实现硬件全自动测量

1)进行基本配置

time1测量周期和占空比,用其输出捕获通道1和2

 time2、time3分别输出不同频率PWM波

2)进行编码

重定义time1的 捕获中断3处理函数,计算频率和占空比

// 捕获值变量
uint32_t IC1Value = 0; // 通道 1 当前捕获值(上升沿)
uint32_t Last_IC1Value = 0; // 通道 1 上一次捕获值(上升沿)
uint32_t IC2Value = 0;  // 通道 2 捕获值(下降沿)
uint32_t Period = 0;    // 周期时间
uint32_t HighTime = 0;  // 高电平时间
uint32_t Frequency = 0; // 计算的 PWM 频率
uint32_t DutyCycle = 0; // 计算的 PWM 占空比

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM1) // 确认是 TIM1
    {
        if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) // 通道 1 上升沿捕获
        {
            Last_IC1Value = IC1Value; // 保存上一次捕获值
            IC1Value = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); // 当前捕获值

            // 计算周期
            if (IC1Value > Last_IC1Value)
            {
                Period = IC1Value - Last_IC1Value;
            }
            else // 计数器溢出处理
            {
                Period = (htim->Init.Period - Last_IC1Value) + IC1Value + 1;
            }
        }
        else if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2) // 通道 2 下降沿捕获
        {
            IC2Value = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2); // 捕获值(下降沿)

            // 计算高电平时间
            if (IC2Value > IC1Value)
            {
                HighTime = IC2Value - IC1Value;
            }
            else // 计数器溢出处理
            {
                HighTime = (htim->Init.Period - IC1Value) + IC2Value + 1;
            }

            // 计算频率和占空比
            if (Period != 0) // 避免除零
            {
                Frequency = HAL_RCC_GetPCLK2Freq() / (htim->Init.Prescaler + 1) / Period;
                DutyCycle = (HighTime * 100) / Period;
            }
        }
    }
}

主函数主要是设置time2和time3的参数,并启动输出,以及其他time1

int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM1_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);  //启动PWM输出
	
	__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,50);  //ARR为100,设置占空比为50%
		
	HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);  //启动PWM输出
	
	__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_1,600);  //ARR为1000,设置占空比为60%
	
	HAL_TIM_Base_Start(&htim1);
	
	HAL_TIM_IC_Start_IT(&htim1,TIM_CHANNEL_1);
	HAL_TIM_IC_Start_IT(&htim1,TIM_CHANNEL_2);	

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    sprintf(massage, "Frequency: %lu Hz, Duty Cycle: %lu%%\r\n", Frequency, DutyCycle);
		
		printf("%s",massage);
		
		
		HAL_Delay(1000); // 每 100 毫秒发送一次
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

3)分析

### STM32F103RCT6 定时器使用方法 #### 配置定时器基础参数 为了使STM32F103RCT6定时器正常工作,需先初始化基本参数。这包括设定预分频系数(PSC)和自动重装载值(ARR),两者共同决定了计数频率以及溢出时间。 ```c // 初始化 TIM2 外设结构体 TIM_HandleTypeDef TimHandle; TimHandle.Instance = TIM2; TimHandle.Init.Prescaler = 7999; // 设置预分频值为8000-1 (假设系统时钟为8MHz) TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数模式 TimHandler.Init.Period = 4999; // 自动重载值为5000-1 TimHandle.Init.ClockDivision = 0; TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if(HAL_TIM_Base_Init(&TimHandle)==HAL_OK){ /* 开启定时器 */ HAL_TIM_Base_Start_IT(&TimHandle); } ``` 上述代码片段展示了如何配置一个向上计数模式下的通用定时器(TIM2)[^1]。 #### 中断服务程序实现 当定时器达到其周期结束条件时会触发中断,在此期间可以执行特定的任务处理逻辑。下面是一个简单的例子,它实现了每半秒切换一次LED状态的功能: ```c void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(htim->Instance==TIM2) { static uint16_t tim_delay=0; if(++tim_delay>=500)// 延迟500次即约等于500ms { tim_delay=0; // 切换LED电平高低 HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); } } } ``` 这段C语言函数定义了一个回调机制来响应由硬件产生的周期性事件,并利用静态变量`tim_delay`控制实际的时间间隔[^3]。 #### 调整定时精度 对于更精确的时间测量需求,则可以通过修改PSC(Prescaler)寄存器中的数值改变输入时钟信号被分割的比例;而更改ARR(Auto Reload Register)则能直接影响每次循环所需经历的最大计数值。因此,适当调节这两个参数即可满足不同应用场景的要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

和风化雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值