STM32學習筆記(7)——通用定時器PWM輸出
1、TIMER輸出PWM基本概念
脈沖寬度調制(PWM),是英文“Pulse Width Modulation”的縮寫,簡稱脈寬調制,是利用微處理器的數字輸出來對模擬電路進行控制的一種非常有效的技術。簡單一點,就是對脈沖寬度的控制。一般用來控制步進電機的速度等等。
STM32的定時器除了TIM6和TIM7之外,其他的定時器都可以用來產生PWM輸出,其中高級定時器TIM1和TIM8可以同時產生7路的PWM輸出,而通用定時器也能同時產生4路的PWM輸出。
1.1 PWM輸出模式
STM32的PWM輸出有兩種模式,模式1和模式2,由TIMx_CCMRx寄存器中的OCxM位確定的(“
110:PWM模式1-在向上計數時,一旦TIMx_CNT<TIMx_CCR1時通道1為有效電平,否則為無效電平;在向下計數時,一旦TIMx_CNT>TIMx_CCR1時通道1為無效電平(OC1REF=0),否則為有效電平(OC1REF=1)。
111:PWM模式2-在向上計數時,一旦TIMx_CNT<TIMx_CCR1時通道1為無效電平,否則為有效電平;在向下計數時,一旦TIMx_CNT>TIMx_CCR1時通道1為有效電平,否則為無效電平。
由此看來,模式1和模式2正好互補,互為相反,所以在運用起來差別也並不太大。
而從計數模式上來看,PWM也和TIMx在作定時器時一樣,也有向上計數模式、向下計數模式和中心對齊模式,關於3種模式的具體資料,可以查看《STM32參考手冊》的“14.3.9 PWM模式”一節,在此就不詳細贅述了。
1.2 PWM輸出管腳
PWM的輸出管腳是確定好的,具體的引腳功能可以查看《STM32參考手冊》的“8.3.7 定時器復用功能重映射”一節。在此需要強調的是,不同的TIMx有分配不同的引腳,但是考慮到管腳復用功能,STM32提出了一個重映像的概念,就是說通過設置某一些相關的寄存器,來使得在其他非原始指定的管腳上也能輸出PWM。但是這些重映像的管腳也是由參考手冊給出的。比如說TIM3的第2個通道,在沒有重映像的時候,指定的管腳是PA.7,如果設置部分重映像之後,TIM3_CH2的輸出就被映射到PB.5上了,如果設置了完全重映像的話,TIM3_CH2的輸出就被映射到PC.7上了。
1.3 PWM輸出信號
PWM輸出的是一個方波信號,信號的頻率是由TIMx的時鐘頻率和TIMx_ARR預分頻器所決定的,具體設置方法在前面一個學習筆記中有詳細的交代。而輸出信號的占空比則是由TIMx_CRRx寄存器確定的。其公式為“占空比=(TIMx_CRRx/TIMx_ARR)*100%”,因此,可以通過向CRR中填入適當的數來輸出自己所需的頻率和占空比的方波信號。
2、TIMER輸出PWM實現步驟
1. 設置RCC時鐘;
2. 設置GPIO時鐘;
3. 設置TIMx定時器的相關寄存器;
4. 設置TIMx定時器的PWM相關寄存器。
第1步設置RCC時鐘已經在前文中給出了詳細的代碼,在此就不再多說了。需要註意的是通用定時器TIMx是由APB1提供時鐘,而GPIO則是由APB2提供時鐘。註意,如果需要對PWM的輸出進行重映像的話,還需要開啟引腳復用時鐘AFIO。
第2步設置GPIO時鐘時,GPIO模式應該設置為復用推挽輸出GPIO_Mode_AF_PP,如果需要引腳重映像的話,則需要用GPIO_PinRemapConfig()函數進行設置。
第3步設置TIMx定時器的相關寄存器時,和前一篇學習筆記一樣,設置好相關的TIMx的時鐘和技術模式等等。具體設置參看“TIMER基本定時功能”的學習筆記。
第4步設置PWM相關寄存器,首先要設置PWM模式(默認情況下PWM是凍結的),然後設置占空比(根據前面所述公式進行計算),再設置輸出比較極性:當設置為High時,輸出信號不反相,當設置為Low時,輸出信號反相之後再輸出。最重要是是要使能TIMx的輸出狀態和使能TIMx的PWM輸出使能。
相關設置完成之後,就可以通過TIM_Cmd()來打開TIMx定時器,從而得到PWM輸出了。
3、TIMER輸出PWM源代碼
由於我現在手上的奮鬥開發板是將PB.5接到LED上,因此需要使用TIM3的CH2通道,並且要進行引腳重映像。打開TIM3之後,PWM輸出,使得LED點亮,通過改變PWM_cfg()中的占空比可以調節LED的亮度。
#include "stm32f10x_lib.h" void RCC_cfg(); void GPIO_cfg(); void TIMER_cfg(); void PWM_cfg(); //占空比,取值範圍為0-100 int dutyfactor = 50; int main() { int Temp; RCC_cfg(); GPIO_cfg(); TIMER_cfg(); PWM_cfg(); //使能TIM3計時器,開始輸出PWM TIM_Cmd(TIM3, ENABLE); while(1); } void RCC_cfg() { //定義錯誤狀態變量 ErrorStatus HSEStartUpStatus; //將RCC寄存器重新設置為默認值 RCC_DeInit(); //打開外部高速時鐘晶振 RCC_HSEConfig(RCC_HSE_ON); //等待外部高速時鐘晶振工作 HSEStartUpStatus = RCC_WaitForHSEStartUp(); if(HSEStartUpStatus == SUCCESS) { //設置AHB時鐘(HCLK)為系統時鐘 RCC_HCLKConfig(RCC_SYSCLK_Div1); //設置高速AHB時鐘(APB2)為HCLK時鐘 RCC_PCLK2Config(RCC_HCLK_Div1); //設置低速AHB時鐘(APB1)為HCLK的2分頻 RCC_PCLK1Config(RCC_HCLK_Div2); //設置FLASH代碼延時 FLASH_SetLatency(FLASH_Latency_2); //使能預取指緩存 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //設置PLL時鐘,為HSE的9倍頻 8MHz * 9 = 72MHz RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //使能PLL RCC_PLLCmd(ENABLE); //等待PLL準備就緒 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //設置PLL為系統時鐘源 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //判斷PLL是否是系統時鐘 while(RCC_GetSYSCLKSource() != 0x08); } //開啟TIM3的時鐘 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //開啟GPIOB的時鐘和復用功能 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE); } void GPIO_cfg() { GPIO_InitTypeDef GPIO_InitStructure; //部分映射,將TIM3_CH2映射到PB5 // GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE); GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //選擇引腳5 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //輸出頻率最大50MHz GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //復用推挽輸出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOB,&GPIO_InitStructure); } void TIMER_cfg() { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //重新將Timer設置為缺省值 TIM_DeInit(TIM3); //采用內部時鐘給TIM3提供時鐘源 TIM_InternalClockConfig(TIM3); //預分頻系數為0,即不進行預分頻,此時TIMER的頻率為72MHz TIM_TimeBaseStructure.TIM_Prescaler = 0; //設置時鐘分割 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //設置計數器模式為向上計數模式 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //設置計數溢出大小,每計7200個數就產生一個更新事件,即PWM的輸出頻率為10kHz TIM_TimeBaseStructure.TIM_Period = 7200 - 1; //將配置應用到TIM3中 TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure); } void PWM_cfg() { TIM_OCInitTypeDef TimOCInitStructure; //設置缺省值 TIM_OCStructInit(&TimOCInitStructure); //PWM模式1輸出 TimOCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //設置占空比,占空比=(CCRx/ARR)*100%或(TIM_Pulse/TIM_Period)*100% TimOCInitStructure.TIM_Pulse = dutyfactor * 7200 / 100; //TIM輸出比較極性高 TimOCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //使能輸出狀態 TimOCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //TIM3的CH2輸出 TIM_OC2Init(TIM3, &TimOCInitStructure); //設置TIM3的PWM輸出為使能 TIM_CtrlPWMOutputs(TIM3,ENABLE); }
STM32學習筆記(7)——通用定時器PWM輸出