一、系統(tǒng)方案 1、本設(shè)計采用51單片機作為主控器。 2、DS1302計時顯示年月日時分秒。 3、按鍵可以彈奏以及播放音樂,內(nèi)置16首音樂。
1.jpg (4.73 KB, 下載次數(shù): 35)
下載附件
2023-11-18 15:14 上傳
二、硬件設(shè)計 原理圖如下:
2.jpg (69.95 KB, 下載次數(shù): 37)
下載附件
2023-11-18 15:14 上傳
三、單片機軟件設(shè)計 - 1、首先是系統(tǒng)初始化
- /*************時鐘顯示***************/
- void init_1602_ds1302()
- {
- write_sfm2_ds1302(1,1,shi); //顯示時
- write_sfm2_ds1302(1,4,fen); //顯示分
- write_sfm2_ds1302(1,7,miao); //顯示秒
- write_sfm2_ds1302(2,2,nian); //顯示年
- write_sfm2_ds1302(2,5,yue); //顯示月
- write_sfm2_ds1302(2,8,ri); //顯示日
- }
- 2、液晶顯示程序
- /***********************延時函數(shù)************************/
- void delay_uint(uint q)
- {
- while(q--);
- }
- /***********************lcd1602寫命令函數(shù)************************/
- void write_com(uchar com)
- {
- e=0;
- rs=0;
- rw=0;
- P0=com;
- delay_uint(3);
- e=1;
- delay_uint(25);
- e=0;
- }
- /***********************lcd1602寫數(shù)據(jù)函數(shù)************************/
- void write_data(uchar dat)
- {
- e=0;
- rs=1;
- rw=0;
- P0=dat;
- delay_uint(3);
- e=1;
- delay_uint(25);
- e=0;
- }
- /***********************lcd1602初始化設(shè)置************************/
- void init_1602() //lcd1602初始化設(shè)置
- {
- write_com(0x38); //
- write_com(0x0c);
- write_com(0x06);
- }
- /***********************lcd1602上顯示一位十進制數(shù)************************/
- void write_sfm1(uchar hang,uchar add,uchar date)
- {
- if(hang==1)
- write_com(0x80+add);
- else
- write_com(0x80+0x40+add);
- write_data(table_num[date % 10]);
- }
- /***********************lcd1602上顯示兩位十進制數(shù)************************/
- void write_sfm2(uchar hang,uchar add,uchar date)
- {
- if(hang==1)
- write_com(0x80+add);
- else
- write_com(0x80+0x40+add);
- write_data(table_num[date / 10 % 10]);
- write_data(table_num[date % 10]);
- }
- void write_sfm2_ds1302(uchar hang,uchar add,uchar date)
- {
- if(hang==1)
- write_com(0x80+add);
- else
- write_com(0x80+0x40+add);
- write_data(table_num[date/16]);
- write_data(table_num[date%16]);
- }
- /***********************lcd1602上顯示這字符函數(shù)************************/
- void write_string(uchar hang,uchar add,uchar *p)
- {
- if(hang==1)
- write_com(0x80+add);
- else
- write_com(0x80+0x40+add);
- while(1)
- {
- if(*p == '\0') break;
- write_data(*p);
- p++;
- }
- }
- /*****************控制光標(biāo)函數(shù)********************/
- void write_guanbiao(uchar hang,uchar add,uchar date)
- {
- if(hang==1)
- write_com(0x80+add);
- else
- write_com(0x80+0x40+add);
- if(date == 1)
- write_com(0x0f); //顯示光標(biāo)并且閃爍
- else
- write_com(0x0c); //關(guān)閉光標(biāo)
- }
- /***********************lcd1602清除顯示************************/
- void clear_1602()
- {
- write_string(1,0," ");
- write_string(2,0," ");
- }
- /****************開機液晶顯示函數(shù) 初始化液晶的內(nèi)容********************************/
- void init_1602_dis_csf() //初始化液晶
- {
- write_string(1,0," : : ");
- write_string(2,0,"20 - - ");
- }
- 3、按鍵電路程序
- void anjian() //按鍵鍵值識別
- {
- P1=0xf0; //P1口賦值
- if((P1&0xf0)!=0xf0) //判斷是否有按鍵按下
- {
- delay(); //去抖
- if((P1&0xf0)!=0xf0) //再次判斷有無按鍵按下
- {
- key=getkey(); //掃描按鍵
- Tone_Index=0; //播放音符順序清零
- switch(key) //根據(jù)掃描的按鍵編碼將k賦值
- {
- case 0x88: //按鍵編碼為0x88
- k = 0; //k賦值0
- break; //已經(jīng)確定鍵值后提前跳出switch
- case 0x48: //如果不滿足上一個case則繼續(xù)向下判斷,直到有符合
- 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;
- }
- }
- }
- }
- 4、核心算法程序
- void main(void) //主函數(shù)
- {
- SPK=0;
- LED1=1;
- LED2=0; //開機默認彈奏模式
- senddata_74595(0xc0); //數(shù)碼管顯示0
- IE=0x87; //定義外部中斷控制器
- TMOD=0x01; //定義定時器0的工作方式
- IT0=1; //外部中斷0為下降沿觸發(fā)
- IT1=1; //外部中斷1為下降沿觸發(fā)
- init_1602(); //lcd1602初始化
- init_1602_dis_csf(); //lcd1602初始化顯示
- while(1) //進入死循環(huán)
- {
- read_time(); //讀時間
- init_1602_ds1302(); //顯示時鐘
- P1=0xf0; //P1口賦值
- if((P1&0xf0)!=0xf0) //判斷P0口是否有變化
- {
- anjian(); //讀取鍵值
- senddata_74595(DSY_CODE[k]); //顯示鍵值,也就是顯示音符
- if(FY==0) //如果是彈奏模式
- {
- STH0 = tab[k]/256;
- STL0 = tab[k]%256; //根據(jù)k的值賦初值給T0
- TR0 = 1; //打開定時器用于定時產(chǎn)生頻率發(fā)生
- while ((P1&0xf0)!=0xf0); //按鍵不松開的話,T0就一直產(chǎn)生頻率
- TR0=0; //按鍵松開后關(guān)閉T0計時,頻率停止
- }
- else //如果是播放模式(上面的if語句不成立就執(zhí)行else)
- {
- while (FY==1) //進入播放模式
- {
- read_time(); //讀時間
- init_1602_ds1302(); //顯示時鐘
- 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; //將內(nèi)置音樂數(shù)組的數(shù)據(jù)賦給定時器做為初值計時
- // P0=DSY_CODE[Song[k][Tone_Index]]; //顯示播放的音符
- TR0 = 1; //打開定時器定時開關(guān)
- delay1(300*Len[k][Tone_Index]); //節(jié)拍數(shù)組延時
- Tone_Index++; //變量加準備播放下一個音符
- TR0=0; //停止定時器
- anjian(); //掃描按鍵
- senddata_74595(DSY_CODE[k]); //顯示音樂序號
- while((P1&0xf0)!=0xf0);
- }
- }
- }
- }
- }
復(fù)制代碼
四、 proteus仿真設(shè)計 Proteus軟件是一款應(yīng)用比較廣泛的工具,它可以在沒有硬件平臺的基礎(chǔ)上通過自身的軟件仿真出硬件平臺的運行情況,這樣就可以通過軟件仿真來驗證我們設(shè)計的方案有沒有問題,如果有問題,可以重新選擇器件,連接器件,直到達到我們設(shè)定的目的,避免我們搭建實物的時候,如果當(dāng)初選擇的方案有問題,我們器件都已經(jīng)焊接好了,再去卸載下去,再去焊接新的方案的器件,測試,這樣會浪費人力和物力,也給開發(fā)者帶來一定困惑,Proteus仿真軟件就很好的解決這個問題,我們在設(shè)計之初,就使用該軟件進行模擬仿真,測試,選擇滿足我們設(shè)計的最優(yōu)方案。最后根據(jù)測試沒問題的仿真圖紙,焊接實物,調(diào)試,最終完成本設(shè)計的作品。
|