2.定時器中斷

STM32F429總共有14個:

高級定時器:TIM1 和TIM8
通用定時器:TIM2-TIM5,TIM9-TIM14
基本定時器:TIM6 和 TIM7

掛載的總線:高級定時器及TIM9-TIM11的時鐘來自APB2,其他來自APB1

APB2:TIM1 和 TIM8 、TIM9-TIM11

APB1:TIM2-TIM5、TIM6 和 TIM7、TIM12-TIM14

定時器簡介

STM32F429 的通用定時器包含一個 16 位32 位自動重載計數器( CNT),該計數器由可編程預分頻器( PSC) 驅動。

STM32F429 的通用定時器可以被用於:測量輸入信號的脈衝長度(輸入捕獲)或者產生輸出波形(輸出比較和 PWM)等。

使用定時器預分頻器和 RCC 時鐘控制器預分頻器,脈衝長度和波形週期可以在幾個微秒到幾個毫秒間調整。

STM32F429 的每個通用定時器都是完全獨立的,沒有互相共享的任何資源。
STM32 的通用 TIMx (TIM2~TIM5 和 TIM9~TIM14)定時器功能包括:


  1.   16 位/32 位(僅 TIM2 和 TIM5)向上、向下、向上/向下自動裝載計數器(TIMx_CNT),注意: TIM9~TIM14 只支持向上(遞增)計數方式。

  2.   16 位可編程(可以實時修改)預分頻器(TIMx_PSC),計數器時鐘頻率的分頻係數爲 1~65535 之間的任意數值。

  3.   4 個獨立通道(TIMx_CH14TIM9TIM14 最多 2 個通道),這些通道可以用來作爲:

A.輸入捕獲
B.輸出比較
C. PWM 生成(邊緣或中間對齊模式) ,注意: TIM9~TIM14 不支持中間對齊模式
D.單脈衝模式輸出

  1.   可使用外部信號( TIMx_ETR)控制定時器和定時器互連(可以用 1 個定時器控制另外
    一個定時器)的同步電路。

  2.   如下事件發生時產生中斷/DMA( TIM9~TIM14 不支持 DMA):

    A.更新:計數器向上溢出/向下溢出,計數器初始化(通過軟件或者內部/外部觸發)
    B.觸發事件(計數器啓動、停止、初始化或者由內部/外部觸發計數)
    C.輸入捕獲
    D.輸出比較
    E.支持針對定位的增量(正交)編碼器和霍爾傳感器電路( TIM9~TIM14 不支持)
    F.觸發輸入作爲外部時鐘或者按週期的電流管理( TIM9~TIM14 不支持)


常用的寄存器

TIMx_CR1:(Control Register 1)控制寄存器1

TIM1 和 TIM8:
TIM2-TIM5:
TIM9-TIM12
TIM6 和 TIM7:
qq空間圖片
不會做點進去就是圖片的鏈接,好尷尬。

TIMx_CR2:(Control Register 2)控制寄存器2

分類同TIMx_CR1

TIMx_DIER:(DMA Interrupt Enable Register)DMA/中斷使能寄存器

TIMx_PSC:(Prescaler)預分頻寄存器

TIMx_ARR:(auto-reload register)重裝載寄存器

該寄存器在物理上實際對應着 2 個寄存器,一個是程序員可以直接操作的,另外一個是程序員看不到的,這個看不到的寄存器在《 STM32F4xx 中文參考手冊》裏面被叫做影子寄存器。事實上真正起作用的是影子寄存器。 根
據 TIMx_CR1 寄存器中 APRE 位的設置:APRE=0 時,預裝載寄存器的內容可以隨時傳送到影子寄存器,此時 2 者是連通的;而 PRE=1 時,在每一次更新事件( UEV)時,才把預裝載寄存器( ARR) 的內容傳送到影子寄存器。

TIMx_SR:(status register)狀態寄存器

步驟

  • 1) TIM3 時鐘使能。

這裏我們通過 APB1ENR 的第 1 位來設置 TIM3 的時鐘,因爲 Stm32_Clock_Init 函數裏面
把 APB1的分頻設置爲 4了,所以我們的 TIM3時鐘就是 APB1時鐘的 2倍,等於系統時鐘 ( 90M)。

  • 2) 設置 TIM3_ARR 和 TIM3_PSC 的值。

通過這兩個寄存器,我們來設置自動重裝的值,以及分頻係數。這兩個參數加上時鐘頻率就決定了定時器的溢出時間。

  • 3) 設置 TIM3_DIER 允許更新中斷。

因爲我們要使用 TIM3 的更新中斷,所以設置 DIER 的 UIE 位爲 1,使能更新中斷。

  • 4) 允許 TIM3 工作。

光配置好定時器還不行,沒有開啓定時器,照樣不能用。我們在配置完後要開啓定時器,通過 TIM3_CR1 的 CEN 位來設置。

  • 5) TIM3 中斷分組設置。

在定時器配置完了之後,因爲要產生中斷,必不可少的要設置 NVIC 相關寄存器,以使能TIM3 中斷。

  • 6) 編寫中斷服務函數。

在最後,還是要編寫定時器中斷服務函數,通過該函數來處理定時器產生的相關中斷。在中斷產生後,通過狀態寄存器的值來判斷此次產生的中斷屬於什麼類型。然後執行相關的操作,我們這裏使用的是更新(溢出)中斷,所以在狀態寄存器 SR 的最低位。在處理完中斷之後應該向 TIM3_SR 的最低位寫 0,來清除該中斷標誌

示例代碼

  • 寄存器
/************************/
//C文件內容
#include "tim3.h"


void TIM3_IRQHandler(void)
{
	if (TIM3->SR&0x0001)	//溢出中斷		SR狀態寄存器
	{
		LED0=!LED0;
	}
	TIM3->SR&=~(1<<0);			//狀態寄存器清零
}


void TIM4_IRQHandler(void)
{
	if (TIM4->SR&0x0001)	//溢出中斷		SR狀態寄存器
	{
		LED1=!LED1;
	}
	TIM4->SR&=~(1<<0);			//狀態寄存器清零
}


//通用定時器 3 中斷初始化
//這裏時鐘選擇爲 APB1 的 2 倍,而 APB1 爲 45M
//arr:自動重裝值。
//psc:時鐘預分頻數
//定時器溢出時間計算方法:Tout=((arr+1)*(psc+1))/Ft us.
//Ft=定時器工作頻率,單位:Mhz
//這裏使用的是定時器 3!

void TIM3_Int_Init(u16 arr,u16 psc)
{							//0  	1  	 2     3  ...
	RCC->APB1ENR|=1<<1;		//TIM2 TIM3 TIM4 TIM5  ...
	TIM3->ARR=arr;			//自動重裝載寄存器
	TIM3->PSC=psc;			//時鐘預分頻寄存器
	TIM3->DIER|=1<<0;		//允許更新中斷
	TIM3->CR1|=0x01;		//控制寄存器1  使能定時器3
	MY_NVIC_Init(1,3,TIM3_IRQn,2);		//搶佔1 ,子優先級 3
}

void TIM4_Int_Init(u16 arr,u16 psc)
{							//0  	1  	 2     3  ...
	RCC->APB1ENR|=1<<2;		//TIM2 TIM3 TIM4 TIM5  ...
	TIM4->ARR=arr;			//自動重裝載寄存器
	TIM4->PSC=psc;			//時鐘預分頻寄存器
	TIM4->DIER|=1<<0;		//允許更新中斷
	TIM4->CR1|=0x01;		//控制寄存器1  使能定時器3
	MY_NVIC_Init(2,3,TIM4_IRQn,2);		//搶佔1 ,子優先級 3
}

/************************/
//頭文件內容
#ifndef __TIM3_H_
#define __TIM3_H

#include "sys.h"
#include "led.h"

	void TIM3_Int_Init(u16 arr,u16 psc);
	void TIM4_Int_Init(u16 arr,u16 psc);

#endif

  • 庫函數
/*********************/
//c文件

#include "timer.h"

TIM_HandleTypeDef TIM2_Handler;	
TIM_HandleTypeDef TIM3_Handler;	

//arr:自動重裝載
//psc:時鐘分頻數
void TIM2_Init(u16 arr,u16 psc)	
{
	TIM2_Handler.Instance=TIM2;
	TIM2_Handler.Init.Prescaler=psc;
	TIM2_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;
	TIM2_Handler.Init.Period=arr;
	TIM2_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
	HAL_TIM_Base_Init(&TIM2_Handler);
	//使能
	HAL_TIM_Base_Start_IT(&TIM2_Handler);
}
void TIM3_Init(u16 arr,u16 psc)	
{
	TIM3_Handler.Instance=TIM3;
	TIM3_Handler.Init.Prescaler=psc;
	TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;
	TIM3_Handler.Init.Period=arr;
	TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;	
	HAL_TIM_Base_Init(&TIM3_Handler);
	//使能
	HAL_TIM_Base_Start_IT(&TIM3_Handler);
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
	if (htim==&TIM2_Handler)
	{
		__HAL_RCC_TIM2_CLK_ENABLE(); //使能 TIM3 時鐘
		HAL_NVIC_SetPriority(TIM2_IRQn,0,3); //設置中斷優先級,搶佔 1,子優先級 3
		HAL_NVIC_EnableIRQ(TIM2_IRQn); //開啓 ITM3 中斷
	}
	if (htim==&TIM3_Handler)
	{
		__HAL_RCC_TIM3_CLK_ENABLE(); //使能 TIM3 時鐘
		HAL_NVIC_SetPriority(TIM3_IRQn,1,3); //設置中斷優先級,搶佔 1,子優先級 3
		HAL_NVIC_EnableIRQ(TIM3_IRQn); //開啓 ITM3 中斷
	}
}

//
void TIM2_IRQHandler(void)
{
	HAL_TIM_IRQHandler(&TIM2_Handler);
}

//
void TIM3_IRQHandler(void)
{
	HAL_TIM_IRQHandler(&TIM3_Handler);
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if (htim==&TIM2_Handler)
	{
		LED1=!LED1;
	}
	
	if (htim==&TIM3_Handler)
	{
		LED0=!LED0;
	}
}

/************************************/
//頭文件

#ifndef __TIMER_H__
#define __TIMER_H__


#include "sys.h"
#include "led.h"


	void TIM2_Init(u16 arr,u16 psc);
	void TIM3_Init(u16 arr,u16 psc);

#endif





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