本文介紹如何使用STM32標准外設庫配置並使用定時器,定時器就是設置一個計時器,待計時時間到之后產生一個中斷,程序接收到中斷之后可以執行特定的程序,跟現實中的鬧鍾功能類似。與延時功能不同,定時器計時過程中程序可以執行其他程序。最簡單直觀的應用為定時翻轉指定IO引腳。本例程使用通用定時器TIM3,每100ms翻轉GPIOB的Pin5輸出,如果該引腳外接有LED燈,可以看到LED燈周期性的閃爍。
STM32F103VE系列共有8個定時器,分為基本定時器、通用定時器和高級定時器,其中通用定時器包括TIM2/3/4/5共4個,如果一個定時器不夠用,可以啟動其他幾個定時器。
本文適合對單片機及C語言有一定基礎的開發人員閱讀,MCU使用STM32F103VE系列。
TIM通用定時器分為兩部分,初始化和控制。
1. 初始化分兩步:通用中斷、TIM。
1.1. 通用中斷:優先級分組、中斷源、優先級、使能
- 優先級分組:設定合適的優先級分組
- 中斷源:選擇指定的TIM中斷源:TIM3_IRQn
- 優先級:設定合適的優先級
- 使能:調用庫函數即可
1.2. TIM:時鍾、預分頻器、定時器周期、分頻因子、計數模式、初始化定時器、開啟定時器中斷、使能計數器。
結構體:
typedef struct{ uint16_t TIM_Prescaler; uint16_t TIM_CounterMode; uint16_t TIM_Period; uint16_t TIM_ClockDivision; uint8_t TIM_RepetitionCounter; } TIM_TimeBaseInitTypeDef;
- 時鍾:需要使能定時器時鍾
//開啟定時器時鍾,即內部時鍾CK_INT=72M RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
- 預分頻器:默認定時器時鍾頻率為72M,那么預分頻器設置為71,那么一次計數為1us
//時鍾預分頻數為71,則計數器計數一次時間為1us TIM_TimeBaseStructure.TIM_Prescaler = 71;
- 定時器周期:設置為999,那么產生一次定時器中斷的時間為1ms
//自動重裝載寄存器為999,則產生一次中斷時間為1ms TIM_TimeBaseStructure.TIM_Period = 1000 - 1;
- 計數模式:一般選擇向上計數模式
// 計數器計數模式,選擇向上計數模式 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
- 時鍾分頻因子:一般選擇1分頻
// 時鍾分頻因子,選擇1分頻 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
- 重復計數器的值:僅對高級定時器有效,無需設置
- 初始化定時器:調用庫函數即可
//初始化定時器 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
- 開啟定時器中斷
//開啟計數器中斷 TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
- 使能計數器
//使能計數器 TIM_Cmd(TIM3, ENABLE);
2. 處理
2.1. 中斷服務函數
定時器TIM3的中斷服務函數名稱為TIM3_IRQHandler ()。
void TIM3_IRQHandler(void);
2.2. 中斷處理
中斷服務函數中調用TIM_GetITStatus ()函數判定中斷標志位狀態以確定中斷是否發生,調用TIM_ClearITPendingBit ()函數清除中斷標志位。
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM3, TIM_IT_Update); }
2.3. 計時
在定時器中斷服務函數中累加一個全局變量,在中斷外查詢該全局變量,如果達到預期的定時時間,則清除此全局變量,並執行相應的操作。
舉例來說,如果想要200ms執行某操作,那么該全局變量累加到200之后,將該全局變量置為0,然后再執行相應的操作。
完整代碼(僅自己編寫的部分)
1 uint8_t times; 2 3 void GPIO_OutputConfig(void) 4 { 5 //定義一個GPIO_InitTypeDef類型的結構體 6 GPIO_InitTypeDef GPIO_InitStructure; 7 8 //開啟指定端口的GPIO外設時鍾 9 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); 10 11 //選擇要控制的GPIO引腳 12 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; 13 14 //設置引腳速率為50MHz 15 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 16 17 //設置引腳模式為通用推挽輸出 18 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 19 20 //調用庫函數,初始化GPIO 21 GPIO_Init(GPIOB, &GPIO_InitStructure); 22 23 //設置初始狀態 24 GPIO_ResetBits(GPIOB, GPIO_Pin_5); 25 } 26 27 //中斷優先級配置 28 void TIM_NVICConfig(void) 29 { 30 NVIC_InitTypeDef NVIC_InitStructure; 31 32 // 設置中斷組為2 33 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 34 // 設置中斷來源為TIM3 35 NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn ; 36 // 設置搶占優先級為0 37 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 38 // 設置子優先級為3 39 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; 40 // 使能 41 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 42 43 NVIC_Init(&NVIC_InitStructure); 44 } 45 46 //TIM配置 47 void TIM_Config(void) 48 { 49 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 50 51 //開啟定時器時鍾,即內部時鍾CK_INT=72M 52 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); 53 54 //時鍾預分頻數為71,則計數器計數一次時間為1us 55 TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1; 56 57 //自動重裝載寄存器為999,則產生一次中斷時間為1ms 58 TIM_TimeBaseStructure.TIM_Period = 1000 - 1; 59 60 // 計數器計數模式,選擇向上計數模式 61 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 62 63 // 時鍾分頻因子,選擇1分頻 64 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 65 66 // 重復計數器的值,高級定時器有效 67 // TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; 68 69 //初始化定時器 70 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 71 72 //開啟計數器中斷 73 TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); 74 75 //使能計數器 76 TIM_Cmd(TIM3, ENABLE); 77 } 78 79 //定時器初始化函數 80 void TIM_Init(void) 81 { 82 TIM_Config(); 83 TIM_NVICConfig(); 84 } 85 86 //TIM3中斷服務函數 87 void TIM3_IRQHandler(void) 88 { 89 if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) 90 { 91 TIM_ClearITPendingBit(TIM3, TIM_IT_Update); 92 times++; 93 } 94 } 95 96 int main(void) 97 { 98 GPIO_OutputConfig(); 99 TIM_Init(); 100 101 //每100ms翻轉一次GPIOB pin5 102 while(1) 103 { 104 if(times == 100) 105 { 106 GPIO_SetBits(GPIOB, GPIO_Pin_5); 107 }else if(times >= 200){ 108 GPIO_ResetBits(GPIOB, GPIO_Pin_5); 109 times = 0; 110 } 111 } 112 }
仿真結果
程序編譯成功后,點擊開始仿真,點擊
,顯示邏輯分析窗口,點擊Setup,顯示設置串口,點擊新建
,然后輸入要查看的端口,可同時查看多個端口,比如要查看PORTB.5,那么輸入(PORTB & 0x00000020) >>5,Display type選擇Bit,Color中選擇合適的顏色,點擊Close關閉對話框,點擊
運行程序,可在邏輯分析串口看到該端口的波形。通過鼠標滾輪可對顯示波形進行縮放。
示例仿真波形如下:
從仿真結果來看,PORTB.5每隔100ms電平會翻轉一次,跟程序設計一致,因此TIM定時器有效。
源碼下載:(不包括工程文件和庫文件)
https://files.cnblogs.com/files/greatpumpkin/TIM_general.rar