晶振值33.1776MHz
功能簡介:K16控制暫停與繼續
K4 上一曲
K12下一曲
數碼管顯示當前歌曲序號
具有lcd1602顯示功能
應用EEPROM具有掉電記憶
默認演奏上次斷電所演奏的歌曲
主函數
- #include <stc12c5a60s2.h>
- #define Xtal 33177600 //賦晶振值
- #define All 4 //歌曲總數
- sbit BUZZ = P1^3; //蜂鳴器控制引腳
- sbit KEY = P2^4; //按鍵定義
- sbit KEY4 = P2^7;
- sbit KEY12 = P2^5;
- /*sbit ADDR0 = P2^0; //數碼管顯示控制
- sbit ADDR1 = P2^1;
- sbit ADDR2 = P2^2;
- sbit ENLED = P1^1; //總線收發器*/
- bit KeySta = 1; //當前按鍵狀態
- bit KeySta4 = 1;
- bit KeySta12 = 1;
- bit backup = 1; //默認彈起時時一
- bit backup4 = 1;
- bit backup12 = 1;
- bit cntkey = 0; //判斷暫停還是播放
- bit breakflage = 0;//用按鍵改變歌曲標志
- unsigned char keybuf = 0xFF;
- unsigned char keybuf4 = 0xFF;
- unsigned char keybuf12 = 0xFF;
- unsigned char Num; //第幾首歌
- unsigned char sizeofNote;//節拍的多少
- void E2WriteByte(unsigned char addr, unsigned char dat);
- unsigned char E2ReadByte(unsigned char addr);
- void Delay_ms(unsigned int ms);//延時函數
- extern void I2CStart();
- extern void I2CStop();
- extern unsigned char I2CReadNAK();
- extern bit I2CWrite(unsigned char dat);
- extern void LcdWriteCmd(unsigned char cmd);
- extern void LcdWaitReady();
- extern void InitLcd1602();
- extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);
- void lcd1602updata();
- void PlayControl(unsigned char Num);//歌曲選擇函數
- void Play();//演奏函數
- //unsigned char code LedChar[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E};//數碼管顯示字符轉換表
- unsigned int code NoteFrequ[] = { //中音1-7低音1-7和高音1-7對應頻率列表
- 523, 587, 659, 698, 784, 880, 988, //中音1-7
- 1047, 1175, 1319, 1397, 1568, 1760, 1976, //高音1-7
- 262, 294, 330, 349, 392, 440, 494,300//低音1-7 最后一個純屬湊數
- };
- unsigned int code NoteReload[] = { //中音1-7和高音1-7對應的定時器重載值
- 65536 - (Xtal/12) / (523*2), //中音1
- 65536 - (Xtal/12) / (587*2), //2
- 65536 - (Xtal/12) / (659*2), //3
- 65536 - (Xtal/12) / (698*2), //4
- 65536 - (Xtal/12) / (784*2), //5
- 65536 - (Xtal/12) / (880*2), //6
- 65536 - (Xtal/12) / (988*2), //7
- 65536 - (Xtal/12) / (1047*2), //高音1
- 65536 - (Xtal/12) / (1175*2), //2
- 65536 - (Xtal/12) / (1319*2), //3
- 65536 - (Xtal/12) / (1397*2), //4
- 65536 - (Xtal/12) / (1568*2), //5
- 65536 - (Xtal/12) / (1760*2), //6
- 65536 - (Xtal/12) / (1976*2), //7
- 65536 - (Xtal/12) / (262*2), //低音1
- 65536 - (Xtal/12) / (294*2), //2
- 65536 - (Xtal/12) / (330*2), //3
- 65536 - (Xtal/12) / (349*2), //4
- 65536 - (Xtal/12) / (392*2), //5
- 65536 - (Xtal/12) / (440*2), //6
- 65536 - (Xtal/12) / (494*2), //7
- 65536 - (Xtal/12) / (300*2), //純屬湊數
- };
- unsigned char *SongNote, *SongBeat;//指針
- unsigned char code XiaoXingXingNote[] = { //小星星
- 1, 1, 5, 5, 6, 6, 5, 4, 4, 3, 3, 2, 2, 1,
- 5, 5, 4, 4, 3, 3, 2, 5, 5, 4, 4, 3, 3, 2 ,
- 1, 1, 5, 5, 6, 6, 5, 4, 4, 3, 3, 2, 2, 1, 0xff };
- unsigned char code XiaoXingXingBeat[] = {
- 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 8,
- 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 8,
- 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 8,};
- unsigned char code TwoTigerNote[] = { //兩只老虎音符表
- 1, 2, 3, 1, 1, 2, 3, 1, 3, 4, 5, 3, 4, 5,
- 5,6, 5,4, 3, 1, 5,6, 5,4, 3, 1, 1, 5, 1, 1, 5, 1,0xff};
- unsigned char code TwoTigerBeat[] = { //兩只老虎節拍表,4表示一拍,1就是1/4拍,8就是2拍
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 4, 4, 8,
- 3,1, 3,1, 4, 4, 3,1, 3,1, 4, 4, 4, 4, 8, 4, 4, 8,
- };
- unsigned char code HappybirthdayNote[] = { //生日快樂歌
- 5, 5, 6, 5, 8, 7, 22, 5, 5, 6, 5, 9, 8, 5, 5, 12, 10, 8, 7, 6, 11, 11, 10, 8, 9, 8,0xff };
- unsigned char code HappybirthdayBeat[] = {
- 2, 2, 4, 4, 4, 4, 4, 2, 2, 4, 4, 4, 8, 2, 2, 4, 4, 4, 4, 8, 2, 2, 4, 4, 4, 8};
- unsigned char code ZhiduanqingchangNote[] = { //紙短情長
- //8, 9, 10, 9, 8, 6, 22, 11, 10, 9, 22, 7, 8, 9, 7, 7, 5, 22, 7, 9, 8, 8, 3, 4, 2, 3, 1, 1, 5, 2, //前奏
- 19, 3, 3, 3, 2, 3, 1, 2, 2, 2, 1, 2, 5, 1, 1, 1, 20, 1, 20, 19, 2, 2, 2, 3, 20, 19, 4, 4, 4, 3, 4, 1, 2, 2, 2, 1, 2, 5,
- 1, 1, 1, 20, 1, 20, 3, 2, 2, 1, 1, 22, 22, 22, 1, 1, 2, 3, 3, 3, 22, 3, 2, 1, 21, 6, 5, 22, 5, 6, 7, 8, 3, 3, 22, 8, 7, 8,
- 7, 3, 5, 5, 6, 8, 5, 6, 22, 6, 5, 4,5, 3, 2, 1, 20, 1, 3, 2, 2, 1, 2, 5, 1, 2, 5, 22, 22, 22, 1, 1, 2,
- 3, 3, 2, 3, 22, 3, 2, 1, 5, 5, 3, 5, 22, 5, 6, 7, 8, 8, 8, 8, 8, 7, 6, 7, 6, 3, 5, 5, 5, 6, 8, 5, 6, 22, 6, 5, 4,
- 5, 3, 2, 1, 6, 1, 3, 2, 2, 1, 2, 1, 20, 1, 22, 22, 20, 1, 3, 2, 2, 22, 2, 1, 2, 1, 1, 22, 20, 1, 1, 0xff};
- unsigned char code ZhiduanqingchangBeat[] = {
- //2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 8, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 8, 8, 12, 4, 5, 4, 8, 8, 4, //前奏
- 8, 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 4, 5, 2, 2, 2, 2, 2, 5,
- 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 8, 4, 4, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2,
- 4, 2, 5, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 4, 2, 5, 1, 1, 2, 2, 2, 2, 2, 4, 2, 16, 16,4, 4, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 4, 2, 2, 2, 4, 2, 2, 2, 2, 2,
- 2, 4, 2, 5, 1, 1, 2, 2, 2, 2, 2, 4, 1, 12, 4, 2, 1, 1, 2, 2, 8, 2, 1, 1, 2, 2, 8, 2, 2, 12, 16};
- bit enable = 1; //蜂鳴器發聲使能標志
- bit tmrflag = 0; //定時器中斷完成標志
- unsigned char T0RH = 0xFF; //T0重載值的高字節
- unsigned char T0RL = 0x00; //T0重載值的低字節
- void main()
- {
- unsigned char dat;
- EA = 1; //使能全局中斷
- TMOD = 0x11; //配置T0,T1工作在模式1
- TH0 = T0RH;
- TL0 = T0RL;
- ET0 = 1; //使能T0中斷
- ET1 = 1; //使能T1中斷
- TR1 = 1; //啟動T1
- // ENLED = 0x00; //使能總線收發器
- // ADDR2=1; ADDR1=0; ADDR0=1;//選擇最右邊的數碼管
- P23 = 0; //啟用KEY
- InitLcd1602();
- dat = E2ReadByte(0x01); //讀取指定地址上的一個字節
- if(dat>All||dat<=0)
- Num = 1;
- else
- Num = dat;
- while (1)
- {
- //P0 = LedChar[Num]; //數碼管顯示當前歌曲序號
- LcdWriteCmd(0x01); //清屏
- lcd1602updata();
- PlayControl(Num);
- if(breakflage == 1)
- breakflage = 0;
- else
- Delay_ms(500);
- }
- }
- void PlayControl(unsigned char Num)
- {
- E2WriteByte(0x01, Num); //再寫回到對應的地址上
- switch(Num)
- {
- case 4:SongNote = XiaoXingXingNote; SongBeat = XiaoXingXingBeat; sizeofNote = sizeof(XiaoXingXingNote); Play();break;
- case 2:SongNote = TwoTigerNote; SongBeat =TwoTigerBeat; sizeofNote = sizeof(TwoTigerNote); Play();break;
- case 3:SongNote = HappybirthdayNote; SongBeat =HappybirthdayBeat; sizeofNote = sizeof(HappybirthdayNote); Play();break;
- case 1:SongNote = ZhiduanqingchangNote;SongBeat =ZhiduanqingchangBeat;sizeofNote = sizeof(ZhiduanqingchangNote);Play();break;
- default:break;
- }
- }
- void lcd1602updata()
- {
- switch(Num)
- {
- case 1:LcdShowStr(4,0,"1.zhiduanqingchang");break;
- case 2:LcdShowStr(4,0,"2.liangzhilaohu");break;
- case 3:LcdShowStr(4,0,"3.zhunishengrikuaile");break;
- case 4:LcdShowStr(4,0,"4.xiaoxingxing");break;
- default:break;
- }
- }
- /* 演奏函數 */
- void Play()//演奏函數
- {
- unsigned char beat; //當前節拍索引
- unsigned char note; //當前節拍對應的音符
- unsigned int time = 0; //當前節拍計時
- unsigned int beatTime = 0; //當前節拍總時間
- unsigned int soundTime = 0; //當前節拍需發聲時間
- for (beat=0; beat<sizeofNote; ) //用節拍索引作為循環變量
- {
- if(breakflage == 1)
- break;
- while (!tmrflag); //每次定時器中斷完成后,檢測并處理節拍
- tmrflag = 0;
- if (time == 0) //當前節拍播完則啟動一個新節拍
- {
- if(breakflage == 1)
- break;
- note = SongNote[beat] - 1;
- if(note == 0xfe)
- {
- if(Num == All)
- Num = 1;
- else
- Num++;
- break;
- }
- T0RH = NoteReload[note] >> 8;
- T0RL = NoteReload[note];
- beatTime = (SongBeat[beat] * NoteFrequ[note]) >> 2;//計算節拍總時間,右移2位相當于除4,移位代替除法可以加快執行速度
- soundTime = beatTime - (beatTime >> 2);//計算發聲時間,
- enable = 1; //指示蜂鳴器開始發聲
- if (note == 21)//簡譜的0 等待
- enable =0;
- time++;
- }
- else //當前節拍未播完則處理當前節拍
- {
- if (time >= beatTime) //當前持續時間到達節拍總時間時歸零,
- { //并遞增節拍索引,以準備啟動新節拍
- time = 0;
- beat++;
- }
- else //當前持續時間未達到總時間時,
- {
- time++; //累加時間計數
- if (time == soundTime) //到達發聲時間后,指示關閉蜂鳴器,
- { //插入0.25*總時間的靜音間隔,
- enable = 0; //用以區分連續的兩個節拍
- }
- }
- }
- }
- }
- void Delay_ms(unsigned int ms)
- {
- for(;ms > 0;ms--)
- {
- unsigned char i, j;
- i = 33;
- j = 66;
- do
- {
- while (--j);
- } while (--i);
- }
- }
- unsigned char E2ReadByte(unsigned char addr)
- {
- unsigned char dat;
- I2CStart();
- I2CWrite(0x51<<1);//發送E2PROM地址
- I2CWrite(addr);//要讀取的地址
- I2CStart(); //重新發送起始信號
- I2CWrite((0x51<<1) |0x01);
- dat = I2CReadNAK();
- I2CStop();
- return dat;
- }
- void E2WriteByte(unsigned char addr, unsigned char dat)
- {
- I2CStart();
- I2CWrite(0x51<<1);//發送E2PROM地址
- I2CWrite(addr);//要寫入的地址
- I2CWrite(dat);//要寫入的數據
- I2CStop();
- }
- /*控制蜂鳴器發聲 */
- void InterruptTimer0() interrupt 1
- {
- TH0 = T0RH; //重新加載重載值
- TL0 = T0RL;
- tmrflag = 1;
- if (enable) //使能時反轉蜂鳴器控制電平
- BUZZ = ~BUZZ;
- else //未使能時關閉蜂鳴器
- BUZZ = 1;
- }
- /*按鍵掃描*/
- void InterruptTimer1() interrupt 3 //按鍵部分參看之前的帖子 帶有計次功能的秒表
- {
- TH1 = 0xC9;
- TL1 = 0xEA;
-
- keybuf = (keybuf<<1) | KEY;
- if (keybuf == 0x00)
- KeySta = 0;
- else if (keybuf == 0xFF)
- KeySta = 1;
- else{}
-
- keybuf4 = (keybuf4<<1) | KEY4;
- if (keybuf4 == 0x00)
- KeySta4 = 0;
- else if (keybuf4 == 0xFF)
- KeySta4 = 1;
- else{}
-
- keybuf12= (keybuf12<<1) | KEY12;
- if (keybuf12 == 0x00)
- KeySta12 = 0;
- else if (keybuf12 == 0xFF)
- KeySta12 = 1;
- else{}
-
- if (KeySta != backup)
- {
- if (backup == 0)
- {
- cntkey=~cntkey;
- TR0 = cntkey;
- }
- backup = KeySta;
- }
- if (KeySta4 != backup4)
- {
- if(backup4 ==0)
- {
- breakflage = 1;
- if(Num <All)
- Num++;
- else if(Num == All)
- Num =1;
- LcdWriteCmd(0x01); //清屏
- lcd1602updata();
- //P0 = LedChar[Num];
- }
- backup4 = KeySta4;
- }
-
- if (KeySta12 != backup12)
- {
- if(backup12 ==0)
- {
- breakflage = 1;
- if(Num >1)
- Num--;
- else if(Num == 1)
- Num =All;
-
- LcdWriteCmd(0x01); //清屏
- lcd1602updata();
- //P0 = LedChar[Num];
- }
- backup12 = KeySta12;
- }
-
- }
復制代碼 LCD1602函數
|