目錄
一、定時器
(一)定時器簡介
(二)定時器類型
1、常見定時器
2、定時器的主要功能
3、常規定時器
(三)定時器配置
1、定時器標準外設庫接口函數
2、定時器標準外設庫配置
二、PWM
(一)PWM簡介
1、介紹及其功能
2、占空比
(二)PWM的工作原理
1、產生PWM的定時器:
2、產生PWM的原因:
3、PWM的工作原理解釋
(三)PWM標準外設庫輸出配置過程
三、實際應用
(一)關于定時器的題目
1、題目要求
2、代碼
3、實物效果
(二)關于PWM的題目
1、題目要求
2、代碼
3、Keil波形圖?編輯
4、實物效果
四、總結
一、定時器
(一)定時器簡介
????????STM32定時器是STM32微控制器中的重要塊,用于生成精確的時間基準。它可以用于測量時間間隔、產生脈沖、實現定時中斷等功能。通過配置寄存器,用戶可以靈活地控制定時器的工作模式和參數,實現各種實時控制和定時任務。????????
(二)定時器類型
1、常見定時器
- SysTick定時器:
SysTick系統時鐘位于Cortex-M3內核,是一個24位的遞減計數器,主要用于:
1)精確延時,在多任務操作系統中為系統提供時間基準(時基);
2)任務切換,為每個任務分配時間片。
- WatchDog定時器:
1)作用:當微控制器受到外部干擾或程序中出現不可預知的邏輯故障導致應用程序脫離正常的執行流程時(俗稱程序跑飛),在一定的時間間隔內使系統復位,回到初始狀態;
2)看門狗設計是用來監視MCU程序運行狀態的,是確保系統可靠穩定運行的一種有效措施。
WatchDog又可以分為獨立看門狗和窗口看門狗,區別如下:
獨立看門狗:采用獨立時鐘,不受其他時鐘和總線影響,可在停機和待機模式下工作。適用于獨立于主程序之外、能夠獨立工作且對時間精度要求不高的場合。
窗口看門狗:計數值有一個上限時間和下限時間,低于下限時間或高于上限時間都會觸發MCU復位。適用于精確計時窗口起作用的應用程序。
- 基本定時器(下方重點介紹):TIM6和TIM7。
- 通用定時器(下方重點介紹):TIM2、TIM3、TIM4和TIM5。
- 高級定時器(下方重點介紹):TIM1和TIM8。
2、定時器的主要功能
- 計數:脈沖計數,使用使用微控制器內部的外部時鐘(PCLK)來計數,是對固定周期的脈沖信號計數。
- 定時:時間控制,通過對微控制器內部的時鐘脈沖進行計數實現定時功能。
- 輸入捕獲:對輸入信號進行捕獲,實現對脈沖的頻率測量,可用于對外部輸入信號脈沖寬度的測量,比如測量電機轉速。
- 輸出比較:將計數器計數值和設定值進行比較,根據比較結果輸出不同電平,用于控制輸出波形,比如直流電機的調速。
3、常規定時器
STM32定時器分類比較表
(1)基本定時器
簡介:
STM32有2個基本定時器TIM6和TIM7,可用作: 通用的16位計數或者 產生DAC觸發信號,基本定時器的計數模式只有向上計數模式。
(2)通用定時器
簡介:
????????TIM2、TIM3、TIM4、TIM5為STM32的4個獨立的16位通用定時器,具有定時、測量輸入信號的脈沖長度(輸入捕獲)、輸出所需波形(輸出比較、產生PWM、單脈沖輸出等)等功能。如下圖為通用定時器內部結構框圖。
????????STM32F103系列微控制器的定時器功能十分強大,內部結構也比較復雜,STM32通用定時器TIMx(x=2,3,4,5)主要由時鐘源、時鐘單元、捕獲和比較通道等構成,核心是可編程預分頻驅動的16位自動裝載計數器。通過對通用定時器內部結構進一步簡化得到如下圖所示的內部簡化圖:
通用定時器相關參數:
1)通用定時器的時鐘源:
如下圖為通用定時器框圖中有關時鐘源的部分:
當定時器使用內部時鐘時,定時器的時鐘源統稱為TIMxCLK。雖然在系統默認的配置中,TIMxCLK的時鐘頻率都是72MHz,但其時鐘來源并不相同。
- 定時器TIM2~TIM7掛接在APB1上
- 定時器TIM1和TIM8掛接在APB2上
若外部晶振的頻率為8MHz,則系統默認的時鐘頻率為72MHz
- APB1預分頻器的分頻系數設置為2,則PCLK1=36MHz;
- APB2預分頻系數設置為1,則PCLK2=72MHz,TIM1和TIM8的時鐘頻率TIMxCLK=72MHz;
- Cortex系統時鐘由AHB時鐘(HCLK)8分頻得到,即SysTick的頻率為9MHz。
2)預分頻器PSC:
如圖為預分頻器時序圖:
簡介:
PSC參數代表預分頻器(Prescaler)。預分頻器用于將定時器的時鐘頻率分頻,以便獲得所需的計數頻率。在定時器工作時,計數器將以預分頻器所設定的頻率遞增,直到達到設定的自動重載值(ARR,Auto-Reload Register)為止,然后重新開始計數。
限制:可以以1~65535之間的任意數值對時鐘源CK_PSC的時鐘頻率進行分頻,輸出CK_CNT脈沖供計數器CNT進行計數。
計數器計數頻率計算公式:CK_CNT = CK_PSC / (PSC + 1)
3)計數器CNT:
如圖為計數器時序圖:
簡介:
- TIMxCNT是一個16位的寄存器,計數范圍為1~65535,可以向上計數、向下計數或向下向上雙向計數。
- 要得到想要的計數值,需要對輸入時鐘頻率進行分頻。
- 當計數值達到設定值時,便產生溢出事件,溢出時產生中斷或DMA請求,然后再由自動裝載寄存器進行重新加載或更新。
- 計數器溢出中斷屬于軟件中斷,執行相應的定時器中斷服務程序。、
計數器溢出頻率計算公式:CK_CNT_OV = CK_CNT / (ARR + 1) ?? ??? ??? ??? ??? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? = CK_PSC / (PSC + 1) / (ARR + 1)
4)自動裝載寄存器ARR
定時器的定時時間主要取決于定時周期和預分頻因子,這里ARR+1是因為計數器都是從0開始計數的。計算公式為:
定時時間=(ARR+1)×(預分頻值PSC+1)/輸入時鐘頻率? 或者??
T=(TIM_Period +1)*(TIM_Prescaler +1)/TIMxCLK
例如下方實踐中要求延時2秒閃爍及定時器設為2s,假設系統時鐘為72MHz,通用定時器時鐘TIMxCLK為72MHz,設置如下:
預分頻系數PSC=6000-1;?? ?ARR=4000-1;
則,定時時間=4000×36000/72000000=2s。
(3)高級定時器
簡介:TIM1和TIM8是STM32的2個16位的高級定時器,高級定時器相比基本定時器、通用定時器,功能更為強大? ?
功能: 高級定時器除了通用定時器的功能外,還支持更高級的特性,如相位鎖定回路(PLL)、編碼器接口、三角波生成等。
用途場景: 適用于需要更高級、復雜計時功能的應用,例如音頻處理、電機控制、編碼器接口等。重復計數器、死區生成、互補輸出、剎車輸入等功能。
(三)定時器配置
1、定時器標準外設庫接口函數
簡介:
STM32F103系列微控制器的定時器庫函數存放在STM32標準外設庫的stm32f10x_tim.c和stm32f10x_tim.h文件中,stm32f10x_tim.h頭文件中聲明了定時器有關的庫函數以及相關的宏定義、結構體等。由于STM32的定時器功能較為強大,其庫函數也較多,如下圖所示:
TIM_TimeBaseInit()庫函數
用于定時器TIMx的參數初始化,函數原型:
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);typedef struct
{uint16_t TIM_Prescaler; uint16_t TIM_CounterMode; uint16_t TIM_Period; uint16_t TIM_ClockDivision; uint8_t TIM_RepetitionCounter;
} TIM_TimeBaseInitTypeDef;
其中
(1)typedef struct(第二行)是被定義在定義在stm32f10x_tim.h頭文件中。
(2)uint16_t TIM_Prescaler(第四行),TIMx預分頻寄存器TIMx_PSC的值,數值上等于TIMx計數器TIMxCNT的預分頻系數減1
(3)uint8_t TIM_RepetitionCounter(第八行),為TIM1和TIM8高級定時器所特有。
(4)TIM_CounterMode(第五行):TIMx計數器TIMxCNT的計數模式分為向上計數和向下計數以及三種中央對其模式計數。
- TIM_CounterMode_Up:向上計數模式,從0遞增,計到TIMx_ARR計數器的自動裝載值,并產生計數溢出脈沖
- TIM_CounterMode_Down:向下計數模式,從TIMx_ARR計數器的自動裝載值遞減,計到0,并產生計數溢出脈沖
- TIM_CounterMode_CenterAligned1:中央對齊模式1計數器交替地向上和向下計數,輸出比較中斷標志位,只在計數器向下計數時被設置;
- TIM_CounterMode_CenterAligned2:中央對齊模式2計數器交替地向上和向下計數,輸出比較中斷標志位,只在計數器向上計數時被設置;
- TIM_CounterMode_CenterAligned3:中央對齊模式3計數器交替地向上和向下計數,輸出比較中斷標志位,在計數器向下和向上計數時均可被設置。
(5)?uint16_t TIM_Period(第六行); ?下一個更新事件時裝入自動重裝載寄存器TIMx_ARR的周期值,數值上等于TIMx計數器TIMxCNT的計數周期減1。
- ? TIM_Period是一個16位無符號整型數據,取值范圍為0~65535。 ? ?
- ?定時器定時時間主要取決于預分頻因子TIM_Prescaler和定時周期TIM_Period
T=(TIM_Prescaler+1)*(TIM_Period+1)/TIMxCLK ? ?
- TIMxCLK為定時器TIMx的時鐘頻率,STM32F103的TIMxCLK默認設置為72MHz。
(6)?uint16_t TIM_ClockDivision(第七行);?與TIMx_CR寄存器中bit[9:8]的CKD[1:0]對應,用于計數器工作模式時濾除高頻干擾,有如下選擇:
- “00”——采樣頻率基準fDTS=定時器輸入頻率fCK_INT;
- “01”——fDTS=fCK_INT/2;
- “10”——fDTS=fCK_INT/4。
2、定時器標準外設庫配置
(1)步驟一:TIM2時鐘使能
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
(2)步驟二:初始化定時器參數,設置自動重裝值,分頻系數,計數方式
定時器初始化使用TIM_TimeBaseInit()函數,如下所示:
void TIM_TimeBaseInit(TIM_TypeDef*TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
- 第一個參數TIMx是具體定時器,x可為2~4
- 第二個參數為TimeBaseInitStruct結構體指針。
下面以初始化通用定時器TIM2為例,進行以下配置:
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //定義TIM初始化類型結構體變量
TIM_TimeBaseStructure.TIM_Period = (36000-1); //設置自動重載計數周期值
TIM_TimeBaseStructure.TIM_Prescaler = (4000-1); //設置分頻系數
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //設置時鐘分頻因子
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //設置為向上計數方式
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure); //初始化定時器TIM2
TIM_Cmd(TIM2,ENABLE); //使能TIM2定時器
(3)步驟三:設置TIM2允許更新中斷
為了避免在初始化定時器時進入中斷,需要在初始化過程中清除中斷標志。中斷在使用前必須先使能再使用,如使能定時器TIM2的更新模式中斷,則調用庫函數TIM_ITConfig(),函數原型為:
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);
其中:
- 第一個參數TIMx是具體定時器,x可為2~4。
- 第二個參數用來指明所使能定時器的中斷類型。
- 第三個參數為TIMx中斷的狀態,該參數可取值為ENABLE(使能)或者DISABLE(失能)。
(4)步驟四:TIM2中斷優先級設置
如圖為定時中斷基本結構
結合先前學習的中斷編程,參考博客:中斷編程入門-CSDN博客??????
對TIM2中斷做如下所示的配置:
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
(5)步驟五:使能TIM2
使用TIM_Cmd()函數使能相應的定時器,其函數原型為:
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState) ;
其中:
- 第一個參數TIMx是具體定時器,x可為2~4
- 第二個參數為TIMx的狀態,該參數可取值為ENABLE(使能)或者DISABLE(失能)
例如,使能定時器TIM2的更新中斷,配置如下:? ? ? ? ? ? ??
?TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
(6)步驟六:編寫中斷服務函數
STM32標準外設庫函數中用來讀取中斷狀態的庫函數為:
ITStatus TIM_GetITStatus (TIM_TypeDef* TIMx, uint16_t) ;
清除定時器相應中斷標志位的函數為:
void TIM_ClearITPendingBit (TIM_TypeDef* TIMx, uint16_t TIM_IT) ;
?例如想要通過定時器設定某時間后GPIOA5引腳的燈反轉,則中斷服務函數如下所示:
void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){GPIO_WriteBit(GPIOA,GPIO_Pin_5,(BitAction)((1- GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_5))));TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}
因此我們可以得到一個TIM2中斷服務函數的模板以便以后使用時可以直接填入。
/* 定時器中斷函數,可以復制到使用它的地方
void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}
*/
二、PWM
(一)PWM簡介
PWM基本結構
1、介紹及其功能
????????PWM(Pulse Width Modulation,脈沖寬度調制)是一種利用脈沖寬度即占空比實現對模擬信號進行控制的技術,即是對模擬信號電平進行數字表示的方法。
????????廣泛應用于電力電子技術中,比如PWM控制技術在逆變電路中的應用;PWM還應用于直流電機調速,如變頻空調的交直流變頻調速,除實現調速外,還具有節能等特性。
下圖是一個周期為10ms(頻率為100Hz)的PWM波形圖
2、占空比
占空比(Duty Cycle),是指在一個周期內,高電平時間占整個信號周期的百分比,即高電平時間與周期的比值: 占空比=Tp/T。
(二)PWM的工作原理
1、產生PWM的定時器:
- 在STM32的定時器中除了TIM6和TIM7,其他定時器都可以用來產生PWM輸出;
- 高級定時器TIM1和TIM8可以同時產生多達7路的PWM輸出;
- 通用定時器能同時產生多達4路的PWM輸出
2、產生PWM的原因:
- STM32中每個定時器有4個輸入通道:TIMx_CH1~TIMx_CH4;
- 每個通道對應1個捕獲/比較寄存器TIMx_CRRx,將寄存器值和計數器值相比較,通過比較結果輸出高低電平,從而得到PWM信號;
- 脈沖寬度調制模式可以產生一個由TIMx_ARR寄存器確定頻率、由TIMx_CCRx寄存器確定占空比的信號。
3、PWM的工作原理解釋
- 在PWM的一個周期內,定時器從0開始向上計數,在0-t1時間段,定時器計數器TIMx_CNT值小于TIMx_CCRx值,輸出低電平;
- 在t1-t2時間段,定時器計數器TIMx_CNT值大于TIMx_CCRx值,輸出高電平;
- 當定時器計數器的值TIMx_CNT達到ARR時,定時器溢出,重新從0開始向上計數,如此循環。
(三)PWM標準外設庫輸出配置過程
(1)步驟一:配置PWM輸出通道,開啟TIM2時鐘
STM32規定了具體的引腳作為PWM輸出引腳,選擇不同的引腳時,還必須使用重定向功能(Remap)。
定時器TIM1的引腳復用功能映像:
?定時器TIM2的引腳復用功能映像:
定時器TIM3的引腳復用功能映像:
- 使用定時器3的通道2(TIM2_CH1)作為PWM的輸出引腳;
- 對PA0引腳進行配置,配置PA0為復用推挽輸出模式(GPIO_Mode_AF_PP)代碼如下所示:
/*開啟時鐘*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //開啟TIM2的時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //開啟GPIOA的時鐘/*GPIO重映射*/
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //開啟AFIO的時鐘,重映射必須先開啟AFIO的時鐘
// GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE); //將TIM2的引腳部分重映射,具體的映射方案需查看參考手冊
// GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //將JTAG引腳失能,作為普通GPIO引腳使用/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);
(2)步驟二:初始化定時器TIM2
設置預分頻系數PSC、自動重載計數值ARR、計數模式、時鐘分割等,代碼如下所示。下方實驗中要求呼吸燈的周期為1~2s,且設置為向上計數法則如下配置。
/*配置時鐘源*/TIM_InternalClockConfig(TIM2); //選擇TIM2為內部時鐘,若不調用此函數,TIM默認也為內部時鐘/*時基單元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定義結構體變量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //時鐘分頻,選擇不分頻,此參數用于配置濾波器時鐘,不影響時基單元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //計數器模式,選擇向上計數TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //計數周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //預分頻器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重復計數器,高級定時器才會用到TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //將結構體變量交給TIM_TimeBaseInit,配置TIM2的時基單元
(3)步驟三:設置TIM2_CH1的PWM模式,使能TIM2的CH1輸出
如下配置TIM2_CH1的PWM模式使能TIM2的CH1能夠正常輸出,配置情況如下所示:
TIM_OCInitTypeDef TIM_OCInitStructure; //定義結構體變量TIM_OCStructInit(&TIM_OCInitStructure); //結構體初始化,若結構體沒有完整賦值//則最好執行此函數,給結構體所有成員都賦一個默認值//避免結構體初值不確定的問題TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //輸出比較模式,選擇PWM模式1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //輸出極性,選擇為高,若選擇極性為低,則輸出高低電平取反TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //輸出使能TIM_OCInitStructure.TIM_Pulse = 0; //初始的CCR值TIM_OC1Init(TIM2, &TIM_OCInitStructure); //將結構體變量交給TIM_OC1Init,配置TIM2的輸出比較通道1
(4)步驟四:使能定時器TIM2
?最后使能TIM2,定時器開始運行:
TIM_Cmd(TIM2, ENABLE);
三、實際應用
(一)關于定時器的題目
1、題目要求
使用STM32F103的 Tim2~Tim5其一定時器的某一個通道pin(與GPIOx管腳復用,見下圖),連接一個LED,用定時器計數方式,控制LED以2s的頻率周期性地亮-滅。
2、代碼
(1)Timer.c
#include "stm32f10x.h" // Device header/*** 函 數:定時中斷初始化* 參 數:無* 返 回 值:無*/
void Timer_Init(void)
{/*開啟時鐘*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //開啟TIM2的時鐘/*配置時鐘源*/TIM_InternalClockConfig(TIM2); //選擇TIM2為內部時鐘,若不調用此函數,TIM默認也為內部時鐘/*時基單元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定義結構體變量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //時鐘分頻,選擇不分頻,此參數用于配置濾波器時鐘,不影響時基單元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //計數器模式,選擇向上計數TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1; //計數周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1; //預分頻器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重復計數器,高級定時器才會用到TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //將結構體變量交給TIM_TimeBaseInit,配置TIM2的時基單元 /*中斷輸出配置*/TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除定時器更新標志位//TIM_TimeBaseInit函數末尾,手動產生了更新事件//若不清除此標志位,則開啟中斷后,會立刻進入一次中斷//如果不介意此問題,則不清除此標志位也可TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //開啟TIM2的更新中斷/*NVIC中斷分組*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC為分組2//即搶占優先級范圍:0~3,響應優先級范圍:0~3//此分組配置在整個工程中僅需調用一次//若有多個中斷,可以把此代碼放在main函數內,while循環之前//若調用多次配置分組的代碼,則后執行的配置會覆蓋先執行的配置/*NVIC配置*/NVIC_InitTypeDef NVIC_InitStructure; //定義結構體變量NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //選擇配置NVIC的TIM2線NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC線路使能NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //指定NVIC線路的搶占優先級為2NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定NVIC線路的響應優先級為1NVIC_Init(&NVIC_InitStructure); //將結構體變量交給NVIC_Init,配置NVIC外設/*TIM使能*/TIM_Cmd(TIM2, ENABLE); //使能TIM2,定時器開始運行
}/* 定時器中斷函數,可以復制到使用它的地方
void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}
*/
(2)LED.c
#include "stm32f10x.h" // Device headervoid LED_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);
}
?(3)main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "Timer.h"
#include "LED.h"int main(void)
{LED_Init();Timer_Init(); while (1){}
}void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){GPIO_WriteBit(GPIOA,GPIO_Pin_5,(BitAction)((1- GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_5))));TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}
3、實物效果
定時器控制LED
(二)關于PWM的題目
1、題目要求
采用定時器PWM模式,讓 LED 以呼吸燈方式漸亮漸滅,周期為1~2秒,自己調整占空比變化到一個滿意效果;使用Keil虛擬示波器,觀察 PWM輸出波形。
2、代碼
(1)PWM.c
#include "stm32f10x.h" // Device header/*** 函 數:PWM初始化* 參 數:無* 返 回 值:無*/
void PWM_Init(void)
{/*開啟時鐘*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //開啟TIM2的時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //開啟GPIOA的時鐘/*GPIO重映射*/
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //開啟AFIO的時鐘,重映射必須先開啟AFIO的時鐘
// GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE); //將TIM2的引腳部分重映射,具體的映射方案需查看參考手冊
// GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //將JTAG引腳失能,作為普通GPIO引腳使用/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIO_Pin_15;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure); //將PA0引腳初始化為復用推挽輸出 //受外設控制的引腳,均需要配置為復用模式 /*配置時鐘源*/TIM_InternalClockConfig(TIM2); //選擇TIM2為內部時鐘,若不調用此函數,TIM默認也為內部時鐘/*時基單元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定義結構體變量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //時鐘分頻,選擇不分頻,此參數用于配置濾波器時鐘,不影響時基單元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //計數器模式,選擇向上計數TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //計數周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //預分頻器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重復計數器,高級定時器才會用到TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //將結構體變量交給TIM_TimeBaseInit,配置TIM2的時基單元/*輸出比較初始化*/TIM_OCInitTypeDef TIM_OCInitStructure; //定義結構體變量TIM_OCStructInit(&TIM_OCInitStructure); //結構體初始化,若結構體沒有完整賦值//則最好執行此函數,給結構體所有成員都賦一個默認值//避免結構體初值不確定的問題TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //輸出比較模式,選擇PWM模式1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //輸出極性,選擇為高,若選擇極性為低,則輸出高低電平取反TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //輸出使能TIM_OCInitStructure.TIM_Pulse = 0; //初始的CCR值TIM_OC1Init(TIM2, &TIM_OCInitStructure); //將結構體變量交給TIM_OC1Init,配置TIM2的輸出比較通道1/*TIM使能*/TIM_Cmd(TIM2, ENABLE); //使能TIM2,定時器開始運行
}/*** 函 數:PWM設置CCR* 參 數:Compare 要寫入的CCR的值,范圍:0~100* 返 回 值:無* 注意事項:CCR和ARR共同決定占空比,此函數僅設置CCR的值,并不直接是占空比* 占空比Duty = CCR / (ARR + 1)*/
void PWM_SetCompare1(uint16_t Compare)
{TIM_SetCompare1(TIM2, Compare); //設置CCR1的值
}
(2)main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "PWM.h"uint8_t i; //定義for循環的變量int main(void)
{/*模塊初始化*/PWM_Init(); //PWM初始化while (1){for (i = 0; i <= 100; i++){PWM_SetCompare1(i); //依次將定時器的CCR寄存器設置為0~100,PWM占空比逐漸增大,LED逐漸變亮Delay_ms(15); //延時500ms}for (i = 0; i <= 100; i++){PWM_SetCompare1(100 - i); //依次將定時器的CCR寄存器設置為100~0,PWM占空比逐漸減小,LED逐漸變暗Delay_ms(15); //延時500ms}}
}
3、Keil波形圖
4、實物效果
呼吸燈
四、總結
學習完定時器相關內容,就像掌握了一個鬧鐘。通過自己設定時間,當時間走完則自動運行預先選擇做出的行動,為以后的單片機開發提供了一個新的思路。在學習了PWM之后,發現原來點燈也變得有趣起來了,可以通過賦予脈沖使得燈逐亮逐滅,為后續學習舵機等外設打好了基礎。