STM32輸入捕獲模式設置並用DMA接收數據


參考: STM32的PWM輸入模式設置並用DMA接收數據

Input capture mode

The input stage samples the corresponding TIx input to generate a filtered signal TIxF.

Then, an edge detector with polarity selection generates a signal (TIxFPx)

which can be used as trigger input by the slave mode controller or as the capture command.

It is prescaled before the capture register (ICxPS).

In Input capture mode, the Capture/Compare Registers (TIMx_CCRx) are used to latch the value of the counter

after a transition detected by the corresponding ICx signal.

When a capture occurs, the corresponding CCXIF flag (TIMx_SR register) is set and an interrupt

or a DMA request can be sent if they are enabled.

If a capture occurs while the CCxIF flag was already high, then the over-capture flag CCxOF (TIMx_SR register) is set.

CCxIF can be cleared by software by writing it to ‘0’ or by reading the captured data stored in the TIMx_CCRx register.

CCxOF is cleared when you write it to ‘0’. 

 

The following example shows how to capture the counter value in TIMx_CCR1 when TI1 input rises.

To do this, use the following procedure:

 Select the active input:
TIMx_CCR1 must be linked to the TI1 input, so write the CC1S bits to 01 in the TIMx_CCMR1 register.
As soon as CC1S becomes different from 00, the channel is configured in input and the TIMx_CCR1 register becomes read-only.

 Program the input filter duration you need with respect to the signal you connect to the timer
(by programming ICxF bits in the TIMx_CCMRx register if the input is a TIx input).
Let’s imagine that, when toggling, the input signal is not stable during at must 5 internal clock cycles.
We must program a filter duration longer than these 5 clock cycles.
We can validate a transition on TI1 when 8 consecutive samples with the new level have been detected (sampled at fDTS frequency).
Then write IC1F bits to 0011 in the TIMx_CCMR1 register.

 Select the edge of the active transition on the TI1 channel by writing CC1P and CC1NP bits to 0
in the TIMx_CCER register (rising edge in this case).

 Program the input prescaler. In our example, we wish the capture to be performed at each valid transition,
so the prescaler is disabled (write IC1PS bits to ‘00’ in the TIMx_CCMR1 register).


 Enable capture from the counter into the capture register by setting the CC1E bit in the TIMx_CCER register.
 If needed, enable the related interrupt request by setting the CC1IE bit in the TIMx_DIER register,
and/or the DMA request by setting the CC1DE bit in the TIMx_DIER register.


When an input capture occurs:
 The TIMx_CCR1 register gets the value of the counter on the active transition.
 CC1IF flag is set (interrupt flag). CC1OF is also set if at least two consecutive captures occurred whereas the flag was not cleared.
 An interrupt is generated depending on the CC1IE bit.
 A DMA request is generated depending on the CC1DE bit.
In order to handle the overcapture, it is recommended to read the data before the overcapture flag.
This is to avoid missing an overcapture which could happen after reading the flag and before reading the data.

Note:

IC interrupt and/or DMA requests can be generated by software by setting the corresponding CCxG bit in the TIMx_EGR register.

 

 

STM32輸入捕獲模式設置並用DMA接收數據

本文博客鏈接:http://blog.csdn.net/jdh99,作者:jdh

環境:

主機:WIN7

開發環境:MDK4.72

MCU:STM32F103

說明:

項目中需要進行紅外學習,於是采用輸入捕獲取得電平變化時間.並將數據放在DMA中.這樣可以避免頻繁中斷消耗CPU資源.

采用的是PB1腳,對應TIM3的通道4.

/*********************************************************************
*                            接口函數:初始化紅外學習模塊
**********************************************************************/

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_1;
    //設置為輸入           
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 
    //初始化                
    GPIO_Init(GPIOB, &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通道3配置
    DMA_DeInit(DMA1_Channel3);
    //外設地址
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&TIM3->CCR4);
    //內存地址
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Rx_Buf_Tim_Dma;
    //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_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
    //重新將Timer設置為缺省值
    TIM_DeInit(TIM3);
    //采用內部時鍾給TIM3提供時鍾源
    TIM_InternalClockConfig(TIM3);
    //預分頻
    timInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;    
    //計數頻率為500ns跳轉1次             
    timInitStruct.TIM_Prescaler = SystemCoreClock / 2000000 - 1;     
    //向上計數                  
    timInitStruct.TIM_CounterMode = TIM_CounterMode_Up;     
    timInitStruct.TIM_RepetitionCounter = 0;
    //這個值實際上就是TIMX->ARR,延時開始時重新設定即可    
    timInitStruct.TIM_Period = 0xffff;                                 
    //初始化定時器3
    TIM_TimeBaseInit(TIM3, &timInitStruct);
    
    //輸入捕獲配置
    //選擇通道
    tim_icinit.TIM_Channel = TIM_Channel_4;
    //硬件濾波
    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(TIM3,&tim_icinit);
    
    //禁止ARR預裝載緩沖器  
    TIM_ARRPreloadConfig(TIM3, DISABLE);  

    //輸入跳變選擇
    TIM_SelectInputTrigger(TIM3, TIM_TS_TI2FP2);
    //從機模式:復位模式
    TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
    //主從模式選擇
    TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);
 
    //配置定時器的DMA
    TIM_DMAConfig(TIM3,TIM_DMABase_CCR4,TIM_DMABurstLength_2Bytes);
    //產生DMA請求信號
    TIM_DMACmd(TIM3, TIM_DMA_CC4, ENABLE);
    //打開定時器
    TIM_Cmd(TIM3, ENABLE);
}

/*********************************************************************
*                            接口函數:打開定時器
*參數:state:狀態:0:關閉,1:打開
**********************************************************************/

void inf_infrared_study_open_timer(uint8_t state)
{
    if (state)
    {
        TIM_Cmd(TIM3, ENABLE);
    }
    else
    {
        TIM_Cmd(TIM3, 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_Channel3,ENABLE);
    }
    else
    {
        DMA_Cmd(DMA1_Channel3,DISABLE);
    }
}

/*********************************************************************
*                            接口函數:得到DMA接收幀長
*返回:幀長
**********************************************************************/

uint16_t inf_infrared_study_dma_rx_len(void)
{
    //獲得接收幀幀長
    return (RX_LEN_TIM_DMA - DMA_GetCurrDataCounter(DMA1_Channel3));
}

注意:

除TIM6和TIM7之外的定時器都只能采用上升沿或者下降沿捕捉而不能采用雙邊沿捕捉.

#define  TIM_ICPolarity_Rising             ((uint16_t)0x0000)
#define  TIM_ICPolarity_Falling            ((uint16_t)0x0002)
#define  TIM_ICPolarity_BothEdge           ((uint16_t)0x000A)
#define IS_TIM_IC_POLARITY(POLARITY) (((POLARITY) == TIM_ICPolarity_Rising) || 
                                      ((POLARITY) == TIM_ICPolarity_Falling))
#define IS_TIM_IC_POLARITY_LITE(POLARITY) (((POLARITY) == TIM_ICPolarity_Rising) || 
                                           ((POLARITY) == TIM_ICPolarity_Falling)|| 
                                           ((POLARITY) == TIM_ICPolarity_BothEdge))  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM