使用有源蜂鳴器,只能發出固定的”滴滴“聲,當然不能滿足于此呀。使用無源蜂鳴器,只要輸出不同頻率的PWM波,即可發出不同的音符。不同的音符組合起來就是一個曲子了。
1 樂譜簡析
1.1 音階
音階是音樂必不可少的要素,主要由聲音的頻率決定。通過給蜂鳴器不同頻率的音頻脈沖,可以產生不同的音階,而要產生某頻率的音頻脈沖,最簡單的辦法是算出該音頻的周期,然后將此周期除以2即為半周期的時間。通過程序控制單片機某引腳半周期為“高”、半周期為“低”,不斷交替變換,即可產生該頻率的矩形波,接到蜂鳴器上就可發出該頻率的聲音。若想改變音階,只需要改變半周期時間即可。下表為各音調音符頻率對照表,據此可產生不同音階的音符。“#”表示半音,用于上升或下降半個音,乘以2就提升該聲音一個8度音階,減半則降一個8度。
1.2 節拍
若要構成音樂,光有音階是不夠的,還需要節拍,也就是音符持續時間的長短,一般用拍數表示。至于1拍是多少秒,沒有嚴格的規定,只要節拍適宜,聲音悅耳即可。假如某首歌曲的節奏是每分鐘120拍,那么1拍為0.5 s,1/4拍為0.125 s,以此類推可得到其他節拍對應的時長。這樣,利用不同的頻率,加上與拍數對應的延時,就構成了樂曲。
2 STM32中的定時器
音階的產生與聲音頻率有關,為了實現不同音階,必須能為蜂鳴器提供不同頻率的脈沖。為此,選擇STM32芯片,利用其自帶的定時器,通過PWM產生脈沖信號。STM32中一共有11個定時器,包含2個高級控制定時器、4個普通定時器、2個基本定時器,以及2個看門狗定時器和1個系統滴答定時器SysTiek。其中,TIM1和TIM8是高級定時器,時鐘由APB2的輸出產生。TIM2~TIM5是普通定時器,TIM6和TIM7是基本定時器,這6個定時器的時鐘由APB1的輸出產生。
2.1 定時時長的計算
定時器的一個主要功能就是到指定時間就會產生一個溢出事件,這個時間的設置與定時器時鐘有關,在定時器時鐘基礎上進行預分頻,設置計數溢出大小即可。
2.1.1 系統時鐘設置
要保證定時的準確性,必須先確保系統時鐘的設置是我們所預期的。定時器時鐘分配可查看數據手冊。通過編程使SYSCLK為72 MHz,APB1預分頻后得到PCLK1為36 MHz,再經TIM2~TIM7倍頻器得到TIM2~TIM7時鐘72 MHz。時鐘源多采用HSE(外部時鐘源),對于STM32F103,其外部時鐘為8 MHz,而STM32F107外部時鐘為25 MHz,因此,在使用HSE做時鐘源時,這兩種器件產生SYSCLK的分頻和倍頻方式不同,需要使用者引起注意。
2.1.2 定時器相關參數設置
定時器的參數由結構體TimeBaselnitTypeDef定義,主要包括預分頻系數、時鐘分割、計數器模式、計數溢出大小等。例如,要由TIM3(定時器3)產生一個時長為1 s的定時,首先,應進行系統時鐘的設置,得到TIM3CLK=72MHz,然后進行定時器設置。其中,預分頻系數為35 999,此時,TIM3時鐘為72 MHz/36 000=2 kHz,無時鐘分割。設置計數溢出大小為1 999,即每計2 000個數就產生一個更新事件,輸出頻率為2 kHz/2 000=1 Hz。
2.2 STM32的PWM輸出
脈沖寬度調制(Pulse Width Modulation,PWM)是利用微處理器的數字輸出來對模擬電路進行控制的一種非常有效的技術,簡而言之,就是實現對輸出信號脈沖寬度的控制,一般用來控制步進電機等。STM32的定時器除了TIM6和TIM7之外,其他的定時器都可以用來產生PWM輸出,其中,高級定時器TIM1和TIM8能夠產生3對PWM互補輸出,而TIM2~TIM5也能同時產生4路的PWM輸出。
2.2.1 PWM輸出引腳
STM32給不同的定時器分配了不同的輸出引腳,考慮到引腳復用功能,STM32還提出了一個“重映像”的概念,就是通過設置某一些相關的寄存器,使得在其他非原始指定的引腳上也能輸出PWM波形,但是這種重映像不是隨意的,使用方法可參照參考文獻。例如,TIM3的通道2,在沒有重映像的時候,指定的引腳是PA7。如果設置部分重映像之后,輸出就被映像到PB5上了;如果設置完全重映像的話,輸出就被映像到PC7上。
2.2.2 占空比的計算
占空比(Duty Ratio)有如下含義:在一串理想的脈沖周期序列(如方波)中,正脈沖的持續時間與脈沖總周期的比值。
當TIM_Period為1 999時,若想得到占空比50%,則TIM_Pulse應設置為(1999+1)/2=1000。
3.2 程序設計
改變PWM的音調,可以輸出Do re mi fa so la si do這樣的7個音符,還可以輸出不同音調的Do re mi fa so la si do。
在實例程序里面,我定義了低中高三個音階。音符的頻率則是mbed提供的。已經宏定義好了。
只要改變PWM的輸出周期,即可發出不同的音調(頻率是周期的倒數)。
為了方便起見,寫了一個音階類(Pitch),虛基類。里面有一個perform函數,參數是音符和持續時間。例如要發出Do這個聲音,持續0.5s,只要perform(1,0.5)就好。
還有一個Stop函數,停止響聲0.5s則stop(0.5),無參數則直接停止。后面的Low、Mid、High類則是派生類,實現了Pitch的虛函數。
程序里面包括:
1、發出低中高三個聲調的Do re mi fa so la si do音。
2、中音版的小星星。
3、低音版的小星星。
#include “mbed.h”
#define NOTE_B031
#define NOTE_C133
#define NOTE_CS1 35
#define NOTE_D137
#define NOTE_DS1 39
#define NOTE_E141
#define NOTE_F144
#define NOTE_FS1 46
#define NOTE_G149
#define NOTE_GS1 52
#define NOTE_A155
#define NOTE_AS1 58
#define NOTE_B162
#define NOTE_C265
#define NOTE_CS2 69
#define NOTE_D273
#define NOTE_DS2 78
#define NOTE_E282
#define NOTE_F287
#define NOTE_FS2 93
#define NOTE_G298
#define NOTE_GS2 104
#define NOTE_A2110
#define NOTE_AS2 117
#define NOTE_B2123
#define NOTE_C3131
#define NOTE_CS3 139
#define NOTE_D3147
#define NOTE_DS3 156
#define NOTE_E3165
#define NOTE_F3175
#define NOTE_FS3 185
#define NOTE_G3196
#define NOTE_GS3 208
#define NOTE_A3220
#define NOTE_AS3 233
#define NOTE_B3247
#define NOTE_C4262
#define NOTE_CS4 277
#define NOTE_D4294
#define NOTE_DS4 311
#define NOTE_E4330
#define NOTE_F4349
#define NOTE_FS4 370
#define NOTE_G4392
#define NOTE_GS4 415
#define NOTE_A4440
#define NOTE_AS4 466
#define NOTE_B4494
#define NOTE_C5523
#define NOTE_CS5 554
#define NOTE_D5587
#define NOTE_DS5 622
#define NOTE_E5659
#define NOTE_F5698
#define NOTE_FS5 740
#define NOTE_G5784
#define NOTE_GS5 831
#define NOTE_A5880
#define NOTE_AS5 932
#define NOTE_B5988
#define NOTE_C61047
#define NOTE_CS6 1109
#define NOTE_D61175
#define NOTE_DS6 1245
#define NOTE_E61319
#define NOTE_F61397
#define NOTE_FS6 1480
#define NOTE_G61568
#define NOTE_GS6 1661
#define NOTE_A61760
#define NOTE_AS6 1865
#define NOTE_B61976
#define NOTE_C72093
#define NOTE_CS7 2217
#define NOTE_D72349
#define NOTE_DS7 2489
#define NOTE_E72637
#define NOTE_F72794
#define NOTE_FS7 2960
#define NOTE_G73136
#define NOTE_GS7 3322
#define NOTE_A73520
#define NOTE_AS7 3729
#define NOTE_B73951
#define NOTE_C84186
#define NOTE_CS8 4435
#define NOTE_D84699
#define NOTE_DS8 4978
//7個音符組成了美妙的音樂
//低Do re mi fa so la si do
int melody[] = {NOTE_C4, NOTE_D4,NOTE_E4, NOTE_F4, NOTE_G4,NOTE_A4,NOTE_B4,NOTE_C5};
//中Do re mi fa so la si do
int melody2[] = {NOTE_C5, NOTE_D5,NOTE_E5, NOTE_F5, NOTE_G5,NOTE_A5,NOTE_B5,NOTE_C6};
//高
int melody3[] = {NOTE_C6, NOTE_D6,NOTE_E6, NOTE_F6, NOTE_G6,NOTE_A6,NOTE_B6,NOTE_C7};
//PWM輸出口
PwmOut m(PB_13);
//音調類
class Pitch{
public:
virtual void perfrom(int,double)=0;
void stop(double time = 0){
if(time==0)
m = 1;
else{
m = 1;
wait(time);
}//end else
}//end stop
};
class Low:public Pitch{
public:
void perfrom(int index,double time){
m.period_us(1000000/melody[index-1]);
m.write(0.5);
wait(time);
}
}
來源;21ic