1. 程式人生 > >STM32 通用定時器作為輸入捕獲 學習筆記

STM32 通用定時器作為輸入捕獲 學習筆記

STM32 通用定時器作為輸入捕獲 
通用定時器作為輸入捕獲的使用。我們將用TIM5的通道1(PA0)來做輸入捕獲,捕獲PA0上高電平的脈寬(用 WK_UP 按鍵輸入高電平),通過串列埠列印高電平脈寬時間。
 
輸入捕獲簡介:
輸入捕獲模式可以用來測量脈衝寬度或者測量頻率。STM32的定時器,除了TIM6和TIM7,其他定時器都有輸入捕獲功能。
STM32 的輸入捕獲,簡單的說就是通過檢測 TIMx_CHx 上的邊沿訊號,在邊沿訊號發生跳變(比如上升沿/下降沿)的時候,
將當前定時器的值(TIMx_CNT)存放到對應的通道的捕獲/比較暫存器(TIMx_CCRx)裡面,完成一次捕獲。同時還可以配置捕獲時是否觸發中斷/DMA 等。
我們用到TIM5_CH1來捕獲高電平脈寬,也就是要先設定輸入捕獲為上升沿檢測,記錄發生上升沿的時候 TIM5_CNT 的值。
然後配置捕獲訊號為下降沿捕獲,當下降沿到來時,發生捕獲,並記錄此時的 TIM5_CNT 值。這樣,前後兩次 TIM5_CNT 之差,就是高電平的脈寬,同時 TIM5 的計數頻率我們是知道的,從而可以計算出高電平脈寬的準確時間。
輸入捕獲的配置步驟:
1)開啟 TIM5 時鐘和 GPIOA 時鐘,配置 PA0 為下拉輸入。
要使用 TIM5,我們必須先開啟 TIM5 的時鐘。這裡我們還要配置 PA0 為下拉輸入,因為我們要捕獲 TIM5_CH1 上面的高電平脈寬,而 TIM5_CH1 是連線在 PA0 上面的。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);  //使能 TIM5 時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能 GPIOA 時鐘

2)初始化 TIM5,設定 TIM5 的 ARR 和 PSC。
在開啟了 TIM5 的時鐘之後,我們要設定 ARR 和 PSC 兩個暫存器的值來設定輸入捕獲的自動重灌載值和與分頻數。 這在庫函式中是通過 TIM_TimeBaseInit 函式實現的
   TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
   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);

3)設定 TIM5 的輸入比較引數,開啟輸入捕獲
輸入比較引數的設定包括對映關係,濾波,分頻以及捕獲方式等。這裡我們需要設定通道 1為輸入模式,且IC1對映到 TI1(通道 1)上面,並且不使用濾波(提高響應速度)器,上升沿捕獲。
庫函式是通過 TIM_ICInit 函式來初始化輸入比較引數的:
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
同樣,我們來看看引數設定結構體 TIM_ICInitTypeDef 的定義:
   typedef struct
   {
       uint16_t TIM_Channel; //設定通道
       uint16_t TIM_ICPolarity; //設 置 輸 入 信 號 的 有效 捕獲 極性 
       uint16_t TIM_ICSelection; //設定對映關係
       uint16_t TIM_ICPrescaler; //設定 輸入捕獲分頻係數
       uint16_t TIM_ICFilter; //設定濾波器長度
   } TIM_ICInitTypeDef;

配置程式碼是:
   TIM_ICInitTypeDef TIM5_ICInitStructure; 
   TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //選擇輸入端 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);

4)使能捕獲和更新中斷(設定 TIM5 的 DIER 暫存器)
因為我們要捕獲的是高電平訊號的脈寬,所以,第一次捕獲是上升沿,第二次捕獲時下降沿,必須在捕獲上升沿之後,設定捕獲邊沿為下降沿,
同時,如果脈寬比較長,那麼定時器就會溢位,對溢位必須做處理,否則結果就不準了。這兩件事,我們都在中斷裡面做,所以必須開啟捕獲中斷和更新中斷。 
這裡我們使用定時器的開中斷函式 TIM_ITConfig 即可使能捕獲和更新中斷:
TIM_ITConfig( TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允許更新中斷和捕獲中斷

5)設定中斷分組,編寫中斷服務函式
設定中斷分組主要是通過函式 NVIC_Init()來完成。分組完成後,我們還需要在中斷函式裡面完成資料處理和捕獲設定等關鍵操作,從而實現高電平脈寬統計。
在中斷服務函式裡面,跟以前的外部中斷和定時器中斷實驗中一樣,我們在中斷開始的時候要進行中斷型別判斷,在中斷結束的時候要清除中斷標誌位。
使用到的函式分別為 TIM_GetITStatus()函式和 TIM_ClearITPendingBit()函式。
if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET){}//判斷是否為更新中斷
if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET){}//判斷是否發生捕獲事件
TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update);//清除中斷和捕獲標誌位

6)使能定時器(設定 TIM5的CR1暫存器) 
最後,必須開啟定時器的計數器開關,啟動 TIM5 的計數器,開始輸入捕獲。 
TIM_Cmd(TIM5,ENABLE ); //使能定時器 5

貼下正點原子的例程:
#include "timer.h"
#include "led.h"
#include "usart.h"

void TIM5_Cap_Init(u16 arr,u16 psc)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_ICInitTypeDef TIM5_ICInitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); 
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; 
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    GPIO_ResetBits(GPIOA,GPIO_Pin_0); 
    
    TIM_TimeBaseStructure.TIM_Period = arr; 
    TIM_TimeBaseStructure.TIM_Prescaler = psc; 
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 
    TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure); 
    
    TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1;     
    TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; 
    TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; 
    TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; 
    TIM5_ICInitStructure.TIM_ICFilter = 0; 
    TIM_ICInit(TIM5,&TIM5_ICInitStructure); 
     
    NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;    
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
    NVIC_Init(&NVIC_InitStructure);
    
    TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);
    TIM_Cmd(TIM5,ENABLE);     
}

u8 TIM5CH1_CAPTURE_STA=0;    //輸入捕獲狀態                         
u16 TIM5CH1_CAPTURE_VAL;    //輸入捕獲值

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)
        {
            if(TIM5CH1_CAPTURE_STA & 0x40)
            {
                TIM5CH1_CAPTURE_STA|=0X80;        //標記成功捕獲到一次上升沿
                TIM5CH1_CAPTURE_VAL = TIM_GetCounter(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 設定為下降沿捕獲
            }
        }
        
    }
    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_Configuration();  //設定NVIC中斷分組2:2位搶佔優先順序,2位響應優先順序
uart_init(9600);       //串列埠初始化為9600
LED_Init();           //LED埠初始化

TIM5_Cap_Init(0XFFFF,72-1);    //以1Mhz的頻率計數 
while(1)
{
delay_ms(10);
 
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;//開啟下一次捕獲
}
}
}

相關推薦

STM32 通用定時作為輸入捕獲 學習筆記

STM32 通用定時器作為輸入捕獲  通用定時器作為輸入捕獲的使用。我們將用TIM5的通道1(PA0)來做輸入捕獲,捕獲PA0上高電平的脈寬(用 WK_UP 按鍵輸入高電平),通過串列埠列印高電平脈寬時間。   輸入捕獲簡介: 輸入捕獲模式可以用來測量脈衝寬度或者測量頻率。

STM32通用定時輸入捕獲(例項:輸入捕獲

STM32F1xx官方資料:《STM32中文參考手冊V10》-第14章  通用定時器通用定時器輸入捕獲概述輸入捕獲的工作原理在通用定時器框圖中,主要涉及到最頂上的一部分(計數時鐘的選擇)、中間部分(時基單元)、左下部分(輸入捕獲輸入捕獲模式可以用來測量脈衝寬度或者測量頻率。S

STM32 通用定時的輸出PWM功能 學習筆記

首先來說,你要使用PWM模式你得先選擇用哪個定時器來輸出PWM吧!除了TIM6、TIM7這兩個普通的定時器無法輸出PWM外,其餘的定時器都可以輸出PWM,每個通用定時器可以輸出4路PWM,高階定時器TIM1、TIM8每個可輸出7路PWM。選好定時器及通道後,下一步就是要使能

STM32 通用定時定時功能 學習筆記

這節主要講下STM32 通用定時器的定時功能。 一、TIMx的時鐘源問題: STM32有8路暫存器,包括TIM1和TIM8兩個高階定時器,TIM6和TIM7兩個基本定時器,TIM2-TIM5四個通用定時器,定時器是完全獨立的,而且沒有互相共享任何資源,它們可以一起同步操作,

STM32-通用定時基本定時功能

數字 vision 實現 定義 還要 可能 輸出 給定 禁止 1. STM32的Timer簡介 STM32中一共有11個定時器,其中2個高級控制定時器,4個普通定時器和2個基本定時器,以及2個看門狗定時器和1個系統嘀嗒定時器。其中系統嘀嗒定時器是前文中所描述的Sys

STM32通用定時配置

STM32通用定時器配置 一、STM32通用定時器原理                   

STM32通用定時的基本定時功能實現燈閃爍

/*MAIN.C*/ /* Includes ------------------------------------------------------------------*/#inclu

使用STM32定時進行輸入脈衝的計數

3、外部觸發無濾波器:0000。    可選項:  0:無濾波器,以fDTS取樣  1:取樣頻率fSAMPLING=fCK_INT,N=2  2:取樣頻率fSAMPLING=fCK_INT,N=4  3:取樣頻率fSAMPLING=fCK_INT,N=8  4:取樣頻率fSAMPLING=fDTS/2,N=6

STM32通用定時TIM2、3、4

STM32通用定時器用法 ---附原始碼 1.STM32通用定時器的基本用法,即簡單的定時功能。支援向上計數、向下計數、中央對其模式,這裡僅以向上計數講解。 2.向上計數原理:從0開始,每經過一個時鐘脈衝加1,直到到達通過TIMx_ARR暫存器設定的值時為止,至此產生更新事

關於STM32通用定時更新事件中斷

 //定時器3中斷服務程式   void TIM3_IRQHandler(void)  {                    if(TIM3->SR&0X0001) //產生更新事件   {    LED1=!LED1;    LED0=!LED0;  

stm32通用定時用做外部脈衝計數器的例程

最近幾天要用到stm32對外部輸入脈衝進行計數,很自然想到定時器,可是手上資料沒有講解stm32定時器如何用作外部計數器的,在網上找例程,也沒找到幾個正確的,自己硬著頭皮仔細研究參考手冊,終於知道如何配置了,並寫了一個例程,希望將來對一些網友有用。 其實stm32通用定時

STM32學習筆記(5)——通用定時PWM輸出

part 大小 模式 lan 晶振 kcon 筆記 利用 .cn 1、TIMER輸出PWM基本概念 脈沖寬度調制(PWM),是英文“Pulse Width Modulation”的縮寫,簡稱脈寬調制,是利用微處理器的數字輸出來對模擬

STM32學習筆記(7)——通用定時PWM輸出

nbsp 錯誤 buffer put inter def internal reset 有效 1、TIMER輸出PWM基本概念 脈沖寬度調制(PWM),是英文“Pulse Width Modulation”的縮寫,簡稱脈寬調制,是利

微控制器入門學習十三 STM32微控制器學習通用定時

本篇重點記錄的是STM32F1的通用定時器。 STM32F103ZE有8個定時器,其中2個高階定時器(TIM1、TIM8),4個通用定時器(TIM2、TIM3、TIM4、TIM5),2個基本定時器(TIM6、TIM7)。下表是對這8個定時器的詳細描述。

STM32學習筆記(5):通用定時PWM輸出

PWM的輸出管腳是確定好的,具體的引腳功能可以檢視《STM32參考手冊》的“8.3.7 定時器複用功能重對映”一節。在此需要強調的是,不同的TIMx有分配不同的引腳,但是考慮到管腳複用功能,STM32提出了一個重映像的概念,就是說通過設定某一些相關的暫存器,來使得在其他非原始指定的管腳上也能輸出PWM。但是這

STM32學習筆記通用定時基本設定

STM32 包含11個定時器,其中TIM2~TIM5為通用定時器。 通用定時器掛載在低速外設匯流排APB1上,其時鐘來源於輸入為APB1的一個倍頻器,只要APB1的時鐘分頻數不為1,TIMx的時鐘頻率就會為APB1時鐘頻率的2倍,即72MHz 。 配置通用定時器需要4步(

通用定時——輸入捕獲實驗

輸入捕獲模式可以用來測量脈衝寬度或者測量頻率。STM32 的定時器,除了 TIM6 和 TIM7,其他定時器都有輸入捕獲功能。 STM32 的輸入捕獲,簡單的說就是通過檢測 TIMx_CHx 上的邊沿訊號,在邊沿訊號發生跳變(比如上升沿/下降沿)的時候,將當前定

TIM通用定時(三):PWM輸入捕獲模式

一、概念理解 PWM輸入捕獲模式是輸入捕獲模式的特例,自己理解如下 1. 每個定時器有四個輸入捕獲通道IC1、IC2、IC3、IC4。且IC1 IC2一組,IC3 IC4一組。並且可是設定管腳和暫存器的對應關係。 2. 同一個TIx輸入映射了兩個ICx訊號。 3. 這兩個IC

STM32定時有兩種捕獲模式——PWM輸入模式和普通輸入模式

一個定時器最多能同時捕獲幾路PWM波? 我只需要得到PWM的高電平寬度,PWM的頻率是50HZ STM32的定時器有兩種捕獲模式 PWM輸入模式和普通輸入模式 在PWM輸入模式下,一個定時器只能同時捕獲一路PWM波 在普通輸入模式下,理論上是可以同時捕獲4路PWM波 即,在定時器中斷中改變觸發模式(上升沿、下

小熊STM32學習總結:STM32定時--輸入捕捉模式

除錯STM32的定時器好幾天了,也算是對STM32的定時器有了點清楚的認識了。我需要測量4路訊號的頻率然後通過DMA將訊號的頻率傳輸到儲存器區域,手冊說的很明白每個定時器有4個獨立通道。然後我就想能不能將這4路訊號都連線到一個定時器的4個通道上去。理論上應該是行的通的。剛開始俺使用的是TIM2的1 2 3