天天看點

《51單片機應用開發從入門到精通》——2.11 歌曲演奏執行個體

本節書摘來異步社群《51單片機應用開發從入門到精通》一書中的第2章,第2.11節,作者:張華傑 ,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視

51單片機應用開發從入門到精通

本執行個體是利用單片機演奏一首生日快樂歌。

1.演奏器原理

(1)通過控制單片機定時器的定時時間産生不同頻率的音頻脈沖,經放大後驅動蜂鳴器發出不同音節的聲音。

(2)用軟體延時來控制發音時間的長短,控制節拍,表2-14是各調1/4節拍的時間表。

《51單片機應用開發從入門到精通》——2.11 歌曲演奏執行個體

(3)把樂譜中的音符和相應的節拍變換為定時常數和延時常數,作為資料表格存放在存儲器中。由程式查表得到定時常數和延時常數,分别用來控制定時器産生的脈沖頻率和發出該音頻脈沖的持續時間。

(4)表2-15為單片機晶振頻率為12mhz時,樂曲中的音符、頻率及定時常數之間的對應關系表。

《51單片機應用開發從入門到精通》——2.11 歌曲演奏執行個體
《51單片機應用開發從入門到精通》——2.11 歌曲演奏執行個體

2.歌譜

《51單片機應用開發從入門到精通》——2.11 歌曲演奏執行個體

3.建立步驟

(1)先把樂譜的音符找出,然後根據表2-15給出的定時值按樂譜的音符順序建立編碼表table。

定時值為十六進制4位數,拆開分為兩組,如5對應的定時值為fd80h,拆分為fdh和80h兩組。前組裝入定時器的高位th0,後組裝入定時器的低位tl0。程式中将進行兩次查表來完成一個音符對應的定時初值的裝入。

(2)在程式中使用定時器t0方式1來産生歌譜中各音符對應頻率的音頻脈沖,由 p3.4輸出,再經三極管将信号放大後驅動蜂鳴器發出不同音節的聲音。

(3)程式中節拍的控制是通過調用延時子程式delay的次數來實作的,1拍為 748 ms,即需要調用4次delay;3/4拍需要調用3次delay;2/4拍需要調用2次delay。

(4)節拍的控制碼在表table中位于音符碼的後面。如第1行“db 0fdh,80h, 03h,…”中,0fdh和80h是音符5的音符碼,其後邊的03h是節拍碼,即3/4拍的時間。

(5)當一個音符的發音時間到時,再查下一個音符的定時常數和延時常數。依此進行下去,就可演奏出悅耳動聽的樂曲。

1.流程圖

程式設計流程如圖2-18所示。

《51單片機應用開發從入門到精通》——2.11 歌曲演奏執行個體

2.程式

彙編語言編寫的歌曲演奏源程式fs03.asm代碼如下:

1.标号說明

start:程式開始的進入點。

loop:處理下一個音符的進入點。

next:裝入定時初值的進入點。

next0:關閉定時器、停止發音的進入點。

next1:查找延時常數的進入點。

loop1:處理節拍時間的進入點。

ext0:中斷子程式的進入點。

delay:延時180ms子程式的進入點。

2.寄存器使用配置設定情況

r0、r1、r2、r5、r6、r7:普通寄存器。其中r0存放低位定時器初值;r1存放高位定時器初值;r2存放延時常數值;r5、r6和r7在延時子程式中作計數器用。

a和dptr:特殊功能寄存器,其中a又稱累加器,dptr為資料指針。在程式中把表table的首位址存入dptr作基礎位址,a作為變址寄存器。将基址寄存器和變址寄存器的内容相加(@a + dptr)形成操作數的位址。

tmod:定時器工作模式控制寄存器。

tl0和th0:定時器0的計數器,tl0為低8位,th0為高8位。

tr0:定時器0控制寄存器tcon的一個控制位。

ie:中斷允許控制寄存器。

p3.4:對内是p3寄存器的一個位,對外是輸入/輸出端口的一個引腳,作音頻信号輸出端口。

3.程式分析解釋

01~04:設定入口位址。其中定時器中斷是從标号ext0處進入中斷子程式。

05~07:設定定時器t0為方式1,并允許t0中斷。其中07行語句将表table的首位址存入資料指針寄存器dptr中。

08~10:第一次查表,取出表中的第一個碼,即樂譜中的第一個音符5的定時常數(定時初值)fd80h中的高位部分fdh,并存入寄存器r1中。

11~14:第二次查表,取出表中的第二個碼,即樂譜中的第一個音符5的定時常數fd80h中的低位部分(即80h),并存入寄存器r0中。

15~20:判斷、轉移語句。對二次查取到的碼,檢查是否有休止符碼,該判斷是通過第15行語句“orl a,r1”對a和r1寄存器的内容進行或運算實作的。

如果累加器a中的值是00h,r1寄存器的值也是00h,進行或運算後再存入累加器a中,此時累加器a中的值是全0,說明取到的是休止符碼。通過第16行語句“jz next0”,跳轉至标号next0處,關閉定時器,停止發音,完成樂譜中休止符的作用。

取碼時是否取到了結束碼是通過第18行語句指令anl對a和r1進行與運算來判斷的。如果累加器a中的值是ffh,r1寄存器的值也是ffh,進行與運算後再存入累加器a中,此時累加器a中的值是全1,說明取到的是結束碼。

第19行語句“cjne a,#0ffh,next”,如果累加器a中的值與#0ffh不相等,則跳轉移到next處,開始向定時器裝入定時常數;如果a與#0ffh相等,說明取到的碼是結束碼,程式向下執行,即從頭開始循環演奏。

21~23:開始向定時器裝入定時常數并啟動定時器工作。

24~25:處理拍節。

26~29:查取延時碼并存入r2。

30~31:決定拍節時間。如果取來的碼是02h,程式調用兩次delay延時,即為2/4拍節時間;如果取來的碼是04h,程式調用4次drlay延時,即為1拍節時間。

32~33:每次查表取碼後,資料指針都要加1,以便指向下一個待查的碼。第33行語句将程式運作跳轉到标号loop處,處理下一個音符。

34~37:中斷子程式。當定時器計時滿後将産生中斷,由标号ext0處進入中斷子程式。在中斷子程式中重裝定時值,并通過第36行語句在p3.4端口輸出音頻信号。

38~44:延時187ms子程式。

45~61:編碼表table。在表中每個音節由3個碼組成,前兩個為音符碼,後一個為節拍碼。如表中第1行“0fdh,80h,03h”,其中0fdh和80h即為fd80h,是音符5的發音編碼;03h是節拍碼,3/4節拍。

表中的最後一行“0ffh,0ffh”是結束碼,表示樂曲演奏結束。

4.邊用邊學指令

本程式用到新的指令有orl和jz。

 orl:邏輯運算及位移類指令中的按位或操作指令。該指令将累加器a中的内容與源操作數所指出的内容按位進行邏輯或運算,結果存入a中。

 jz:控制轉移類指令,功能是當累加器a為0時跳轉。

1.模拟仿真前注意事項

在23與24行語句之間,加一條“setb tf0”語句,該語句使定時器t0的溢出标志位tf0為1,模拟産生中斷,使程式能進入中斷子程式中運作。

在39~43行語句的前邊加分号,使延時子程式的延時時間縮短為2ms,縮短模拟仿真時間。

2.模拟仿真中注意事項

觀察程式主要運作路線:第一次查表→第二次查表→中斷子程式及傳回→第三次查 表→進入延時子程式及傳回→處理下一個音符(跳轉到loop處)。

觀察累加器a中值的變化。第一次查表執行第09行語句“movc a,@a + dptr”後,a值為fdh。第二次查表,執行第13行語句“movc a,@a + dptr”後,a值為80h。兩次查表取回音符5的對應碼fd80h。第三次查表,執行第28行語句“movc a,@a + dptr”後,a值為03h,取回的是音符5的對應拍節碼。

将寫入歌曲演奏程式的單片機插入實驗闆插座内,并檢查實驗闆上蜂鳴器接口是否與程式中聲音輸出端口一緻,當檢查無誤後接通電源,就會聽到生日快樂歌。

在用單片機作可程式設計樂曲演奏器的程式裡,一般用定時器t0方式1來控制音符的頻率,調用延時子程式delay來控制節拍。

程式采用查表的方法,将樂譜轉換成控制碼并制成表table,然後進行三次查表。第一、第二次查表完成對音符的控制,第三次查表讀取節拍碼,完成對節拍的控制。

在完成第一、第二次查取音符的控制碼後,程式中還設有判斷語句,如果判斷出取來的是休止符碼,就将定時器關閉一段時間;如果判斷出取來的是結束碼,程式就從頭開始循環。

繼續閱讀