zoukankan      html  css  js  c++  java
  • 定时器配置 中断配置 GPIO

    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);


    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
    GPIO_Init(GPIOF, &GPIO_InitStructure);

     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;


    GPIO_Init(GPIOF, &GPIO_InitStructure);

    NVIC_InitTypeDef NVIC_InitStructure;
    EXTI_InitTypeDef EXTI_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);


    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOF, EXTI_PinSource6);
    //SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOF, EXTI_PinSource7);

    EXTI_InitStructure.EXTI_Line = EXTI_Line6;//LINE6
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; //
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x03;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    void EXTI9_5_IRQHandler(void)
    {

    if(1) cnt

    if(0)cnt end

    gengxin quanju  distance

    EXTI_ClearITPendingBit(EXTI_Line6);

    }

    while (1)
    {
    GPIO_SetBits(GPIOA,GPIO_Pin_8);
    delay_nus(20);//拉高超过10us,发射超声波
    GPIO_ResetBits(GPIOA,GPIO_Pin_8);
     
    TIM2->CNT=0;//计数器清0
    while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_9)==0);//等待ECHO脚高电平
     
    TIM_Cmd(TIM2, ENABLE);// TIM2 enable counter [允许tim2计数]

     
    while((GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_9)==1)&&(TIM2->CNT<TIM2->ARR-10));

     
    TIM_Cmd(TIM2, DISABLE);

     
    count=TIM2->CNT;//ECHO脚低电平后读取计数器的值,从而算出往返时间
    length=count/58.0;
    Display_List_Char(1,9," ");
    Display_List_Float(1,9,length);
    delay_nms(200);
    }

     定时器4开启,设置中断 上升沿开始,下降沿计算distance

    定时器11开启,用输入捕获

    STM32的输入捕获,就是通过检测通道上的边沿信号,在边沿信号发生跳变(比如说突然来个上升沿或者下降沿),计数器就把此刻的计数值存放到对应通道的捕获比较寄存器,就这样、、就捕捉到了“美女”、话是这么说、、可操作起来不仅仅是几句话、因为初始化和对捕获的处理是不一样的、所以,为了做好迎接捕获的准备,我们来介绍下几个比较陌生的位:

           对于定时器的一些寄存器,在之前的博客都有涉及到,如

          TIMx_CR1,

         捕获/比较模式寄存器1(TIMx_CCMR1),

         捕获/比较使能寄存器(TIMx_CCER),

         计数器(TIMx_CNT)

         预分频器(TIMx_PSC)

        自动重装载寄存器(TIMx_ARR)

        捕获/比较寄存器1(TIMx_CCR1)

       我们再来看看 捕获/比较模式寄存器1(TIMx_CCMR1) ,由于我们是用TIM5_CH1,所以该寄存器中

       CC1S[1:0] :捕获/比较1选择 (Capture/Compare 1 selection)我们选择 01:CC1通道被配置为输入,IC1映射在TI1上;这个知道为啥是TI1吗??请看我那销魂美丽的涂鸦:

        这里我们检测高电平的宽度,所以我们检测的时候只要遇到上升沿就触发捕获一次,但是我们要怎么设置呢,请看这几位:

       IC1PSC[1:0] :输入/捕获1预分频器 (Input capture 1 prescaler) 00:无预分频器,捕获输入口上检测到的每一个边沿都触发一次捕获;

       神奇吧,好了,IC1F[3:0]:输入捕获1滤波器 (Input capture 1 filter)(这个就是上图中的输入滤波器,在这里我们不做滤波处理,为什么,请看以下解释) 

                   在这里解释下: 数字滤波器由一个事件计数器组成,它记录到N个事件后会产生一个输出的跳变: 这个N可以取值具体参考中文手册,意思是说:我采样高电平,只有连续采样到N个电平是高电平的话我才认为是有效的高电平,低于N个我就认为是无效的、在这篇博客里,我们只要是采样到高电平就行,所以这里就不采用数字滤波。

       我们来看看这个寄存器       捕获/比较使能寄存器(TIMx_CCER) ,要使捕获使能,我们就需要设置使能位

         CC1E:输入/捕获1输出使能 (Capture/Compare 1 output enable)为0;

       对于我们输入捕获后要处理的我们交给我们的 中断,所以在这里我们要开启中断使能位  

        DMA/中断使能寄存器(TIMx_DIER)    CC1IE:允许捕获/比较1中断 (Capture/Compare 1 interrupt enable)为1;

       介绍了以上几位大神,接下来,我们要怎么个思路呢??==当我们捕获到上升沿时,我们把此时的CNT中的值读出来,然后等待下降沿的到来,这时候要分为两种情况:

      第一:下降沿来了,我们就记录此刻CNT的值,(捕获值)然后重复以上动作

     第二:下降沿没来,可是这时候定时器的计数值已经到了,也就是要溢出了,这时候要特殊处理下,也就是直接把计数值返回

    (注:在这里,要注意捕获值跟计数值的差别,他们是不一样的、) 至于为什么不一样,大家可以思考思考、、

     所以我们将两次捕获的值相减,(下降沿的值减去上升沿的值)就可以得到高电平的脉宽了、、而这些事,我们都在中断服务函数里处理 (中断喔、、想起没??要做什么知道吧、、注意,这时候有两个中断触发:更新中断和捕获中断,更新中断用来处理定时器计数溢出,捕获中断用来处理捕获事件)

       接下来,我们看看我们具体的实现步骤

         1:开启挂载在ABP1的TIM5时钟,开启挂载在ABP2的GPIOA的时钟,并初始化TIM5和GPIOA,由于这两个初始化前几篇博客有涉及到,故直接贴出代码:

     1           RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
     2           RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);
     3           
     4           KEY_Init(); //IO我已在按键的函数里初始化了
     5           
     6           TIM_TimeBaseStructure.TIM_Period = arr;              
     7           TIM_TimeBaseStructure.TIM_Prescaler = psc;
     8           TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
     9           TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    10           TIM_TimeBaseInit(TIM5, & TIM_TimeBaseStructure);

          2、设置TIM_CH1的输入捕获功能,打开“stm3210x.tim.h”我们可以看到

     1 typedef struct
     2 {
     3 
     4   uint16_t TIM_Channel;      /*!< Specifies the TIM channel.设置通道
     5                                   This parameter can be a value of @ref TIM_Channel */
     6 
     7   uint16_t TIM_ICPolarity;   /*!< Specifies the active edge of the input signal.设置输入信号的有效捕获极性
     8                                   This parameter can be a value of @ref TIM_Input_Capture_Polarity */
     9 
    10   uint16_t TIM_ICSelection;  /*!< Specifies the input. 设置映射关系
    11                                   This parameter can be a value of @ref TIM_Input_Capture_Selection */
    12 
    13   uint16_t TIM_ICPrescaler;  /*!< Specifies the Input Capture Prescaler. 设置捕获的分配系数
    14                                   This parameter can be a value of @ref TIM_Input_Capture_Prescaler */
    15 
    16   uint16_t TIM_ICFilter;     /*!< Specifies the input capture filter. 设置数字滤波器的长度
    17                                   This parameter can be a number between 0x0 and 0xF */
    18 } TIM_ICInitTypeDef;

    根据我们以上的了解,我们设置,请看以下代码:

    1                 TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;     //通道1
    2                 TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;   //上升沿捕获
    3                 TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;  //映射到TI1
    4                 TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;  //不分频
    5                 TIM_ICInitStructure.TIM_ICFilter = 0x0;                //不滤波
    6                 TIM_ICInit(TIM5, &TIM_ICInitStructure);

         3、设置中断优先级、在这里比较简单,直接看代码:

    1         NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;                               
    2         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    3         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    4         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    
    5         NVIC_Init(&NVIC_InitStructure);

        4.使能中断并开启定时器

    1  
    2     TIM_ITConfig(TIM5, TIM_IT_Update | TIM_IT_CC1, ENABLE );      
    3             
    4      TIM_Cmd(TIM5, ENABLE);

       5、编写中断服务函数    

     1 u8 TM5_CH1_CAPTURE_STA = 0;//8位0x00~0x80
     2  u16 TM5_CH1_CAPTURE_VAL;  //捕获高电平后定时器溢出的次数
     3 
     4 void TIM5_IRQHandler(void)
     5 {
     6    if((TM5_CH1_CAPTURE_STA & 0x80) == 0 )  //未成功捕获,0x80捕获完成
     7      {
     8       if(TIM_GetITStatus(TIM5, TIM_IT_Update) == SET)  //数据更新中断产生
     9             {
    10            if(TM5_CH1_CAPTURE_STA & 0x40)     //已经捕获到高电平
    11                      {
    12                          if((TM5_CH1_CAPTURE_STA & 0x3f)==0x3f)   //­溢出
    13                          {
    14                           TM5_CH1_CAPTURE_STA |= 0x80;  //强制捕获成功
    15                           TM5_CH1_CAPTURE_VAL = 0xffff;  //此时的计数值
    16                          }
    17                          else
    18                          {
    19                            TM5_CH1_CAPTURE_STA++; 
    20                          }
    21                          
    22                       }
    23              }
    24             if(TIM_GetITStatus(TIM5, TIM_IT_CC1) == SET)//发生捕获
    25             {
    26         if(TM5_CH1_CAPTURE_STA & 0x40)  //成功捕获到一次下降沿,但不是第一次捕获
    27                 {
    28                      TM5_CH1_CAPTURE_STA |= 0x80;  //捕获成功
    29                       TM5_CH1_CAPTURE_VAL = TIM_GetCapture1(TIM5);//获取捕获值
    30                       TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Rising);//要设置为上升沿,等待下降沿的来临
    31         }
    32                 else  //第一次捕获
    33                 {
    34                     TM5_CH1_CAPTURE_STA = 0;
    35                     TM5_CH1_CAPTURE_VAL = 0;
    36                     TIM_SetCounter(TIM5, 0);  //还没等到下降沿来时把所有的都清零
    37                     TM5_CH1_CAPTURE_STA |= 0x40;
    38                     TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Falling);//要设置成下降沿,等到上升沿的来临
    39                  }
    40                 
    41       }
    42    }
    43       TIM_ClearITPendingBit(TIM5, TIM_IT_CC1 | TIM_IT_Update);
    44 
    45 }

           6、注意红色标注部分,好好理解刚开始说的计数值和捕获值的区别、还有

    TIM_SetCounter(TIM5, 0); //设置计数器寄存器值
    TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Falling);//设置通道1输入捕获极性
    这两个函数是库函数为我们提高的可以单独对通道进行操作的叔叔,非常方便

          7、到这里,我们需要在主函数里稍微写下:

    1  if(TM5_CH1_CAPTURE_STA & 0x80)
    2          {
    3                temp =  (TM5_CH1_CAPTURE_VAL & 0x3f);
    4                temp *= 65536; //计数器为0~65535,也就是65536一次
    5                temp +=  TM5_CH1_CAPTURE_VAL;
    6                printf("HIGH is %d
    ",temp);
    7                TM5_CH1_CAPTURE_STA = 0;//这里因为我们在之前的捕获时,若捕获成功则为1,并没有清楚,所以要进行下一次捕获,在这里则需要清零
    8      }

          8、好了,至于我标题说的小应用,也就是把我们上次PWM的输出给这次的输入捕获,大家通过串口就可以看到高电平的脉宽了。当然,在这篇博客的程序里也需要保留上次PWM输出的程序方可、、

  • 相关阅读:
    深度可分离卷积、分组卷积、空洞卷积、转置卷积
    Batch Normalization
    激活函数
    容器————vector
    39XML文档类
    38初识xml
    37QT程序打包
    36可视化操作数据库
    35使用模型操作数据库
    34sqlite
  • 原文地址:https://www.cnblogs.com/Viewsky/p/4564851.html
Copyright © 2011-2022 走看看