簡介:STM32一共有8個通用16位Timer,其中TIMER1和TIMER8是高級定時器,其它的TIMER2~TIMER7是普通定時器。此外還有一個Systick(系統滴答定時器),這個定時器通常在操作系統中作為系統的任務切換周期。還有一個RTC,是一個毫秒定時器,支持秒級中斷,用來做實時時鐘計數器。看門狗定時器 也可以算一個。
8個定時器中,Timer1 和Timer8是由APB2(輸出最高頻率為72MHZ)預分頻后,再通過一個倍頻器得到時鐘頻率,最高為72MHz。Timer2~Timer7則是由APB1(輸出最高頻率為36MHZ)預分頻后,再通過一個倍頻器得到時鐘頻率,最高為36MHz。
1、如何進行程序編寫
這里我通過定時器來控制一個LED亮0.5s 滅0.5s ,交替閃爍。當然要讓定時器正常工作起來,還要配置中斷NVIC。定時器計數到某個數,產生中斷,從而進入中斷服務程序,點亮LED燈。
main函數分析:
#include "stm32f10x.h"
void GPIO_Config(void)//GPIO配置
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//使能gpioc的時
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //選擇管腳PC.13作LED燈
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管腳速度為50M
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //設置輸出模式為推挽輸出
GPIO_Init(GPIOC, &GPIO_InitStructure); //將上述設置寫入到GPIOC里去
}
void NVIC_Config(void) //中斷控制器的配置
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //優先組設置
NVIC_InitStructure.NVIC_IRQChannel =TIM2_IRQn ; //TIM2中斷選通
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //搶占優先級
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子優先級
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中斷控制
NVIC_Init(&NVIC_InitStructure);
}
void Timer_Config(void) //定時器的配置
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE); //Timer2 時鐘使能
TIM_DeInit(TIM2); //復位TIM2定時器
TIM_TimeBaseStructure.TIM_Period=1000; //定時器周期
TIM_TimeBaseStructure.TIM_Prescaler=36000-1; //預分頻數
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; //TIM2時鐘分頻,為1表示不分頻
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;//定時器計數為向上計數模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除定時器2的溢出標志位
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); //使能定時器2溢出中斷
TIM_Cmd(TIM2, ENABLE); //定時器2使能
}
int main(void)
{
SystemInit();//初始化時鐘,配置為72MHz,我試過將這句注釋掉,好像不影響結果。查
了一下,在配置
//main函數之前的啟動代碼有這樣一句 LDR R0, =SystemInit,我疑惑的是難
道啟動的時候就配成72Mhz?
GPIO_Config();
NVIC_Config();
Timer_Config();
while(1)
{
;
}
}
中斷服務函數
void TIM2_IRQHandler(void)
{
static int flag_bit=0;//定義一個標志位
if ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET ) //判斷中斷溢出標志為是否為1
{
TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update); //清除溢出中斷標志位
flag_bit = !flag_bit;
if(flag_bit == 1)
GPIO_SetBits(GPIOC, GPIO_Pin_13); //熄滅LED
if(flag_bit == 0)
GPIO_ResetBits(GPIOC, GPIO_Pin_13); //點亮LED
}
這個函數是寫在stm32f10x_it.c 里面的,我對TIM2_IRQHandler()函數的理解應該是這樣的:
首先由定時器定時,定時好了產生中斷溢出標志位,發送中斷
然后進入中斷服務函數TIM2_IRQHandler(),進入函數之后要做的就是清除中斷溢出
標志位。
最后再執行函數里的其他內容。
定時器定時時間計算是這兩句:
TIM_TimeBaseStructure.TIM_Period=1000; //定時器周期
TIM_TimeBaseStructure.TIM_Prescaler=36000-1; //預分頻數
Prescaler可以理解為定時器的基數是72M / Prescaler+1 = 2000k,也就是500us ,Period 可以理解為要計數多少次,這里是1000次。 所以就是每500us記一次,計數1000次,就是500ms。
公式為:
Period / (72M / (Prescaler+1) )=____ 秒
1000 / (72 M/ (35999+1) ) = 0.5 秒
我有的一些疑問:1、進入中斷函數之后,定時器要干些什么,是不是就停止計數了?
2、計數記到1000發生中斷,計數值是不是有自動清零
問題先放到這兒,邊學習,邊解決。
2、仿真結果觀察
前面第三章已經過如何仿真波形的步驟,可以參看前面。點擊setup 按鈕 會彈出一個窗口,在窗口的右上邊,有個new的按鈕,點擊后輸入 PORTC.13
仿真運行結果如下:
可以從仿真結果中觀察到,方波的周期為一秒。占空比為0.5 ,跟預期一致。
3、對第四章串口的補充
第四章介紹了串口的打印函數printf 是如何調用實現的。但要使用keil自帶的微庫microLIB ,那能不能不使用這個微庫呢。我參照野火的教程,修改了程序,自己編寫usart_printf()函數來實現打印的功能。
USRT1的配置不改變,主要的就是添加打印函數實現串口輸出功能。代碼感覺可能很長,但無非就是一些判斷,看看字符串最后一位是不是 主站蜘蛛池模板: 富顺县| 灵丘县| 衡阳市| 长海县| 双鸭山市| 雅江县| 读书| 宁安市| 商城县| 揭西县| 莆田市| 四子王旗| 长垣县| 会理县| 东兰县| 石河子市| 屯留县| 孝义市| 珲春市| 永丰县| 平和县| 邵东县| 黑河市| 台中县| 龙里县| 攀枝花市| 余干县| 壶关县| 江安县| 成都市| 宜城市| 长汀县| 泾川县| 东莞市| 邹平县| 江源县| 沐川县| 郓城县| 台中县| 蕲春县| 商洛市|