STM32定时器输出、捕获PWM

硬件:德飞莱STM32F407
功能:TIM4_CH1->PB6输出PWM,TIM3_CH1->PC6捕获高电平时间

#include "timer.h"

void TIM4_PWM_Init(void)
{
	RCC->APB1ENR|=1<<2;				//打开定时器4时钟
	RCC->AHB1ENR|=1<<1;				//打开GPIOB的时钟
	
	GPIOB->MODER|=2<<12;			//PB6 复用模式
	GPIOB->OTYPER&=~(1<<6);		//PB6	推挽输出
	GPIOB->OSPEEDR|=11<<12;		//PB6 输出速度100M
	GPIOB->PUPDR|=1<<6;				//PB6	上拉
	
	GPIOB->AFR[0]|=2<<24;			//PB6	AF2
	
	TIM4->ARR=500-1;
	TIM4->PSC=84-1;						//频率为2K
	
	TIM4->CCR1=250;						//高电平时间为500-250    占空比为(500-250)/500=50%
	
	TIM4->CCMR1&=~(3<<0);			//配置为输出
	TIM4->CCMR1|=1<<2;				//输出比较快速使能
	TIM4->CCMR1|=1<<3;				//输出比较预装载使能
	TIM4->CCMR1|=7<<4;				//PWM2模式
	TIM4->CCER|=1<<0;					//输出使能,在相应输出引脚上输出 OC1 信号
	TIM4->CCER|=1<<1;					//低电平有效
	TIM4->CR1|=1<<7;					//自动重装载预装载使能
	TIM4->CR1|=1<<0;					//打开定时器4
}


void TIM3_Cap_Init(void)//TIM3_CH1定时器获取
{
	RCC->APB1ENR|=1<<1;				//打开定时器3时钟
	RCC->AHB1ENR|=1<<2;				//打开GPIOC的时钟
	
	GPIOC->MODER|=(2<<12);		//PC6 输入模式
	GPIOC->PUPDR|=2<<6;				//PC6	下拉
	
	GPIOC->AFR[0]|=2<<24;			//PC6	AF2
	
	TIM3->ARR=0xFFFFFFFF;					//计数周期设置为最大,计数周期65536
	TIM3->PSC=72-1;						//计数频率1M,每隔1us捕获一次
	
	TIM3->CCMR1|=1<<0;				//配置为输入,映射到T1上
	TIM3->CCMR1&=~(3<<2);			//不分频
	TIM3->CCMR1&=~(15<<4);		//不滤波
	
	TIM3->CCER|=1<<0;					//使能捕获
	TIM3->CCER&=~(3<<1);			//上升沿捕获
	
	TIM3->DIER|=1<<0;					//允许更新中断
	TIM3->DIER|=1<<1;					//使能通道1捕获中断
	
	TIM3->CR1|=1<<0;					//使能计数器
	
	MY_NVIC_Init(2,1,TIM3_IRQn,2);//抢占2,子优先级1,组2	  
}

u8 TIM3_IRQ_STA=0;
u32 TIM3_IRQ_VAL=0;
void TIM3_IRQHandler(void)
{
	u16 sr;
	sr=TIM3->SR;
	if(!(TIM3_IRQ_STA&0x80))					//未捕获完成
	{
		if(sr&0x01)											//产生更新中断,上升沿时间超过一个计数周期65536us,记录超过了几次
		{
			if(TIM3_IRQ_STA&0X40)					//已经捕获到高电平了
			{
				if((TIM3_IRQ_STA&0X3F)==0X3F)//高电平太长了
				{
					TIM3_IRQ_STA|=0X80;				//高电平时间过长,强制标记成功捕获了一次
					TIM3_IRQ_VAL=0XFFFFFFFF;
				}else TIM3_IRQ_STA++;
			}	 
		}
		if(sr&0x02)											//产生捕获中断
		{
			if(TIM3_IRQ_STA&0x40)					//此时状态为,已经捕获到上升沿,定时器设置为下降沿捕获,且进入中断,也即是捕获到上升沿之后又捕获到下降沿
			{
				//标记捕获完成一次
				TIM3_IRQ_STA|=0x80;					//标记完成一次捕获
				TIM3_IRQ_VAL=TIM3->CCR1;
				TIM3->CCER&=~(1<<1);				//配置为上升沿捕获,开始新的一轮捕获
			}
			else													//此时进来肯定是只捕获到上升沿,开始计数上升沿时间
			{
				TIM3_IRQ_STA=0;							//清空状态寄存器
				TIM3_IRQ_VAL=0;							//清空计数
				TIM3_IRQ_STA|=0x40;					//标记捕获到上升沿
				TIM3->CR1&=~(1<<0);					//关闭定时器,配置捕获的边缘信号
				TIM3->CNT=0;								//清空计数器
				TIM3->CCER|=1<<1;						//配置为下降沿捕获
				TIM3->CR1|=1<<0;						//开启定时器
			}
		}
	}
	TIM3->SR=0;												//清除中断标志位 
}
/*main.c*/
extern u8  TIM3_IRQ_STA;		//输入捕获状态		    				
extern u32	TIM3_IRQ_VAL;	//输入捕获值

while(1)
{
if(TIM3_IRQ_STA&0X80)//成功捕获到了一次高电平
		{
			temp=TIM3_IRQ_STA&0X3F; 
			temp*=0XFFFFFFFF;		 		//溢出时间总和
			temp+=TIM3_IRQ_VAL;		//得到总的高电平时间
			printf("HIGH  >> :%lld us
",temp);//打印总的高点平时间
			TIM3_IRQ_STA=0;			//开启下一次捕获
		}
}

原文地址:https://www.cnblogs.com/hhsxy/p/14018408.html