一種基于單片機(jī)的電子琴設(shè)計(jì),它是以STC89C52單片機(jī)為控制核心,輔以一些外圍器件,采用C語(yǔ)言編寫程序,可以進(jìn)行8個(gè)音調(diào)值的彈奏,且內(nèi)置電子音樂(lè)曲目,實(shí)現(xiàn)基于單片機(jī)的電子琴設(shè)計(jì)。
整個(gè)系統(tǒng)電路結(jié)構(gòu)簡(jiǎn)單,可靠性能高,測(cè)試結(jié)果滿足設(shè)計(jì)要求。本文著重介紹了該系統(tǒng)的設(shè)計(jì)原理,硬件設(shè)計(jì)方法與軟件編程思路
本電子琴基于STC89C52單片機(jī)為核心控制芯片。在發(fā)音硬件的選擇,蜂鳴器。彈奏鍵盤則采用鼠標(biāo)按鍵來(lái)代替普通的按鍵,鼠標(biāo)按鍵無(wú)論在外形、手感、還是質(zhì)量上,都更加適合作為電子琴的彈奏按鍵;通過(guò)單片機(jī)IO口控制采集按鍵的狀態(tài),實(shí)現(xiàn)歌曲的切換和復(fù)位等功能。顯示設(shè)備則采用一位共陽(yáng)數(shù)碼管,通過(guò)單片機(jī)P0口給出數(shù)據(jù)信號(hào),可以通過(guò)數(shù)碼管查看當(dāng)前正在播放的音調(diào)編號(hào)。
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
有備注講解
單片機(jī)源程序如下:
- #include <reg52.h>
- #define SONG 4 // 歌曲的數(shù)量
- #define uchar unsigned char // 以后unsigned char就可以用uchar代替
- #define uint unsigned int // 以后unsigned int 就可以用uint 代替
- #define ulong unsigned long // 以后unsigned long就可以用ulong代替
- sbit Key1_P = P1^3; // 彈奏鍵1的管腳
- sbit Key2_P = P1^7; // 彈奏鍵2的管腳
- sbit Key3_P = P3^2; // 彈奏鍵3的管腳
- sbit Key4_P = P3^3; // 彈奏鍵4的管腳
- sbit Key5_P = P1^2; // 彈奏鍵5的管腳
- sbit Key6_P = P1^6; // 彈奏鍵6的管腳
- sbit Key7_P = P3^1; // 彈奏鍵7的管腳
- sbit Key8_P = P3^5; // 彈奏鍵8的管腳
- sbit Key9_P = P1^4; // 播放內(nèi)置歌曲的按鍵管腳
- sbit Beep_P = P2^7; // 揚(yáng)聲器管腳
- uchar gTone=0; // gTone代表當(dāng)前要播放的音調(diào)
- uchar gPlayStatus; // gPlayStatus代表當(dāng)前的播放狀態(tài),0是停止,1是播放
- uchar gSong; // gSong代表當(dāng)前播放到第幾首歌
- /* 定時(shí)器初值 低1 低2 低3 低4 低5 低6 低7 中1 中2 中3 中4 中5 中6 中7 高1 高2 高3 高4 高5 高6 高7 */
- uchar code ArrTL0[]={ 140, 91, 21, 103, 4, 144, 12, 68, 121, 220, 52, 130, 200, 6, 34, 86, 133, 154, 193, 228, 3 };
- uchar code ArrTH0[]={ 248, 249, 250, 250, 251, 251, 252, 252, 252, 252, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 255 };
- // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
- /* 數(shù)碼管的顯示值 1 2 3 4 5 6 7 */
- uchar code ArrDig[]={ 0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8};
- /* 《水手》的樂(lè)譜 */
- uchar code Music1[]={
- 5,4, 9,2, 8,2, 9,4, 8,2, 9,2,
- 10,3, 11,1, 10,2, 8,2, 9,8, 9,1,
- 10,2, 10,1, 9,1, 8,2, 7,1, 7,1, 8,2, 7,1, 7,1, 8,2, 9,2,
- 7,2, 6,2, 5,2, 7,2, 6,8,
- 5,4, 9,2, 8,2, 9,4, 8,2, 9,2,
- 10,2, 10,1, 11,1, 9,2, 8,2, 9,8,
- 10,3, 9,1, 8,2, 7,2, 8,2, 8,1, 7,1, 8,2, 8,1, 9,1,
- 6,2, 6,2, 5,2, 4,2, 5,8,
- 8,3, 8,1, 8,2, 8,2, 10,2, 10,1, 9,1, 8,2, 7,1, 7,1,
- 9,3, 8,1, 7,2, 8,1, 7,1, 5,8,
- 8,3, 8,1, 8,2, 8,2, 8,2, 8,1, 8,1, 8,2, 7,1, 8,1,
- 9,2, 9,2, 9,1, 8,1, 7,1, 8,1, 9,8,
- 8,3, 8,1, 8,2, 8,2, 10,2, 9,2, 8,2, 8,2,
- 9,2, 8,2, 7,2, 8,1, 7,1, 5,7, 5,1,
- 8,3, 8,1, 8,2, 8,1, 8,1, 8,2, 8,2, 7,2, 8,2,
- 9,2, 9,2, 8,2, 7,2, 9,4, 9,2, 11,2,
- 12,4, 11,4, 9,4, 8,2, 7,2,
- 8,2, 9,1, 8,1, 7,2, 6,2, 5,4, 5,2, 6,2,
- 7,4, 7,2, 9,2, 8,4, 6,1, 5,1, 4,2,
- 5,3, 5,1, 7,2, 8,2, 9,4, 9,2, 11,2,
- 12,4, 11,4, 9,4, 8,2, 7,2,
- 8,2, 9,1, 8,1, 7,2, 6,2, 5,4, 5,2, 6,2,
- 7,4, 7,2, 9,2, 8,4, 7,2, 6,2, 5,12
- };
- /* 《揮著翅膀的女孩》的樂(lè)譜 */
- uchar code Music2[]={
- 9,4, 9,2, 10,2, 11,4, 7,2, 8,2,
- 9,2, 9,2, 9,2, 10,2, 11,4, 8,2, 9,2,
- 10,4, 10,2, 9,2, 7,4, 10,2, 9,2,
- 10,4, 5,2, 7,2, 8,4, 7,2, 8,2,
- 9,4, 9,2, 10,2, 11,4, 12,2, 13,2,
- 14,2, 14,2, 9,2, 10,2, 11,4, 8,2, 9,2,
- 10,2, 9,2, 10,2, 14,2, 14,4, 8,2, 9,2,
- 10,2, 9,2, 10,2, 15,2, 15,4, 14,2, 13,2,
- 14,6, 15,2, 16,2, 15,2, 14,2, 13,2,
- 14,6, 14,2, 13,2, 11,2, 11,2, 7,2,
- 12,6, 12,2, 11,2, 7,2, 7,2, 9,2,
- 8,6, 9,1, 10,1, 10,2, 11,2, 14,2, 13,2,
- 14,6, 15,2, 16,2, 15,2, 14,2, 13,2,
- 14,6, 14,2, 13,2, 11,2, 11,2, 7,2,
- 12,6, 12,2, 11,2, 11,2, 14,2, 13,2,
- 14,16
- };
- /* 《茉莉花》的樂(lè)譜 */
- uchar code Music3[]={
- 9,4, 9,2, 11,2, 12,2, 14,2, 14,2, 12,2,
- 11,4, 11,2, 12,2, 11,8,
- 9,4, 9,2, 11,2, 12,2, 14,2, 14,2, 12,2,
- 11,4, 11,2, 12,2, 11,8,
- 11,4, 11,4, 11,4, 9,2, 11,2,
- 12,4, 12,4, 11,8,
- 9,4, 8,2, 9,2, 11,4, 9,2, 8,2,
- 7,4, 7,2, 8,2, 7,8,
- 9,2, 8,2, 7,2, 9,2, 8,6, 9,2,
- 11,4, 12,2, 14,2, 11,8,
- 8,4, 9,2, 11,2, 8,2, 9,2, 7,2, 5,2,
- 4,8, 5,4, 7,4,
- 8,6, 9,2, 7,2, 8,2, 7,2, 5,2,
- 4,12
- };
- /* 《歡樂(lè)頌》的樂(lè)譜 */
- uchar code Music4[]={
- 9,2, 9,2, 10,2, 11,2,
- 11,2, 10,2, 9,2, 8,2,
- 7,2, 7,2, 8,2, 9,2,
- 9,3, 8,1, 8,4,
- 9,2, 9,2, 10,2, 11,2,
- 11,2, 10,2, 9,2, 8,2,
- 7,2, 7,2, 8,2, 9,2,
- 8,3, 7,1, 7,4,
- 8,2, 8,2, 9,2, 7,2,
- 8,2, 9,1, 10,1, 9,2, 7,2,
- 8,2, 9,1, 10,1, 9,2, 8,2,
- 7,2, 8,2, 4,2, 9,2,
- 9,2, 9,2, 10,2, 11,2,
- 11,2, 10,2, 9,2, 10,1, 8,1,
- 7,2, 7,2, 8,2, 9,2,
- 8,3, 7,1, 7,4
- } ;
- /********************************************************************
- * 名稱 : uchar ChangeFor(uchar dat)
- * 功能 : 交換一個(gè)字節(jié)位的位置,用于數(shù)碼管顯示
- * 輸入 : 需要改變的數(shù)
- * 輸出 : 改變后的數(shù)
- ***********************************************************************/
- #define LED_a 6 //數(shù)碼管段選的a段接在段選IO口的第0位
- #define LED_b 7
- #define LED_c 5
- #define LED_d 3
- #define LED_e 2
- #define LED_f 1
- #define LED_g 0
- #define LED_dp 4
- uchar ChangeFor(uchar dat)
- {
- uchar temp=0;
- if(dat&0x01) //判斷數(shù)據(jù)的第一位是否為1
- temp|=0x01<<LED_a;//如果為1,放到控制數(shù)碼管a段的位置
- if(dat&0x02)
- temp|=0x01<<LED_b;
- if(dat&0x04)
- temp|=0x01<<LED_c;
- if(dat&0x08)
- temp|=0x01<<LED_d;
- if(dat&0x10)
- temp|=0x01<<LED_e;
- if(dat&0x20)
- temp|=0x01<<LED_f;
- if(dat&0x40)
- temp|=0x01<<LED_g;
- if(dat&0x80)
- temp|=0x01<<LED_dp;
- return temp;
- }
- /*********************************************************/
- // 毫秒級(jí)的延時(shí)函數(shù),time是要延時(shí)的毫秒數(shù)
- /*********************************************************/
- void DelayMs(uint time)
- {
- uint i,j;
- for(i=time;i>0;i--)
- for(j=110;j>0;j--);
- }
- /*********************************************************/
- // 發(fā)出指定音調(diào)及其節(jié)拍的聲音,tone代表音調(diào),beat代表節(jié)拍
- /*********************************************************/
- void PlayTone(uchar tone,float beat)
- {
- int i;
- P0=ChangeFor(ArrDig[tone%7]); // 數(shù)碼管顯示當(dāng)前音調(diào)值
- gTone=tone; // 將音調(diào)值賦給全局變量gTone
- TH0 = ArrTH0[tone]; // 裝入定時(shí)器TH0的初值
- TL0 = ArrTL0[tone]; // 裝入定時(shí)器TL0的初值
- TR0=1; // 啟動(dòng)定時(shí)器
- for(i=0;i<beat;i++)
- {
- DelayMs(200);
- }
- TR0=0; // 停止定時(shí)器
- P0=0xff; // 關(guān)閉數(shù)碼管顯示
- }
- /*********************************************************/
- // 播放內(nèi)置的音樂(lè)
- // arr[]是要播放的樂(lè)譜數(shù)組,num是數(shù)組里面的元素個(gè)數(shù)
- /*********************************************************/
- void PlayMusic(uchar music[],uint num)
- {
- uint i=0;
- while(i<num)
- {
- if(gPlayStatus==1) // 判斷播放狀態(tài)是否為播放還是暫停
- {
- PlayTone(music[i],music[i+1]); // 開始演奏一個(gè)節(jié)拍
- i+=2; // 進(jìn)入下一個(gè)節(jié)拍,因?yàn)槊?個(gè)數(shù)為1組,所以每次要加2
- if(i==num) // 判斷歌曲是否播放完了
- {
- gPlayStatus=0; // 播放完了的話,則把播放狀態(tài)改為暫停,否則會(huì)循環(huán)播放
- }
- }
-
- if(Key9_P==0) // 下一曲
- {
- DelayMs(10); // 消除按鍵按下的抖動(dòng)
- while(!Key9_P); // 等待按鍵釋放
- DelayMs(10); // 消除按鍵松開的抖動(dòng)
- gSong++; // 把當(dāng)前播放到第幾首歌的變量gSong加1,即切到下一曲
- if(gSong>SONG) // 如果gSong為SONG,說(shuō)明到后面的盡頭了,則轉(zhuǎn)為第一首
- gSong=1;
- break;
- }
- }
- }
- /*********************************************************/
- // 定時(shí)器初始化函數(shù)
- /*********************************************************/
- void TimerInit()
- {
- TMOD=1; // 定時(shí)器0,工作方式1
- TH0=0; // 裝定時(shí)器TH0的初值
- TL0=0; // 裝定時(shí)器TL0的初值
- ET0=1; // 開啟定時(shí)器0中斷
- EA=1; // 開啟總中斷
- }
- /*********************************************************/
- // 彈奏鍵掃描函數(shù)
- /*********************************************************/
- uchar KeyScanf()
- {
- if(Key1_P==0) // 按鍵1被按下,返回1
- return 1;
- if(Key2_P==0) // 按鍵2被按下,返回2
- return 2;
- if(Key3_P==0) // 按鍵3被按下,返回3
- return 3;
- if(Key4_P==0) // 按鍵4被按下,返回4
- return 4;
- if(Key5_P==0) // 按鍵5被按下,返回5
- return 5;
- if(Key6_P==0) // 按鍵6被按下,返回6
- return 6;
- if(Key7_P==0) // 按鍵7被按下,返回7
- return 7;
- if(Key8_P==0) // 按鍵8被按下,返回8
- return 8;
- return 0; // 8個(gè)按鍵都沒被按下,返回0
- }
- /*********************************************************/
- // 主函數(shù),程序從這里開始執(zhí)行
- /*********************************************************/
- void main()
- {
- uchar ret; // 用于保存音調(diào)鍵函數(shù)的返回值
- TimerInit();
- gSong=0; // 上電默認(rèn)第一首歌
- gPlayStatus=0; // 上電默認(rèn)是0停止?fàn)顟B(tài)(1為播放狀態(tài))
- while(1)
- {
- if(gPlayStatus==1) // 如果處于播放狀態(tài),則判斷是哪一首歌曲需要播放
- {
- switch(gSong)
- {
- case 1 : PlayMusic(Music1,sizeof(Music1)); break;
- case 2 : PlayMusic(Music2,sizeof(Music2)); break;
- case 3 : PlayMusic(Music3,sizeof(Music3)); break;
- case 4 : PlayMusic(Music4,sizeof(Music4)); break;
- default: break;
- }
- }
-
- if(Key9_P==0) // 開始播放
- {
- DelayMs(10); // 消除按鍵按下的抖動(dòng)
- while(!Key9_P); // 等待按鍵釋放
- DelayMs(10); // 消除按鍵松開的抖動(dòng)
- gSong++; // 把當(dāng)前播放到第幾首歌的變量gSong加1,即切到下一曲
- if(gSong>SONG) // 如果gSong為SONG,說(shuō)明到后面的盡頭了,則轉(zhuǎn)為第一首
- gSong=1;
- gPlayStatus=1; // 播放狀態(tài)改為1,即播放
-
- }
-
- ret=KeyScanf();
- if(ret!=0)
- {
- P0=ChangeFor(ArrDig[(ret-1)%7]); // 數(shù)碼管顯示當(dāng)前音調(diào)值
- TH0 = ArrTH0[ret+6]; // 裝入定時(shí)器TH0的初值
- TL0 = ArrTL0[ret+6]; // 裝入定時(shí)器TL0的初值
- gTone=ret+6;
- TR0=1;
- while(KeyScanf()); // 等待按鍵釋放
- DelayMs(70); // 按鍵釋放之后,再播放70毫秒,達(dá)到余音的效果
- TR0=0; // 停止定時(shí)器
- P0=0xff; // 關(guān)閉數(shù)碼管顯示
- }
- }
- }
-
- /*********************************************************/
- // 功能:定時(shí)器0中斷處理函數(shù)
- /*********************************************************/
- void time0() interrupt 1
- {
- Beep_P=!Beep_P; // 將控制揚(yáng)聲器的管腳取反
- TH0=ArrTH0[gTone]; // 重裝定時(shí)器TH0的初值
- TL0=ArrTL0[gTone]; // 重裝定時(shí)器TL0的初值
- }
復(fù)制代碼
所有資料51hei附件下載:
仿真程序.7z
(108.8 KB, 下載次數(shù): 114)
2022-9-26 02:29 上傳
點(diǎn)擊文件名下載附件
|