《嵌入式蓝桥杯》定时器TIM3的PWM输出和TIM2的输入捕获测量频率记录

本文介绍了如何使用STM32的TIM3定时器生成可调频率和占空比的PWM波形,并通过TIM2的输入捕获功能测量该PWM波形的频率。详细阐述了TIM3的PWM配置和TIM2的输入捕获初始化过程,以及实验中可能出现的频率测量误差和解决方案。
摘要由CSDN通过智能技术生成

作者博客主页
作者 : Eterlove
一笔一画,记录我的学习生活!站在巨人的肩上Standing on Shoulders of Giants!
该文章为原创,转载请注明出处和作者

声明:这段时间较忙,相关知识点分析讲解后面抽时间补上。

1.学习记录

    用定时器TIM3来产生一个PWM的波形【频率可调,占空比可调–>相对可调】,然后用TIM2的输入捕获功能测量该波形的频率

PA1---->TIM2_CH2
PA2---->TIM2_CH3
PA6---->TIM3_CH1
PA7---->TIM3_CH2

2.产生PWM波形TIM3_CH1_PA6
/*  PA6----TIM3_CH1
    PA7----TIM3_CH2  */
#include "stm32f10x.h"
#include "TIM3.h"

// The TIM3 is running at 1 KHz: TIM3 Frequency = TIM3 counter clock/(ARR + 1)
//                        1 KHz                 = 1MHZ  /1000                                        

//ARR = (TIM3 counter clock /Frequency)-1

//PWM 信号频率可调,占空比可调  PA6	
void TIM3_PWM_Output(float Duty , uint32_t Frequency)
{
	
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_OCInitTypeDef  TIM_OCInitStructure;
  NVIC_InitTypeDef  NVIC_InitStructure;
  GPIO_InitTypeDef  GPIO_InitStructure;

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

  /* GPIOA  clock enable */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO ,ENABLE);

  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
	 /* Time base configuration */ 
  TIM_TimeBaseStructure.TIM_Period = (1000000/Frequency)-1;  //ARR = (TIM3 counter clock /Frequency)-1
  TIM_TimeBaseStructure.TIM_Prescaler = 71;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
	
	
  /* PWM1 Mode configuration: Channel1 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = ((1000000/Frequency)-1)*Duty;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  TIM_OC1Init(TIM3, &TIM_OCInitStructure);

  TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
	
	
  TIM_ARRPreloadConfig(TIM3, ENABLE);

  /* TIM3 enable counter */
  TIM_Cmd(TIM3, ENABLE);
	
}

为什么说频率和占空比相对可调?
TIM_TimeBaseStructure.TIM_Prescaler = 71;
这里我固定了计数时钟频率72MHZ/72 =1MHZ
TIM_TimeBaseStructure.TIM_Period = (1000000/Frequency)-1; //ARR = (TIM3 counter clock /Frequency)-1
Frequency这个变量值如果非常的”奇葩“,那么TIM_Period 只能除整,会造成一点误差。同理占空比也是。所以我这样写只是方便在主函数中直接输入参数调用,具体问题具体分析,遇到一些不好处理的数值请重新配置,自己去“凑整”
TIM_OCInitStructure.TIM_Pulse = ((1000000/Frequency)-1)*Duty;

3.TIM2的输入捕获测量频率TIM2_CH2_PA1
//Input_Capture.C文件
#include "Input_Capture.h"
//PA1---->TIM2_CH2
//PA2---->TIM2_CH3

__IO uint16_t IC2ReadValue1 = 0, IC2ReadValue2 = 0;
__IO uint16_t CaptureNumber = 0;
__IO uint32_t Capture = 0;
__IO uint32_t TIM2Freq = 0;

void Input_Capture_Init()
{
	GPIO_InitTypeDef GPIO_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_ICInitTypeDef  TIM_ICInitStructure;
	
	//留下一个问题,这里为什么不使能AFIO??
	/* 参考手册P121   对寄存器AFIO_EVCR,AFIO_MAPR和AFIO_EXTICRX进行读写操作前,应当首先打开AFIO
   的时钟。参考第6.3.7节APB2外设时钟使能寄存器(RCC_APB2ENR)。 */
	
	 /* TIM2 clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

  /* GPIOA and GPIOB clock enable */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

	
	
	 /* TIM2 channel 2,3 pin (PA.01,PA.02) configuration */
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_1 | GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	 /* Enable the TIM2 global Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
		 /* Time base configuration */
  TIM_TimeBaseStructure.TIM_Period = 65535 ;
  TIM_TimeBaseStructure.TIM_Prescaler = 71;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
	
	//输入捕获配置  TIM2_CH2
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; 
  TIM_ICInitStructure.TIM_ICFilter = 0x0;   //滤波器
  TIM_ICInit(TIM2, &TIM_ICInitStructure);                                                                                                        
	//输入捕获配置  TIM2_CH3
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_3;
	TIM_ICInit(TIM2, &TIM_ICInitStructure);
	
	  /* TIM enable counter */
  TIM_Cmd(TIM2, ENABLE);
  /* Enable the CC2 Interrupt Request */
  TIM_ITConfig(TIM2, TIM_IT_CC2|TIM_IT_CC3, ENABLE);
	
}


void TIM2_IRQHandler(void)
{ 
  if(TIM_GetITStatus(TIM2, TIM_IT_CC2) == SET) 
  {
    /* Clear TIM2 Capture compare interrupt pending bit */
    TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
    if(CaptureNumber == 0)
    {
      /* Get the Input Capture value */
      IC2ReadValue1 = TIM_GetCapture2(TIM2);
      CaptureNumber = 1;
    }
		
		
    else if(CaptureNumber == 1)
    {
      /* Get the Input Capture value */
      IC2ReadValue2 = TIM_GetCapture2(TIM2); 
      
      /* Capture computation */
      if (IC2ReadValue2 > IC2ReadValue1)
      {
        Capture = (IC2ReadValue2 - IC2ReadValue1); 
      }
      else
      {
        Capture = ((0xFFFF - IC2ReadValue1) + IC2ReadValue2); 
      }
      /* Frequency computation */ 
        //TIM2Freq = (uint32_t) SystemCoreClock/72/ Capture;
			  TIM2Freq = (uint32_t)1000000 / Capture;
      CaptureNumber = 0;
    }
  }
}

Input_Capture.C文件,这里为什么要把TIM2 /72分频 得到1MHZ的计数频率呢?

因为我们的CCRx寄存器是一个16bit的寄存器计数范围为0 到0xFFFF,即0~65535,可是当测量的矩形波周期太长,脉冲宽度太宽,二我们的计数又太快,很容易出现CCRx溢出现象,所以,我们在测量低频信号时,一定要对TIM的时钟进行分频,这样我们的计数就不会那么快了,也不会产生溢出现象.

		 /* Time base configuration */
  TIM_TimeBaseStructure.TIM_Period = 65535 ;
  TIM_TimeBaseStructure.TIM_Prescaler = 71;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
4.实验现象
#include "stm32f10x.h"
#include "lcd.h"
#include "stdio.h"
#include "Key.h"
#include "TIM3.h"
#include "LED.h"
#include "string.h"
#include "Input_Capture.h"
	
u32 TimingDelay = 0;
void Delay_Ms(u32 nTime);

u8 TIM2FreqBuffer[20] = {0};
extern __IO uint32_t TIM2Freq;

//Main Body

int main(void)
{
	SysTick_Config(SystemCoreClock/1000);
	Delay_Ms(200);
	STM3210B_LCD_Init();
	LCD_Clear(Black);
	LCD_SetBackColor(Black);  
	LCD_SetTextColor(White);
	Led_Init();    //LED初始化
	Led_Control(LED_ALL , OFF); //LED全关
    Key_Init();  //按键初始化
    TIM3_PWM_Output(0.40 , 1000); //PWM 信号频率可调 ,占空比可调  PA6	
	Input_Capture_Init();  //定时器TIM2 捕获初始化
	
	while(1)
	{
	   //测得频率显示在LCD
		sprintf(TIM2FreqBuffer , "TIM2Freq:%d HZ"  ,TIM2Freq);
		LCD_DisplayStringLine(Line5 ,  TIM2FreqBuffer );	
	}
} 

//毫秒延时函数
void Delay_Ms(u32 nTime)
{
	TimingDelay = nTime;
	while(TimingDelay != 0);	
}

(1)例如输出为duty:40% , 1KHZ的PWM波形

    TIM3_PWM_Output(0.40 , 1000); //PWM 信号频率可调 ,占空比可调  PA6	

用示波器验证,测量PA6引脚输出PWM的频率,防止意外发生
在这里插入图片描述
在这里插入图片描述

    Input_Capture_Init();  //定时器TIM2 捕获初始化

将PA6和PA1相连
在这里插入图片描述

把PWM的波形频率调高至55KHZ

  TIM3_PWM_Output(0.40 , 55000); //PWM 信号频率可调 ,占空比可调  PA6	
  Input_Capture_Init();  //定时器TIM2 捕获初始化

在这里插入图片描述
感谢大家阅读!

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

嵌入式历练者

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

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

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

打赏作者

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

抵扣说明:

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

余额充值