GD32F130C8T6定时器高精度PWM捕获模式
1.理论:PWM捕获有两种方法,第一种是通过定时器一个通道捕获检测到 上升沿开始捕获,下降沿结束捕获,即得到高电平时间(该方法正点原子视频有讲),第二种方法是通过定时器两个通道捕获一个通道捕获上升沿,一个通道捕获下降沿,捕获完了定时器计数值会自动复位。
第一种方法精度不高,第二种精度更高,第二种详细理论见(转载):https://blog.csdn.net/qq_29413829/article/details/52743273
第一种代码:
#include "pwm.h"
u8 TIM16CH1_CAPTURE_STA=0; //输入捕获状态
float CAPTURE_PWM_CNT=0;//进入中断次数
float CAPTURE_PWM_TIME=0;//高电平时间us
float CAPTURE_PWM_TIME_TEMP=0;
void Timer16_pwm_capture(void)
{
TIMER_BaseInitPara TIM_TimeBaseStructure;
NVIC_InitPara NVIC_InitStructure;
GPIO_InitPara GPIO_InitStructure;
TIMER_ICInitPara TIMER_ICInitParaStruct;
RCC_AHBPeriphClock_Enable(RCC_AHBPERIPH_GPIOB, ENABLE);//GPIO时钟使能
RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_CFG, ENABLE); //映射时钟
RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_TIMER16, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_PIN_8; //输入捕获
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_50MHZ;
GPIO_InitStructure.GPIO_OType = GPIO_OTYPE_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PUPD_PULLDOWN;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig( GPIOB, GPIO_PINSOURCE8, GPIO_AF_2); //TIM16_CH1
TIM_TimeBaseStructure.TIMER_Period = 7200-1;
TIM_TimeBaseStructure.TIMER_Prescaler = 1-1;
TIM_TimeBaseStructure.TIMER_ClockDivision = TIMER_CDIV_DIV1;
TIM_TimeBaseStructure.TIMER_CounterMode = TIMER_COUNTER_UP;//向上计数
TIMER_BaseInit(TIMER16, &TIM_TimeBaseStructure); //使能定时器
TIMER_ICInitParaStruct.TIMER_CH = TIMER_CH_1;//捕获通道
TIMER_ICInitParaStruct.TIMER_ICPolarity =TIMER_IC_POLARITY_RISING;//捕获极性,上升沿捕获
TIMER_ICInitParaStruct.TIMER_ICSelection =TIMER_IC_SELECTION_DIRECTTI;//映射关系
TIMER_ICInitParaStruct.TIMER_ICPrescaler =TIMER_IC_PSC_DIV1;//分频系数
TIMER_ICInitParaStruct.TIMER_ICFilter =0x00;//滤波器
**TIMER_ICInit(TIMER16,&TIMER_ICInitParaStruct);**
NVIC_InitStructure.NVIC_IRQ = TIMER16_IRQn; //中断响应优先级
NVIC_InitStructure.NVIC_IRQPreemptPriority=0;
NVIC_InitStructure.NVIC_IRQSubPriority = 0;
NVIC_InitStructure.NVIC_IRQEnable = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIMER_ClearIntBitState(TIMER16, TIMER_INT_UPDATE);//清除定时器中断标志
TIMER_ClearIntBitState(TIMER16,TIMER_INT_CH1);
TIMER_INTConfig(TIMER16, TIMER_INT_UPDATE | TIMER_INT_CH1, ENABLE);//使能定时器中断
TIMER_SetCounter(TIMER16,0x0000);//设置计数器的值
TIMER_Enable(TIMER16, ENABLE);//使能定时器
}
void TIM16_IRQHandler(void)
{
if(TIMER_GetIntBitState(TIMER16,TIMER_INT_UPDATE)!= RESET)//更新事件
{
if(TIM16CH1_CAPTURE_STA)//捕获到了上升沿,但还没有捕获到下降沿,定时器中断就来了
{
CAPTURE_PWM_CNT++;
}
TIMER_ClearIntBitState(TIMER16,TIMER_INT_UPDATE);
}
if(TIMER_GetIntBitState(TIMER16,TIMER_INT_CH1)!= RESET)//捕获事件
{
if(TIM16CH1_CAPTURE_STA) // 捕获到了下降沿
{
TIMER_ICInitPara TIMER_ICInitParaStruct;//配置下次上升沿捕获
TIM16CH1_CAPTURE_STA=0;//完成捕获,并清除标记状态
TIMER_GetCapture1(TIMER16);//获取捕获值
//根据定时器配置,每进一次中断计数器就计数7200次,进了CAPTURE_PWM_CNT 次中断
CAPTURE_PWM_TIME_TEMP = (CAPTURE_PWM_CNT * 7200.0 + CAPTURE_PWM_TIME_TEMP) ;
//每一个计数值=(100.0/7200.0)us, 捕获到高电平时间=CAPTURE_PWM_TIME ;
CAPTURE_PWM_TIME = CAPTURE_PWM_TIME_TEMP * (100.0/7200.0);
CAPTURE_PWM_CNT=0;//清空中断次数
TIMER_SetCounter(TIMER16,0x0000);//设置计数器的值
TIMER_ICInitParaStruct.TIMER_CH = TIMER_CH_1;
TIMER_ICInitParaStruct.TIMER_ICPolarity=TIMER_IC_POLARITY_RISING;
TIMER_ICInitParaStruct.TIMER_ICSelection=TIMER_IC_SELECTION_DIRECTTI;//映射关系
TIMER_ICInitParaStruct.TIMER_ICPrescaler=TIMER_IC_PSC_DIV1;//分频系数
TIMER_ICInitParaStruct.TIMER_ICFilter=0x00;//滤波器
TIMER_PWMCaptureConfig(TIMER16,&TIMER_ICInitParaStruct);
}
else //成功捕获到上升沿,并将通道配置为下降沿捕获
{
TIMER_ICInitPara TIMER_ICInitParaStruct;//配置下次下降沿捕获
TIMER_SetCounter(TIMER16,0x0000);//设置计数器的值为0
TIM16CH1_CAPTURE_STA=0x01; //标记捕获到了上升沿
TIMER_ICInitParaStruct.TIMER_CH = TIMER_CH_1;
TIMER_ICInitParaStruct.TIMER_ICPolarity=TIMER_IC_POLARITY_FALLING;
TIMER_ICInitParaStruct.TIMER_ICSelection=TIMER_IC_SELECTION_DIRECTTI;//映射关系
TIMER_ICInitParaStruct.TIMER_ICPrescaler=TIMER_IC_PSC_DIV1;//分频系数
TIMER_ICInitParaStruct.TIMER_ICFilter=0x00;//滤波器
TIMER_PWMCaptureConfig(TIMER16,&TIMER_ICInitParaStruct);
}
TIMER_ClearIntBitState(TIMER16,TIMER_INT_CH1);
}
}
第二种方法:
float CAPTURE_PWM_TIME_UP=0;
float CAPTURE_PWM_TIME_ALL=0;
float CAPTURE_PWM_TIME_LAST=0;
float CAPTURE_PWM_DUTY=0;//占空比
float CAPTURE_PWM_FRE=0;//pwm频率
/*----------------------------- TIMER14 500hz -----------------------------------*/
void Timer15_pwm_capture(void)
{
TIMER_BaseInitPara TIM_TimeBaseStructure;
NVIC_InitPara NVIC_InitStructure;
GPIO_InitPara GPIO_InitStructure;
TIMER_ICInitPara TIMER_ICInitParaStruct;
RCC_AHBPeriphClock_Enable(RCC_AHBPERIPH_GPIOA , ENABLE);//GPIO时钟使能
RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_CFG, ENABLE); //映射时钟
RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_TIMER15, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_PIN_3; //输入捕获
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_50MHZ;
GPIO_InitStructure.GPIO_OType = GPIO_OTYPE_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PUPD_PULLDOWN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA,GPIO_PINSOURCE3,GPIO_AF_0);//配置映射为 TIM15_CH2
TIMER_DeInit(TIMER15);
TIM_TimeBaseStructure.TIMER_Period = 30000-1; // 72000000/30000=2.4k
TIM_TimeBaseStructure.TIMER_Prescaler = 1-1;
TIM_TimeBaseStructure.TIMER_ClockDivision = TIMER_CDIV_DIV1;
TIM_TimeBaseStructure.TIMER_CounterMode = TIMER_COUNTER_UP;//向上计数
TIMER_BaseInit(TIMER15, &TIM_TimeBaseStructure); //使能定时器
NVIC_InitStructure.NVIC_IRQ = TIMER15_IRQn; //中断响应优先级
NVIC_InitStructure.NVIC_IRQPreemptPriority=0;
NVIC_InitStructure.NVIC_IRQSubPriority = 0;
NVIC_InitStructure.NVIC_IRQEnable = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//这里配置了一个通道,另一个通道会自动配置
TIMER_ICInitParaStruct.TIMER_CH = TIMER_CH_2;//捕获通道 TIMER_CH_2
TIMER_ICInitParaStruct.TIMER_ICPolarity =TIMER_IC_POLARITY_RISING;//捕获极性上升沿捕获
TIMER_ICInitParaStruct.TIMER_ICSelection =TIMER_IC_SELECTION_DIRECTTI;//映射关系
TIMER_ICInitParaStruct.TIMER_ICPrescaler =TIMER_IC_PSC_DIV1;//分频系数
TIMER_ICInitParaStruct.TIMER_ICFilter =0x00;//滤波器
**TIMER_PWMCaptureConfig(TIMER15,&TIMER_ICInitParaStruct);**//第一种是配置 TIMER_ICInit(),现在这里配置的是TIMER_PWMCaptureConfig();
TIMER_SelectInputTrigger(TIMER15,TIMER_TS_TI2FP2);
TIMER_SelectSlaveMode(TIMER15,TIMER_SLAVE_MODE_RESET);
TIMER_SelectMasterSlaveMode(TIMER15,TIMER_MASTER_SLAVE_MODE_ENABLE);
TIMER_ClearIntBitState(TIMER15, TIMER_INT_UPDATE);//清除定时器中断标志
TIMER_ClearIntBitState(TIMER15, TIMER_INT_CH2);
TIMER_INTConfig(TIMER15,TIMER_INT_CH2, ENABLE);//使能定时器中断
TIMER_SetCounter(TIMER15,0x0000);//设置计数器的值
TIMER_Enable(TIMER15, ENABLE);//使能定时器
}
void TIM15_IRQHandler(void)
{
CAPTURE_PWM_TIME_UP = (float)(TIMER15->CHCC1);//上升沿计数值,读取捕获值会自动清空中断标志
CAPTURE_PWM_TIME_ALL =(float)(TIMER15->CHCC2);//总pwm计数值,读取捕获值会自动清空中断标志
if(CAPTURE_PWM_TIME_ALL!=0){
CAPTURE_PWM_DUTY=CAPTURE_PWM_TIME_UP /CAPTURE_PWM_TIME_ALL; //计算占空比
CAPTURE_PWM_FRE=72000000/CAPTURE_PWM_TIME_ALL;//计算捕获的PWM频率,72000000为该捕获定时器分频后的时钟,我这里没分频(1-1)
}
}