学习笔记——STM32定时器程序应用(二)

PWM输入捕获代码讲解
大家好,我终于出现了,由于要开始准备考研的复习,再加上32的学习已经学到了摄像头,就鸽了几天。

好,话不多说,我们直接进入正题。

这个实验其实就是用于测量PWM信号,同一个定时器不能同时使用输入捕获和输出比较,因此这个实验中我们使用通用定时器来产生信号,高级定时器来捕获信号。

与之前的实验一样,在例程中的User文件夹下添加bsp_AdvanceTim.c和bsp_AdvanceTim.h文件。 这里注意一点,要把advance和general文件夹。这是因为使用不同的定时器时,对应的GPIO是不一样的。

我们先对PIO进行初始化:

static void ADVANCE_TIM_GPIO_Config(void) 
{
    
    
  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1_GPIO_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  ADVANCE_TIM_CH1_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  
  GPIO_Init(ADVANCE_TIM_CH1_PORT, &GPIO_InitStructure);
}

这里注意一点,要把GPIO设置为IN_FLOATING浮空输入,用来捕获方波。

再移植例程中的.h文件:

#ifndef __BSP_ADVANCETIME_H
#define __BSP_ADVANCETIME_H

#include "stm32f10x.h"

#define            ADVANCE_TIM                   TIM1
#define            ADVANCE_TIM_APBxClock_FUN     RCC_APB2PeriphClockCmd
#define            ADVANCE_TIM_CLK               RCC_APB2Periph_TIM1

//输入捕获能捕获到的最小频率为72M/{(ARR+1)*(PSC+1)}
#define            ADVANCE_TIM_PERIOD            (1000-1)
#define            ADVANCE_TIM_PSC               (72-1)

//中断相关宏定义
#define            ADVANCE_TIM_IRQ               TIM1_CC_IRQn
#define            ADVANCE_TIM_IRQHandler        TIM1_CC_IRQHandler

//TIM1输入捕获通道一
#define            ADVANCE_TIM_CH1_GPIO_CLK      RCC_APB2Periph_GPIOA
#define            ADVANCE_TIM_CH1_PORT          GPIOA
#define            ADVANCE_TIM_CH1_PIN           GPIO_Pin_8

#define            ADVANCE_TIM_IC1PWM_CHANNEL    TIM_Channel_1

void ADVANCE_TIM_Init(void);

#endif

在.c文件中配置完GPIO后,我们需要对其进行初始化:

static void ADVANCE_TIM_GPIO_Config(void) 
{
    
    
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1_GPIO_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  ADVANCE_TIM_CH1_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  
  GPIO_Init(ADVANCE_TIM_CH1_PORT, &GPIO_InitStructure); 
}

这里有一个重点要特别注意:当我们在配置时,Period和PSC的值不能随意配置。我们假设生成的方波是100K,则周期为1/100=10us,如果计数周期<10us,那就无法对周期进行捕获,如果<1khz,或>10亅,那就无法捕获。一般的常用电机的驱动频率在10K~25K之间。

记下来,我们需要设置中断优先级以及输入捕获结构体初始化:

static void ADVANCE_TIM_Mode_Config(void)
{
    
    
 ADVANCE_TIM_APBxClock_FUN(ADVANCE_TIM_CLK,ENABLE);

 TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

 TIM_TimeBaseStructure.TIM_Period=ADVANCE_TIM_PERIOD; 
 //自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新中断 
 TIM_TimeBaseStructure.TIM_Prescaler= ADVANCE_TIM_PSC; 
 //驱动CNT计数器的时钟
 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
  //时钟分频因子,配置死区时间要用
  TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;  
  //计数模式,设置为向上计数
  TIM_TimeBaseStructure.TIM_RepetitionCounter=0; 
  //重复计数器的值
  TIM_TimeBaseInit(ADVANCE_TIM, &TIM_TimeBaseStructure);
  //初始化定时器

  TIM_ICInitTypeDef  TIM_ICInitStructure;

  TIM_ICInitStructure.TIM_Channel = ADVANCE_TIM_IC1PWM_CHANNEL;
  //捕获通道IC1配置
  //选择捕获通道
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  //设置捕获的边沿
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  //设置捕获通道的信号来自于哪个输入通道,由直连和非直连两种
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  //1分频,即捕获信号的每个有效边沿都捕获
  TIM_ICInitStructure.TIM_ICFilter = 0x0;
  //不滤波
  TIM_PWMIConfig(ADVANCE_TIM, &TIM_ICInitStructure);
  //初始化PWM输入模式
  

  TIM_SelectInputTrigger(ADVANCE_TIM, TIM_TS_TI1FP1); 
  //选择输入捕获的触发信号
  TIM_SelectSlaveMode(ADVANCE_TIM, TIM_SlaveMode_Reset);
  TIM_SelectMasterSlaveMode(ADVANCE_TIM,TIM_MasterSlaveMode_Enable);
  //选择从模式:复位模式
  //PWM输入模式时,从模式必须工作在复位模式,当捕获开始时,计数器CNT会被复位
  TIM_ITConfig(ADVANCE_TIM, TIM_IT_CC1, ENABLE);
  //使能捕获中断,这个中断针对的是主捕获通道
  TIM_ClearITPendingBit(ADVANCE_TIM, TIM_IT_CC1);
  //清除中断标志位
  TIM_Cmd(ADVANCE_TIM, ENABLE);
  //使能高级控制定时器,计数器开始计数

中断优先级为:

static void ADVANCE_TIM_NVIC_Config(void)
{
    
    
 NVIC_InitTypeDef NVIC_InitStructure;
 
 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
 //设置中断组为0
 NVIC_InitStructure.NVIC_IRQChannel = ADVANCE_TIM_IRQ; 
 //设置中断来源
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
 //设置抢占优先级
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
 //设置子优先级
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 NVIC_Init(&NVIC_InitStructure); 
}

最后,我们把.h里面写的三个函数,放进定时器的初始化函数:

void ADVANCE_TIM_Init(void)
{
    
    
 ADVANCE_TIM_NVIC_Config();
 ADVANCE_TIM_GPIO_Config();
 ADVANCE_TIM_Mode_Config();  
}

我们需要在it.c中编写中断服务函数:

void ADVANCE_TIM_IRQHandler(void)
{
    
    
  TIM_ClearITPendingBit(ADVANCE_TIM, TIM_IT_CC1);
  //清除中断标志位
  IC1Value = TIM_GetCapture1(ADVANCE_TIM);
  IC2Value = TIM_GetCapture2(ADVANCE_TIM);
  //获取输入捕获值
  if (IC1Value != 0)
  //注意:捕获寄存器CCR1和CCR2的值在计算占空比和频率的时候必须+1
  {
    
    
    DutyCycle = (float)((IC2Value+1) * 100) / (IC1Value+1);
    //占空比计算
    Frequency = (72000000/(ADVANCE_TIM_PSC+1))/(float)(IC1Value+1);
    //频率计算
    printf("Õ¼¿Õ±È£º%0.2f%%   ƵÂÊ£º%0.2fHz\n",DutyCycle,Frequency);
  }
  else
  {
    
    
    DutyCycle = 0;
    Frequency = 0;
  }
}
``如果是第一个上升沿中断,计数器会被复位,锁存到CCR1的值为0,CCR2的值也是0.无法计算频率与占空比; 当第二次上升沿到来的时候,CCR1和CCR2捕获到的值为有效的值,其中CCR1对应的是周期,CCR2对应的是占空比。

好的,到这里程序基本上就编写完成了,但是如果现在别写程序的时候就会出现:DutyCycle、Frequency未定义的情况出现,因此我们还需要加最后一步。就是在中断服务函数掐面加上定义:

```c
__IO uint16_t IC2Value = 0;
__IO uint16_t IC1Value = 0;
__IO float DutyCycle = 0;
__IO float Frequency = 0;

最后,我们整理一下main.c就行了:

#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_GeneralTim.h"  
#include "bsp_AdvanceTim.h" 
#include "bsp_usart.h"

int main(void)
{
    
     
  USART_Config();
  GENERAL_TIM_Init();
  ADVANCE_TIM_Init();

  while(1)
  {
    
    
  }
}

好的,那么定时器的所有相关都讲完了,下次更新就是摄像头的章节了。要是对于定时器还有不懂的,可以在下方评论留言或者进入一下网址查看完整视频:https://www.bilibili.com/video/av28951854?from=search&seid=13956434192947447162

猜你喜欢

转载自blog.csdn.net/weixin_41679822/article/details/102497284