PWM输出:比较常见应用在控制电机转速,舵机转角、控制某些特定的LED灯
输入捕获计时:实际应用在测量PWM、输入波形的周期与占空比。用于仪表仪器上,检测当前的电平计数等(检测超声波、检测温度等一些特殊的需要计时的传感器)
#include "bsp_PWM.h"
#include <stdbool.h>
//函数功能 : 初始化定时器1的PWM输出,其中PWM输出端口为PE9、PE11、PE13、PE14;PWM的输出频率为400HZ,精度为10000
bool PWM_Out_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_11|GPIO_Pin_13|GPIO_Pin_14;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed;
GPIO_Init(GPIOE,&GPIO_InitStruct);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource9,GPIO_AF_TIM1);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource11,GPIO_AF_TIM1);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource13,GPIO_AF_TIM1);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource14,GPIO_AF_TIM1);
//输出频率为400HZ,精度为10000
//计算公式:1/400 = (psc*10000)/时钟周期(84MHZ*2)
//因为APB2时钟为84Mhz(在时钟源下2分频得到),当APB预分频为1时,
//定时器时钟频率等于APB的频率,否则,等于APB域的频率的两倍
uint32_t hz_set =FREQUENCY * acc;
uint16_t psc = (uint16_t)((84000000 * 2)/hz_set) -1;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //定时器向上计数模式
TIM_TimeBaseInitStruct.TIM_Period = acc; //预装载值
TIM_TimeBaseInitStruct.TIM_Prescaler = psc; //预分频系数
TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStruct);
TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Set; //定时器通道的空闲输出状态
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; //PWM1调制模式
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性高
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;//比较输出使能
TIM_OCInitStruct.TIM_Pulse = 2000; //设置占空比 CCRx x = (1,2,3,4)
TIM_OC1Init(TIM1,&TIM_OCInitStruct);
TIM_ARRPreloadConfig(TIM1,ENABLE); //ARPE使能 (自动装载预装载功能使能[影子寄存器])
TIM_CtrlPWMOutputs(TIM1,ENABLE); //TIM1主输出使能(高级定时器才需要这一步)
TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); //使能TIM1在CCR1上的预装载寄存器
TIM_OC2Init(TIM1,&TIM_OCInitStruct);
TIM_OC2PreloadConfig(TIM1,TIM_OCPreload_Enable); //使能TIM1在CCR2上的预装载寄存器
TIM_OC3Init(TIM1,&TIM_OCInitStruct);
TIM_OC3PreloadConfig(TIM1,TIM_OCPreload_Enable); //使能TIM1在CCR3上的预装载寄存器
TIM_OC4Init(TIM1,&TIM_OCInitStruct);
TIM_OC4PreloadConfig(TIM1,TIM_OCPreload_Enable); //使能TIM1在CCR4上的预装载寄存器
TIM_Cmd(TIM1,ENABLE);//定时器1使能
return true;
}
//函数功能 : 初始化定时器3的输入捕获,,其输入捕获的引脚为PB0、PB1、PB4、PB5
void TIM_Cap_Init(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_ICInitTypeDef TIM_ICInitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_4|GPIO_Pin_5;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed;
GPIO_Init(GPIOB,&GPIO_InitStruct);
//端口复用
GPIO_PinAFConfig(GPIOB,GPIO_PinSource0,GPIO_AF_TIM3);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource1,GPIO_AF_TIM3);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_TIM3);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_TIM3);
//定时器初始化,这里初始化捕获定时器计数频率为1Mhz,也就是1us
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseInitStruct.TIM_Period = 0xFFFF;
TIM_TimeBaseInitStruct.TIM_Prescaler = 84-1;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
//开启捕获中断
TIM_ITConfig(TIM3,TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4,ENABLE);
//设置输入捕获参数
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1; //选择输入端通道1,将IC1映射到TC1上
TIM_ICInitStruct.TIM_ICFilter = 0xF; //配置滤波器,不滤波
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_BothEdge; //设置双边沿中断捕获
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;//映射到TC1
TIM_ICInit(TIM3,&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel = TIM_Channel_2; //选择输入端通道2,将IC1映射到TC1上
TIM_ICInitStruct.TIM_ICFilter = 0xF; //配置滤波器,不滤波
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_BothEdge; //设置双边沿中断捕获
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;//映射到TC1
TIM_ICInit(TIM3,&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel = TIM_Channel_3; //选择输入端通道3,将IC1映射到TC1上
TIM_ICInitStruct.TIM_ICFilter = 0xF; //配置滤波器,不滤波
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_BothEdge; //设置双边沿中断捕获
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;//映射到TC1
TIM_ICInit(TIM3,&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel = TIM_Channel_4; //选择输入端通道4,将IC1映射到TC1上
TIM_ICInitStruct.TIM_ICFilter = 0xF; //配置滤波器,不滤波
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_BothEdge; //设置双边沿中断捕获
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;//映射到TC1
TIM_ICInit(TIM3,&TIM_ICInitStruct);
NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn; //配置定时器中断
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3;
NVIC_Init(&NVIC_InitStruct);
TIM_Cmd(TIM3,ENABLE);
}
uint16_t riseCNT[4];
uint16_t fallCNT[4];
uint16_t time[4] = {0}; //高电平的持续时间
void TIM3_IRQHandler()
{
if(TIM_GetITStatus(TIM3,TIM_IT_CC1) == SET)
{
TIM_ClearITPendingBit(TIM3,TIM_IT_CC1); //清除中断标志位
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4)) //通道1读取输入捕获引脚高低电平
{
riseCNT[0] = (uint16_t)TIM_GetCounter(TIM3);//获取高电平时定时器的预装载值
}
else
{
fallCNT[0] = (uint16_t)TIM_GetCounter(TIM3);//获取低电平时定时器的预装载值
if(riseCNT[0]>fallCNT[0]) //周期溢出
{
time[0] = 0xFFFF - riseCNT[0] +fallCNT[0] +1;
}
else
{
time[0] = fallCNT[0] - riseCNT[0];
}
}
}
//该中断服务函数计算的是PWM波高电平的持续时间, 定时器1输出PWM的频率为400Hz,即一个周期(上升沿+下降沿)2.5ms,定时器1的预装载值为10000,其CCR1设置为2000,所以其占空比(高电平)为20%,则高电平持续时间为2.5ms * 20% = 500us。
//输入捕获定时器3的预装载值为最大0xFFFF(65535),它的预分频为84M,则计数频率为84/84 = 1Mhz = 1us。所以通过计算PWM波高低电平到达时的预装载值的差,直接可以PWM波的高电平持续时间。
if(TIM_GetITStatus(TIM3,TIM_IT_CC2) == SET)
{
TIM_ClearITPendingBit(TIM3,TIM_IT_CC2);
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)) //通道2读取输入捕获引脚高低电平
{
riseCNT[1] = (uint16_t)TIM_GetCounter(TIM3);
}
else
{
fallCNT[1] = (uint16_t)TIM_GetCounter(TIM3);
if(riseCNT[1]>fallCNT[1])
{
time[1] = 0xFFFF - riseCNT[1] + fallCNT[1] + 1;
}
else
{
time[1] = fallCNT[1] - riseCNT[1];
}
}
}
if(TIM_GetITStatus(TIM3,TIM_IT_CC3) == SET)
{
TIM_ClearITPendingBit(TIM3,TIM_IT_CC3);
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)) //通道3读取输入捕获引脚高低电平
{
riseCNT[2] = (uint16_t)TIM_GetCounter(TIM3);
}
else
{
fallCNT[2] = (uint16_t)TIM_GetCounter(TIM3);
if(riseCNT[2]>fallCNT[2])
{
time[2] = 0xFFFF - riseCNT[2] + fallCNT[2] + 1;
}
else
{
time[2] = fallCNT[2] - riseCNT[2];
}
}
}
if(TIM_GetITStatus(TIM3,TIM_IT_CC4) == SET)
{
TIM_ClearITPendingBit(TIM3,TIM_IT_CC4);
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)) //通道4读取输入捕获引脚高低电平
{
riseCNT[3] = (uint16_t)TIM_GetCounter(TIM3);
}
else
{
fallCNT[3] = (uint16_t)TIM_GetCounter(TIM3);
if(riseCNT[3]>fallCNT[3])
{
time[3] = 0xFFFF - riseCNT[3] + fallCNT[3] + 1;
}
else
{
time[3] = fallCNT[3] - riseCNT[3];
}
}
}
}
程序执行结果:将PWM输出四个引脚通道与输入捕获四个引脚通道连接起来,通过调试watch窗口查看数组time的值为500,单位us。