无人机底层驱动+STM32F4学习心得-4.PWM初始化及输入捕获

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。

猜你喜欢

转载自blog.csdn.net/qq_41422043/article/details/83783135
今日推荐