• STM32的PWM输入模式设置并用DMA接收数据


    参考 :STM32输入捕获模式设置并用DMA接收数据

    PWM input mode

    This mode is a particular case of input capture mode.

    The procedure is the same except:

     Two ICx signals are mapped on the same TIx input.
     These 2 ICx signals are active on edges with opposite polarity.
     One of the two TIxFP signals is selected as trigger input and the slave mode controller is configured in reset mode.


    For example, you can measure the period (in TIMx_CCR1 register) and the duty cycle (in TIMx_CCR2 register)

    of the PWM applied on TI1 using the following procedure (depending on CK_INT frequency and prescaler value):

     Select the active input for TIMx_CCR1: write the CC1S bits to 01 in the TIMx_CCMR1 register (TI1 selected).
     Select the active polarity for TI1FP1 (used both for capture in TIMx_CCR1 and counter clear): write the CC1P and CC1NP bits to ‘0’ (active on rising edge).
     Select the active input for TIMx_CCR2: write the CC2S bits to 10 in the TIMx_CCMR1 register (TI1 selected).
     Select the active polarity for TI1FP2 (used for capture in TIMx_CCR2): write the CC2P and CC2NP bits to ‘1’ (active on falling edge).
     Select the valid trigger input: write the TS bits to 101 in the TIMx_SMCR register (TI1FP1 selected).
     Configure the slave mode controller in reset mode: write the SMS bits to 100 in the TIMx_SMCR register.
     Enable the captures: write the CC1E and CC2E bits to ‘1’ in the TIMx_CCER register.

     

     

    STM32的PWM输入模式设置并用DMA接收数据

    项目中需要进行红外学习,如果采用输入捕获的方式,因为定时器只能捕获上升沿或者下降沿,

    所以只能获得周期,而不能得到具体的红外波的高低电平的时间.

    所以采用PWM输入的方式进行捕获. 采用的是PA8脚,对应TIM1的通道1.

    /*********************************************************************
     *             函数
     **********************************************************************/
    
    /*********************************************************************
     *             接口函数:初始化红外学习模块
     **********************************************************************/
    
    void inf_infrared_study_init( void )
    {
      //初始化io口
      inf_init_io( );
      //初始化中断
      //inf_init_irq();
      //初始化定时器
      inf_init_timer( );
      
      //打开DMA
      inf_infrared_study_open_dma( 1 );
      //打开定时器
      inf_infrared_study_open_timer( 1 );
    }
    
    /*********************************************************************
     *             初始化io口
     **********************************************************************/
    
    static void inf_init_io( void )
    {
      //定义IO初始化结构体
      GPIO_InitTypeDef GPIO_InitStructure;
      
      //初始化时钟
      RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
      //管脚初始化  
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
      //设置为输入           
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
      //初始化         
      GPIO_Init( GPIOA, &GPIO_InitStructure );
    }
    
    /*********************************************************************
     *             初始化中断
     **********************************************************************/
    
    static void inf_init_irq( void )
    {
      //定义外部中断结构体
      EXTI_InitTypeDef EXTI_InitStructure;
      
      //初始化中断脚复用时钟
      RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE );
      //配置中断源
      GPIO_EXTILineConfig( GPIO_PortSourceGPIOB, GPIO_PinSource1 );
      // 配置下降沿触发
      EXTI_ClearITPendingBit( EXTI_Line1 );
      EXTI_InitStructure.EXTI_Line = EXTI_Line1;
      EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
      EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
      EXTI_InitStructure.EXTI_LineCmd = ENABLE;
      EXTI_Init( &EXTI_InitStructure );
    }
    
    /*********************************************************************
     *             初始化定时器
     **********************************************************************/
    
    static void inf_init_timer( void )
    {
      //定义定时器结构体
      TIM_TimeBaseInitTypeDef timInitStruct;
      //输入捕获结构体
      TIM_ICInitTypeDef tim_icinit;
      //定义DMA结构体
      DMA_InitTypeDef DMA_InitStructure;
      
      //启动DMA时钟
      RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1, ENABLE );
      //DMA1通道配置
      DMA_DeInit( DMA1_Channel2 );
      //外设地址
      DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) ( &TIM1->CCR1 );
      //内存地址
      DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) Rx_Buf_Tim_Dma1;
      //dma传输方向单向
      DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
      //设置DMA在传输时缓冲区的长度
      DMA_InitStructure.DMA_BufferSize = RX_LEN_TIM_DMA;
      //设置DMA的外设递增模式,一个外设
      DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
      //设置DMA的内存递增模式
      DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
      //外设数据字长
      DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
      //内存数据字长
      DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
      //设置DMA的传输模式
      //DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
      DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
      //设置DMA的优先级别
      DMA_InitStructure.DMA_Priority = DMA_Priority_High;
      //设置DMA的2个memory中的变量互相访问
      DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
      DMA_Init( DMA1_Channel2, &DMA_InitStructure );
      
      //启动DMA时钟
      RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1, ENABLE );
      //DMA1通道配置
      DMA_DeInit( DMA1_Channel3 );
      //外设地址
      DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) ( &TIM1->CCR2 );
      //内存地址
      DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) Rx_Buf_Tim_Dma2;
      //dma传输方向单向
      DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
      //设置DMA在传输时缓冲区的长度
      DMA_InitStructure.DMA_BufferSize = RX_LEN_TIM_DMA;
      //设置DMA的外设递增模式,一个外设
      DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
      //设置DMA的内存递增模式
      DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
      //外设数据字长
      DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
      //内存数据字长
      DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
      //设置DMA的传输模式
      //DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
      DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
      //设置DMA的优先级别
      DMA_InitStructure.DMA_Priority = DMA_Priority_High;
      //设置DMA的2个memory中的变量互相访问
      DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
      DMA_Init( DMA1_Channel3, &DMA_InitStructure );
      
      //开启时钟
      RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM1, ENABLE );
      //重新将Timer设置为缺省值
      TIM_DeInit( TIM1 );
      //采用内部时钟提供时钟源
      TIM_InternalClockConfig( TIM1 );
      //预分频
      timInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
      //计数频率为500ns跳转1次      
      timInitStruct.TIM_Prescaler = SystemCoreClock / 1000000 - 1;
      //向上计数          
      timInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
      timInitStruct.TIM_RepetitionCounter = 0;
      //这个值实际上就是TIMX->ARR,延时开始时重新设定即可 
      timInitStruct.TIM_Period = 0xffff;
      //初始化定时器
      TIM_TimeBaseInit( TIM1, &timInitStruct );
      
      //输入捕获配置
      //选择通道
      tim_icinit.TIM_Channel = TIM_Channel_1;
      //硬件滤波
      tim_icinit.TIM_ICFilter = 0x0;
      //触发捕获的电平
      tim_icinit.TIM_ICPolarity = TIM_ICPolarity_Falling;
      //每次检测到触发电平都捕获
      tim_icinit.TIM_ICPrescaler = TIM_ICPSC_DIV1;
      //通道方向选择
      tim_icinit.TIM_ICSelection = TIM_ICSelection_DirectTI;
      //初始化
      //TIM_ICInit(TIM1,&tim_icinit);
      TIM_PWMIConfig( TIM1, &tim_icinit );
      //禁止ARR预装载缓冲器  
      //TIM_ARRPreloadConfig(TIM1, DISABLE);  
      
      //输入跳变选择
      TIM_SelectInputTrigger( TIM1, TIM_TS_TI1FP1 );
      //从机模式:复位模式
      TIM_SelectSlaveMode( TIM1, TIM_SlaveMode_Reset );
      //主从模式选择
      TIM_SelectMasterSlaveMode( TIM1, TIM_MasterSlaveMode_Enable );
      
      //配置定时器的DMA
      TIM_DMAConfig( TIM1, TIM_DMABase_CCR1, TIM_DMABurstLength_2Bytes );
      //产生DMA请求信号
      TIM_DMACmd( TIM1, TIM_DMA_CC1, ENABLE );
      
      //配置定时器的DMA
      TIM_DMAConfig( TIM1, TIM_DMABase_CCR2, TIM_DMABurstLength_2Bytes );
      //产生DMA请求信号
      TIM_DMACmd( TIM1, TIM_DMA_CC2, ENABLE );
      
      //打开定时器
      TIM_Cmd( TIM1, ENABLE );
    }
    
    /*********************************************************************
     *             接口函数:打开定时器
     *参数:state:状态:0:关闭,1:打开
     **********************************************************************/
    
    void inf_infrared_study_open_timer( uint8_t state )
    {
      if ( state )
      {
        TIM_Cmd( TIM1, ENABLE );
      }
      else
      {
        TIM_Cmd( TIM1, DISABLE );
      }
    }
    
    /*********************************************************************
     *             接口函数:打开中断
     *参数:state:状态:0:关闭,1:打开
     **********************************************************************/
    
    void inf_infrared_study_open_irq( uint8_t state )
    {
      //定义中断结构体
      NVIC_InitTypeDef NVIC_InitStructure;
      
      if ( state )
      {
        //打开中断
        NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;        //通道设置为外部中断线
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;     //中断抢占先等级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            //中断响应优先级
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;               //打开中断
        NVIC_Init( &NVIC_InitStructure );                                 //初始化
      }
      else
      {
        //关闭中断
        NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;        //通道设置为外部中断线
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;     //中断抢占先等级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            //中断响应优先级
        NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;              //打开中断
        NVIC_Init( &NVIC_InitStructure );                                 //初始化
      }
    }
    
    /*********************************************************************
     *             接口函数:打开DMA
     *参数:state:状态:0:关闭,1:打开
     **********************************************************************/
    
    void inf_infrared_study_open_dma( uint8_t state )
    {
      if ( state )
      {
        //设置传输数据长度
        //DMA_SetCurrDataCounter(DMA1_Channel3,RX_LEN_TIM_DMA);
        //打开DMA
        DMA_Cmd( DMA1_Channel2, ENABLE );
        DMA_Cmd( DMA1_Channel3, ENABLE );
      }
      else
      {
        DMA_Cmd( DMA1_Channel2, DISABLE );
        DMA_Cmd( DMA1_Channel3, ENABLE );
      }
    }
    
    /*********************************************************************
     *             接口函数:得到DMA接收帧长
     *返回:帧长
     **********************************************************************/
    
    uint16_t inf_infrared_study_dma_rx_len( void )
    {
      //获得接收帧帧长
      return ( RX_LEN_TIM_DMA - DMA_GetCurrDataCounter( DMA1_Channel2 ) );
    }
  • 相关阅读:
    Go语言 函数return值的几种情况
    VSCode 常用快捷键 Mac
    Java异常处理
    Java面向对象《三》
    C++类模板
    C++函数模板
    盛最多水的容器
    实现 Trie (前缀树)
    排序链表
    类似某团app搜索城市界面中 点击右侧城市首字母,对应城市区域置顶的功能(uniapp)
  • 原文地址:https://www.cnblogs.com/shangdawei/p/4748791.html
Copyright © 2020-2023  润新知