PWM實現呼吸燈

PWM實現呼吸燈

一、PWM簡介
脈衝寬度調製(PWM),是英文“Pulse Width Modulation” 的縮寫,簡稱脈寬調製,是利用微處理器的數字輸出來對模擬電路進行控制的一種非常有效的技術。簡單一點,就是對脈衝寬度的控制, PWM 原理如圖 14.1.1 所示:
在這裏插入圖片描述
圖 14.1.1 就是一個簡單的 PWM 原理示意圖。圖中,我們假定定時器工作在向上計數 PWM模式,且當 CNT<CCRx 時,輸出 0,當 CNT>=CCRx 時輸出 1。那麼就可以得到如上的 PWM示意圖:當 CNT 值小於 CCRx 的時候, IO 輸出低電平(0),當 CNT 值大於等於 CCRx 的時候,IO 輸出高電平(1), 當 CNT 達到 ARR 值的時候,重新歸零,然後重新向上計數,依次循環。改變 CCRx 的值,就可以改變 PWM 輸出的佔空比,改變 ARR 的值,就可以改變 PWM 輸出的頻率,這就是 PWM 輸出的原理。
STM32 的定時器除了 TIM6 和 7。其他的定時器都可以用來產生 PWM 輸出。其中高級定時器 TIM1 和 TIM8 可以同時產生多達 7 路的 PWM 輸出。而通用定時器也能同時產生多達 4路的 PWM 輸出,這樣, STM32 最多可以同時產生 30 路 PWM 輸出!這裏我們使用 TIM3的 CH2 產生一路 PWM 輸出。
要使 STM32 的通用定時器 TIMx 產生 PWM 輸出,我們會用到這 3 個寄存器 來控制 PWM 的 。這三個寄存器分別是 :捕獲 /比較模式寄存器(TIMx_CCMR1/2)、捕獲/比較使能寄存器(TIMx_CCER)、捕獲/比較寄存器(TIMx_CCR1~4)。接下來我們簡單介紹一下這三個寄存器。
首先是捕獲/比較模式寄存器(TIMx_CCMR1/2),該寄存器總共有 2 個, TIMx _CCMR1和 TIMx _CCMR2。 TIMx_CCMR1 控制 CH1 和 2,而 TIMx_CCMR2 控制 CH3 和 4。該寄存器的各位描述如圖 14.1.2 所示:
在這裏插入圖片描述
該寄存器的有些位在不同模式下,功能不一樣,所以在圖 14.1.2 中,我們把寄存器分了 2層,上面一層對應輸出而下面的則對應輸入。這裏我們需要說明的是模式設置位 OCxM,總共可以配置成 7 種模式,我們使用的是 PWM 模式,所以這 3 位必須設置爲 110/111。這兩種 PWM 模式的區別就是輸出電平的極性相反。 另外 CCxS 用於設置通道的方向(輸入/輸出)默認設置爲 0,就是設置通道作爲輸出使用。接下來,我們介紹捕獲/比較使能寄存器(TIMx_CCER),該寄存器控制着各個輸入輸出通道的開關。該寄存器的各位描述如圖 14.1.3 所示:
在這裏插入圖片描述
該寄存器比較簡單, 我們這裏只用到了 CC2E 位,該位是輸入/捕獲 2 輸出使能位,要想PWM 從 IO 口輸出,這個位必須設置爲 1,所以我們需要設置該位爲1。
最後,我們介紹一下捕獲/比較寄存器(TIMx_CCR1~4),該寄存器總共有 4 個,對應 4 個輸通道 CH1~4。因爲這 4 個寄存器都差不多,我們僅以 TIMx_CCR1 爲例介紹,該寄存器的各位描述如圖 14.1.4 所示:
在這裏插入圖片描述
在輸出模式下,該寄存器的值與 CNT 的值比較,根據比較結果產生相應動作。利用這點,我們通過修改這個寄存器的值,就可以控制 PWM 的輸出脈寬了。 本章,我們使用的是 TIM3的通道 2,所以我們需要修改 TIM3_CCR2 以實現脈寬控制 DS0 的亮度。
我們要使用 TIM3 的 CH2 輸出 PWM 來控制 DS0 的亮度,但是 TIM3_CH2 默認是接在 PA7上面的,而我們的 DS0 接在 PB5 上面,如果普通 MCU,可能就只能用飛線把 PA7 飛到 PB5上來實現了,不過,我們用的是 STM32,它比較高級,可以通過重映射功能,把 TIM3_CH2映射到 PB5 上。
STM32 的重映射控制是由複用重映射和調試 IO 配置寄存器(AFIO_MAPR)控制的,該寄存器的各位描述如圖 14.1.5 所示:
在這裏插入圖片描述
我們這裏用到的是 TIM3 的重映射,從上圖可以看出, TIM3_REMAP 是[11:10]這 2 個位控制的。 TIM3_REMAP[1:0]重映射控制表如表 14.1.1 所示:
在這裏插入圖片描述
默認條件下, TIM3_REMAP[1:0]爲 00,是沒有重映射的,所以 TIM3_CH1~TIM3_CH4 分別是接在 PA6、 PA7、 PB0 和 PB1 上的,而我們想讓 TIM3_CH2 映射到 PB5 上,則需要設置TIM3_REMAP[1:0]=10,即部分重映射,這裏需要注意,此時 TIM3_CH1 也被映射到 PB4 上了。
至此,我們把本章要用的幾個相關寄存器都介紹完了, 本章要實現通過重映射 TIM3_CH2到 PB5 上,由 TIM3_CH2 輸出 PWM 來控制 DS0 的亮度。 下面我們介紹配置步驟:
1)開啓 TIM3 時鐘,配置 PB5 爲複用輸出。
要使用 TIM3,我們必須先開啓 TIM3 的時鐘(通過 APB1ENR 設置),這點相信大家看了這麼多代碼,應該明白了。這裏我們還要配置 PB5 爲複用輸出,這是因爲 TIM3_CH2 通道將重映射到 PB5 上,此時, PB5 屬於複用功能輸出。
2) 設置 TIM3_CH2 重映射到 PB5 上。
因爲 TIM3_CH2 默認是接在 PA7 上的,所以我們需要設置 TIM3_REMAP 爲部分重映射(通過 AFIO_MAPR 配置),讓 TIM3_CH2 重映射到 PB5 上面。
3)設置 TIM3 的 ARR 和 PSC。
在開啓了 TIM3 的時鐘之後,我們要設置 ARR 和 PSC 兩個寄存器的值來控制輸出 PWM 的週期。當 PWM 週期太慢(低於 50Hz)的時候,我們就會明顯感覺到閃爍了。因此, PWM 週期在這裏不宜設置的太小。
4)設置 TIM3_CH2 的 PWM 模式。
接下來,我們要設置 TIM3_CH2 爲 PWM 模式(默認是凍結的),因爲我們的 DS0 是低電平亮,而我們希望當 CCR2 的值小的時候, DS0 就暗, CCR2 值大的時候, DS0 就亮,所以我們要通過配置 TIM3_CCMR1 的相關位來控制 TIM3_CH2 的模式。
5)使能 TIM3 的 CH2 輸出,使能 TIM3。
在完成以上設置了之後,我們需要開啓 TIM3 的通道 2 輸出以及 TIM3。前者通過
TIM3_CCER1 來設置,是單個通道的開關,而後者則通過 TIM3_CR1 來設置,是整個 TIM3 的總開關。只有設置了這兩個寄存器,這樣我們才能在 TIM3 的通道 2 上看到 PWM 波輸出。
6)修改 TIM3_CCR2 來控制佔空比。
最後,在經過以上設置之後, PWM 其實已經開始輸出了,只是其佔空比和頻率都是固定的,而我們通過修改 TIM3_CCR2 則可以控制 CH2 的輸出佔空比。繼而控制 DS0 的亮度。
通過以上 6 個步驟,我們就可以控制 TIM3 的 CH2 輸出 PWM 波了。

//TIM3 PWM 部分初始化
//PWM 輸出初始化
//arr:自動重裝值
//psc:時鐘預分頻數
void TIM3_PWM_Init(u16 arr,u16 psc)
{
//此部分需手動修改 IO 口設置
	RCC->APB1ENR|=1<<1; //TIM3 時鐘使能
	RCC->APB2ENR|=1<<3; //使能 PORTB 時鐘
	GPIOB->CRL&=0XFF0FFFFF; //PB5 輸出
	GPIOB->CRL|=0X00B00000; //複用功能輸出
	RCC->APB2ENR|=1<<0; //開啓輔助時鐘
	AFIO->MAPR&=0XFFFFF3FF; //清除 MAPR 的[11:10]
	AFIO->MAPR|=1<<11; //部分重映像,TIM3_CH2->PB5
	TIM3->ARR=arr; //設定計數器自動重裝值
	TIM3->PSC=psc; //預分頻器不分頻
	TIM3->CCMR1|=7<<12; //CH2 PWM2 模式
	TIM3->CCMR1|=1<<11; //CH2 預裝載使能
	TIM3->CCER|=1<<4; //OC2 輸出使能
	TIM3->CR1=0x0080; //ARPE 使能
	TIM3->CR1|=0x01; //使能定時器 3
}

此部分代碼包含了上面介紹的 PWM 輸出設置的前 5 個步驟。這裏我們關於 TIM3 的設置就不再說了, 這裏提醒下:在配置 AFIO 相關寄存器的時候,必須先開啓輔助功能時鐘。

void LED_Init(void)
{
	RCC->APB2ENR|=1<<3;    //使能PORTB時鐘	   	 
	RCC->APB2ENR|=1<<6;    //使能PORTE時鐘	
	   	 
	GPIOB->CRL&=0XFF0FFFFF; 
	GPIOB->CRL|=0X00300000;//PB.5 推輓輸出   	 
    GPIOB->ODR|=1<<5;      //PB.5 輸出高
											  
	GPIOE->CRL&=0XFF0FFFFF;
	GPIOE->CRL|=0X00300000;//PE.5推輓輸出
	GPIOE->ODR|=1<<5;      //PE.5輸出高 
}

初始化PB5和PE5爲輸出口.並使能這兩個口的時鐘 LED IO初始化

void TIM3_IRQHandler(void)
{ 		    		  			    
	if(TIM3->SR&0X0001)//溢出中斷
	{
		LED1=!LED1;			    				   				     	    	
	}				   
	TIM3->SR&=~(1<<0);//清除中斷標誌位 	    
}

該部分代碼主要是定時器3中斷服務函數。

void TIM3_Int_Init(u16 arr,u16 psc)
{
	RCC->APB1ENR|=1<<1;	//TIM3時鐘使能    
 	TIM3->ARR=arr;  	//設定計數器自動重裝值//剛好1ms    
	TIM3->PSC=psc;  	//預分頻器7200,得到10Khz的計數時鐘		  
	TIM3->DIER|=1<<0;   //允許更新中斷	  
	TIM3->CR1|=0x01;    //使能定時器3
  	MY_NVIC_Init(1,3,TIM3_IRQn,2);//搶佔1,子優先級3,組2	
 }

通用定時器初始化。

#include "sys.h"
#include "delay.h"
#include "usart.h" 
#include "led.h" 
#include "timer.h" 
//ALIENTEK精英STM32F103開發板 實驗9
//PWM輸出 實驗  
//技術支持:www.openedv.com
//廣州市星翼電子科技有限公司 
int main(void)
{					   
	u16 led0pwmval=0;    
	u8 dir=1;	
	Stm32_Clock_Init(9);	//系統時鐘設置
	uart_init(72,115200);	//串口初始化爲115200
	delay_init(72);	   	 	//延時初始化 
	LED_Init();		  		//初始化與LED連接的硬件接口
  	TIM3_PWM_Init(899,0);	//不分頻。PWM頻率=72000/(899+1)=80Khz
   	while(1)
	{
 		delay_ms(10);	 
		if(dir)led0pwmval++;
		else led0pwmval--;	 
 		if(led0pwmval>300)dir=0;
		if(led0pwmval==0)dir=1;	   					 
		LED0_PWM_VAL=led0pwmval;	   
	}
}

主函數代碼。
通過以上的程序就可以通過PWM實現呼吸燈閃爍。接下來將通過STM32來完成一個4輪避障小車。實現一個定時器的4個通道來實現PWM電機調速。來加深對PWM的理解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章