1. 程式人生 > >STM32 定時器(基於HAL庫)

STM32 定時器(基於HAL庫)

l  16位的向上、向下、向上/向下(中心對齊)計數模式,支援自動重灌載

l  16位的預分頻器

l  每個定時器都有多個獨立通道,每個通道可用於

*  輸入捕獲

*  輸出比較

*  PWM輸出

*  單脈衝模式

l  高階定時器還可以產生互補輸出

l  可以產生中斷/DMA請求:

*  更新事件:計數器向上/向下溢位,計數器初始化(通過軟或者內部/外部觸發)

*  觸發事件:計數器啟動,停止,初始化或者有內部/外部觸發計數

*  輸入捕獲

*  輸出比較

一、定時器之計數模式

(一)  計數模式

向上計數

計數器從0向上計數(遞增)到自動裝載值,然後再次回到0開始計數,併產生一個計數溢位事件

 

向下計數

計數器從自動裝載值向下計數(遞減)到0,然後再次回到自動裝載值開始計數,併產生一個計數器向下溢位事件

 

中央對齊模式(向上/向下計數)

計數器從0開始計數到自動裝載值-1,併產生一個計數器溢位事件,然後再向下計數到0+1,併產生一個計數溢位事件,然後再向上計數。

 

(二)定時器的溢位時間計算

time=(ARR+1)*(PSC+1)/Tclk

 

ARR為自動裝載值

PSC:預分頻係數

Tclk:定時器的APB時鐘,通常等於系統時鐘

 

如:

tclk為72M

psc為7199

arr為4999

 

time=(4999+1)*(7199+1)/72 000 000 = 0.5s = 500ms

(三)CubeMX設定

這裡需要注意的是你所需要使用的定時器是掛載在APB1還是APB2。相應的要調節他們時鐘頻率

 選擇

 選擇內部時鐘

基礎配置,這裡配置的是1秒計數

l  Prescaler (PSC- 16 bits value),預分頻器(PSC- 16位值)

l  Counter Mode,計數器模式:

up 向上

down 向下

Center Aligned mode 中心對齊模式

l  Counter Period (AutoReload Register - 16 bits value),重灌載值

l  auto-reload preload,自動重灌載開啟

 

開啟更新中斷

中斷優先順序數字越低越高

(四)程式設計記錄

中斷開啟

HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)

溢位事件回撥函式

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
   if(htim->Instance == TIM1){
         
        HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);//單獨輸出電平取反
     
     }
}

開啟中斷

HAL_TIM_Base_Start_IT(&htim1);

二、 定時器之PWM

PWM即脈衝寬度調製,是一種模擬控制方式,通常用於LED的亮度調節。其實就是快速的高低電平變化讓人感覺不出來。

(一)瞭解一下HZ的概念

1HZ表示1秒變化一個週期

在家用交流點中:

50HZ表示電流每秒鐘來回變化50次,方向改變100次。

50HZ是50個週期,所以有50個正玄波形

這個圖表示的是1HZ變化,1個週期,1個正玄波

50HZ表示每個週期的時間=1S/50=0.02S=20ms

 

微控制器檢測交流電可以200ms內沒有檢測到高電平,則表示無輸入。

 

在計算機cpu等使用1khz=1000hz

在電磁波和機械波等,1Khz=1024hz

 

在PWM中

 

hz是頻率的單位

1hz 表示PWM的週期是一秒

1Khz表示一秒鐘有一千個週期,也就是週期是1ms

1KKhz、1Mhz表示一秒鐘有100萬個週期,也就是週期是1us

 

y秒=1/xHZ

 

1/1000=0.001S=1ms

1/1000000=0.000001S=1us

 

如果實現週期是100us

100us=0.0001S=1/0.0001= 10,000HZ

(二)PWM配置

ARR為自動裝載值

CCRx 為捕獲比較暫存器值

 

預分頻係數決定了PWM的時鐘速度

ARR的大小決定了PWM的週期

CRRx決定了輸出有效訊號的時間

 

有效訊號:

高電平

低電平

 

PWM模式:

模式1,不管是向上還是向下計數,當計數值小於重灌載值是輸出有效電平。

模式2,不管是向上還是向下計數,當計數值小於重灌載值是輸出無效電平。

 

PWM週期計算

Fpwm = 100M / ((arr+1)*(psc+1))(單位:Hz)

 

Fpwm = 100M / (arr+1)/(psc+1)(單位:Hz)

 

arr 是計數值

psc 是預分頻值

如:

3. 主頻=100M

4. arr=100

5. psc=1000

100,000,000/100/1000=1000Hz

(三) CubeMX設定

設定定時器使用內部時鐘

設定定時器的PWM通道1開啟

STM32F103C8T6對應的PWM通道為PA8

設定基礎引數

Prescaler,分配係數為36

Counter Period,重灌載值為100

所以:

PWM的頻率為:72 000 000/35/100=20 000 HZ(20KHZ),週期為 1/20000= 0.00005秒

PWM脈寬調製的最大值與重灌載值一致,其範圍為[0,100]

通道可以設定的值:

Mode,PWM的模式,可以選擇模式1或模式2

CH Polarity,有效電平,可選高或底

(四)程式設計

初始化

//開啟PWM輸出
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
//設定預設的佔空比值
__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,10);

while迴圈改變值

HAL_Delay(30);//延時30ms

//變數修改
if(i<100) i++;
else i=0;

//設定佔空比值
__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,i);    

三、 定時器之輸入捕獲

通過檢查定時器通道上的邊沿訊號,在邊沿訊號跳變(上升沿或者下降沿)的時候,將當前定時器的計數值儲存到對應的捕獲/比較暫存器裡面,完成一次捕獲。

 

通常用於檢測高電平持續時間、低電平持續時間、兩次下降沿的持續時間、兩次上升沿的持續時間

濾波器:

裡可以設定以什麼頻率採集多少次有效電平才說明邊沿觸發成功,如設定的是上升沿觸發,當上升沿發生時,濾波器或以fDTS的頻率採集ICF設定的次數,每次檢測是否是高電平,這樣可以防止誤觸發所帶來的計算干擾。

 

邊沿檢測器:

設定捕獲的觸發邊沿,可以設定上升沿或下降沿

 

通道選擇

通過暫存器可以設定其它通道輸入的值到該通道上

如通道1和通道2都可以對映到IC1,但通常是通道1是IC1,通道2是IC2,每個獨立一對一對映,互不干擾。

 

分頻器:

每2個事件觸發一次捕獲,如上升沿捕獲時,連續獲取到兩個上升沿後才會觸發計數

每4個事件觸發一次捕獲

每8個事件觸發一次捕獲

(一) CubeMX設定

開啟TIM4的通道1作為輸入捕獲通道,對應是PB6引腳

Internal Clock表示內部時鐘

input capture direct mode 表示輸入捕獲

根據硬體連線,這裡設定為上拉

開啟中斷

基礎配置

時鐘:72 000 000 /72 = 1 000 000 HZ= 1MHZ,所以計數一次為1us

最大計數值為65536,約為65ms

prolarity selection 為觸發計數邊沿,下降沿

(二)程式設計

測量低電平的持續時間,先下降沿後上升沿,記錄計數值,最終輸出us單位。

通用函式

//變數儲存
typedef struct 
{   
    uint8_t   flg; //0為未開始,1已經開始,2為結束
    uint16_t  num;//計數值
    uint16_t  num_period;//溢位次數
}COUNT_TEMP;

COUNT_TEMP count_temp={0};

//捕獲中斷髮送時的回撥函式
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
      //判斷定時器2
        if(TIM2 == htim->Instance){
            if ( count_temp.flg == 0 )
            {   
                // 清零定時器計數
                __HAL_TIM_SET_COUNTER(htim,0); 
                //設定上升沿觸發
                __HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING);
                count_temp .flg = 1;    //設定已經開始    
                count_temp .num_period = 0;    //溢位計數清零        
                count_temp .num = 0; //計數清零
            }        
            else
            {
                // 獲取定時器計數值
                count_temp .num = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_2);
                //設定下降沿觸發
                __HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_FALLING);
                count_temp .flg = 2;
            }
        }
}    

//定時器溢位回撥函式
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(TIM2 == htim->Instance){
    //每次溢位時間為65536us
    if(count_temp.flg==1)//還未成功捕獲
    {
                if(count_temp.num_period==0XFFFF)//電平太長了
                {
                    count_temp.flg=2;        //標記成功捕獲了一次
                    count_temp .num=0XFFFF;
                }else count_temp .num_period ++;
    }
    }
}

初始化

//開啟定時器溢位中斷
HAL_TIM_Base_Start_IT(&htim2);  
//開啟輸入捕獲中斷,設定下降沿觸發中斷
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_FALLING); 
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);    //啟動輸入捕獲

while迴圈

//等待測量完畢
if(count_temp.flg == 2 )
{
    //計數計數值,0xFFFF為最大計數
    uint32_t ulTime = (uint32_t)count_temp .num_period * 0xFFFF + count_temp .num;
    //輸出測量的值
    printf ( "低電平時間:%d us\n",ulTime); 
    count_temp .flg = 0;            
}

 

原文地址:https://www.cnblogs.com/dongxiaodong/p/14351398.html

 

找作者:https://space.bilibili.com/162091292

 


&n