實驗圖
單片機源程序如下:- #include <reg51.h> //頭文件
- #define uchar unsigned char
- #define uint unsigned int //宏定義
- uchar STH0; //定時器變量
- uchar STL0; //定時器變量
- bit FY=0; //模式變量,為0時彈奏模式,為1時播放模式
- uchar Song_Index=0,Tone_Index=0;//單首歌曲音符數
- uchar k, key; //k:按鍵數值變量。key:按鍵的鍵值(也就是有按鍵按下時的P0口狀態)
- sbit SPK=P3^7 ; //定義喇叭的接口
- sbit LED1=P3^5;
- sbit LED2=P3^4; //定義兩個LED的接口
- uchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,//數碼管顯示的數組(1 2 3 4 5 6 7 8 9)
- 0x88,0x83,0xc6,0xa1,0x86,0x8e,0x89,0xa3,0x8c,0xc8}; //(A B C D E F H O P N)
- unsigned char code num1[]= " Music: ";
- uchar code Song[][100]= //內置音樂數組,song【歌曲序號】【音符順序】
- {
- // 1 2 3 4 5 6 7
- // 8 9 10 11 12 13 14
- // 15 16 17 18 19 20 21
- {12,10,9,9,10,8,9,10,
- 12,10,9,9,5,10,11,10,
- 10,10,14,10,9,8,7,8,
- 9,10,13,6,8,10,9,6,
- 8,7,5,6,12,10,9,9,
- 9,10,8,9,10,12,10,9,
- 9,9,5,10,11,10,10,10,
- 14,10,9,8,7,8,9,10,
- 13,6,8,10,9,6,8,7,
- 5,6,-1}, //煙花易冷
- {13,12,10,12,15,13,
- 12,13,10,12,13,12,10,8,6,12,
- 10,9,9,10,12,12,13,10,9,
- 8,12,10,9,8,6,8,5,-1},//世上只有媽媽好
- {10,10,11,10,9,8,9,12,9,9,
- 8,8,9,8,7,6,7,10,7,7,
- 6,9,10,9,8,6,5,9,10,9,
- 8,6,6,9,10,9,8,6,7,8,-1}, //當你孤單你會想起誰
- {5,3,5,8,6,8,
- 5,5,1,2,3,2,1,2,5,
- 3,5,8,7,6,8,5,5,2,
- 3,4,0,1,6,8,8,7,6,
- 7,8,6,7,8,6,6,5,3,
- 1,2,5,3,5,8,7,6,8,
- 5,5,2,3,4,0,1,-1}, //送別
- {5,6,8,6,6,5,6,5,3,5,
- 5,6,8,6,6,5,6,5,6,1,
- 1,2,3,2,2,2,1,2,1,6,
- 3,2,5,6,8,6,6,5,6,5,
- 6,1,1,2,3,4,4,5,6,6,
- 5,6,8,6,8,6,5,5,1,6,
- 5,5,6,8,3,2,3,1,-1}, //最浪漫的事
- {5,9,10,9,10,12,13,12,8,9,
- 10,13,12,10,12,12,13,15,13,12,
- 10,12,10,8,9,10,8,6,10,9,
- 12,9,10,9,10,12,13,12,8,9,
- 10,13,12,12,13,15,13,
- 12,10,12,10,8,6,10,9,8,6,
- 8,9,9,8,-1}, //發如雪
- {5,8,9,10,9,10,11,12,12,12,
- 11,10,9,5,8,9,10,11,12,12,
- 12,13,12,9,10,8,8,6,9,9,
- 10,10,8,12,8,12,8,7,8,8,6,
- 9,9,10,10,12,12,
- 12,13,12,9,10,8,
- 5,8,9,10,9,10,11,12,12,12,
- 11,10,9,5,8,9,10,9,10,11,
- 12,12,12,9,10,8,8,6,9,9,
- 10,10,8,12,8,12,12,7,8,-1}, //簡單愛
- {8,9,10,8,8,9,10,8,10,11,12,10,11,12,
- 12,13,12,11,10,8,12,13,12,11,10,8,8,5,8,8,5,8,-1}, //兩只老虎
- {5,5,6,5,8,7,
- 5,5,6,5,9,8,
- 5,5,12,10,8,7,6,
- 11,11,10,8,9,8,-1}, //生日快樂
- {6,8,9,10,12,10,8,9,6,8,9,10,
- 12,12,13,9,10,10,12,13,
- 12,13,15,14,13,12,13,10,8,9,10,12,8,6,
- 8,9,10,13,12,10,13,13,
- 12,11,10,9,10,12,6,8,9,8,9,
- 10,12,13,15,14,13,12,10,13,-1}, //讓我們蕩起雙槳
- {8,8,12,12,13,13,12,
- 11,11,10,10,9,9,8,
- 12,12,11,11,10,10,9,
- 12,12,11,11,10,10,9,
- 8,8,12,12,13,13,12,
- 11,11,10,10,9,9,8,-1}, //小星星
- {12,10,12,10,12,10,8,9,11,10,9,12,
- 12,10,12,10,12,10,8,9,11,10,9,8,
- 9,9,11,11,10,8,12,9,11,10,9,12,
- 12,10,12,10,12,10,8,9,11,10,9,8,-1}, //粉刷匠
- {8,9,10,11,12,12,12,11,10,
- 11,11,11,10,9,8,10,12,
- 8,9,10,11,12,12,12,11,10,
- 11,11,11,10,9,8,10,8,
- 13,13,13,12,11,12,12,12,11,10,
- 11,11,11,10,9,8,10,12,
- 13,13,13,12,11,12,12,12,11,10,
- 11,11,11,10,9,8,10,8,-1}, //洋娃娃和小熊跳舞
- {12,10,12,13,15,16,17,16,15,13,12,15,
- 17,16,15,12,17,16,15,12,
- 10,12,13,15,16,17,15,13,15,16,
- 13,13,14,13,13,17,15,14,15,13,
- 12,10,12,13,15,16,17,16,15,13,12,15,
- 17,17,17,17,15,16,16,16,16,12,
- 12,10,12,13,15,16,17,16,15,13,12,
- 15,15,-1}, //小紅花
- {8,9,10,11,12,10,8,15,13,11,12,12,10,
- 8,9,10,11,12,10,9,8,9,10,9,12,
- 8,9,10,11,12,10,8,15,13,11,12,10,
- 8,9,10,11,12,10,9,8,9,10,8,8,
- 15,13,11,12,12,8,15,13,11,12,10,
- 8,9,10,11,12,10,9,8,9,10,8,8,
- 15,13,11,12,12,8,15,13,11,12,10,
- 8,9,10,11,12,10,9,8,9,10,8,8,-1}, //小紅帽
- {10,12,16,15,12,11,10,10,10,11,12,
- 13,12,10,12,16,15,12,11,
- 10,12,12,13,14,15,15,16,12,12,14,13,12,
- 10,12,15,13,15,16,15,14,12,10,12,
- 16,15,12,11,10,12,12,13,14,15,15,-1}, //雪絨花
- };
- uchar code Len[][100]= //內置音樂對應的節拍(音符持續時間)
- {
- {1,1,2,4,1,1,1,4,
- 1,1,2,2,1,1,1,4,
- 1,1,1,1,2,1,1,1,
- 1,1,3,1,1,1,1,1,
- 1,1,1,6,1,1,2,1,
- 1,1,1,1,4,1,1,2,
- 1,1,1,1,1,4,1,1,
- 3,1,2,1,1,3,1,2,1,1,1,1,1,
- 3,1,1,1,1,1,1,2,
- 2,6,-1},
- {3,1,2,2,2,1,
- 1,4,2,1,1,2,2,1,1,1,
- 1,4,3,1,2,1,1,2,2,
- 4,3,1,1,1,1,1,6,-1},
- {2,1,1,2,1,1,2,2,2,3,
- 2,1,1,2,1,1,2,2,2,3,
- 2,1,1,1,1,2,2,1,1,1,
- 1,2,2,1,1,1,1,1,1,6,-1},
- {2,3,1,3,2,2,
- 4,2,1,1,2,1,1,4,2,
- 1,1,2,1,2,2,4,2,1,
- 1,2,1,4,2,2,4,2,1,
- 1,4,1,1,1,1,1,1,1,
- 1,8,2,1,1,2,1,2,2,
- 4,2,1,1,2,2,4,-1},
- {1,1,1,2,1,1,1,1,1,5,
- 1,1,1,2,1,1,1,1,1,5,
- 1,1,1,1,1,1,1,1,1,1,
- 2,3,1,1,1,2,1,1,1,1,
- 1,5,1,1,1,2,1,1,1,1,
- 1,2,1,3,1,1,1,4,1,1,
- 5,1,1,1,1,1,1,6,-1},
- {1,1,2,1,1,1,1,3,1,1,
- 1,1,1,1,3,1,1,2,1,1,
- 1,1,2,1,1,1,1,1,1,1,
- 1,1,2,1,1,1,1,3,1,1,
- 1,1,3,1,1,2,1,
- 1,1,1,2,1,1,1,1,1,1,
- 1,1,1,4,-1},
- {1,1,1,1,1,1,1,1,1,1,
- 1,1,3,1,1,1,1,1,1,1,
- 1,1,2,1,1,2,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,
- 1,1,2,1,1,2,
- 1,1,2,1,1,1,1,1,1,1,
- 1,1,3,1,1,1,1,1,1,1,
- 1,1,2,1,1,2,1,1,1,1,
- 1,1,2,1,1,1,1,1,1,-1},
- {2,2,2,2,2,2,2,2,2,2,4,2,2,4,
- 1,1,1,1,2,2,1,1,1,1,2,2,2,2,4,2,2,4,-1},
- {1,1,2,2,2,4,
- 1,1,2,2,2,4,
- 1,1,2,2,2,2,2,
- 1,1,2,2,2,4,-1},
- {1,1,1,3,1,1,1,2,4,1,1,1,
- 3,1,2,2,4,1,1,4,
- 3,1,1,1,1,1,1,2,1,1,3,1,2,2,
- 1,1,1,1,5,4,3,1,
- 1,1,2,4,3,1,1,1,3,1,1,
- 2,2,2,2,1,1,1,1,4,-1},
- {2,2,2,2,2,2,3,
- 2,2,2,2,2,2,3,
- 2,2,2,2,2,2,3,
- 2,2,2,2,2,2,3,
- 2,2,2,2,2,2,3,
- 2,2,2,2,2,2,4,-1},
- {1,1,1,1,1,1,2,1,1,1,1,2,
- 1,1,1,1,1,1,2,1,1,1,1,2,
- 1,1,1,1,1,1,2,1,1,1,1,2,
- 1,1,1,1,1,1,2,1,1,1,1,3,-1},
- {1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,2,
- 1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,2,
- 1,1,1,1,1,1,1,1,1,2,
- 1,1,1,1,1,1,1,2,
- 1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,3,-1},
- {1,1,1,1,1,1,2,1,1,1,1,4,
- 2,1,1,4,2,1,1,4,
- 2,1,1,2,2,1,1,1,1,4,
- 2,1,1,3,1,1,1,1,1,4,
- 1,1,1,1,1,1,2,1,1,1,1,4,
- 1,1,1,1,4,1,1,1,1,4,
- 1,1,1,1,1,1,2,1,1,1,1,
- 4,4,-1},
- {1,1,1,1,2,1,1,2,1,1,1,1,2,
- 1,1,1,1,1,1,1,1,2,2,2,2,
- 1,1,1,1,2,1,1,2,1,1,2,2,
- 1,1,1,1,1,1,1,1,2,2,2,2,
- 2,1,1,1,1,2,2,1,1,2,2,
- 1,1,1,1,1,1,1,1,2,2,2,2,
- 2,1,1,1,1,2,2,1,1,2,2,
- 1,1,1,1,1,1,1,1,2,2,2,2,-1},
- {2,2,4,2,2,4,2,2,1,1,2,
- 4,4,2,2,4,2,2,4,
- 2,2,1,1,2,4,4,4,1,2,1,1,2,
- 2,2,4,2,2,2,2,4,4,2,2,
- 4,2,2,4,2,2,1,1,1,4,4,-1}
- };
- uint code tab[]={ //內置16個音符彈奏和播放時都是調用此數組內的數據用于定時器初值
- 63500, //超低音 si
- 63628,63835,64021,64103,64260,64400,64524, //低音do-si
- 64580,64684,64777,64820,64898,64968,65030, // do-si
- 65058,65110,65157,65178,65217,65252,65283, //高音do-si
- 65313 }; //超高音do
- void delay1 (uint ms) //粗略1ms延時函數,不精確
- {
- uchar t;
- while (ms--)
- for(t=0;t<120;t++);
- }
- void delay(void)
- {
- uchar i;
- for (i=300;i>0;i--);
- }
- uchar getkey(void) //矩陣按鍵掃描函數
- {
- uchar scancode,tmpcode;
- if((P1&0xf0)==0xf0) //無按鍵按下時此表達式成立
- return (0); //此函數返回值為0
- scancode = 0xfe; //如果上面的if表達式不成立,此語句才可以執行
- while((scancode&0x10)!=0) //有按鍵按下時,此表達式成立
- {
- P1=scancode; //將P0口賦值
- if((P1&0xf0)!=0xf0) //判斷P0口的狀態
- {
- tmpcode = (P1&0xf0)|0x0f; //P0口的狀態與上0xf0,然后或上0x0f
- return((~scancode)+(~tmpcode)); //將兩個變量的值取反相加后返回此函數
- }
- else scancode=(scancode<<1)|0x01; //如果上面的if語句不成立,將scancode左移一位
- }
- return(0xff);
- }
- void anjian() //按鍵鍵值識別
- {
- P1=0xf0; //P1口賦值
- if((P1&0xf0)!=0xf0) //判斷是否有按鍵按下
- {
- delay(); //去抖
- if((P1&0xf0)!=0xf0) //再次判斷有無按鍵按下
- {
- key=getkey(); //掃描按鍵
- Tone_Index=0; //播放音符順序清零
- switch(key) //根據掃描的按鍵編碼將k賦值
- {
- case 0x88: //按鍵編碼為0x88
- k = 0; //k賦值0k = 0; //k賦值0
- break; //已經確定鍵值后提前跳出switch
- case 0x48: //如果不滿足上一個case則繼續向下判斷,直到有符合
- k = 1; //k賦值1
- break; //下同,略
- case 0x28:
- k = 2 ;
- break;
- case 0x18:
- k = 3 ;
- break;
- case 0x84:
- k = 4 ;
- break;
- case 0x44:
- k = 5 ;
- break;
- case 0x24:
- k = 6 ;
- break;
- case 0x14:
- k = 7 ;
- break;
- case 0x82:
- k = 8 ;
- break;
- case 0x42:
- k = 9 ;
- break;
- case 0x22:
- k = 10 ;
- break;
- case 0x12:
- k = 11 ;
- break;
- case 0x81:
- k = 12 ;
- break;
- case 0x41:
- k = 13 ;
- break;
- case 0x21:
- k = 14 ;
- break;
- case 0x11:
- k = 15 ;
- break;
- default : //如果以上都不符合,直接跳出,無鍵值輸出
- break;
- }
- }
- }
- }
- void main(void) //主函數
- {
- SPK=0;
- LED1=1;
- LED2=0; //開機默認彈奏模式
- P0=0xc0; //數碼管顯示0
- IE=0x87; //定義外部中斷控制器
- TMOD=0x01; //定義定時器0的工作方式
- IT0=1; //外部中斷0為下降沿觸發
- IT1=1; //外部中斷1為下降沿觸發
- while(1) //進入死循環
- {
- P1=0xf0; //P1口賦值
- if((P1&0xf0)!=0xf0) //判斷P0口是否有變化
- {
- anjian(); //讀取鍵值anjian(); //讀取鍵值
- P0=DSY_CODE[k]; //顯示鍵值,也就是顯示音符
- if(FY==0) //如果是彈奏模式
- {
- STH0 = tab[k]/256;
- STL0 = tab[k]%256; //根據k的值賦初值給T0
- TR0 = 1; //打開定時器用于定時產生頻率發生
- while ((P1&0xf0)!=0xf0); //按鍵不松開的話,T0就一直產生頻率
- TR0=0; //按鍵松開后關閉T0計時,頻率停止
- }
- else //如果是播放模式(上面的if語句不成立就執行else)
- {
- while (FY==1) //進入播放模式
- {
- if(Song[k][Tone_Index]==-1) //一首播放完退出
- {
- Tone_Index=0;
- SPK=0;
- break;
- }
- STH0=(tab[Song[k][Tone_Index]])/256;
- STL0=(tab[Song[k][Tone_Index]])%256; //將內置音樂數組的數據賦給定時器做為初值計時
- // P0=DSY_CODE[Song[k][Tone_Index]]; //顯示播放的音符
- TR0 = 1; //打開定時器定時開關
- delay1(300*Len[k][Tone_Index]); //節拍數組延時
- Tone_Index++; //變量加準備播放下一個音符
- TR0=0; //停止定時器
- anjian(); //掃描按鍵
- P0=DSY_CODE[k]; //顯示音樂序號
- while((P1&0xf0)!=0xf0);
- }
- }
- }
- }
- }
- void EXO_IXT() interrupt 0 //外部中斷0
- {
- FY=0; //彈奏模式
- LED1=1;
- LED2=0; //點亮彈奏模式指示燈
- Tone_Index=0; //歌曲音符序號清零,以便于下次播放內置音樂時從頭播放
- }
- void EX1_INT() interrupt 2 //外部中斷1
- {
- FY=1; //播放模式
- LED1=0; //點亮播放模式指示燈
- LED2=1;
- }
- void time0_int(void) interrupt 1 using 0 //定時器0
- {
- TH0 = STH0; //定時器賦初值
- TL0 = STL0;
- SPK=!SPK; //喇叭引腳取反,產生頻率的音樂
- }
復制代碼
|