- 開發環境:Window 7
- 開發工具:Keil uVision4
- 硬件:STM32F103VCT6
定時器最基本的功能就是定時處理事情。比如定時發送USART數據、定時採集AD數據、定時檢測IO口電位、還可以通過IO口輸出波形等。可以實現非常豐富的功能。
STM32系列的定時器分爲基本定時器、通用定時器、高級控制定時器。後者包括前者的全部功能。所以先掌握基本定時器可以更好理解後面功能繁多的定時器。
通常地,STM32高級定時器TIM1、TIM8,通用定時器TIM2、TIM3、TIM4、TIM5,基本定時器TIM6、TIM7。
有用過STM32的話都知道,STM32所有的外設初始化都是使用標準庫裏的初始化結構體和初始化函數,下面先說一下IM_TimeBaseInitTypeDef structure 結構體成員的含義。
TIM_TimeBaseInitTypeDef 定義於文件“stm32f10x_tim.h”:
typedef struct
{
u16 TIM_Period;
u16 TIM_Prescaler;
u8 TIM_ClockDivision;
u16 TIM_CounterMode;
u8 TIM_RepetitionCounter;
} TIM_TimeBaseInitTypeDef;
- TIM_Period:定時器週期,當計數寄存器的值遞增到等於該值時,將相關事件標誌位置位。範圍0~65535。
- TIM_Prescaler:定時器預分頻設置。時鐘源經該預分頻器纔是定時器時鐘。範圍0~65535。
- TIM_ClockDivision:時鐘分頻。基本定時器沒有這個功能,無需設置。
- TIM_CounterMode:定時器計數方式設置。基本定時器只能向上計數,無需設置。
- TIM_RepetitionCounter :重複計數器,基本定時器沒有這個功能,無需設置。
雖然定時器初始化結構體有5個成員,但是對於基本定時器只需設置其中兩個就可以了。下面是一個定時0.5s翻轉IO口電平的例子。
循環定時時間的計算:基本定時器只有內部時鐘72MHz,定時器的實際時鐘=內部時鐘/(定時器預分頻+1),那麼TIM_Prescaler設置爲7200-1,內部時鐘源經過定時器預分頻後即可得到10kHz(72MHz/((7200-1)+1))的頻率。然後TIM_Period設置爲5000-1,(這裏因爲計數是從0開始的,所以要減1),即可以得到定時爲0.5s(5000*(1/10kHz))的定時器。代碼如下:
創建一個TIME_base.h
#ifndef __TIMER_BASE_H
#define __TIMER_BASE_H
#include "stm32f10x.h"
void TIME_NVIC_Configuration(void);
void TIME_Configuration(void);
void GPIO_Config(void);
#endif
創建一個TIME_base.c
#include "TIME_base.h"
void TIME_NVIC_Configuration(void)//如果系統會產生多種中斷,那麼就存在中斷響應的優先級
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設置優先級分組
NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn; //指定IRQ通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //指定先佔優先級
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //從優先級
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //定義的IRQ是被使能還是失能
NVIC_Init(&NVIC_InitStructure);
}
void TIME_Configuration(void)//配置TIM6
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
TIM_TimeBaseStructure.TIM_Period = 5000; //設置了在下一個更新事件裝入活動的自動重裝載寄存器週期的值 範圍是0x0000-0xFFFF
TIM_TimeBaseStructure.TIM_Prescaler =(7200-1); //設置了用來作爲 TIMx 時鐘頻率除數的預分頻值
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM6,TIM_IT_Update|TIM_IT_Trigger,ENABLE);//使能或者失能 TIM 的中斷,詳見附錄圖1
TIM_Cmd(TIM6, ENABLE);
}
void GPIO_Config(void)//配置一個IO口:
{
/*定義一個GPIO_InitTypeDef類型的結構體*/
GPIO_InitTypeDef GPIO_InitStructure;
/*開啓GPIOB的外設時鐘*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/*選擇要控制的GPIOB引腳*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
/*設置引腳模式爲通用推輓輸出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/*設置引腳速率爲50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/*調用庫函數,初始化GPIOB*/
GPIO_Init(GPIOB, &GPIO_InitStructure);
/*PB.0 輸出高*/
GPIO_SetBits(GPIOB,GPIO_Pin_0);
}
附錄圖1:
在stm32f10x_it.c添加定時器觸發的中斷處理函數:
void TIM6_IRQHandler(void)
{
if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET) //獲取中斷狀態
{
TIM_ClearITPendingBit(TIM6, TIM_IT_Update ); //清除中斷標誌
//在這裏做中斷需要處理的事情,儘可能精簡,避免過長時間停留在中斷裏面
GPIO_WriteBit(GPIOB, GPIO_Pin_0, (BitAction)(1-(GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_0))));
}
}
創建一個main.c
#include "TIME_base.h"
int main(void)
{
/* IO端口配置 */
GPIO_Config();
/* TIM6 定時配置 */
TIME_NVIC_Configuration();
TIME_Configuration();
while(1){
}
}
將上面的TIM6全部換成TIM7也是可以的。
然後就可以把編譯好的程序下載到開發板了,可以在PB.0引腳處接一個led,那麼led就會每0.5s閃爍一次。
水平有限,僅供參考,錯誤以及不足之處還望多多指教。