STM32F103C8T6定時器的使用

關於STM32F103C8T6工程文件自己下載https://download.csdn.net/download/weixin_45488643/12522971這個僅僅是一個核心工程文件,只需要自己添加以下代碼就可以。

  STM32 的定時器功能十分強大,有 TIME1 和 TIME8 等高級定時器,也有 TIME2~TIME5 等通用定時器,還有 TIME6 和IME7 等基本定時器。STM32F103C8T6是中容量的芯片,由高級定時器TIME1 和通用定時器 TIME1~TIME5。

1、STM32F103C8T6通用定時器簡介

  STM32 的通用定時器是一個通過可編程預分頻器(PSC)驅動的 16 位自動裝載計數器(CNT)構成。 STM32 的通用定時器可以被用於:測量輸入信號的脈衝長度(輸入捕獲)或者產生輸出波形(輸出比較和 PWM)等。 使用定時器預分頻器和 RCC 時鐘控制器預分頻器,脈衝長度和波形
週期可以在幾個微秒到幾個毫秒間調整。 STM32 的每個通用定時器都是完全獨立的,沒有互相共享的任何資源。
  STM3 的通用 TIMx (TIM2、 TIM3、 TIM4 和 TIM5)定時器功能  包括:
  1)16 位向上、向下、向上/向下自動裝載計數器(TIMx_CNT)。
  2)16 位可編程(可以實時修改)預分頻器(TIMx_PSC),計數器時鐘頻率的分頻係數爲 1~
  65535 之間的任意數值。
    3) 4 個獨立通道(TIMx_CH1~4),這些通道可以用來作爲:
    A.輸入捕獲
    B.輸出比較
    C. PWM 生成(邊緣或中間對齊模式)
    D.單脈衝模式輸出
  4)可使用外部信號(TIMx_ETR)控制定時器和定時器互連(可以用 1 個定時器控制另外
一個定時器)的同步電路。
  5)如下事件發生時產生中斷/DMA:
    A.更新:計數器向上溢出/向下溢出,計數器初始化(通過軟件或者內部/外部觸發)
    B.觸發事件(計數器啓動、停止、初始化或者由內部/外部觸發計數)
    C.輸入捕獲
    D.輸出比較
    E.支持針對定位的增量(正交)編碼器和霍爾傳感器電路
    F.觸發輸入作爲外部時鐘或者按週期的電流管理

2、通用定時器 TIM3 中斷控制PC13

  1) TIM3 時鐘使能。
  TIM3 是掛載在 APB1 之下,所以我們通過 APB1 總線下的時鐘使能函數來使能 TIM3。調用的函數是:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //時鐘使能

  2)初始化定時器參數,設置自動重裝值, 分頻係數,計數方式等。
  在庫函數中,定時器的初始化參數是通過初始化函數 TIM_TimeBaseInit 實現的:

voidTIM_TimeBaseInit(TIM_TypeDef*TIMx,
                     TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

  第一個參數是確定是哪個定時器,這個比較容易理解。第二個參數是定時器初始化參數結構體指針,結構體類型爲 TIM_TimeBaseInitTypeDef,下面我們看看這個結構體的定義:

typedef struct
{
uint16_t TIM_Prescaler;
uint16_t TIM_CounterMode;
uint16_t TIM_Period;
uint16_t TIM_ClockDivision;
uint8_t TIM_RepetitionCounter;
} TIM_TimeBaseInitTypeDef;

  這個結構體一共有 5 個成員變量,要說明的是,對於通用定時器只有前面四個參數有用,最後一個參數 TIM_RepetitionCounter 是高級定時器纔有用的,這裏不多解釋。
  第一個參數 TIM_Prescaler 是用來設置分頻係數的。
  第二個參數 TIM_CounterMode 是用來設置計數方式,上面講解過,可以設置爲向上計數,向下計數方式還有中央對齊計數方式,比較常用的是向上計數模式 TIM_CounterMode_Up 和向下計數模式TIM_CounterMode_Down。
  第三個參數是設置自動重載計數週期值,這在前面也已經講解過。
  第四個參數是用來設置時鐘分頻因子。
  針對 TIM3 初始化範例代碼格式:

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 5000;
TIM_TimeBaseStructure.TIM_Prescaler =7199;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

  3)設置 TIM3_DIER 允許更新中斷。
  因爲我們要使用 TIM3 的更新中斷,寄存器的相應位便可使能更新中斷。在庫函數裏面定時器中斷使能是通過 TIM_ITConfig 函數來實現的:

void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)

  第一個參數是選擇定時器號,這個容易理解,取值爲 TIM1~TIM17。
  第二個參數非常關鍵,是用來指明我們使能的定時器中斷的類型,定時器中斷的類型有很
多種,包括更新中斷 TIM_IT_Update,觸發中斷 TIM_IT_Trigger,以及輸入捕獲中斷等等。
  第三個參數就很簡單了,就是失能還是使能。
  例如我們要使能 TIM3 的更新中斷,格式爲:

TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE );

  4) TIM3 中斷優先級設置。
  在定時器中斷使能之後,因爲要產生中斷,必不可少的要設置 NVIC 相關寄存器,設置中斷優先級。之前多次講解到用 NVIC_Init 函數實現中斷優先級的設置。
  5)允許 TIM3 工作,也就是使能 TIM3。
光配置好定時器還不行,沒有開啓定時器,照樣不能用。我們在配置完後要開啓定時器,通過 TIM3_CR1 的 CEN 位來設置。在固件庫裏面使能定時器的函數是通過 TIM_Cmd 函數來實現的:

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)

這個函數非常簡單,比如我們要使能定時器 3,方法爲:

TIM_Cmd(TIM3, ENABLE); //使能 TIMx 外設

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

ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t)

該函數的作用是,判斷定時器 TIMx 的中斷類型 TIM_IT 是否發生中斷。比如,我們要判斷定時器 3 是否發生更新(溢出)中斷,方法爲:

if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET){}

固件庫中清除中斷標誌位的函數是:

void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT)

該函數的作用是,清除定時器 TIMx 的中斷 TIM_IT 標誌位。使用起來非常簡單,比如我們在TIM3 的溢出中斷髮生後,我們要清除中斷標誌位,方法是:

TIM_ClearITPendingBit(TIM3, TIM_IT_Update );

  這裏需要說明一下,固件庫還提供了兩個函數用來判斷定時器狀態以及清除定時器狀態標誌位的函數 TIM_GetFlagStatus 和 TIM_ClearFlag,他們的作用和前面兩個函數的作用類似。只是在 TIM_GetITStatus 函數中會先判斷這種中斷是否使能,使能了纔去判斷中斷標誌位,而
TIM_GetFlagStatus 直接用來判斷狀態標誌位。
中斷時間計算公式:

Tout= ((arr+1)*(psc+1))/Tclk;
Tclk: TIM3 的輸入時鐘頻率(單位爲 Mhz)。 72M
Tout: TIM3 溢出時間(單位爲 us)。

  關於在代碼裏面使用的LED燈代碼(點擊鏈接查看)我以前的博客。

main函數

#include "sys.h"
#include "delay.h"
#include "led.h"
#include "timer.h"
void time(int t)
{
	int i;
	while(t--)
	{
		for(i=0;i<120;i++);
	}
}
int main(void)
{			  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設置NVIC中斷分組2:2位搶佔優先級,2位響應優先級
	uart_init(9600);	 //串口初始化爲9600
  delay_init();	    	 //延時函數初始化
  LED_Init();
  TIM3_Int_Init(4999,7199); //10Khz 的計數頻率,計數到 5000 爲 500ms
	LED0=0;
	while(1{
	}

timer.c函數

#include "timer.h"
#include "led.h"

//通用定時器中斷初始化
//這裏時鐘選擇爲APB1的2倍,而APB1爲36M
//arr:自動重裝值。
//psc:時鐘預分頻數
//這裏使用的是定時器3!
void TIM3_Int_Init(u16 arr,u16 psc)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //時鐘使能APB1

	TIM_TimeBaseStructure.TIM_Period = arr; //設置在下一個更新事件裝入活動的自動重裝載寄存器週期的值	 計數到5000爲500ms
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //設置用來作爲TIMx時鐘頻率除數的預分頻值  10Khz的計數頻率  
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設置時鐘分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上計數模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根據TIM_TimeBaseInitStruct中指定的參數初始化TIMx的時間基數單位
 
	TIM_ITConfig(  //使能或者失能指定的TIM中斷
		TIM3, //TIM3
		TIM_IT_Update ,//更新中斷
		ENABLE  //使能
		);
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中斷
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先佔優先級0級
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //從優先級3級
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
	NVIC_Init(&NVIC_InitStructure);  //根據NVIC_InitStruct中指定的參數初始化外設NVIC寄存器

	TIM_Cmd(TIM3, ENABLE);  //使能TIMx外設 定時器使能
							 
}

void TIM3_IRQHandler(void)   //TIM3中斷
{ 
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //檢查指定的TIM中斷髮生與否:TIM 中斷源 
		{
			LED0=!LED0;   //定義的LED燈
			TIM_ClearITPendingBit(TIM3, TIM_IT_Update);  //清除TIMx的中斷待處理位:TIM 中斷源 
		}
}

timer.h頭文件

#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"

void TIM3_Int_Init(u16 arr,u16 psc); 
 
#endif

:代碼來源正點原子開發板。

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