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