前几期我们介绍了STM32CubeMX中关于定时器的各个配置参数及其功能,本期我们来介绍各个功能的具体代码实现。

    分别是:定时器中断,PWM模式,输出捕获模式,比较输出模式,强制输出模式

 打开CubeMX,配置定时器分频系数为170-1,周期计数值为1000,主频为170MHZ。由此我们可以计算一次溢出的为:

   170M/(170+1)/1000 = 1000即1ms一次。

开启定时器中断以确保我们的定时器中断回调函数能被正常触发。

接着选择好编译器和文件路径和文件名( 不要用中文路径)生成工程。


  /* USER CODE BEGIN 2 */
  HAL_TIM_Base_Start_IT(&htim1);
  /* USER CODE END 2 */

    添加启动定时器并启用中断的函数,参数为我们开启的定时器句柄。


  //开启定时器并开启中断
  HAL_TIM_Base_Start_IT(&htim1);
  //开启定时器不开启中断
  //HAL_TIM_Base_Start(&htim1);

    当然也有不启用中断的,后者仅仅开启定时器计数功能,但是会发生定时器溢出产生事件更新,不过不会触发中断请求。


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    static int number = 0;
    if(htim->Instance == TIM1)  // 判断是否是 TIM1 触发的中断
    {
        // 1ms触发一次
        number++;
        if(number==1000)
        {
            //1ms*1000 = 1s
            HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);
            number = 0;//清零
        }
    }
}

    接着我们需要重写定时器中断回调函数来实现我们的功能,由于我们定时器是1ms触发一次,因此我们使用一个计数器来判断触发的次数。当我们定时时间到达1s时,使我们的LED灯翻转。

 我们可以看到,中断回调函数在底层被一个虚函数定义,这段注释告诉用户,不要修改这个函数的默认实现。如果需要自定义的回调行为,应该在用户的代码中重新实现这个回调函数。

    当我们在程序中需要修改定时器触发时间的时候,我们可以重新修改定时器的参数并进行初始化。


htim1.Init.Prescaler = new_prescaler;//新的分频系数
htim1.Init.Period = new_arr;//新的周期值
HAL_TIM_Base_Init(&htim1);  // 重新初始化定时器
HAL_TIM_Base_Start_IT(&htim1);  // 重新启动定时器

    下面要用。

 上面我们设置了定时器的单周期参数为1000,接着我们设置PWM的比较值(Output compare preload)为500,那么占空比就是:500/1000 = 50%

     接着生成我们的代码。


  /* USER CODE BEGIN 2 */
  HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
  /* USER CODE END 2 */

启动定时器PWM,参数分别为定时器句柄和通道

这样子我们通道一对应的IO就可以输出方波了。


htim1.Init.Prescaler = new_prescaler;//新的分频系数
htim1.Init.Period = new_arr;//新的周期值
HAL_TIM_Base_Init(&htim1);  // 重新初始化定时器
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);  // 重新启动PWM

    通过修改定时器的计数频率来修改PWM的频率。


  /* USER CODE BEGIN 2 */
  __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, duty);  //修改占空比
  /* USER CODE END 2 */

    通过修改通道的比较值CCR来改变PWM的占空比 = CCR/ARR.


通道配置为输入捕获之后,需要注意捕获模式是上升沿捕获、下降沿捕获还是双边捕获。


    这里要开启中断,我们需要使用中断回调函数。


HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);  // 启动定时器并使能中断

    调用开启输入捕获的函数,接着重写输入捕获的回调函数。


void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    static uint32_t last_capture = 0;  // 上次捕获的计数值
    uint32_t capture_value = 0;
    if (htim->Instance == TIM1)  // 判断是否是定时器1触发的中断
    {
        capture_value = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);  // 读取捕获
        // 计算捕获值之间的时间差(信号周期或脉冲宽度)
        if (capture_value > last_capture)
        {
            uint32_t pulse_width = capture_value - last_capture;  // 计算脉冲宽度
            last_capture = capture_value;  // 更新上次捕获值
        }
    }
}

    当外部信号来临的时候,我们可以读取通道值来获得当前的计数值。通过比较两次的计数值可以知道两个信号之间的触发事件。

    这种方法我们也可以用来测量PWM的高低电平时间。通过修改触发方式,当上升沿触发的时候,修改触发方式为下降沿,就可以知道高电平的时间。反过来就可以知道低电平的时间。


// 输入捕获中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    capture_value = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);  // 读取捕获值
    if (htim->Instance == TIM1)  // 判断是否是定时器2触发的中断
    {
        if (capture_value > last_capture)  // 如果是上升沿
        {
            // 处理上升沿捕获逻辑
            printf("上升沿时间: %lu\n", capture_value);
            // 修改下一次捕获为下降沿触发
            TIM_IC_InitTypeDef sConfigIC = {0};
            sConfigIC.ICPolarity = TIM_ICPOLARITY_FALLING;  // 设置为下降沿触发
            sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;  // 直接从输入端口获取信号
            sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;  // 不进行预分频
            sConfigIC.ICFilter = 0;  // 无输入滤波器
            HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1);  // 配置通道1为下降沿触发
        }
        else  // 如果是下降沿
        {
            // 处理下降沿捕获逻辑
            printf("下降沿时间: %lu\n", capture_value);
            // 修改下一次捕获为上升沿触发
            TIM_IC_InitTypeDef sConfigIC = {0};
            sConfigIC.ICPolarity = TIM_ICPOLARITY_RISING;  // 设置为上升沿触发
            sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;  // 直接从输入端口获取信号
            sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;  // 不进行预分频
            sConfigIC.ICFilter = 0;  // 无输入滤波器
            HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1);  // 配置通道1为上升沿触发
        }
        last_capture = capture_value;  // 更新上次捕获值
    }
}
嘉立创PCB

还没有评论,抢个沙发!