(stm32f103學習總結)—stm32 PMW輸出實驗


一.PWM簡介

  PWM是 Pulse Width Modulation 的縮寫,中文意思就是脈沖寬度調 制,簡稱脈寬調制。它是利用微處理器的數字輸出來對模擬電路進行控 制的一種非常有效的技術,其控制簡單、靈活和動態響應好等優點而成 為電力電子技術最廣泛應用的控制方式,其應用領域包括測量,通信, 功率控制與變換,電動機控制、伺服控制、調光、開關電源,甚至某些 音頻放大器,因此學習PWM具有十分重要的現實意義。 其實我們也可以這樣理解,PWM是一種對模擬信號電平進行數字編碼 的方法。通過高分辨率計數器的使用,方波的占空比被調制用來對一個 具體模擬信號的電平進行編碼。PWM 信號仍然是數字的,因為在給定的 任何時刻,滿幅值的直流供電要么完全有(ON),要么完全無(OFF)。電壓 或電流源是以一種通(ON)或斷(OFF)的重復脈沖序列被加到模擬負載上去 的。通的時候即是直流供電被加到負載上的時候,斷的時候即是供電被 斷開的時候。只要帶寬足夠,任何模擬值都可以使用 PWM 進行編碼。

 

 

二.STM32F1 PWM介紹

  STM32F1除了基本定時器TIM6和TIM7,其他定時器都可以產生PWM輸出 。其中高級定時器 TIM1 和 TIM8 可以同時產生多達 7 路的 PWM 輸出 。而通用定時器也能同時產生多達 4路的 PWM 輸出,這些在定時器中斷 章節中已經介紹過。 PWM的輸出其實就是對外輸出脈寬可調(即占空比調節)的方波信號 ,信號頻率是由自動重裝寄存器 ARR 的值決定,占空比由比較寄存器 CCR 的值決定。

 

 

  PWM輸出比較模式總共有8種,具體由寄存器 CCMRx 的位 OCxM[2:0] 配置。我們這里只講解最常用的兩種PWM輸出模式:PWM1和PWM2,其他幾 種模式可以參考《STM32F10x中文參考手冊》13、14、15定時器章節。

  PWM1和PWM2這兩種模式用法差不多,區別之處就是輸出電平的極性不 同。

   PWM模式根據計數器CNT計數方式,可分為邊沿對齊模式和中心對齊模 式。

(1)PWM邊沿對齊模式

  當 TIMx_CR1 寄存器中的 DIR 位為低時執行遞增計數,計數器CNT從 0 計數到自動重載值(TIMx_ARR 寄存器的內容),然后重新從 0 開始 計數並生成計數器上溢事件。 以 PWM 模式 1 為例。只要TIMx_CNT < TIMx_CCRx, PWM 參考信號 OCxREF 便為有效的高電平,否則為無效的低電平。如果 TIMx_CCRx 中 的比較值小於自動重載值(TIMx_ARR 中),則 OCxREF 保持為“ 1”。 如果比較值為 0, 則 OCxREF 保持為“ 0”。

   當 TIMx_CR1 寄存器中的 DIR 位為高時執行遞減計數,計數器CNT從 自動重載值(TIMx_ARR 寄存器的內容)遞減計數到0,然后重新從 TIMx_ARR值開始計數並生成計數器下溢事件。 以 PWM 模式 1 為例。只要TIMx_CNT >TIMx_CCRx, PWM 參考信號 OCxREF 便為無效的低電平,否則為有效的高電平。如果 TIMx_CCRx 中 的比較值大於自動重載值(TIMx_ARR 中),則 OCxREF 保持為“ 1”。 此模式下不能產生0%的PWM波形。

(2)PWM中心對齊模式

  在中心對齊模式下,計數器 CNT 是工作做遞增/遞減模式下。開始的 時候, 計數器CNT 從 0 開始計數到自動重載值減 1(ARR-1),生成計數 器上溢事件;然后從自動重載值開始向下計數到 1 並生成計數器下溢事 件。之后從 0 開始重新計數。

  我們以ARR=8,CCRx=4為例進行介紹。第一階段計數器CNT工作在遞增 計數方式,從0開始計數,當TIMx_CNT < TIMx_CCRx時,PWM 參考信號 OCxREF為高電平,當TIMx_CNT >= TIMx_CCRx時,PWM 參考信號 OCxREF 為低電平。第二階段計數器CNT工作在遞減計數方式,從ARR開始遞減計 數,當TIMx_CNT > TIMx_CCRx時,PWM 參考信號 OCxREF為低電平,當 TIMx_CNT <= TIMx_CCRx時,PWM 參考信號 OCxREF為高電平。

 

三.PWM輸出配置步驟

(1)使能定時器及端口時鍾,並設置引腳復用器映射 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE); 可選的參數在 stm32f10x_gpio.h 都已經列出來非常詳細

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//復用推挽輸出

(2)初始化定時器參數,包含自動重裝值,分頻系數,計數方式等

void TIM_TimeBaseInit(TIM_TypeDef*TIMx,TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

(3)初始化PWM輸出參數,包含PWM模式、輸出極性,使能等

void TIM_OCxInit(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);

(4)開啟定時器

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState); TIM_Cmd(TIM3,ENABLE); //開啟定時器

(5)修改TIMx_CCRx的值控制占空比

void TIM_SetCompare1(TIM_TypeDef* TIMx, uint32_t Compare1);

(6)使能TIMx在CCRx上的預裝載寄存器 使能輸出比較預裝載庫函數是:

void  TIM_OCxPreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);

第一個參數用於選擇定時器,第二個參數用於選擇使能還是失能輸出比較預裝載寄存器,可選擇為TIM_OCPreload_Enable、TIM_OCPreload_Disable。

(7)使能 TIMx 在 ARR 上的預裝載寄存器允許位 使能 TIMx 在 ARR 上的預裝載寄存器允許位庫函數是:

void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);  //第一個參數用於選擇定時器,第二個參數用於選擇使能還是失能。

  高級定時器要想輸出PWM波形,必須要設置一個 MOE 位(TIMx_BDTR 的第 15 位),以使能主輸出,否則不會輸出 PWM。庫函數設置的函數為:

   void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);

 

pwm.h
1
#ifndef _pwm_H 2 #define _pwm_H 3 4 #include "system.h" 5 6 void TIM3_CH1_PWM_Init(u16 per,u16 psc); 7 8 #endif

 問題一:19行問什么要AFIO使能   27行改變管腳映射怎么回事

  27行改變管腳映射是對應第三步而言的,就是將定時器輸出的管腳TIM_CH1即PA6管腳映射到PC6管腳輸出(這里以TIM_CH1為例)

  而管腳映射需要用到AFIO這個外設里面寄存器的配置才能實現

 

 問題二:24行為什么GPIOC使用復用推挽輸出,為什么使用復用功能

  復用功能是接受其他外設所傳遞的數據(這里是復用的定時器結構圖右下角所輸出的數據)然后通過管腳輸出

 

 

 

   總結:所比較的數據從TIM3_CH1口出來,經過AFIO外設內寄存器的配置將TIM3_CH1管腳即PA6管腳所映射到的PC6管腳上,經過PC6管腳的復用功能輸出的模式將TIM3_CH1的數據輸出

 

四、PWM代碼

pwm.c
1
#include "pwm.h" 2 3 /******************************************************************************* 4 * 函 數 名 : TIM3_CH1_PWM_Init 5 * 函數功能 : TIM3通道1 PWM初始化函數 6 * 輸 入 : per:重裝載值 7 psc:分頻系數 8 * 輸 出 : 無 9 *******************************************************************************/ 10 void TIM3_CH1_PWM_Init(u16 per,u16 psc) 11 { 12 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; 13 TIM_OCInitTypeDef TIM_OCInitStructure; 14 GPIO_InitTypeDef GPIO_InitStructure; 15 16 /* 開啟時鍾 */ 17 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); 18 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); 19 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //AFIO使能 20 21 /* 配置GPIO的模式和IO口 */ 22 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6; 23 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; 24 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//復用推挽輸出 25 GPIO_Init(GPIOC,&GPIO_InitStructure); 26 27 GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE);//改變指定管腳的映射 28 29 TIM_TimeBaseInitStructure.TIM_Period=per; //自動裝載值 30 TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //分頻系數 31 TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; 32 TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //設置向上計數模式 33 TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure); 34 35 TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1; 36 TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low; 37 TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable; 38 TIM_OC1Init(TIM3,&TIM_OCInitStructure); //輸出比較通道1初始化 39 40 TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable); //使能TIMx在 CCR1 上的預裝載寄存器 41 TIM_ARRPreloadConfig(TIM3,ENABLE);//使能預裝載寄存器 42 43 TIM_Cmd(TIM3,ENABLE); //使能定時器 44 45 }

 

 

 main.c
1
#include "system.h" 2 #include "SysTick.h" 3 #include "led.h" 4 #include "pwm.h" 5 6 int main() 7 { 8 u16 i=0; 9 u8 fx=0; 10 SysTick_Init(72); 11 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中斷優先級分組 分2組 12 LED_Init(); 13 TIM3_CH1_PWM_Init(500,72-1); //頻率是2Kh 14 15 while(1) 16 { 17 18 if(fx==0) 19 { 20 i++; 21 if(i==300) 22 { 23 fx=1; 24 } 25 } 26 else 27 { 28 i--; 29 if(i==0) 30 { 31 fx=0; 32 } 33 } 34 TIM_SetCompare1(TIM3,i); //i值最大可以取499,因為ARR最大值是499. 35 delay_ms(10); 36 } 37 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM