寒假学习之stm32(9)----PWM进行输入捕获

来源:互联网 发布:魔法盾软件 编辑:程序博客网 时间:2024/05/17 06:42

应用
呃,说到应用,目前能想到的最主要的应用就是检测输入波的频率,其他的暂时没想,日后再更新吧~


工作过程
通过检测TIMx_CHx(某一个定时器的某一个通道)的边沿信号,在边沿信号发生跳定(上升或者下降)定时,将当前定时器的值(TIMx_CNT)存放到对应的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。
这里写图片描述

详细的工作过程:1. 设置输入捕获滤波器(去抖动,滤噪音,可以设定N个周期检测一次高电平)2.  设定输入捕获极性(上升沿捕获 or 下降沿捕获)3.  设置输入捕获映射通道(输入 or 输出)4.  设置输入捕获分频器(每n个事件捕获一次)5.  捕获到有效信号开启中断

配置过程:

1. 初始化时钟2. 初始化IO,注意,此时GPIO_Mode_IPD 或者 GPIO_Mode_IPU3.  初始化定时器,    ARR,PSC。。 TIM_TimeBaseInit()4.  初始化输入捕获通道    TIM_ICInit()5.  开启捕获中断    TIM_ITConfig()    NVIC_Init()6. 使能定时器    TIM_Cmd()7. 编写中断服务函数    TIMx_IRQHandler()

配置的过程和上一讲极其类似,代码就贴出来吧:

#include"stm32f10x.h"void TIM5_Cap_Init(u16 arr,u16 psc){        GPIO_InitTypeDef GPIO_InitStructure;    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;    NVIC_InitTypeDef NVIC_InitStructure;    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);    //使能TIM5时钟    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //使能GPIOA时钟    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;  //PA0 清除之前设置      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 输入      GPIO_Init(GPIOA, &GPIO_InitStructure);    GPIO_ResetBits(GPIOA,GPIO_Pin_0);                        //PA0 下拉    //初始化定时器5 TIM5       TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值     TIM_TimeBaseStructure.TIM_Prescaler =psc;   //预分频器       TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式    TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位    //初始化TIM5输入捕获参数    TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01     选择输入端 IC1映射到TI1上    TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;    //上升沿捕获    TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上    TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;   //配置输入分频,不分频     TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波    TIM_ICInit(TIM5, &TIM5_ICInitStructure);    //中断分组初始化    NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;  //TIM3中断    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;  //先占优先级2级    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //从优先级0级    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能    NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器     TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断 ,允许CC1IE捕获中断        TIM_Cmd(TIM5,ENABLE );  //使能定时器5}u8  TIM5CH1_CAPTURE_STA=0;  //输入捕获状态                            u16 TIM5CH1_CAPTURE_VAL;    //输入捕获值//定时器5中断服务程序     void TIM5_IRQHandler(void){     if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获       {             if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)        {                   if(TIM5CH1_CAPTURE_STA&0X40)//已经捕获到高电平了            {                if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了                {                    TIM5CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次                    TIM5CH1_CAPTURE_VAL=0XFFFF;                }else TIM5CH1_CAPTURE_STA++;            }            }    if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)//捕获1发生捕获事件        {               if(TIM5CH1_CAPTURE_STA&0X40)        //捕获到一个下降沿                  {                               TIM5CH1_CAPTURE_STA|=0X80;      //标记成功捕获到一次高电平脉宽                TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);                TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获            }else                               //还未开始,第一次捕获上升沿            {                TIM5CH1_CAPTURE_STA=0;          //清空                TIM5CH1_CAPTURE_VAL=0;                TIM_SetCounter(TIM5,0);                TIM5CH1_CAPTURE_STA|=0X40;      //标记捕获到了上升沿                TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);     /*CC1P=1 设置为下降沿捕获库函数只提供给了下面的函数输出比较极性函数:void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity); 根据有效性判断这个函数的入口参数为:#define TIM_OCPolarity_High                ((uint16_t)0x0000)#define TIM_OCPolarity_Low                 ((uint16_t)0x0002)第二个参数取值判断:#define IS_TIM_OC_POLARITY(POLARITY) (((POLARITY) == TIM_OCPolarity_High) || \                                      ((POLARITY) == TIM_OCPolarity_Low))查看了固件库V1.5版本,并没有输入捕获极性判断的函数,但是因为在两种模式下,都是配置同一个位,而且,#define  TIM_ICPolarity_Rising             ((uint16_t)0x0000)#define  TIM_ICPolarity_Falling            ((uint16_t)0x0002)也就是说: TIM_OCPolarity_High         =       TIM_ICPolarity_Rising                TIM_OCPolarity_Low         =         TIM_ICPolarity_Falling            所以:TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);   和   TIM_OC1PolarityConfig(TIM5,TIM_OCPolarity_Low);都是对寄存器CCER配置:  TIM5->CCER|=1<<1;  */            }                   }                                                  }    TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位}extern u8  TIM5CH1_CAPTURE_STA;     //输入捕获状态                            extern u16  TIM5CH1_CAPTURE_VAL;    //输入捕获值  int main(void) {          u32 temp=0;     delay_init();            //延时函数初始化        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //设置NVIC中断分组2:2位抢占优先级,2位响应优先级    uart_init(115200);   //串口初始化为115200    LED_Init();              //LED端口初始化    TIM3_PWM_Init(899,0);       //不分频。PWM频率=72000/(899+1)=80Khz    TIM5_Cap_Init(0XFFFF,72-1); //以1Mhz的频率计数     while(1)    {        delay_ms(10);        TIM_SetCompare2(TIM3,TIM_GetCapture2(TIM3)+1);        if(TIM_GetCapture2(TIM3)==300)TIM_SetCompare2(TIM3,0);          if(TIM5CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿        {            temp=TIM5CH1_CAPTURE_STA&0X3F;            temp*=65536;//溢出时间总和            temp+=TIM5CH1_CAPTURE_VAL;//得到总的高电平时间            printf("HIGH:%d us\r\n",temp);//打印总的高点平时间            TIM5CH1_CAPTURE_STA=0;//开启下一次捕获        }    } }
1 0