基于-51單片機的電子琴設計【附原理圖、PCB和程序】
《基于-51單片機的電子琴設計【附原理圖、PCB和程序】》由會員分享,可在線閱讀,更多相關《基于-51單片機的電子琴設計【附原理圖、PCB和程序】(33頁珍藏版)》請在裝配圖網上搜索。
1、 課程設計說明書 題 目:基于單片機的電子琴設計 院 〔系〕:電子工程與自動化學院 專 業(yè): 測控技術與儀器(卓越) 學生: 學 號: 指導教師: 2013 年 9 月 21 日 31 / 33 目 錄 1 摘要 …………………………………………………………………… 1 2 關鍵字 ………………………………………………………………… 1 3 設計任務及要求 ……………………………………………………… 1 4 方案可行性論證 …………
2、…………………………………………… 1 5 程序框圖 ……………………………………………………………… 2 6 關鍵單元電路與程序介紹 …………………………………………… 3 6.1 復位與震蕩電路 ……………………………………………… 3 6.2 4x4矩陣鍵盤 ………………………………………………… 3 6.3數碼管與LED燈 ……………………………………………… 4 6.4 蜂鳴器 ………………………………………………………… 6 6.5 音樂相關知識 ………………………………………………… 7 7 調試過程 ………
3、……………………………………………………… 11 8 總結與體會 …………………………………………………………… 11 9 參考文獻……………………………………………………………… 11 10 附錄 …………………………………………………………………… 12 10.1 設備與儀器…………………………………………………… 12 10.2 軟件 …………………………………………………………… 12 10.3 原件清單 ……………………………………………………… 12 10.4原理圖與PCB圖 ……………………………………………… 13
4、 10.5 總程序…………………………………………………………… 14 10.6 實物圖 …………………………………………………………… 31 【摘要】: 打造一個多功能電子琴,核心是一塊單片機。單片機讀取鍵值,為置定時器賦初值,定時器每溢出一次,驅動蜂鳴器的引腳電平就取反一次,產生相應頻率的方波,即音調;設好鍵值與數碼管段碼表的對應關系,鍵按下時,數碼管顯示對應音調。 一首音樂儲存在一個表中,表中的數據是音調與節(jié)拍,單片機讀取音符的音調與節(jié)拍,根據音調賦予定時器初值,根據節(jié)拍決定定時器工作的時間,也就是蜂鳴器響的時間,一個接一個地讀取音符,即可播放一首歌曲。 節(jié)拍
5、用led燈的點亮個數表示。單片機讀取音樂表中的節(jié)拍,控制led燈的點亮個數,到達顯示節(jié)拍的效果。 特別要注意的是:該方案采用了兩個定時器,T0、T1。T0作為驅動蜂鳴器的定時器,要給予高優(yōu)先級,不然會被T1干擾,音質變差。 【關鍵字】:單片機、stc89c52、電子琴、C51、keil。 【設計任務及要求】: 1.通過按鍵能夠發(fā)出相應的音符并播放產生樂音,實現演奏; 2.演奏的同時可數字顯示當前的音調,利于培養(yǎng)樂感 3.可以選定播放固定樂曲自動演奏,演奏時LED進展節(jié)拍指示; 4.在自動演奏和奏樂的過程中按停頓鍵那么中斷演奏; 5.可以選擇調節(jié)音或小。 【方案可行性論證】:
6、 本課題采用stc89c52單片機作為核心器件,實現根本的音樂彈奏、音樂播放、音調顯示和音樂節(jié)拍指示的功能。 1. 音樂彈奏:通過程序識別4x4矩陣鍵盤中按下的鍵的坐標〔x,y〕, 然后根據〔x,y〕從計數初值表中讀取對應的計數初值,賦值給定時器0,定時器產生對應頻率的方波,到達播放對應音調的功能。 2. 音樂播放:先建立一個包含一首音樂的音調與節(jié)拍的表。其中,音調就是0x01(低音、do)、0x12(中音、re)、0x23〔高音、mi〕之類的數;節(jié)拍就是0x02〔半拍〕,0x04〔一拍〕之類的數。然后,根據音調讀取計數初值,再將計數初值賦給定時器T0 -> 開啟定時器T0 -> 讀取節(jié)
7、拍并延時 -> 關閉定時器T0 。這樣就發(fā)出了一個音,然后再讀下一個音的初值與節(jié)拍,重復上一個操作即可?!簿唧w實現方法見附錄總程序〕 3. 數碼管顯示音調: ① 按鍵:讀出按鍵坐標〔x,y〕,用if語句來判斷〔x,y〕該給數碼管賦什么值,然后從uchar code num[] 表中讀取這個值賦給數碼管(例如P0)。 ② 播放歌曲時:讀入音調,根據音調的值來判斷num[i]這個表中的i,再把num[i]賦給P0口。 4.led燈的節(jié)拍指示:采用定時器1來控制,作為節(jié)拍指示。 ①按鍵時:根據按下的時長來控制led的點亮個數,并且是按一定的時間間隔逐個點亮;釋放按鍵時,led燈按一定的時間
8、間隔逐個熄滅,從而到達一種比擬簡單的節(jié)拍指示效果。 ②播放音樂時:根據音符的節(jié)拍,控制點亮到哪一個燈,在點亮那個燈之前,前面的燈逐個等時距點亮。音符完畢后,led燈全部一起熄滅。這樣,到達了一個準確顯示節(jié)拍的效果。 開場 【程序框圖】: 掃描鍵盤 根據音調給T0賦初值 開啟T0 T1 是否停頓播放 讀下一個音符 關閉T0 T1數碼管與led 數碼管顯示音調 Led指示節(jié)拍 否 按節(jié)拍延遲 算出音符的音調、節(jié)拍 是否完畢符 關閉定時器 P0口置0 否 否 是 按鍵是否釋放 開啟定時器,并賦初值,蜂鳴器發(fā)聲 算出定時器初值
9、 數碼管顯示音調 識別按鍵 有矩陣鍵按下 否 否 播放鍵按下 讀取歌曲 是 是 是 【復位與震蕩電路】: 原件的參數如下圖。 C1,C2 可采用30pF 無極性瓷電容;C3可采用10μF記性電解質電容。 值得注意的是,晶振不能隨便摸!尤其在通電工作的時候,觸摸容易損壞。自從摸過一次后,震蕩頻率變得不穩(wěn)定,蜂鳴器聲音時好時壞。 【4x4矩陣鍵盤】: 鍵盤掃描的根本思路是:先得出觸發(fā)按鍵的“行〞,即橫坐標x,再得出他的“列〞,即縱坐標y。 以下是獲取橫坐標x的代碼: uchar key_x() /*P1口高位接縱坐標〔P1.7 - P
10、1.4〕 低位接橫坐標(P1.3 - P1.0)*/ { uchar i; P1 = 0x0f; /*有按鍵按下后 對應按鍵的橫坐標電位被拉低〔 注意低電位引腳不能被高電位引腳抬高,只能是低電位拉低高電位〕*/ if(P1_0 == 0) { delayms(5); //延時5ms 去抖動 if(P1_0 == 0) i = 1; } else if(P1_1 == 0) { delayms(5); if(P1_1 == 0) i = 2; } else if(P1_2 == 0) { delayms(5);
11、 if(P1_2 == 0) i = 3; } else if(P1_3 == 0) { delayms(5); if(P1_3 == 0) i = 4; } else i = 0; return (i); //0表示按鍵未按下 } 獲取y的方法與獲取x的方法類似,具體可以參考附件總程序。 得到觸發(fā)按鍵的坐標〔x,y〕之后,可以通過x,y的值來確定按鍵的功能。例如 x==1,y==1時〔S1按下〕,可以讓數碼管顯示1: if(x == 1 && y == 1) P0 = led_table[1]; 或者更方便一點:if(
12、x == 1) P0 = led_table[y]; 就能顯示第一行的所有的數了。 【數碼管與LED燈】: 數碼管: 在本課題中,數碼管要顯示A - G , 1 - 7, 1. - 7. ,所以段碼比擬另類。num[0]的值是沒用到的,起占位作用。 uchar code num[]={0x00, //共陰極數碼管段選碼 0x77,0x7c,0x39,0x5e,0x79,0x71,0x3d, //a - g 0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, //1 - 7 0x86,0xdb
13、,0xcf,0xe6,0xed,0xfd,0x87 //1. - 7. }; 編寫程序時,要根據實際情況來編寫: 比方16個按鍵不能夠把低中高音都全部表示完全,只能選取適宜的局部。 我讓第一行的按鍵 觸發(fā)低音 4 - 7,第二行觸發(fā)中音1 - 4,第三行觸發(fā)中音5 - 7和高音1,第四行觸發(fā)高音2 - 5。這樣設置能彈奏大局部曲目。 以下是控制數碼管的代碼片段: if(x == 1) P0 = num[3 + y] ; //低音4 - 7 else if(x == 2) P0 = num[7 + y]; //中音1 - 4 els
14、e if(x == 3) P0 = num[11 + y]; //中音5 - 7 和 高音 1 else if(x == 4) P0 = num[15 + y]; //高音2 - 5 LED燈: 因為LED燈要按一定的時間逐個點亮或者逐個熄滅,所以我用定時器1來控制它。 定時器1每溢出一次并滿足一定條件時flash變量就+1或者-1,然后從led_table[]這個表中讀出相應的數賦給P2口。 表: uchar code led_tabl
15、e[]={0xff,0x7f,0x3f,0x1f,0x0f,0x07,0x03,0x01,0x00};/*發(fā)光二極管閃爍表*/ 代碼: if(x != 0 && y != 0 && flash < 8 ) //最大加到8 ++flash; else if(x == 0 && y == 0 && flash >0 ) //最小減到0 --flash; P2 = led_table[flash]; 播放音樂時又有所不同: 播放音樂時,led燈要準確地顯示當前音符的節(jié)拍,所以if語句里加了一條限制語句:flash < jiepai)
16、
代碼:
if(out == 1 && flash < 8 && flash < jiepai) /*out ==1 表示有歌曲發(fā)聲時,(flash
17、 蜂鳴器采用一個s8550 NPN三極管驅動,一個可變電阻改變音量。三極管的選用要注意放大倍數,放大倍數太小會導致蜂鳴器聲音很小。最初采用8050就造成了這個問題。 另外,采用P3.0口連接接蜂鳴器是一個錯誤。因為P3.0、P3.1是燒寫程序用到的接口。倘假設連接了其他器件,每次調試都要拔下燒寫線,很不方便。 【音樂相關知識】: 【表6.5.1】音符頻率對照表 音符 頻率〔HZ〕 簡譜碼〔T值〕 音符 頻率〔HZ〕 簡譜碼〔T值〕 低1 DO 262 63628 0xf88c # 4 FA# 740 64860 #1 DO#
18、277 63731 中 5 SO 784 64898 0xfd82 低2 RE 294 63835 0xf95b # 5 SO# 831 64934 #2 RE# 311 63928 中 6 LA 880 64968 0xfdc8 低 3 M 330 64021 0xfa15 # 6 932 64994 低 4 FA 349 64103 0xfa67 中 7 SI 988 65030 0xfe06 # 4 FA# 370 64185 高 1 DO 1046 65058 0xfe22 低 5 SO 392 64
19、260 0xfb04 # 1 DO# 1109 65085 # 5 SO# 415 64331 高 2 RE 1175 65110 0xfe56 低 6 LA 440 64400 0xfb90 # 2 RE# 1245 65134 # 6 466 64463 高 3 M 1318 65157 0xfe85 低 7 SI 494 64524 0xfc0c 高 4 FA 1397 65178 0xfe9a 中 1 DO 523 64580 0xfc44 # 4 FA# 1480 65198 # 1 DO# 554
20、 64633 高 5 SO 1568 65217 0xfec1 中 2 RE 587 64684 0xfcac # 5 SO# 1661 65235 # 2 RE# 622 64732 高 6 LA 1760 65252 0xfee4 中 3 M 659 64777 0xfd09 # 6 1865 65268 中 4 FA 698 64820 0xfd34 高 7 SI 1967 65283 0xff03 音調、節(jié)拍以及編碼確實定方法: 一般說來,單片機演奏音樂根本都是單音頻率,它不包含相應幅度的諧波頻率,也
21、就是說不能像電子琴那樣能奏出多種音色的聲音。因此單片機奏樂只需弄清楚兩個概念即可,也就是“音調〞和節(jié)拍。其中節(jié)拍表示一個音符唱多長的時間。 音調確實定: 不同音高的樂音是用C、D、E、F、G、A、B來表示,這7個字母就是音樂的音名,它們一般依次唱成DO、RE、MI、FA、SO、LA、SI,即唱成簡譜的1、2、3、4、5、6、7,相當于漢字“多來米發(fā)梭拉西〞的讀音,這是唱曲時樂音的發(fā)音,所以叫“音調〞,即Tone。把C、D、E、F、G、A、B這一組音的距離分成12個等份,每一個等份叫一個“半音〞。兩個音之間的距離有兩個“半音〞,就叫“全音〞。在鋼琴等鍵盤樂器上,C–D、D–E、F–G、G
22、–A、A–B兩音之間隔著一個黑鍵,他們之間的距離就是全音;E–F、B–C兩音之間沒有黑鍵相隔,它們之間的距離就是半音。通常唱成1、2、3、4、5、6、7的音叫自然音,那些在它們的左上角加上﹟號或者b號的叫變化音。﹟叫升記號,表示把音在原來的根底上升高半音,b叫降記音,表示在原來的根底上降低半音。例如高音DO的頻率〔1046Hz〕剛好是中音DO的頻率〔523Hz〕的一倍,中音DO的頻率〔523Hz〕剛好是低音DO頻率〔266 Hz〕的一倍;同樣的,高音RE的頻率〔1175Hz〕剛好是中音RE的頻率〔587Hz〕的一倍,中音RE的頻率〔587Hz〕剛好是低音RE頻率〔294 Hz〕的一倍。 1〕
23、要產生音頻脈沖,只要算出某一音頻的周期〔1/頻率〕,然后將此周期除以2,即為半周期的時間。利用定時器計時這半個周期時間,每當計時到后就將輸出脈沖的I/O反相,然后重復計時此半周期時間再對I/O反相,就可在I/O腳上得到此頻率的脈沖。 2〕利用stc89c52的部定時器使其工作在計數器模式MODE1下,改變計數值TH0及TL0以產生不同頻率的方法。 此外完畢符和休止符可以分別用代碼00H和FFH來表示,假設查表結果為00H,那么表示曲子終了;假設查表結果為FFH,那么產生相應的停頓效果。 3〕例如頻率為523Hz,其周期T=1/523=1912us,因此只要令計數器計時956us/1us
24、=956,在每次計數956次時將I/O反相,就可得到中音DO〔523Hz〕。 計數脈沖值與頻率的關系公式如下: N=Fi2Fr N:計算值; Fi:部計時一次為1us,故其頻率為1MHz; 4) 其計數值的求法如下: T=65536-N=65536-Fi2Fr 例如:設K=65536,F=1000000=Fi=1MHz,求低音DO〔261Hz〕。中音DO〔523Hz〕。高音的DO〔1046Hz〕的計算值 T=65536-N=65536-Fi2Fr=65536-10000002Fr=65536-500000/Fr 低音DO的T=65536-500000/262=63627
25、 中音DO的T=65536-500000/523=64580 高音DO的T=65536-500000/1047=65059 5) C調各音符頻率與計數值T的對照表如表1.6.5.2所示。 低音 頻率 T 參數 中音 頻率 T 參數 高音 頻率 T 參數 Do 262 1908 229 Do 523 956 115 Do 1046 57 57 Do﹟ 277 1805 217 Do﹟ 554 903 108 Do﹟ 1109 54 54 Re 294 1701 204 Re 587 852 102 Re
26、 1175 51 51 Re﹟ 311 1608 193 Re﹟ 622 804 97 Re﹟ 1245 48 48 Mi 330 1515 182 Mi 659 759 91 Mi 1318 45 45 Fa 349 1433 172 Fa 698 716 86 Fa 1397 43 43 Fa﹟ 370 1351 162 Fa﹟ 740 676 81 Fa﹟ 1480 41 41 So 392 1276 153 So 784 638 77 So 1568 38 38
27、 So﹟ 415 1205 145 So﹟ 831 602 72 So﹟ 1661 36 36 La 440 1136 136 La 880 568 68 La 1760 34 34 La﹟ 464 1078 129 La﹟ 932 536 64 La﹟ 1865 32 32 Si 494 1012 121 Si 988 506 61 Si 1976 30 30 表6.5.2 C調各音符頻率與計數值T的對照表 節(jié)拍確實定: 假設要構成音樂,光有音調是不夠的,還需要節(jié)拍,讓音樂具有
28、旋律〔固定的律動〕,而且可以調節(jié)各個音的快滿度。“節(jié)拍〞,即Beat,簡單說就是打拍子,就像我們聽音樂不自主的隨之拍手或跺腳。假設1拍實0.5s,那么1/4 拍為0.125s。至于1拍多少s,并沒有嚴格規(guī)定,就像人的心跳一樣,大局部人的心跳是每分鐘72下,有些人快一點,有些人慢一點,只要聽的悅耳就好。音持續(xù)時間的長短即時值,一般用拍數表示。休止符表示暫停發(fā)音。 一首音樂是由許多不同的音符組成的,而每個音符對應著不同頻率,這樣就可以利用不同的頻率的組合,加以與拍數對應的延時,構成音樂。了解音樂的一些根底知識,我們可知產生不同頻率的音頻脈沖即能產生音樂。對于單片機來說,產生不同頻率的脈沖是非常方
29、便的,利用單片機的定時/計數器來產生這樣的方波頻率信號。因此,需要弄清楚音樂中的音符和對應的頻率,以及單片機定時計數的關系。 音樂的編碼: 每個音符采用2個字節(jié)。第一個字節(jié)表示音調,第二個字節(jié)表示節(jié)拍。 音調字節(jié)中,高四位表示低中高音,0表示低音,1表示中音,2表示高音;低四位表示“音調〞。比方:0x11表示中音do。 節(jié)拍字節(jié)中,數值i表示代表著延遲i個十六分音符。比方:0x04,表示延時4個16分音符,即延時1個四分之一音符。在以四分音符為一拍的歌曲中,0x04就代表一拍。底下沒有橫線,右側也沒有橫線的數字〔音調〕,就用0x04表示他的延時。底下有一橫線:0x02;右側有一橫:
30、0x08;右側兩橫:0x0c;右側三橫:0x10;右下角有一點:加上當前延時的一半。 由于不同的歌曲有不同的播放速度,即曲速〔單位——拍每分鐘〕。所以音樂編碼表中的第0和第1元素用來表示曲速。 我們可以找到任意歌曲的簡譜圖,然后根據上述規(guī)那么編寫出單片機識別的簡譜表。 例如: 可以翻譯成: uchar code ymt[]={//玉滿堂 0x96,0x00, //曲速 0x96表示 150拍/分 0x00,0x0a,0x05,0x02,0x15,0x02,0x12,0x02, 0x13,0x04,0x13,0x02,0x15,0x
31、02,0x12,0x04,0x12,0x02,0x13,0x02, 0x12,0x10, 0x13,0x04,0x13,0x02,0x12,0x02,0x13,0x04,0x15,0x02,0x16,0x02, 0x15,0x0c,0x13,0x02,0x15,0x02, 0x16,0x04,0x16,0x02,0x21,0x02,0x16,0x04,0x15,0x02,0x13,0x02, 0x15,0x0c,0x15,0x02,0x16,0x02, 0x21,0x04,0x21,0x02,0x22,0x02,0x23,0x04,0x22,0x02,0x21,0x02, 0x2
32、2,0x10, 0x23,0x08,0x15,0x02,0x16,0x02,0x21,0x02,0x22,0x02, 0x23,0x04,0x23,0x02,0x22,0x02,0x21,0x06,0x21,0x02, 0x16,0x04,0x16,0x02,0x21,0x02,0x16,0x04,0x13,0x04, 0x15,0x10, 0x16,0x04,0x16,0x02,0x21,0x02,0x16,0x04,0x21,0x02,0x22,0x02, 0x23,0x04,0x23,0x02,0x22,0x02,0x21,0x06,0x21,0x02, 0x16,0x02
33、,0x21,0x02,0x16,0x02,0x21,0x02,0x22,0x02,0x23,0x02,0x25,0x02,0x23,0x02, 0x22,0x0c,0x21,0x02,0x22,0x02, 0x23,0x06,0x15,0x02,0x16,0x02,0x21,0x02,0x22,0x02, 0x23,0x04,0x23,0x02,0x22,0x02,0x21,0x06,0x21,0x02, 0x16,0x04,0x16,0x02,0x21,0x02,0x16,0x02,0x21,0x02,0x15,0x02,0x13,0x02, 0x15,0x0c,0x13,0x02
34、,0x15,0x02, 0x16,0x04,0x16,0x02,0x21,0x02,0x16,0x04,0x16,0x02,0x21,0x02, 0x22,0x04,0x22,0x02,0x23,0x02,0x22,0x04,0x22,0x02,0x23,0x02, 0x25,0x02,0x26,0x02,0x23,0x02,0x25,0x02,0x22,0x02,0x23,0x02,0x21,0x02,0x16,0x02, 0x21,0x10, 0xff }; 【調試過程】: 編寫程序階段,一個功能、一個模塊地編寫。先寫好鍵盤掃描程序,然后再到數碼管顯示、蜂鳴器發(fā)聲、
35、led節(jié)拍指示。分部進展,個個擊破。 【總結體會】: 本課題讓我更深刻地認識到了單片機這種器件,特別是對單片機里面的定時器收獲最多。 而且這是我第一次焊雙面板,意義不同凡響。有了這次經歷,對以后做板子定有深遠的影響。 制作過程中,感觸最深的是解決雜音問題。在彈奏與播放時,蜂鳴器聲音不純,有顫音,影響音樂美感。為此,我煞費苦心,花了很多時間找原因。想到了精簡定時器中斷程序里的代碼和運算,但效果甚微。直到最后,突然想到了定時器有優(yōu)先級的說法。試了一下,將控制蜂鳴器的定時器T0設為高優(yōu)先級。終于問題解決了!而且是如此的簡單,但是過程卻是又如此的艱辛,讓人感覺不太值得。。不過,終歸是值
36、得的! 【參考文獻】: ?單片微機原理、匯編與C51及接口技術?〔朱定華 戴穎穎 川香 著〕 序 號 名 稱 數 量 備 注 1 四腳開關 18 6x6 mm 2 12Mhz晶振 1 3 30pF瓷電容 2 4 10μF無極性電容 1 5 10K 2.2K電阻 9 10K x9 ;2.2K x1 6 240電阻 10 7 NPN 三極管 1 s8550 8 七段共陰極數碼管 2 9 無源蜂鳴器 1 10 電位器 1 11 發(fā)光二極管 10 紅色 x8
37、 黃x1 綠 x1
12
排針
3排
13
雙面覆銅銅板
1
15x10 cm
14
40P杜邦線
1
15
單片機底座
2
16
電源開關
1
17
Stc89c52單片機
1
【附錄】:
設備與儀器:電腦、單片機開發(fā)板〔或者單片機燒寫器〕
軟件:Keil uVision4 、DXP 09
原件清單:
原理圖與PCB圖:
總程序:
#include
38、 #define uint unsigned int #define allsong 4 //歌曲總數 按實際寫 sbit P1_0 = P1^0; sbit P1_1 = P1^1; sbit P1_2 = P1^2; sbit P1_3 = P1^3; sbit P1_4 = P1^4; sbit P1_5 = P1^5; sbit P1_6 = P1^6; sbit P1_7 = P1^7; sbit beep = P3^0; sbit key_play = P3^1; uchar x = 0; /*矩陣鍵盤橫坐標 從1開場 0為未按下的標志
39、*/ uchar y = 0; /*矩陣鍵盤縱坐標 從1開場 0為未按下的標志 */ uchar flash = 0; //控制led燈顯示 的變量 */ uchar f_l; /*按鍵發(fā)出音調的初值(低位〕*/ uchar f_h; //高位 uchar song_l; /*歌曲音調的初值〔低位〕*/ uchar song_h; //高位 uchar out = 0; /*聲音輸出變量 1表示有輸出 0表示無輸出 */ uchar yindiao; /*音調 定義為全局變量 為了在播放時數碼管能顯示當前音調*/ uchar yind
40、iao_h; //音調的高四位 uchar yindiao_l; //音調的低四位 uchar jiepai; /*節(jié)拍〔簡而言之就是一個音調響的時間長度〕*/ uchar song_id = 1; //歌曲序號變量 uchar temp_id = 1; //歌曲臨時序號 uint which = 2; /*簡譜表里的第幾個音 從第2個開場 第0個用來存曲速,第1個占位*/ uchar same = 0; /*在暫停時選了同一首歌曲,用于跳出暫停循環(huán)*/ uchar key_x(); //獲取鍵盤橫坐標 函數 uchar key_y(); //獲取鍵盤縱坐標
41、函數 void play(); //播放歌曲 函數 void delayms(uint ms);//延時xx ms 函數 void delay(uint pai);//節(jié)拍延時 函數 void key_check(); //檢查按鍵狀態(tài) 函數 void display(); //數碼管顯示對應音調 函數 void speak(); /*按鍵后 給定時器0賦對應音調的初值 從而發(fā)出聲音*/ uchar choose(); /*播放狀態(tài)下 選歌函數 釋放按鍵后才跳出函數,返回歌曲序號*/ uchar choose2(); /*暫停狀態(tài)下 選歌函數 不用釋放按鍵即可跳出
42、函數,返回歌曲序號 */ void play(); //播放歌曲 函數 uchar code num[]={0x00, //數碼管段選碼 0x77,0x7c,0x39,0x5e,0x79,0x71,0x3d, //a - g 0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, //1 - 7 0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87 //1. - 7. }; uchar code led_table[]={0xff,0x7f,0x3f,0x1f,0x0f,0x07,0x03,0x01,0x00};/*發(fā)光二極管閃爍表
43、*/ uchar code chuzhi[]={ //音調對應的計數初值 0xff,0xff,//占0位 0xf8,0x8c,//低1 (0x01) a -數碼管顯示方式 0xf9,0x5b,// 2 b 0xfa,0x15,// 3 c 0xfa,0x67,// 4 d 0xfb,0x04,// 5 e 0xfb,0x90,// 6 f 0xfc,0x0c,//低7〔0x07〕g 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*占位 0x08 - 0x0b
44、(8 - 11)*/ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,/*占位 0x0c - 0x10 (12 - 16)*/ 0xfc,0x44,//中1 〔0x11〕 (17) 0xfc,0xac,// 2 0xfd,0x09,// 3 0xfd,0x34,// 4 0xfd,0x82,// 5 0xfd,0xc8,// 6 0xfe,0x06,//中7 〔0x17〕 (23) 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*占位
45、0x18 - 0x1b (24 - 27)*/ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*占位 0x1c - 0x20 (28 - 32)*/ 0xfe,0x22,//高1 〔0x21〕1. (33) 0xfe,0x56,// 2 2. 0xfe,0x85,// 3 3. 0xfe,0x9a,// 4 4. 0xfe,0xc1,// 5 5. 0xfe,0xe4,// 6 6. 0xff,0x03 //高7 〔0x27〕7. (39) };
46、 uchar code ymt[]={//玉滿堂 0x96,0x00, //曲速 0x96表示 150拍/分 0x00,0x0a,0x05,0x02,0x15,0x02,0x12,0x02, 0x13,0x04,0x13,0x02,0x15,0x02,0x12,0x04,0x12,0x02,0x13,0x02, 0x12,0x10, 0x13,0x04,0x13,0x02,0x12,0x02,0x13,0x04,0x15,0x02,0x16,0x02, 0x15,0x0c,0x13,0x02,0x15,0x02, 0x16,0x04,0x16,0x02,0x21,0x02
47、,0x16,0x04,0x15,0x02,0x13,0x02, 0x15,0x0c,0x15,0x02,0x16,0x02, 0x21,0x04,0x21,0x02,0x22,0x02,0x23,0x04,0x22,0x02,0x21,0x02, 0x22,0x10, 0x23,0x08,0x15,0x02,0x16,0x02,0x21,0x02,0x22,0x02, 0x23,0x04,0x23,0x02,0x22,0x02,0x21,0x06,0x21,0x02, 0x16,0x04,0x16,0x02,0x21,0x02,0x16,0x04,0x13,0x04, 0x15,
48、0x10, 0x16,0x04,0x16,0x02,0x21,0x02,0x16,0x04,0x21,0x02,0x22,0x02, 0x23,0x04,0x23,0x02,0x22,0x02,0x21,0x06,0x21,0x02, 0x16,0x02,0x21,0x02,0x16,0x02,0x21,0x02,0x22,0x02,0x23,0x02,0x25,0x02,0x23,0x02, 0x22,0x0c,0x21,0x02,0x22,0x02, 0x23,0x06,0x15,0x02,0x16,0x02,0x21,0x02,0x22,0x02, 0x23,0x04,0x2
49、3,0x02,0x22,0x02,0x21,0x06,0x21,0x02, 0x16,0x04,0x16,0x02,0x21,0x02,0x16,0x02,0x21,0x02,0x15,0x02,0x13,0x02, 0x15,0x0c,0x13,0x02,0x15,0x02, 0x16,0x04,0x16,0x02,0x21,0x02,0x16,0x04,0x16,0x02,0x21,0x02, 0x22,0x04,0x22,0x02,0x23,0x02,0x22,0x04,0x22,0x02,0x23,0x02, 0x25,0x02,0x26,0x02,0x23,0x02,0x2
50、5,0x02,0x22,0x02,0x23,0x02,0x21,0x02,0x16,0x02, 0x21,0x10, 0xff }; uchar code dl[]={ //蝶戀 0x8c,0x00, //曲速 0x8c表示 140拍/分 0x13,0x04,0x13,0x04,0x13,0x04,0x12,0x04,0x13,0x08, 0x12,0x04,0x13,0x04,0x12,0x04,0x12,0x04,0x06,0x08, 0x06,0x04,0x07,0x04,0x11,0x08,0x12,0x04,0x11,0x04,0x07,0x08,0x06,
51、0x04,0x05,0x04,0x06,0x10, 0x13,0x04,0x13,0x04,0x13,0x04,0x12,0x04,0x13,0x0c, 0x16,0x04,0x15,0x04,0x16,0x04,0x15,0x04,0x15,0x04,0x12,0x04, 0x12,0x04,0x13,0x04,0x14,0x08,0x15,0x04,0x14,0x04,0x13,0x04,0x12,0x04,0x11,0x04,0x13,0x0f,0x13,0x0c, 0x13,0x04,0x16,0x08,0x17,0x04,0x16,0x04,0x15,0x0c,0x13,0x
52、04,0x15,0x0f, 0x13,0x04,0x15,0x04,0x12,0x08,0x16,0x04,0x15,0x04,0x13,0x08,0x12,0x04,0x12,0x04,0x13,0x0c, 0x12,0x08,0x16,0x04,0x16,0x0c, 0x11,0x08,0x16,0x04,0x16,0x08, 0x16,0x04,0x17,0x04,0x21,0x08,0x17,0x04,0x16,0x04,0x17,0x08,0x16,0x04,0x17,0x04,0x13,0x08,0x13,0x0c, 0x13,0x04,0x16,0x08,0x17,0x
53、08,0x16,0x04,0x15,0x0c,0x13,0x04,0x15,0x10, 0x14,0x04,0x15,0x04,0x16,0x08,0x17,0x04,0x16,0x04,0x17,0x08, 0x16,0x04,0x17,0x04,0x13,0x10,0x13,0x10, 0x12,0x08,0x16,0x04,0x16,0x02,0x16,0x10, 0x11,0x04,0x16,0x04,0x16,0x02,0x16,0x08, 0x16,0x04,0x17,0x04,0x21,0x08,0x17,0x04,0x16,0x04,0x17,0x08,0x15,0x
54、08,0x16,0x10, 0x23,0x04,0x22,0x04,0x22,0x04,0x21,0x04,0x21,0x04,0x17,0x04,0x17,0x04,0x16,0x04, 0x21,0x04,0x17,0x04,0x17,0x04,0x16,0x04,0x16,0x04,0x15,0x04,0x15,0x04,0x14,0x04, 0x16,0x04,0x15,0x04,0x15,0x04,0x14,0x04,0x14,0x04,0x13,0x04,0x13,0x04,0x12,0x04, 0x13,0x10,0x13,0x10, 0xff }; uchar
55、 code srkl[]={//生日快樂 0x78,0x00, //曲速 120 0x15,0x02,0x15,0x02, 0x16,0x04,0x15,0x04,0x21,0x04, 0x17,0x04,0x00,0x04,0x15,0x02,0x15,0x02, 0x16,0x04,0x15,0x04,0x22,0x04, 0x21,0x08,0x15,0x02,0x15,0x02, 0x25,0x04,0x23,0x04,0x21,0x04, 0x17,0x04,0x16,0x08, 0x16,0x04,0x00,0x04,0x24,0x02,0x24,0x02, 0
56、x23,0x04,0x21,0x04,0x22,0x04, 0x21,0x08, 0x21,0x08,0x00,0x08, 0x15,0x02,0x15,0x02,//第二遍 0x16,0x04,0x15,0x04,0x21,0x04, 0x17,0x04,0x00,0x04,0x15,0x02,0x15,0x02, 0x16,0x04,0x15,0x04,0x22,0x04, 0x21,0x08,0x15,0x02,0x15,0x02, 0x25,0x04,0x23,0x04,0x21,0x04, 0x17,0x04,0x16,0x08, 0x16,0x04,0x00,0
57、x04,0x24,0x02,0x24,0x02, 0x23,0x04,0x21,0x04,0x22,0x04, 0x21,0x08, 0x21,0x08,0x00,0x04, 0xff }; uchar code test[]={//測試 0x78,0x00, //曲速 0x78表示 120拍/分 0x01,0x04,0x02,0x04,0x03,0x04,0x04,0x04,0x05,0x04,0x06,0x04,0x07,0x04,0x00,0x04, 0x11,0x08,0x12,0x07,0x13,0x06,0x14,0x05,0x15,0x04,0x16,0x03
58、,0x17,0x02,0x00,0x01, 0x21,0x01,0x22,0x02,0x23,0x03,0x24,0x04,0x25,0x05,0x26,0x06,0x27,0x07,0x00,0x08, 0xff, }; void delayms(uint ms) /*ms 等于1時,延時1ms 等于2時,延時2ms,以此類推*/ { uchar a,b,c; //+3 while(ms--) { for(c=1;c>0;c--) // 1+2 = 3 for(b=142;b>0;b--) // 1*(
59、 1+142*2)) = 285 for(a=2;a>0;a--); // 142*(1+2*2) = 710 } } void delay(uint pai) /*pai 是節(jié)拍 pai假設定義成uchar類型,當節(jié)拍>0x0c時,會造成數據溢出,產生失真。*/ { uchar a,b,c; while(pai--) //延遲pai 個 6.25ms { for(c=1;c>0;c--) // 1+2=3 for(b=28;b>0;b--) // 1*(1+28*2) =57
60、 for(a=110;a>0;a--); // 28*(1+110*2) = 6188 } } uchar key_x() /*P1口高位接縱坐標〔P1.7 - P1.4〕 低位接橫坐標(P1.3 - P1.0)*/ { uchar i; P1 = 0x0f; /*有按鍵按下后 對應按鍵的橫坐標電位被拉低〔 注意低電位引腳不能被高電位引腳抬高,只能是低電位拉低高電位〕*/ if(P1_0 == 0) { delayms(5); //延時5ms 去抖動 if(P1_0 == 0) i = 1; } else if(P1_
61、1 == 0) { delayms(5); if(P1_1 == 0) i = 2; } else if(P1_2 == 0) { delayms(5); if(P1_2 == 0) i = 3; } else if(P1_3 == 0) { delayms(5); if(P1_3 == 0) i = 4; } else i = 0; return (i); //0表示按鍵未按下 } uchar key_y() { uchar j; P1 = 0xf0; if(P1_4 ==
62、 0) { delayms(5); if(P1_4 == 0) j = 1; } else if(P1_5 == 0) { delayms(5); if(P1_5 == 0) j = 2; } else if(P1_6 == 0) { delayms(5); if(P1_6 == 0) j = 3; } else if(P1_7 == 0) { delayms(5); if(P1_7 == 0) j = 4; } else j = 0; return (j); } vo
63、id key_check() /*檢查矩陣按鍵坐標、播放鍵的狀態(tài)及播放鍵狀態(tài)設置*/ { x = key_x(); y = key_y(); if(key_play == 0) key_play = 0; /*保持播放鍵引腳低電平,讓其作為歌曲正在播放的標志*/ else key_play = 1; /*保持播放鍵引腳高電平,讓其作為歌曲未播放的標志*/ } void display() /*數碼管顯示相應的音調*/ { if(key_play == 1) //按鍵彈奏時 { if(x != 0 && y != 0
64、) { if(x == 1) P0 = num[3 + y] ; //低音4 - 7 else if(x == 2) P0 = num[7 + y]; //中音1 - 4 else if(x == 3) P0 = num[11 + y]; //中音5 - 7 和 高音 1 else if(x == 4) P0 = num[15 + y]; //高音2 - 5 } else P0 = 0x00; } else //播放音樂時 { if(yindiao_h == 0)
65、 /* yindiao變量的高四位表示 低〔0〕 中〔1〕 高〔2〕 音 */ P0 = num[yindiao_l];/*yindiao變量的低四位表示“調〞, 數碼管顯示當前音調*/ else if(yindiao_h == 1) // 中音 P0 = num[yindiao_l + 7]; else if(yindiao_h == 2) //高音 P0 = num[yindiao_l + 14]; } } void speak() /* 按鍵 ,為定時器0 T0 賦計數初值,讓 T0函數驅動蜂鳴器發(fā)出對應的音調 */ { i
66、f(x == 1) { f_h = chuzhi[2*y + 6]; //低音4 - 7 f_l = chuzhi[2*y + 6 + 1]; } else if(x == 2) { f_h = chuzhi[(16+y)*2]; //中音 1 -4 f_l = chuzhi[(16+y)*2 +1]; } else if(x == 3) { if(y <= 3) { f_h = chuzhi[(20+y)*2]; //中音 5 - 7 f_l = chuzhi[(20+y)*2 + 1]; } else { f_h = chuzhi[66]; //高音1 f_l = chuzhi[67]; } } else if(x == 4) { f_h = chuzhi[(33+y)*2]; //高音2 -5 f_l = chuzhi[(33+y)*2 + 1]; } } void timer0() interr
- 溫馨提示:
1: 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
2: 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
3.本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
5. 裝配圖網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。