stm32之TIM-高級定時器應用實例一(詳細)

  • 硬件:stm32f103c8t6
  • 開發工具:Keil uVision4
  • 下載調試工具:ARM仿真器

        如果第一次接觸定時器,可以先看基本定時器。本篇內容較多,如果想直接動手操作,可以跳到後面的實驗代碼。

        stm32標準庫對定時器外設建立了4個初始化結構體,定時器分爲基本定時器、通用定時器、高級定時器,針對不用的定時器要使用不同初始化結構體。下面是4個初始化結構體的適用分類:

TIM_TimeBaseInitTypeDef  (基本定時器、通用定時器、高級定時器)
TIM_OCInitTypeDef             (通用定時器、高級定時器)
TIM_ICInitTypeDef               (通用定時器、高級定時器)
TIM_BDTRInitTypeDef         (高級定時器)

         使用哪一個定時器,就配置所有相應的初始化結構體,然後調用初始化函數。下面先理解每個結構體成員的含義和其取值範圍。

定時器基本初始化結構體 >>  TIM_TimeBaseInitTypeDef

typedef struct
{
  uint16_t TIM_Prescaler; /*定時器預分頻設置。 value:(0~0xFFFF)*/

  uint16_t TIM_CounterMode;/*選擇了計數器模式。Value:
#define TIM_CounterMode_Up                 ((uint16_t)0x0000) //TIM 向上計數模式
#define TIM_CounterMode_Down               ((uint16_t)0x0010) //TIM 向下計數模式
#define TIM_CounterMode_CenterAligned1     ((uint16_t)0x0020) //TIM 中央對齊模式 1 計數模式
#define TIM_CounterMode_CenterAligned2     ((uint16_t)0x0040) //TIM 中央對齊模式 2 計數模式*/

  uint16_t TIM_Period; /*設置了在下一個更新事件裝入活動的自動重裝載寄存器週期的值。value:0x0000~0xFFFF*/         

  uint16_t TIM_ClockDivision; /*設置定時器時鐘CK_INT頻率與死區發生器以及數字濾波器採樣時鐘頻率分頻化。Value:
#define TIM_CKD_DIV1                       ((uint16_t)0x0000)
#define TIM_CKD_DIV2                       ((uint16_t)0x0100)
#define TIM_CKD_DIV4                       ((uint16_t)0x0200)*/   

  uint8_t TIM_RepetitionCounter; /*是否使用重複定時器,當該值不爲0的時候,計數器計數值達到週期數時,該值減1,計數器重新計數,當該值減到0的時候纔會產生事件。*/
} TIM_TimeBaseInitTypeDef;      

備註: 若是主頻72MHz、TIM_Prescaler的值設置爲(72-1),則定時器時鐘頻率=72MHz/72=1MHz。知道頻率就可以算週期了,用1/1MHz 乘以TIM_Period的值就是定時的時間(週期),如果加入了重複定時器,那麼還要乘以TIM_RepetitionCounter的值纔是定時的時間(週期)。

定時器比較輸出初始化結構體 >> TIM_OCInitTypeDef

typedef struct
{
  uint16_t TIM_OCMode;/*比較輸出模式選擇,共8種。value:
#define TIM_OCMode_Timing                  ((uint16_t)0x0000) // TIM 輸出比較時間模式
#define TIM_OCMode_Active                  ((uint16_t)0x0010) //TIM 輸出比較主動模式
#define TIM_OCMode_Inactive                ((uint16_t)0x0020) //TIM 輸出比較非主動模式
#define TIM_OCMode_Toggle                  ((uint16_t)0x0030) //TIM 輸出比較觸發模式
#define TIM_OCMode_PWM1                    ((uint16_t)0x0060) //TIM 脈衝寬度調製模式 1 
#define TIM_OCMode_PWM2                    ((uint16_t)0x0070) //TIM 脈衝寬度調製模式 2*/      

  uint16_t TIM_OutputState;/*比較輸出使能,決定信號是否通過外部引腳輸出。value:0(Disable)、1(Enable)。 */         

  uint16_t TIM_OutputNState; /*比較互補輸出使能,決定互補信號是否通過外部引腳輸出。value:0(Disable)、1(Enable)。*/

  uint16_t TIM_Pulse; /*比較輸出的脈衝寬度,設置佔空比。Value:0x0000~0xFFFF*/       

  uint16_t TIM_OCPolarity; /*比較輸出極性,決定定時器通道有效電平的極性。Value:
#define TIM_OCPolarity_High                ((uint16_t)0x0000)
#define TIM_OCPolarity_Low                 ((uint16_t)0x0002)*/

  uint16_t TIM_OCNPolarity; /*比較互補輸出極性,可選高電平有效、低電平有效。Value:
#define TIM_OCNPolarity_High               ((uint16_t)0x0000)
#define TIM_OCNPolarity_Low                ((uint16_t)0x0008)*/

  uint16_t TIM_OCIdleState;  /*空閒狀態時通道輸出電平設置,可選高電平、低電平。Value:
#define TIM_OCNPolarity_High               ((uint16_t)0x0000)
#define TIM_OCNPolarity_Low                ((uint16_t)0x0008)*/

  uint16_t TIM_OCNIdleState; /*空閒狀態時互補通道輸出電平設置,可選高電平、低電平,設定值必須跟TIM_OCIdleState相反。Value:
#define TIM_OCNIdleState_Set               ((uint16_t)0x0200)
#define TIM_OCNIdleState_Reset             ((uint16_t)0x0000)*/

} TIM_OCInitTypeDef;

備註:設置TIM_Pulse的值就可以改變輸出波形的佔空比了,如果不使用重複定時器,那麼佔空比=(TIM_Pulse+1)/(TIM_Period+1)x100%。

定時器輸入捕獲初始化結構體  >> TIM_ICInitTypeDef

typedef struct
{
  uint16_t TIM_Channel; /*輸入通道選擇,共4個通道。Value:
#define TIM_Channel_1                      ((uint16_t)0x0000) //使用 TIM 通道 1 
#define TIM_Channel_2                      ((uint16_t)0x0004) //使用 TIM 通道 2 
#define TIM_Channel_3                      ((uint16_t)0x0008) //使用 TIM 通道 3
#define TIM_Channel_4                      ((uint16_t)0x000C) //使用 TIM 通道 4*/     

  uint16_t TIM_ICPolarity; /*輸入捕獲邊沿觸發選擇,可選上升沿觸發、下降沿觸發。Value:
#define  TIM_ICPolarity_Rising             ((uint16_t)0x0000) //TIM 輸入捕獲上升沿
#define  TIM_ICPolarity_Falling            ((uint16_t)0x0002) //TIM 輸入捕獲下降沿*/

  uint16_t TIM_ICSelection; /*輸入通道選擇,共3個通道。Value:
#define TIM_ICSelection_DirectTI           ((uint16_t)0x0001)  //TIM 輸入 2,3 或 4 選擇對應地與 IC1 或 IC2 或IC3 或 IC4 相連       
#define TIM_ICSelection_IndirectTI         ((uint16_t)0x0002)  //TIM 輸入 2,3 或 4 選擇對應地與 IC2 或 IC1 或IC4 或 IC3 相連
#define TIM_ICSelection_TRC                ((uint16_t)0x0003)  //TIM 輸入 2,3 或 4 選擇與 TRC 相連*/

  uint16_t TIM_ICPrescaler; /*輸入捕獲通道預分頻,共(1、2、4、8)種。Value:
#define TIM_ICPSC_DIV1                     ((uint16_t)0x0000) //TIM 捕獲在捕獲輸入上每探測到一個邊沿執行一次
#define TIM_ICPSC_DIV2                     ((uint16_t)0x0004) // TIM 捕獲每 2 個事件執行一次
#define TIM_ICPSC_DIV4                     ((uint16_t)0x0008) //TIM 捕獲每 4 個事件執行一次
#define TIM_ICPSC_DIV8                     ((uint16_t)0x000C) //TIM 捕獲每 8 個事件執行一次*/

  uint16_t TIM_ICFilter;   /*輸入捕獲濾波器設置,value:0x0~0x0F。一般不用,設置爲0*/
} TIM_ICInitTypeDef;

備註:定時器捕獲信號,可以測量輸入信號的脈寬和測量PWM輸入信號的頻率和佔空比;信號的來源可以來自其他的定時器或者外部引腳;濾波器的作用是排除高頻的干擾,採樣的頻率必須大於等於兩倍的輸入信號。

斷路和死區初始化結構體  >>TIM_BDTRInitTypeDef

typedef struct
{
  uint16_t TIM_OSSRState;/*運行模式下關閉狀態選擇。Value:
#define TIM_OSSRState_Enable               ((uint16_t)0x0800)
#define TIM_OSSRState_Disable              ((uint16_t)0x0000)*/       

  uint16_t TIM_OSSIState;/*空閒模式下關閉狀態選擇。Value:
#define TIM_OSSIState_Enable               ((uint16_t)0x0400)
#define TIM_OSSIState_Disable              ((uint16_t)0x0000)*/       

  uint16_t TIM_LOCKLevel;/*鎖定配置。Value:
#define TIM_LOCKLevel_OFF                  ((uint16_t)0x0000)
#define TIM_LOCKLevel_1                    ((uint16_t)0x0100)
#define TIM_LOCKLevel_2                    ((uint16_t)0x0200)
#define TIM_LOCKLevel_3                    ((uint16_t)0x0300)*/       

  uint16_t TIM_DeadTime;/*死區時間。Vlaue:0x0~0xFF*/

  uint16_t TIM_Break;/*短路輸入使能控制。Value:
#define TIM_Break_Enable                   ((uint16_t)0x1000)
#define TIM_Break_Disable                  ((uint16_t)0x0000)*/          

  uint16_t TIM_BreakPolarity;/*斷路輸出極性。Value:
#define TIM_BreakPolarity_Low              ((uint16_t)0x0000)
#define TIM_BreakPolarity_High             ((uint16_t)0x2000)*/    

  uint16_t TIM_AutomaticOutput;/*自動輸出使能。Value:
#define TIM_AutomaticOutput_Enable         ((uint16_t)0x4000)
#define TIM_AutomaticOutput_Disable        ((uint16_t)0x0000)*/

} TIM_BDTRInitTypeDef;

備註:

        上圖的黑影部分是死區時間,死區時間是根據與輸出信號相連接的器件及其特性來調整的,爲了避免OCx和OCxN同時改變時,造成外部器來不及反應所造成的短路問題。

下面通過幾個實例,進一步理解初始化結構體成員的含義,熟悉定時器的使用的流程。

實驗一.PWM互補輸出實驗(帶死區和斷路功能)

一. 設計要求:

雙通道互補PWM,帶死區和剎車功能。
週期:100ms
佔空比:通道一爲25%,通道二爲60%
死區持續時間:12.8ms  

二. 硬件設計:

 採用TIM1的通道一和通道二。

        PA8、PB13引腳是TIM1通道一的互補輸出。PA9、PB14引腳是TIM1通道二的互補輸出。爲增加斷路功能,需要用到TIM1_BKIN引腳,PB12。

三. 設計步驟:

  1. 定時器IO口配置。
  2. 配置時基結構體:TIM_TimeBaseInitTypeDef
  3. 配置輸出比較結構體:TIM_OCInitTypeDef
  4. 配置斷路和死區結構體:TIM_BDTRInitTypeDef
  5. 啓動定時器,輸出使能。

>>死區持續時間的計算:

        TIM_DeadTime的就是配置寄存器DTG[7:0]的值,T_D_T_S是定時器時鐘,T_d_t_g是死區發生器的時鐘,DT是死區持續時間。

本實驗定時器時鐘配置爲10kHz,死區持續時間需要配置成12.8ms,我這裏選用第二條公式,具體選用那一條公式,由DTG[7:5]這幾個bit位決定,如上圖。

根據公式  DTG[7:5]=10x => DT=(64+DTG[5:0]) × Tdtg,Tdtg = 2 × TDTS

那麼先計算 T_d_t_g=2T_D_T_S=2*(1/10kHz)=0.2ms

把參數代入公式 DT=(64+DTG[5:0]) × Tdtg,可算出DTG[5:0]=0,即DTG[7:0]=0x80.

創建TIM_test.h

#ifndef __TIM_TEST_H
#define __TIM_TEST_H
#include "stm32f10x.h"

void GPIO_Configuration(void);
void TIME_Configuration(void);

#endif

創建TIM_test.c

void GPIO_Configuration(void)
{
   /*定義一個GPIO_InitTypeDef類型的結構體*/
   GPIO_InitTypeDef GPIO_InitStructure;

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOA| \
RCC_APB2Periph_GPIOC, ENABLE);//開啓GPIOC的外設時鐘
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); 

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //設置引腳模式爲通用推輓輸出
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
   GPIO_Init(GPIOB, &GPIO_InitStructure); //調用庫函數,初始化GPIOC

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
   GPIO_Init(GPIOA, &GPIO_InitStructure); //調用庫函數,初始化GPIOC

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
   GPIO_Init(GPIOB, &GPIO_InitStructure); //調用庫函數,初始化GPIOC
   GPIO_SetBits(GPIOB,GPIO_Pin_12);
}

#define ADVANCE_TIM TIM1

void TIME_Configuration(void)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_OCInitTypeDef TIM_OCInitStructure;
  TIM_BDTRInitTypeDef TIM_BDTRInitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); //開啓TIM1時鐘

//時基結構體配置
  TIM_TimeBaseStructure.TIM_Period = 1000-1;     //從0開始計數 一個週期1000次
  TIM_TimeBaseStructure.TIM_Prescaler =(7200-1); //計數器頻率爲10kHz  定時器時鐘:72MHz/7200=10kHz 週期:(1/10kHz)*1000=100ms
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //不需要分頻
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //計數方式 向上計數
  TIM_TimeBaseStructure.TIM_RepetitionCounter=0; //重複計數器
  TIM_TimeBaseInit(ADVANCE_TIM, &TIM_TimeBaseStructure); //調用庫函數,初始化TIM1

//輸出比較結構體配置
  TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//選擇PWM1模式
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//信號輸出使能
  TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;//互補信號輸出使能
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
  TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
  TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;

//初始化TIM1的通道一
  TIM_OCInitStructure.TIM_Pulse = 250-1; //佔空比=250/1000=25%
  TIM_OC1Init(ADVANCE_TIM,&TIM_OCInitStructure);
  TIM_OC1PreloadConfig(ADVANCE_TIM,TIM_OCPreload_Enable);

//初始化TIM1通道二
  TIM_OCInitStructure.TIM_Pulse = 600-1; //佔空比=600/1000=60%
  TIM_OC2Init(ADVANCE_TIM,&TIM_OCInitStructure);
  TIM_OC2PreloadConfig(ADVANCE_TIM,TIM_OCPreload_Enable);

//死區和短路結構體配置
  TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
  TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
  TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;
  TIM_BDTRInitStructure.TIM_DeadTime = 0x80;
  TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;
  TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_Low;//低電平有效,如果引腳檢測到高電平則會停止PWM的輸出,不會產生任何波形
  TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
  TIM_BDTRConfig(ADVANCE_TIM,&TIM_BDTRInitStructure);

//使能定時器,計數器開始計數
  TIM_Cmd(ADVANCE_TIM, ENABLE);  
//主動輸出使能
  TIM_CtrlPWMOutputs(ADVANCE_TIM,ENABLE);
}

創建main.c

#include "stm32f10x.h"
#include “TIM_test.h”

int main(void)
{   
  GPIO_Configuration(); //IO口配置
  TIME_Configuration(); //定時器配置
  while(1){
  }
}

四. 實驗結果:

       把程序編譯燒錄到開發板裏面出,再將PA8,PB13引腳和PA9,PB14引腳接到示波器,並把短路輸入引腳PB12拉低,示波器和開發板共地。也可以先在keil裏面進行軟件仿真。用keil4 模擬仿真顯示引腳波形輸出分析的步驟

軟件仿真:

週期:100ms

死區持續時間:12.8ms

佔空比(通道一):25%

佔空比(通道二):60%

硬件調試:

信號1接的是PB13引腳,信號2接的是PA8引腳,調整示波器到合適的參數。

       調試短路功能可以將PB12引腳處接高電平,那麼定時器就會停止產生波形,以達到剎車的功能。高級定時器的PWM輸出的功能特性天生就是用來控制電機的。

       一個高級定時器可以輸出多路PWM,但是他們的週期是一樣的,佔空比可以不一樣,在運行過程中每個通道的佔空比是可以通過調用函數來改變。通用定時器跟高級定時器的區別是前者沒有死區和斷路功能,其他都是一樣。

水平有限,僅供參考,錯誤之處以及不足之處還望多多指教。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章