1. 程式人生 > 實用技巧 >10. 從0學ARM-基於Exynos4412的pwm詳解

10. 從0學ARM-基於Exynos4412的pwm詳解

一、什麼是PWM

PWM,英文名Pulse Width Modulation,是脈衝寬度調製縮寫,它是通過對一系列脈衝的寬度進行調製,等效出所需要的波形(包含形狀以及幅值),對模擬訊號電平進行數字編碼,也就是說通過調節佔空比的變化來調節訊號、能量等的變化,佔空比就是指在一個週期內,訊號處於高電平的時間佔據整個訊號週期的百分比,例如方波的佔空比就是50%.

二、PWM訊號輸出輸出和作用

1. 如果要實現PWM訊號輸出如何輸出呢?

1)可以直接通過晶片內部模組輸出PWM訊號,前提是這個I/O口要有整合的pwm控制器,只需要通過對應的暫存器即可,這種自帶有PWM輸出的功能模組在程式設計更簡便,同時資料更精確。

2)但是如果IC內部沒有PWM功能模組,或者要求不是很高的話可以利用I/O口設定一些引數來輸出PWM訊號,因為PWM 訊號其實就是一高一低的一系列電平組合在一起。具體方法是給I/O加一個定時器,對於你要求輸出的PWM訊號頻率與你的定時器一致,用定時器中斷來計數,但是這種方法一般不採用,除非對於精度、頻率等要求不是很高可以這樣實現。

2. PWM訊號應用

PWM訊號把模擬訊號轉化為數位電路所需要的編碼,現在基本是採用數位電路,因此在很多場合都採用PWM訊號。

我們經常見到的就是交流調光電路,也可以說是無級調速,高電平佔多一點,也就是佔空比大一點亮度就亮一點,佔空比小一點亮度就沒有那麼亮,前提是PWM的頻率要大於我們人眼識別頻率,要不然會出現閃爍現象。

除了在調光電路應用,還有在直流斬波電路、蜂鳴器驅動、電機驅動、逆變電路、加溼機霧化量等都會有應用。

三、蜂鳴器

蜂鳴器廣泛用於計算機、印表機、影印機、報警器、電子玩具、汽車電子裝置、電話機、定時器等電子產品中作發聲器件。

蜂鳴器分為壓電式及電磁式的二大類:

  1. 壓電式蜂鳴器主要由多諧振盪器、壓電蜂鳴片、阻抗匹配器及共鳴箱、外殼等組成。它是以壓電陶瓷的壓電效應,來帶動金屬片的振動而發聲;

  2. 電磁式的蜂鳴器,由振盪器、電磁線圈、磁鐵、振動膜片及外殼等組成。接通電源後,振盪器產生的音訊訊號電流通過電磁線圈,使電磁線圈產生磁場。振動膜片在電磁線圈和磁鐵的相互作用下,週期性地振動發聲。通電時將金屬振動膜吸下,不通電時依振動膜的彈力彈回。

有源蜂鳴器, 只要給它加上恆定的電壓, 就能發聲;
無源蜂鳴器, 必須給它加上一定頻率的方波或正弦波才能發聲

有源蜂鳴器內部帶震盪源,所以一通電就會叫。 而無源內部不帶震盪源,所以如果用直流訊號無法令其鳴叫。

有源蜂鳴器往往比無源的貴,就是因為裡面多個震盪電路。

【優點】
無源蜂鳴器的優點是:

  1. 便宜
  2. 聲音訊率可控,可以做出“多來米發索拉西”的效果。
  3. 在一些特例中,可以和LED複用一個控制口
    有源蜂鳴器的優點是:
  4. 程式控制方便 。

應用:
電風扇、收音機的聲音按鈕、任何模擬值都可以使用PWM進行編碼

四、fs4412電路圖

本例採用fs4412開發板,pwm外接了一個蜂鳴器BUZZER,電路圖如下:
從上面電路圖可知:

  1. 該BUZZER是無源蜂鳴器,如果要想發出聲音,需要正負極產生電流變化,我們通過生成方波,從而實現圖中三極體1->2週期性導通和關閉來讓BUZZER倆邊電壓產生變化,從而實現電流變化;
  2. 三極體的基極連線的是SOC的GPD0_0引腳;
  3. 產生方波我們藉助的是PWM,標號為MOTOR_PWM。

繼續查詢MOTOR_PWM:
由上圖可知,MOTOR_PWM連線的是PWM的XpwmTOUT0,和LCD一起復用引腳GPD0_0,

去datasheet繼續檢視GPD0_0說明,
由上圖可知,GPD0_0配置由暫存器的GPD0CON[3:0]位控制,要想作為PWM輸出,要設定為TOUT_0即0x2。

同時也可以看到,該引腳還可以設定為外部中斷訊號[EXT_INT6]功能即0xF。

五、Exynos 4412 PWM

概述

Exynos 4412 SCP有五個32位脈衝寬度調製(PWM)定時器。這些定時器產生內部中斷對於ARM子系統。此外,定時器0、1、2和3包括驅動外部I/O的PWM功能訊號。定時器0中的PWM有一個可選的死區發生器功能,以支援大量的裝置。定時器4是一個沒有輸出引腳的內部定時器。

定時器使用APB-PCLK作為源時鐘。定時器0和1共享可程式設計8位預分頻器為PCLK提供第一級分頻。定時器2、3和4共享不同的8位預分頻器。每個計時器都有它自己的專用時鐘分頻器,提供第二級時鐘劃分頻(預分頻器除以2、4、8或16)。

每個定時器都有它的32位遞減計數器;定時器時鐘驅動這個計數器。定時器計數緩衝暫存器(TCNTBn)載入遞減計數器的初始值。如果遞減計數器達到零,它將生成計時器中斷請求,通知CPU定時器操作完成。如果定時器下降計數器達到零,相應TCNTBn的值自動重新載入到下一個迴圈開始。但是,如果定時器停止,例如,在定時器執行模式下,通過清除TCONn的定時器使能位,TCNTBn的值將不會重新載入到計數器中。

PWM功能使用TCMPBn暫存器的值。定時器控制邏輯改變輸出電平下計數器值與定時器控制邏輯中比較暫存器的值相匹配。因此,比較暫存器決定PWM輸出的開啟時間或關閉時間。

每個定時器都是雙緩衝結構,帶有TCNTBn和TCMPBn暫存器,允許定時器引數在週期中更新。新值在當前計時器週期完成之前不會生效。

Exynos PWM定時器的特性

1)5個32位定時器;
2)2個8位PCLK分頻器提供一級預分,5個2級分頻器用來預分外部時鐘;
3)可程式設計選擇PWM獨立通道。
4)4個獨立的可程式設計的控制及支援校驗的PWM通道。
5)靜態配置:PWM停止;
6)動態配置:PWM啟動;
7)支援自動重灌模式及觸發脈衝模式;
8)一個外部啟動引腳。
9)兩個PWM輸出可帶Dead-Zone 發生器。
10)中斷髮生器。

PWM內部模組圖

工作的步驟:

  1. 當時鍾PCLK被使能後,定時器計數緩衝暫存器(TCNTBn)把計數器初始值下載到遞減計數器中。
  2. 定時器比較緩衝暫存器(TCMPBn)把其初始值下載到比較暫存器中,並將該值與遞減計數器的值進行比較。當遞減計數器和比較暫存器值相同時,輸出電平翻轉。
  3. 遞減計數器減至0後,輸出電平再次翻轉,完成一個輸出週期。這種基於TCNTBn和TCMPBn的雙緩衝特性使定時器在頻率和佔空比變化時能產生穩定的輸出。
  4. 每個定時器都有一個專用的由定時器時鐘驅動的16位遞減計數器。
    當遞減計數器的計數值達到0時,就會產生定時器中斷請求來通知CPU定時器操作完成。當定時器遞減計數器達到0的時候,如果設定了Auto-Reload 功能,相應的TCNTBn的值會自動過載到遞減計數器中以繼續下次操作。
  5. 然而,如果定時器停止了,比如在定時器執行時清除TCON中定時器使能位,TCNTBn的值不會被過載到遞減計數器中。
  6. TCMPBn 的值用於脈衝寬度調製。當定時器的遞減計數器的值和比較暫存器的值相匹配的時候,定時器控制邏輯將改變輸出電平。因此,比較暫存器決定了PWM 輸出的開關時間。

舉例

下面我們舉個例項來看下,

  1. 初始化暫存器 TCNTBn = 159 (50 + 109) ,TCMPBn =109.
  2. 開啟定時器: 通過設定TCON的開啟位.
    暫存器TCNTBn 的值159將自動載入到遞減暫存器down-counter, 同時輸出引腳TOUTn 設定為低電平.
  3. 當down-counter 的值遞減打破和暫存器TCMPBn 的值109相同時, 輸出引腳將從低拉到高.
  4. 當down-counter遞減到0時, 產生一箇中斷請求.
  5. 如果我們設定成autoreload模式,那麼down-counter會自動載入TCNTBn的值到down-counter,開啟新的一個週期。

我們可以通過設定TCNTBn、TCMPBn來控制佔空比,而每個pwm週期後都可以重新設定新的值到TCNTBn、TCMPBn,我們通過精確的計算來設定TCNTBn、TCMPBn的值並通過設定dead zone我們可以設計出各種複雜的矩形波。

如下圖所示:
本例我們只需要產生規則的舉行方波即可,所以我們只需要設定佔空比為50%即可。

六、暫存器

由第四章可知,我們使用PWM控制器的timer 0,對應的暫存器組如下圖所示:

1、TFCG0

定時器配置暫存器0(TFCG0) ,主要用於預分頻設定。

我們是timer 0,所以只需要設定該暫存器的bite【7:0】即可,最終的輸出頻率和value的公式如下:

參考24.3.1節:


其中方波的頻率必須在音訊範圍內,也就是20Hz到20KHZ之間, 但是20Hz到20KHZ的頻率送給蜂鳴器後, 只有某一點的頻率是最響的, 這個頻率稱為蜂鳴器的諧振頻率, 離它越遠, 蜂鳴器發出的聲音越輕。

所以Prescaler 0 value值應該設定為255,divider value 應該是1/16,值由TCFG1設定。

	PWM.TCFG0 = PWM.TCFG0 & (~(0xff))|0xf9;

2、TCFG1

定時器配置暫存器1(TCFG1) 主要用於PWM定時器的divider value設定。

由上一節分析,秩序設定TCFG1 bite【3:0】為0100即0x2即可。

	PWM.TCFG1 = PWM.TCFG1 & (~(0xf)) | 0x2;

3、TCON

timer控制暫存器TCON

  1. bite[3] : 設定定時器是隻執行一個週期(One-shot)還是週期執行(auto-reload)
  2. bite[1]: 置為1,則更新TCNTB0 、TCMPB0 的值
  3. bit[0]:開啟或者停止定時器

針對不同操作,我們可以設定不同的值:

  1. 裝載
	PWM.TCON = PWM.TCON & (~(0xff)) | (1 << 0) | (1 << 1) ;
  1. 開啟定時器,蜂鳴器響
PWM.TCON = PWM.TCON & (~(0xff)) | (1 << 0) | (1 << 3) ;
  1. 關閉定時器,蜂鳴器滅
PWM.TCON = PWM.TCON & (~(1 << 0)) ;

4、TCNTB0

定時器計數緩衝暫存器(TCNTB0)
根據測算,設定為100

	PWM.TCNTB0 = 100;

5、TCMPB0

定時器比較緩衝暫存器(TCMPB0 )
設定為50,佔空比為50%

	PWM.TCMPB0 = 50;

七、程式碼

完整程式碼後臺回覆【armprintf】

#include "exynos_4412.h"
void  delay_ms(unsigned int num)
{   int i,j;
    for(i=num; i>0;i--)
	for(j=1000;j>0;j--);
}
void pwm_init(void)
{
	GPD0.CON = GPD0.CON & (~(0xf))| 0x2;
	PWM.TCFG0 = PWM.TCFG0 & (~(0xff))|0xf9;
	PWM.TCFG1 = PWM.TCFG1 & (~(0xf)) | 0x2;
	PWM.TCMPB0 = 50;
	PWM.TCNTB0 = 100;
	PWM.TCON = PWM.TCON & (~(0xff)) | (1 << 0) | (1 << 1) ;
}
void beep_on(void)
{
	PWM.TCON = PWM.TCON & (~(0xff)) | (1 << 0) | (1 << 3) ;
}
void beep_off(void)
{
	PWM.TCON = PWM.TCON & (~(1 << 0)) ;
}
#define SYS_SET_FREQUENCE 25000
void beep_set_frequence( unsigned int fre )
{	//若蜂鳴器的發聲頻率為0則返回
	if( 0==fre )
		return ;
	PWM.TCMPB0 =  SYS_SET_FREQUENCE/(fre+fre);//根據設定頻率重新設定計數器比較的值
	PWM.TCNTB0 =  SYS_SET_FREQUENCE/fre;	//根據頻率重新調整計數值
}
int main (void)
{	pwm_init();
	while(1)
	{		beep_on();			//發出一個音
			delay_ms(100);
			beep_off();         //關閉蜂鳴器, 每個音播放完成後有間隔感
			delay_ms(100);
	}
   return 0;
}

我們也可以通過修改頻率和音響的時間來播放音樂。
有興趣讀者關注公眾號【一口Linux】,找一口君獲取原始碼。