分享:定时器和外部中断完成输入捕获功能,并计算频率和占空比。

2019-10-15 20:14发布

其实这样的功能只要用一个定时器就可以完成了,不过为了更深地了解定时器输入捕获的功能,我自己设置了用定时器分开定时,外部中断读取信号的方法。只供参考学习。 程序说明:1、定时器2用于产生PWM信号 PA2                2、定时器3用于定时计算PWM信号的频率和占空比              3、串口发送数值        这里声明一下,如果你要捕获的PWM信号不在ARR,PSC计算的范围内,请自己先计算再使用本程序。 #include "stm32f10x_lib.h"
#include "sys.h"
#include "delay.h" //延时子函数
#include "usart.h"
#include "led.h" #define Input1 PBin(0)// PB0 u16 Counter1;
u16 Counter2; 
void EXTIX_Init(void);
void Timer2_Init(u16 arr,u16 psc); //定时器2用于产生PWM信号 PA2
void Timer3_Init(u16 arr,u16 psc);//定时器3用于定时计算PWM信号的频率和占空比  ,这里7200-1=10K int  main(void)
 {
   Stm32_Clock_Init(9); //系统时钟设置
   delay_init(72);//延时函数初始化
   uart_init(72,9600);
   LED_Init();
   EXTIX_Init();//外部中断初始化PB0
   Timer2_Init(6000,720-1); //定时器2用于产生PWM信号 PA2
   Timer3_Init(6000,7200-1); //定时器3用于定时计算PWM信号的频率和占空比  ,这里7200-1=10K
   while(1)
   {
  printf("counter1 = %d ",(Counter1*100)/Counter2); //计算出占空比
     printf("counter2 = %d ",10000/Counter2);//计算出频率
 
   }
 } /*外部中断用于PWM输入口*/
void EXTIX_Init(void)
{
 RCC->APB2ENR|=1<<3;     //使能PORTB时钟  GPIOB->CRL&=0XFFFFFFF0;//PB0设置成输入  
 GPIOB->CRL|=0X00000008;       
 GPIOB->ODR|=1<<0;    //PB0上拉  Ex_NVIC_Config(GPIO_B,0,3);//上升下降沿触发  MY_NVIC_Init(2,1,EXTI0_IRQChannel,2);//抢占2,子优先级1,组2   
} //外部中断15~10服务程序
void EXTI0_IRQHandler(void)
{     
   if(Input1 ==0)//先是上升沿触发中断
 { 
    Counter1 = TIM3->CNT;//读取高电平时间   
 }
 if(Input1 ==1)//第二次中断是下降沿
 {
    Counter2 = TIM3->CNT;//读取总时间
    delay_us(5);//这里要延时一点点再清计算器
    TIM3->CNT = 0;//请计数器   
 } 
 EXTI->R=1<<0;     //清除LINE0上的中断标志位 
} /*定时器2用于产生PWM信号*/
void Timer2_Init(u16 arr,u16 psc) //定时器2用于adc采样
{
 //此部分需手动修改 IO口设置
 RCC->APB1ENR|=1<<0;       //TIM2 时钟使能 
 RCC->APB2ENR|=1<<0;    //   
 RCC->APB2ENR|=1<<2;    //使能PORTA时钟
     GPIOA->CRL&=0XFFFFF0FF;//PA2输出 
 GPIOA->CRL|=0X00000B00;//复用功能输出      
 GPIOA->ODR|=1<<2;//PA2 上拉   TIM2->ARR=arr;//设定计数器自动重装值  
 TIM2->SC=psc;//预分频器不分频 
 //PWM
 TIM2->CCMR2|=7<<4;  //CH3 PWM2模式     
 TIM2->CCMR2|=1<<3; //CH3 预装载使能   
 TIM2->CCER|=1<<8;  //OC3  输出使能     
 TIM2->CR1=0x0080;   //ARPE使能  //TIM2->CR1|=0x01;    //使能定时器 3  TIM2->CR1|=1<<0; //使能定时器 2
 TIM2->CCR3   = 3000;  //占空比初值 =  1440*50% = 720
            
}
/*定时器3用于产后PWM信号*/
void Timer3_Init(u16 arr,u16 psc)
{
 RCC->APB1ENR|=1<<1;//TIM2时钟使能   
  TIM3->ARR=arr;  //设定计数器自动重装值//刚好1ms   
 TIM3->SC=psc;  //预分频器,  TIM3->DIER|=1<<0;   //允许更新中断    
 TIM3->DIER|=1<<6;   //允许触发中断   
 TIM3->CR1|=0x01;    //使能定时器3
   MY_NVIC_Init(1,3,TIM3_IRQChannel,2);//抢占1,子优先级3,组2         
} //定时器3中断服务程序 
void TIM3_IRQHandler(void)
{                 
 if(TIM3->SR&0X0001)//溢出中断
 {
  LED0=~LED0;               
 }      
 TIM3->SR&=~(1<<0);//清除中断标志位     
}
       
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
21条回答
suqingxiao
2019-10-16 07:00
楼上过奖了,程序中还有不妥的地方,我愿意是计算高电平时间和信号的周期,中断两个边沿进入。我在if(Input1 ==1)//第二次中断是下降沿,这里是不妥的,因为上升源进去应该是高电平,不过我在这里清CNT,得出来的确实是周期。只是呢,我后来想了想,还是在if(Input1 ==1)时读高电平,if(Input1 ==0)读周期再清CNT.

一周热门 更多>