天天看點

stm32 PWM input捕獲輸入模式【原創】調試stm32的TIM輸入捕獲模式

stm32 定時器pwm輸入捕獲

輸入捕捉的功能是記錄下要捕捉的邊沿出現的時刻,如果你僅僅捕捉下降沿,那麼兩次捕捉的差表示輸入信号的周期,即兩次下降沿之間的時間。

如果要測量低電平的寬度,你應該在捕捉到下降沿的中斷進行中把捕捉邊沿改變為上升沿,然後把兩次捕捉的數值相減就得到了需要測量的低電平寬度。

如果要的測量低電平太窄,中斷中來不及改變捕捉方向時,或不想在中斷中改變捕捉方向,則需要使用PWM輸入模式,或使用兩個TIMx通道,一個通道捕捉下降沿,另一個通道捕捉上升沿,然後對兩次捕捉的數值相減。PWM輸入模式也是需要用到兩個通道。使用兩個通道時,最好使用通道1和通道2,或通道3和通道4,這樣上述功能隻需要使用一個I/O管腳,詳細請看STM32技術參考手冊中的TIMx框圖。

、、//0-----------------------

一、概念了解

PWM輸入捕獲模式是輸入捕獲模式的特例,自己了解如下

1. 每個定時器有四個輸入捕獲通道IC1、IC2、IC3、IC4。且IC1IC2一組,IC3 IC4一組。并且可是設定管腳和寄存器的對應關系。

2. 同一個TIx輸入映射了兩個ICx信号。

3. 這兩個ICx信号分别在相反的極性邊沿有效。

4. 兩個邊沿信号中的一個被選為觸發信号,并且從模式控制器被設定成複位模式。

5. 當觸發信号來臨時,被設定成觸發輸入信号的捕獲寄存器,捕獲“一個PWM周期(即連續的兩個上升沿或下降沿)”,它等于包含TIM時鐘周期的個數(即捕獲寄存器中捕獲的為TIM的計數個數n)。

6. 同樣另一個捕獲通道捕獲觸發信号和下一個相反極性的邊沿信号的計數個數m,即(即高電平的周期或低電平的周期)

7. 由此可以計算出PWM的時鐘周期和占空比了

    frequency=f(TIM時鐘頻率)/n。

    duty cycle=(高電平計數個數/n),

    若m為高電平計數個數,則duty cycle=m/n

    若m為低電平計數個數,則duty cycle=(n-m)/n

注:因為計數器為16位,是以一個周期最多計數65535個,是以測得的最小頻率=TIM時鐘頻率/65535。

二、程式設計與分析

1. 程式概述:選擇TIM3作為PWM輸入捕獲。IC2設定為上升沿,并設定為有效的觸發輸入信号。是以IC2的捕獲寄存器捕獲PWM周期,

                   IC1的捕獲寄存器捕獲PWM的高電平周期。

2.程式代碼如下:

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);      //時鐘配置

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

  GPIO_InitStructure.GPIO_Pin= GPIO_Pin_7;                               //GPIO配置

  PIO_InitStructure.GPIO_Mode= GPIO_Mode_IN_FLOATING;

  GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;

  GPIO_Init(GPIOA,&GPIO_InitStructure);

  NVIC_InitStructure.NVIC_IRQChannel= TIM3_IRQn;                     //NVIC配置 

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 0;

  NVIC_InitStructure.NVIC_IRQChannelSubPriority= 1;

  NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;

  NVIC_Init(&NVIC_InitStructure);

  TIM_ICInitStructure.TIM_Channel =TIM_Channel_2;                   //通道選擇

  TIM_ICInitStructure.TIM_ICPolarity= TIM_ICPolarity_Rising;       //上升沿觸發

  TIM_ICInitStructure.TIM_ICSelection= TIM_ICSelection_DirectTI;    //管腳與寄存器對應關系

  TIM_ICInitStructure.TIM_ICPrescaler= TIM_ICPSC_DIV1;           //輸入預分頻。意思是控制在多少個輸入周期做一次捕獲,如果

//輸入的信号頻率沒有變,測得的周期也不會變。比如選擇4分頻,則每四個輸入周期才做一次捕獲,這樣在輸入信号變化不頻繁的情況下,

//可以減少軟體被不斷中斷的次數。

  TIM_ICInitStructure.TIM_ICFilter= 0x0;                            //濾波設定,經曆幾個周期跳變認定波形穩定0x0~0xF

  TIM_PWMIConfig(TIM3,&TIM_ICInitStructure);                 //根據參數配置TIM外設資訊

  TIM_SelectInputTrigger(TIM3,TIM_TS_TI2FP2);                //選擇IC2為始終觸發源

  TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);//TIM從模式:觸發信号的上升沿重新初始化計數器和觸發寄存器的更新事件

  TIM_SelectMasterSlaveMode(TIM3,TIM_MasterSlaveMode_Enable); //啟動定時器的被動觸發

  TIM_Cmd(TIM3,ENABLE);                                 //啟動TIM2

  TIM_ITConfig(TIM3,TIM_IT_CC2, ENABLE);     //打開中斷 

中斷處理函數

voidTIM3_IRQHandler(void)

{

  TIM_ClearITPendingBit(TIM3,TIM_IT_CC2);                //清楚TIM的中斷待處理位

  IC2Value =TIM_GetCapture2(TIM3);                         //讀取IC2捕獲寄存器的值,即為PWM周期的計數值

  if (IC2Value != 0)

  {

    DutyCycle= (TIM_GetCapture1(TIM3) * 100) / IC2Value;         //讀取IC1捕獲寄存器的值,并計算占空比

    Frequency= 72000000 / IC2Value;                                          //計算PWM頻率。

  }

  else

  {

    DutyCycle= 0;

    Frequency= 0;

  }

}

注(一):若想改變測量的PWM頻率範圍,可将TIM時鐘頻率做分頻處理

 TIM_TimeBaseStructure.TIM_Period= 0xFFFF;     //周期0~FFFF

  TIM_TimeBaseStructure.TIM_Prescaler = 5;       //時鐘分頻,分頻數為5+1即6分頻

  TIM_TimeBaseStructure.TIM_ClockDivision = 0;   //時鐘分割

  TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up;//模式

  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);//基本初始化

注注(二):定時器TIM的倍頻器X1或X2。在APB分頻為1時,倍頻值為1,否則為2

、、---------------------------------------------------------------------------------------=============================================

再來看看捕獲/比較模式寄存器 1:TIMx_CCMR1,這個寄存器在輸入捕獲的時候,非常有

用,有必要重新介紹,該寄存器的各位描述如圖 15.1.1 所示:

圖 15.1.1 TIMx_CCMR1 寄存器各位描述

當在輸入捕獲模式下使用的時候,對應圖 15.1.1 的第二行描述,從圖中可以看出,

TIMx_CCMR1 明顯是針對 2 個通道的配置,低八位[7:0]用于捕獲/比較通道 1 的控制,而高八

位[15:8]則用于捕獲/比較通道 2 的控制,因為 TIMx 還有 CCMR2 這個寄存器,是以可以知道

CCMR2 是用來控制通道 3 和通道 4(詳見《STM32 參考手冊》290 頁,14.4.8 節) 。

//==============================================================================================================

其中 CC1S[1:0],這兩個位用于 CCR1 的通道配置,這裡我們設定 IC1S[1:0]=01,也就是配

置 IC1 映射在 TI1 上(關于 IC1,TI1 不明白的,可以看《STM32 參考手冊》14.2 節的圖 98-

通用定時器框圖) ,即 CC1 對應 TIMx_CH1。

//=========================================================================================================================

輸入捕獲 1 預分頻器 IC1PSC[1:0],這個比較好了解。我們是 1 次邊沿就觸發 1 次捕獲,所

以選擇 00 就是了。

輸入捕獲1濾波器IC1F[3:0], 這個用來設定輸入采樣頻率和數字濾波器長度。 其中,

是定時器的輸入頻率(TIMxCLK) ,一般為 72Mhz,而 則是根據 TIMx_CR1 的 CKD[1:0]

的設定來确定的,如果 CKD[1:0]設定為 00,那麼 = 。N 值就是濾波長度,舉個簡

單的例子:假設 IC1F[3:0]=0011,并設定 IC1 映射到通道 1 上,且為上升沿觸發,那麼在捕獲

到上升沿的時候,再以 的頻率,連續采樣到 8 次通道 1 的電平,如果都是高電平,則說

明卻是一個有效的觸發,就會觸發輸入捕獲中斷(如果開啟了的話) 。這樣可以濾除那些高電平

脈寬低于 8 個采樣周期的脈沖信号,進而達到濾波的效果。這裡,我們不做濾波處理,是以設

置 IC1F[3:0]=0000,隻要采集到上升沿,就觸發捕獲。

TIMx的CHx 在輸入捕獲模式下就變味TIx了...

剛剛看了一下手冊,好像有點了解,不知道對不對。 

CCx是指4各通道當中的一個通道,而ICx對應的這個輸入通道,TI1、TI2、TI3、TI4,是指定時器的4個通道的引腳(比如:TIM4_REMAP=0,沒有重映像(TIM4_CH1/PB6,TIM4_CH2/PB7,TIM4_CH3/PB8,TIM4_CH4/PB9))。

//=========================================================================

定時器從0開始計數,計數到TIM_Period後,重新歸零再計數。

捕獲隻是把發生捕獲時刻的計數器目前值拷貝下來,你的IC2Value就是這個數值。

如果配置了 發生捕獲時複位計數器,則計數器沒有計數到TIM_Period時也被歸零并重新計數。

如果你配置比較小的TIM_Period數值,則可能在還沒有發生捕獲時,計數器就被歸零,是以你要在軟體中記錄下計數器被歸零的次數。

當計數器的時鐘頻率為F時,計數器每計數一次表示1/F的時間,是以從捕獲寄存器中讀出的數值表示了一個時間。如果配置了發生捕獲時複位計數器,則這個時間恰好就是要捕獲信号的周期。

從上面原理可以看出,TIM_Period的數值與捕獲的精度沒有關系。

發生捕獲時複位計數器》》》》這個如何實作?通過TI1-->TI1F_ED

//=======================================================================================================

TIM通用定時器(二):輸出比較——翻轉模式

一、基本概念了解

1. 輸出比較:打開一個TIMx計數器,再打開TIMx的一路或幾路輸出比較器(共4路),都配置好以後,計數器開始計數,當計數器裡的值和

                   比較寄存器裡的值相等時,産生輸出比較中斷,在中斷中将計數器中的值讀出,與翻轉周期相加再寫道比較寄存器中,使得和

                   下一個事件有相同的翻轉周期。

2. 舉例說明:例如TIM時鐘頻率設定為12MHZ,輸出比較寄存器中的自裝載值為600(高電平或低電平計數值),則輸出的PWM頻率為

                   frequency = 12MHZ/(600*2)=10KHZ。

二、程式設計與分析

1.  TIM計數器和輸出比較器的配置

uint16_t capture = 0;

extern __IO uint16_t CCR1_Val;

extern __IO uint16_t CCR2_Val;

extern __IO uint16_t CCR3_Val;

extern __IO uint16_t CCR4_Val;

void TIM_Configuration(void)

{

  TIM_TimeBaseStructure.TIM_Period = 65535;         //這裡必須是65535

  TIM_TimeBaseStructure.TIM_Prescaler = 2;            //3分頻

  TIM_TimeBaseStructure.TIM_ClockDivision = 0;      //

  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上計數模式

  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);          //初始化TIM3

  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;    //輸出比較翻轉模式

  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   //使能通道1

  TIM_OCInitStructure.TIM_Pulse = CCR1_Val;                       //待裝入輸出比較寄存器中的脈沖值       

  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;         //輸出為正邏輯 

  TIM_OC1Init(TIM3, &TIM_OCInitStructure);        //寫入配置

  TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Disable);          //使能或者失能TIMx在CCR1上的預裝載寄存器

  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

  TIM_OCInitStructure.TIM_Pulse = CCR2_Val;

  TIM_OC2Init(TIM3, &TIM_OCInitStructure);

  TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Disable);

  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

  TIM_OCInitStructure.TIM_Pulse = CCR3_Val;

  TIM_OC3Init(TIM3, &TIM_OCInitStructure);

  TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Disable);

  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

  TIM_OCInitStructure.TIM_Pulse = CCR4_Val;

  TIM_OC4Init(TIM3, &TIM_OCInitStructure);

  TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Disable);

  TIM_Cmd(TIM3, ENABLE);      //開啟計數器

                 //TIM1中斷源設定,開啟相應通道的捕捉比較中斷

  TIM_ITConfig(TIM3, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE);

}

2.  時鐘配置

3.  GPIO配置

4.  中斷服務程式

void TIM3_IRQHandler(void)

{

  if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)               //檢查指定的TIM中斷發生與否

  {

    TIM_ClearITPendingBit(TIM3, TIM_IT_CC1 );               //清除TIMx的中斷待處理位

    capture = TIM_GetCapture1(TIM3);                            //獲得輸入捕獲值,即計數器中的計數值

    TIM_SetCompare1(TIM3, capture + CCR1_Val );        //将計數值加上翻轉的脈沖值寫入輸出比較寄存器中,以保證下一個TIM事

                                                                                       //件也是相同的脈沖數

  }

  if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET)

  {

    TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);

    capture = TIM_GetCapture2(TIM3);

    TIM_SetCompare2(TIM3, capture + CCR2_Val);

  }

  if (TIM_GetITStatus(TIM3, TIM_IT_CC3) != RESET)

  {

    TIM_ClearITPendingBit(TIM3, TIM_IT_CC3);

    capture = TIM_GetCapture3(TIM3);

    TIM_SetCompare3(TIM3, capture + CCR3_Val);

  }

  if (TIM_GetITStatus(TIM3, TIM_IT_CC4) != RESET)

  {

    TIM_ClearITPendingBit(TIM3, TIM_IT_CC4);

    capture = TIM_GetCapture4(TIM3);

    TIM_SetCompare4(TIM3, capture + CCR4_Val);

  }

}

//=================================================================================================================

TIM_OCMode_Timing是在比較成功後不在對應輸出管腳上産生輸出。

TIM_OCMode_Toggle是在比較成功後翻轉對應輸出管腳上的電平。

TIM_OCMode_Timing是在比較成功後不在對應輸出管腳上産生輸出,但是産生中斷啊,

//=================================================================================

試STM32的定時器好幾天了,也算是對STM32的定時器有了點清楚的認識了。我需要測量4路信号的頻率然後通過DMA将信号的頻率傳輸到存儲器區域,手冊說的很明白每個定時器有4個獨立通道。然後我就想能不能将這4路信号都連接配接到一個定時器的4個通道上去。理論上應該是行的通的。剛開始俺使用的是TIM2的1 2 3通道,TIM4的2通道來進行頻率的測量。由于沒有頻率發生器,是以我用tim3作為信号源,用TIM2,TIM4來進行測量就ok了。

  請看一開始的程式,以TIM2的1,3通道為例子:

  TIM_ICInitStructure.TIM_ICMode = TIM_ICMode_ICAP;                 //配置為輸入捕獲模式         

  TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;                     //選擇通道1

  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;       //輸入上升沿捕獲 

  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;   // 通道方向選擇  

  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;               //每次檢測到捕獲輸入就觸發一次捕獲

  TIM_ICInitStructure.TIM_ICFilter = 0x0;                            //

  TIM_ICInit(TIM2, &TIM_ICInitStructure);

  TIM_ICInitStructure.TIM_ICMode = TIM_ICMode_ICAP;                 //配置為輸入捕獲模式         

  TIM_ICInitStructure.TIM_Channel = TIM_Channel_3;                  //選擇通道3

  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;       //輸入上升沿捕獲 

  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;   //   

  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;               //每次檢測到捕獲輸入就觸發一次捕獲

  TIM_ICInitStructure.TIM_ICFilter = 0x0;                            //

  TIM_ICInit(TIM2, &TIM_ICInitStructure);

  這個是輸入捕獲配置

  還需要做的工作就是(參考stm32參考手冊的TIM的結構框圖):

   

    TIM_SelectInputTrigger(TIM2, TIM_TS_TI1FP1);                      //參考TIM結構圖選擇濾波後的TI1輸入作為觸發源,觸發下面程式的複位

   

    TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);          //複位模式-選中的觸發輸入(TRGI)的上升沿初始化計數器,并且産生一個更新線号

   

    TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable);       

  //主從模式選擇

  這樣我們就可以很輕松的就得到了 連接配接在TIM2的通道1上的信号的頻率,但是3通道的頻率的值永遠都是跳動的不準,測試了半天也沒有找到根本原因,請看TIM的結構框圖的一部分

stm32 PWM input捕獲輸入模式【原創】調試stm32的TIM輸入捕獲模式

  紅色箭頭所指,這才找到原因,觸發的信号源隻有這四種,而通道3上的計數器的值不可能在接受到信号的上升沿時候,有複位這個動作,找到原因了。這就是3通道上的資料不停跳動的原因,要想的到信号的頻率也是有辦法的,可以取連續兩次捕捉的值之差,這個值就是信号的周期,自己根據實際情況去算頻率吧。

  有以上可以得到:

  stm32的TIM的四個通道可以同時配置成輸入捕捉模式,但是計算CH3,CH4信号的頻率步驟有點繁瑣(取前後捕捉的內插補點),但是他的CH1,和CH2可以輕松得到:

  通道1

   

    TIM_SelectInputTrigger(TIM2, TIM_TS_TI1FP1);                      //參考TIM結構圖選擇濾波後的TI1輸入作為觸發源,觸發下面程式的複位

   

    TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);          //複位模式-選中的觸發輸入(TRGI)的上升沿初始化計數器,并且産生一個更新線号

  TIMx->CRR1的值即為信号的周期

  通道2:

    TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2);                      //參考TIM結構圖選擇濾波後的TI1輸入作為觸發源,觸發下面程式的複位

   

    TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);          //複位模式-選中的觸發輸入(TRGI)的上升沿初始化計數器,并且産生一個更新線号

  TIMx->CRR2的值即為信号的周期

//======================================================

TIM設定為輸入捕獲模式的出現的問題 釋出時間:2008-10-14 19:14:10
技術類别:ARM

   在應用的時候将将TIM2的CH1,Ch2兩個通道設定為輸入捕獲模式,為了測量路信号的頻率

   關于TIM2的配置如下

  TIM_ICInitStructure.TIM_ICMode = TIM_ICMode_ICAP;                 //配置為輸入捕獲模式          

  TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;                                 //選擇通道1

  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;       //輸入上升沿捕獲  

  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;   // 通道方向選擇   

  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;                       //每次檢測到捕獲輸入就觸發一次捕獲

  TIM_ICInitStructure.TIM_ICFilter = 0x0;                                                        //

  TIM_ICInit(TIM2, &TIM_ICInitStructure);

  TIM_ICInitStructure.TIM_ICMode = TIM_ICMode_ICAP;                 //配置為輸入捕獲模式          

  TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;                                 //選擇通道2

  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;       //輸入上升沿捕獲  

  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;   // 通道方向選擇   

  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;                       //每次檢測到捕獲輸入就觸發一次捕獲

  TIM_ICInitStructure.TIM_ICFilter = 0x0;                                                        //

  TIM_ICInit(TIM2, &TIM_ICInitStructure);

  TIM_SelectInputTrigger(TIM2,TIM_TS_TI1FP1);                      //參考TIM結構圖選擇濾波後的TI2輸入        寄存器SMCR

  TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_Reset);                  //複位模式-選中的觸發輸入(TRGI)的上升沿初始化計數器,并且産生一個更新線号

  TIM_SelectMasterSlaveMode(TIM2,TIM_MasterSlaveMode_Enable);            //主從模式選擇

這裡注意了 TIM_SelectInputTrigger(TIM2,TIM_TS_TI1FP1);                      //參考TIM結構圖選擇濾波後的TI2輸入        寄存器SMCR

如果這麼設定的輸入觸發源為TI1FP1  我隻是要捕捉CH1的信号頻率 ,但是CH2不接信号讀出來的資料跟CH1一模一樣,如果設定為

TIM_SelectInputTrigger(TIM2,TIM_TS_TI2FP2); 設定的輸入觸發源為TI2FP2,那麼就能準确的讀回來

CH2上的信号頻率,此時CH1沒有接信号度回來全部是0

為什麼設定了前者TIM_SelectInputTrigger(TIM2,TIM_TS_TI1FP1);  兩個通道CH1,CH2都有資料呢   納悶中

希望這個不會是STM32的bug,正在尋找解決的辦法。。。。 答案:你應該選擇pwmi模式才能兩個聯起來,一個測頻率,一個測占空比  正解 、、===================================================================================================== 調試的過程中,總能遇到一些問題,很慶幸能遇到那麼多的問題,也許這就是最好的學習過程:

繼續我的筆記:

    在main函數中,檔案名:main.c

    對TIM2的CH1,CH2配置如下:

      TIM_ICInitStructure.TIM_ICMode = TIM_ICMode_ICAP;                 //配置為輸入捕獲模式          

  TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;                     //選擇通道1

  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;       //輸入上升沿捕獲  

  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;   // 通道方向選擇   

  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;               //每次檢測到捕獲輸入就觸發一次捕獲

  TIM_ICInitStructure.TIM_ICFilter = 0x0;                            //

  TIM_ICInit(TIM2, &TIM_ICInitStructure);

  TIM_ICInitStructure.TIM_ICMode = TIM_ICMode_ICAP;                 //配置為輸入捕獲模式          

  TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;                     //選擇通道2

  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;       //輸入上升沿捕獲  

  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;   // 通道方向選擇   

  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;               //每次檢測到捕獲輸入就觸發一次捕獲

  TIM_ICInitStructure.TIM_ICFilter = 0x0;                            //

  TIM_ICInit(TIM2, &TIM_ICInitStructure);

  TIM1->PSC = 10;  //由于要測量的信号頻率為200-1000HZ 采取10倍的預分頻

  TIM2->PSC = 10;  //如果不分頻最小的頻率為1100hz,分頻後可以測量的頻率為110HZ,為了達到最佳捕捉效果,且滿足要求建議分頻系數設為6;

  TIM_SelectInputTrigger(TIM2,TIM_TS_TI1FP1);                      //參考TIM結構圖選擇濾波後的TI2輸入    寄存器SMCR

  TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_Reset);          //複位模式-選中的觸發輸入(TRGI)的上升沿初始化計數器,并且産生一個更新線号

  TIM_SelectMasterSlaveMode(TIM2,TIM_MasterSlaveMode_Enable);        //主從模式選擇

說說我要測量兩路信号頻率的思路吧:

我想把兩路信号跟别加到TIM2的CH1跟CH2上面去,然後通過TI1FP1跟TI2FP2輪流觸發 ,TIM2->CCR1與TIM2->CCR2記錄下來的資料就是信号的周期,接着根據具體的情況計算出信号的頻率。那麼,究竟是怎麼實作TI1FP1跟TI2FP2輪流觸發呢?這就是DMA的問題了,當信号的周期被TIM2->CRRx收到,DMA就會将這個資料送到一個存儲器區。DMA傳輸完資料後就會發生中斷,我在DMA傳輸中斷函數中修改觸發信号源。

比如說DMA-CH5傳輸到是TIM2->CRR1

他的中斷函數如下:

void DMAChannel5_IRQHandler(void)

{

    if (DMA_GetITStatus(DMA_IT_TC5) != RESET)

    {

        DMA_ClearITPendingBit(DMA_IT_TC5);

        TIM_SelectInputTrigger(TIM2,TIM_TS_TI2FP2);  

        上句就是修改觸發源輪流觸發

    }

}

但是實驗的過程中發現 兩個通道所測量得到信号的周期  怎麼着都隻有一組是正确

例如:

stm32 PWM input捕獲輸入模式【原創】調試stm32的TIM輸入捕獲模式

最後通過高人的指點才發現:

原來這個定時器隻有一個COUNT(計數器)

當我選擇執行 TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_Reset);這個函數,問題就來了,當一路有信号觸發,count複位,那麼另一路永遠也得不到正确的值。。是以測量信号頻率還有待改良。。。。

2008年10.14 晚九點

實驗室看門的又來催了 ,記錄到此  

、、=============================================================================

調試TIM輸入比較模式筆記 釋出時間:2008-10-13 19:12:51
技術類别:ARM

【原創】調試stm32的TIM輸入捕獲模式

應用平台為英貝特EMSTM32V1開發闆

下載下傳例程:http://space.ednchina.com/Upload/2008/10/13/7a65b455-187b-4847-87a7-767f4a60a546.rar

這個程式的要完成的任務是:通過定時器的輸入捕獲模式,測量4路信号的頻率(頻率的範圍200—1000HZ),并且通過相應的DMA通道将測量的值傳送到存儲器部分一個資料緩沖區。

由于STM32的定時器一般都有4個獨立的通道,可以考慮就用一個定時器的4個通道測量信号的頻率,參見下圖

stm32 PWM input捕獲輸入模式【原創】調試stm32的TIM輸入捕獲模式

我們不難發現隻有TIM1,TIM2為其4個通道配備了DMA通道,是以隻能選擇TIM1,TIM2來應用。這裡我實驗選擇了TIM2,但是ch2與ch4共用了一個DMA通道,是以我又開啟了TIM4,利用了TIM4_CH2.

測量信号的4個TIM通道為:

TIM2_CH1  

(PA0)    DMA_CH5

TIM2_CH2  

(PA1)    DMA_CH7

TIM2_CH3  

(PA2)    DMA_CH1

TIM4_CH2  

(PB7)    DMA_CH4

以下為各個部分的配置步驟,全部以TIM2_CH1的配置作示例:

1:Stm32的TIM的輸入模式的配置:

TIM_ICInitStructure.TIM_ICMode =

TIM_ICMode_ICAP;                 //配置為輸入捕獲模式         

TIM_ICInitStructure.TIM_Channel =

TIM_Channel_1;                              //選擇通道2

TIM_ICInitStructure.TIM_ICPolarity =

TIM_ICPolarity_Rising;       //輸入上升沿捕獲 

TIM_ICInitStructure.TIM_ICSelection =

TIM_ICSelection_DirectTI;   //   

TIM_ICInitStructure.TIM_ICPrescaler =

TIM_ICPSC_DIV1;                      //每次檢測到捕獲輸入就觸發一次捕獲

TIM_ICInitStructure.TIM_ICFilter = 0x0;                                                                 //

TIM_ICInit(TIM2, &TIM_ICInitStructure);

注意點:《一》:TIM_ICMode隻有兩種模式供選擇1. TIM_ICMode_ICAP 輸入捕獲模式

2. TIM_ICMode_PWMI   PWM輸入模式。此模式是輸入捕獲模式的一種特殊應用,可以友善的計算出占空比,筆者隻在IC1,IC2上試驗成功,在IC3,IC4上沒有測試

《二》:TIM_ICSelection  是為設定通道的方向以及ICx的映射,可以參考CCMRx這個寄存器的低兩位以及8.9兩位

2:

TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2);                      //參考TIM結構圖選擇濾波後的TI2輸入     寄存器SMCR

TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);              //複位模式-選中的觸發輸入(TRGI)的上升沿初始化計數器,并且産生一個更新線号

TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable);       //主從模式選擇

拿TIM2作為例子,要想把TIM2的一個channel配置為輸入模式這三個函數是必要的

3:預分頻的設定

由于stm32的輸入捕獲模式下,在沒有分頻的情況下可以捕獲的信号的頻率最小為72MHZ/65536約為1100HZ;是以為了滿足測量200-1000HZ的要求,需要配置預分頻系數:

TIM2->PSC

= 10; 在實際應用中為了滿足要求,并且提高精度可以選取6分頻。

4:DMA通道的初始化設定

這裡隻拿channel5作為示例

  DMA_DeInit(DMA_Channel5);

  DMA_InitStructure.DMA_PeripheralBaseAddr =

TIM2_CRR1_Address ;

  DMA_InitStructure.DMA_MemoryBaseAddr =

(u32)&TIM2_Capture_value;

  DMA_InitStructure.DMA_DIR =

DMA_DIR_PeripheralSRC;                          

//設定外設為源位址

  DMA_InitStructure.DMA_BufferSize = 16;

  DMA_InitStructure.DMA_PeripheralInc =

DMA_PeripheralInc_Disable;             //外設位址不要遞增

  DMA_InitStructure.DMA_MemoryInc =

DMA_MemoryInc_Enable;

  DMA_InitStructure.DMA_PeripheralDataSize =

DMA_PeripheralDataSize_HalfWord;

  DMA_InitStructure.DMA_MemoryDataSize =

DMA_MemoryDataSize_HalfWord;

  DMA_InitStructure.DMA_Mode =

DMA_Mode_Circular;

  DMA_InitStructure.DMA_Priority =

DMA_Priority_High;

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                                                        //不是存儲器到存儲器

  DMA_Init(DMA_Channel5,

&DMA_InitStructure);

這裡要注意的是:

1.DMA_InitStructure.DMA_PeripheralBaseAddr

= TIM2_CRR1_Address ;

前面有定義 #define TIM2_CRR1_Address ((u32)0x40000034)

在調試的時候,TIM2的三個通道全部調試通過,但是隻有TIM_CH2收不到信号,這裡就是位址沒有搞對,因為TIM4的位址要在TIM2的基址上加0x0800;是以折騰了大半天也沒有收到信号,這裡要注意一下

2.DMA_InitStructure.DMA_Mode

= DMA_Mode_Circular;

這裡我們的資料是連續不斷的采集的是以需要一個循環緩沖區,隻好設定為DMA_Mode_Circular;

5:關于中斷與DMA

在調試程式的過程中,我遇到這樣的情況:

設定了TIM2的中斷使能信号

  TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);

  TIM_ITConfig(TIM2, TIM_IT_CC2, ENABLE);

同時我需要通過DMA_Channel_7講采集信号的頻率發送到存儲器區域,于是有以下設定:

TIM_DMAConfig(TIM2,TIM_DMABase_CCR1,TIM1_DMABurstLength_2Bytes);

  TIM_DMACmd(TIM2, TIM_DMA_CC1, ENABLE);

這樣中斷與DMA通道的設定就同時被初始化,結果程式運作的時候,當發生TIM_IT_CC2中斷請求的時候,程式并不能進入中斷服務程式,隻響應了相應的DMA請求,當我去掉以上DMA的設定程式的時候,程式很順利就響應了中斷請求進入了中斷服務程式。

是以得到了以下結論:

中斷與DMA的使能不必同時開啟,及時都開啟了,程式在接收到相應的請求信号時候,隻會去響應dma請求。

6:GPIO的配置

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;          

//浮點輸入

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

7:注意打開相應外設的時鐘

RCC_APB1PeriphClock: TIM2,TIM4

RCC_APB2PeriphClock: GPIOx

RCC_AHBPeriphClock: 

DMA

8:關于調試過程中的MDK的使用

A:打開箭頭指向的兩項

stm32 PWM input捕獲輸入模式【原創】調試stm32的TIM輸入捕獲模式

B:在Address裡面分别輸入

0x40000038,0x4000003c,0x40000040以及0x40000838

就可以看到TIM2_CRR1,TIM2_CRR2,TIM2_CRR3以及TIM4_CRR2中的值也就是各個通道捕捉的值value

因為捕獲的數十經過PSC10分頻的是以用72MHZ/10*value就可以得到測量信号的頻率

stm32 PWM input捕獲輸入模式【原創】調試stm32的TIM輸入捕獲模式

C:我們可以在這個框裡點F2輸入我們定義的緩沖區的名字

TIM2_Capture_value

TIM2_Capture_value1

TIM2_Capture_value2

TIM4_Capture_value

就可以看到DMA的各個通道傳輸到存儲器區的資料,這個資料是跟步驟B裡面的資料是一緻的。緩沖區的大小為16,信号的頻率在一段時間内是不變的那麼這16個數就是一樣的

同樣用72MHZ/10*value就可以得到測量信号的頻率

stm32 PWM input捕獲輸入模式【原創】調試stm32的TIM輸入捕獲模式

你幾個問題點沒有把握好,

一個是映射,

一個是主輸入,

一個是從輸入,

隻有從輸入才有第一個跳變複位,第二個跳變存在CCR2或者CCR1中,

主輸入可以先CCR1,也可能選擇CCR2,這裡要從輸入配合,他們不能同用一個CCR.

這幾個問題你能搞清楚了,就很清楚了。

2008.10.13  15:05

剛剛開始做定時器輸入捕獲的時候在這個論壇上找了好久,都沒有人分享,也有很多人問,無奈自己動手寫了。花了一天的時間,這個東西真的不好寫了,對比了庫的例子,仿真,等。可以說付出了很多。現在完成了和大家分享。希望大家多多支援。這個程式是在定時器輸入捕獲的基礎上看手冊完成的,

程式說明:1、程式中定時器4的PB6用于輸出頻率為1K,占空比為50%的PWM信号。

               2、定時器2的PA0用于輸入捕獲,當程式下到闆子上,隻有兩個腳連在一起才會發生捕獲。

               3、序列槽用于發送捕獲的值到PC機上。

               4、定時器2的CCR1存PWM信号的頻率,CCR2存高電平時間。

這裡聲明一下,如果你要捕獲的PWM信号不在ARR,PSC計算的範圍内,請自己先計算再使用本程式。

#include "stm32f10x_lib.h"

#include "sys.h"

#include "delay.h" //延時子函數

#include "usart.h"

u16   IC1Value;

u16   IC2Value;

u16   DutyCycle;

u16   Frequency;

void PWM_Init(u16 arr,u16 psc);

void Capture_Init(u16 arr,u16 psc);

int  main(void)

{

Stm32_Clock_Init(9); //系統時鐘設定

delay_init(72);//延時函數初始化

uart_init(72,9600);

PWM_Init(1000,72-1); //不分頻。PWM頻率=72000/1440=5Khz 

Capture_Init(2000,72-1);

while(1)

{

Frequency = 1000000/IC1Value;

DutyCycle = (IC2Value*100)/IC1Value;//占空比=(IC2Value/IC1Value)*100;

printf("Frequency = %d\r\n",Frequency);

printf("DutyCycle = %d\r\n",DutyCycle);

printf("suqingxiao\r\n");

}

}

//PWM輸出初始化

//arr:自動重裝值

//psc:時鐘預分頻數

void PWM_Init(u16 arr,u16 psc)

{  

//此部分需手動修改 IO口設定  

RCC->APB2ENR|=1<<0;    //  

RCC->APB1ENR|=1<<2;       //TIM4 時鐘使能 

RCC->APB2ENR|=1<<3;    //使能PORTB時鐘 

GPIOB->CRL&=0XF0FFFFFF;//PB6 輸出  

GPIOB->CRL|=0X0B000000;//複用功能輸出       

GPIOB->ODR|=1<<6;//PB6 上拉   

TIM4->ARR=arr;//設定計數器自動重裝值   

TIM4->PSC=psc;//預分頻器不分頻  

TIM4->CCMR1|=7<<4;  //CH1 PWM2模式      

TIM4->CCMR1|=1<<3; //CH1 預裝載使能       

TIM4->CCER|=1<<0;  //OC1  輸出使能      

TIM4->CR1=0x0080;  //ARPE使能   

TIM4->CR1|=0x01;    //使能定時器 3  

TIM4->CCR1   = 500; //占空比初值 =  1440*50% = 720                  

void Capture_Init(u16 arr,u16 psc)

{

//此部分需手動修改 IO口設定  

RCC->APB2ENR|=1<<0;    //  

RCC->APB1ENR|=1<<0;       //TIM2 時鐘使能 

RCC->APB2ENR|=1<<2;    //使能PORTA時鐘 

  TIM2->ARR=arr;  //設定計數器自動重裝值//剛好1ms    

TIM2->PSC=psc;  //預分頻器,

GPIOA->CRL&=0XFFFFFFF0;//PA0 輸出  

GPIOA->CRL|=0X00000004;//複用功能輸出       

GPIOA->ODR|=1<<0;//PA0 上拉

TIM2->SMCR|=0x00D4; 

//TIM2->SMCR|= 1<<5; //MSM=1 主/從模式 

//TIM2->SMCR|= 5<<4; //TS=101 觸發選擇 

//TIM2->SMCR|= 4<<0; //SMS=100 複位模式

TIM2->CCMR1|=1<<0;//CC1S=01 選擇輸入端  

TIM2->CCMR1|=3<<4; //IC1F=0011配置輸入濾波器

TIM2->CCER|=0<<1; //CC1P=0 選擇有效轉換邊沿  上升沿有效

TIM2->CCMR1|=0<<2; //IC1PS=00 配置輸入分頻 

TIM2->CCER|=1<<0; //CC1E=1 允許捕獲計數器的值到捕獲寄存器中

TIM2->CCMR1|=2<<8;//CC2S=10 選擇輸入端 

TIM2->CCER|=1<<5; //CC2P=1 選擇有交轉換邊沿 下降沿有效

TIM2->CCER|=1<<4; //CC2E=1 允許捕獲計數器的值到捕獲寄存器中

TIM2->DIER|=1<<1;   //允許更新捕獲中斷

TIM2->CR1|=0x01;    //使能定時器2

   MY_NVIC_Init(1,3,TIM2_IRQChannel,2);//搶占1,子優先級3,組2  

}

//定時器2中斷服務程式  

void TIM2_IRQHandler(void)

{           

IC1Value = TIM2->CCR1;//讀取CCR1也可以清CC1IF标志位

IC2Value = TIM2->CCR2;//讀取CCR1也可以清CC2IF标志位            

TIM2->SR&=~(1<<1);//清除中斷标志位     

}

//===============================================================

還有上面Capture_Init(2000,72-1); 裡面的參數與PWM_Init(1000,72-1);  裡面的參數有什麼具體關系呢? 謝謝!

關系是:Capture_Init(2000,72-1)中的2000是用于計數的,就是觸發後到下一次觸發的計數,如果捕獲的PWM信号周期太長20000不夠會有溢出的。PWM_Init(1000,72-1);  中的1000是重載,當設定72-1時,分頻為1M,重載1000,就是1M/1000=1K。

如果Capture_Init(2000,72-1)設定72-1,說明分頻為1M,1M的頻率在計數1K的信号那計數器要計數1000次,這個1000次要在Capture_Init(2000,72-1)中的2000内,

如果1000次大于Capture_Init(2000,72-1)中的2000,那就會溢出了。

是以,如果PWM_Init(1000,72-1);  中的1000這個數很大,那Capture_Init(2000,72-1)中的2000要比它大就得了。這樣就不會溢出了。

不穩定不确定說明你重載太少了,已經溢出了。你可以改大一點Capture_Init(65536,72-1); 這樣可以測幾十HZ.

A:這裡是定時器輸入口1,我是IC1映射到TI1, 是以是從TI1PF1觸發的,具體請看PWM輸入圖表。

B:通道選擇請看手冊,CC1通道被配置為輸入,IC1映射到TI1上

C:輸入濾波器請看手冊

D:從輸入選擇了CCR2,通道TI2.

PWM輸入模式  庫函數例程位置 : STM32F10x_StdPeriph_Lib_V3.3.0\Project\STM32F10x_StdPeriph_Examples\TIM\PWM_Input  該模式是輸入捕獲模式的一個特例  例如,你需要測量輸入到TI1上的PWM信号的長度(TIMx_CCR1寄存器)和占空比(TIMx_CCR2寄存器),具體步驟如下(取決于CK_INT的頻率和預分頻器的值) 

● 選擇TIMx_CCR1的有效輸入:置TIMx_CCMR1寄存器的CC1S=01(選擇TI1)。 

● 選擇TI1FP1的有效極性(用來捕獲資料到TIMx_CCR1中和清除計數器):置CC1P=0(上升沿有效)。  

● 選擇TIMx_CCR2的有效輸入:置TIMx_CCMR1寄存器的CC2S=10(選擇TI1)。 

● 選擇TI1FP2的有效極性(捕獲資料到TIMx_CCR2):置CC2P=1(下降沿有效)。 

● 選擇有效的觸發輸入信号:置TIMx_SMCR寄存器中的TS=101(選擇TI1FP1)。 

● 配置從模式控制器為複位模式:置TIMx_SMCR中的SMS=100。 

● 使能捕獲:置TIMx_CCER寄存器中CC1E=1且CC2E=1。

STM32 TImer幾種模式_通用定時器