單片機源程序如下:
#include<reg52.h> #include<intrins.h> #define uchar unsigned char #define uint unsigned int sbit SPEAK=P1^7; //定義蜂鳴器輸出端口 sbit Key0=P1^0; //定義獨立按鍵 sbit Key1=P1^1; sbit Key2=P1^2; sbit Key3=P1^3; sbit RS=P2^0; //定義控制引腳 sbit RW=P2^1; sbit E=P2^2; uchar beat,tl,th; //定義節(jié)拍和T0初值變量 uchar code TABLE[]={ //音符對應的定時器初值表 0xfb,0x04,0xfb,0x90,0xfc,0x09,0xfc,0x44, 0xfc,0xac,0xfd,0x09,0xfd,0x34,0xfd,0x82, 0xfd,0xc8,0xfe,0x06,0xfe,0x22,0xfe,0x56, 0xfe,0x85,0xfe,0x9a,0xfe,0xc1}; uchar code GRACE[]={ //《奇異恩典》音符碼表 0x14,0x48,0x62,0x42,0x68,0x54,0x48,0x24,0x18, 0x14,0x48,0x62,0x42,0x68,0x54,0x8c,0x88, 0x64,0x86,0x62,0x82,0x62,0x48,0x14,0x26,0x42,0x42,0x22,0x18, 0x14,0x48,0x62,0x42,0x68,0x54,0x4c,0x48,0x00}; uchar code JOY[]={ //《歡樂頌》音符碼表 0x64,0x64,0x74,0x84,0x84,0x74,0x64,0x54,0x44,0x44,0x54,0x64,0x66,0x52,0x58, 0x64,0x64,0x74,0x84,0x84,0x74,0x64,0x54,0x44,0x44,0x54,0x64,0x56,0x42,0x48, 0x54,0x54,0x64,0x44,0x54,0x62,0x72,0x64,0x44,0x54,0x62,0x72,0x64,0x54,0x44,0x54,0x18, 0x64,0x64,0x74,0x84,0x84,0x74,0x64,0x54,0x44,0x44,0x54,0x64,0x56,0x42,0x48,0x00}; uchar code HAPPY[]={ //《生日快樂》音符碼表 0x82,0x01,0x81,0x94,0x84,0xB4,0xA4,0x04, 0x82,0x01,0x81,0x94,0x84,0xC4,0xB4,0x04, 0x82,0x01,0x81,0xF4,0xD4,0xB4,0xA4,0x94, 0xE2,0x01,0xE1,0xD4,0xB4,0xC4,0xB4,0x04, 0x82,0x01,0x81,0x94,0x84,0xB4,0xA4,0x04, 0x82,0x01,0x81,0x94,0x84,0xC4,0xB4,0x04, 0x82,0x01,0x81,0xF4,0xD4,0xB4,0xA4,0x94, 0xE2,0x01,0xE1,0xD4,0xB4,0xC4,0xB4,0x04, 0x00}; uchar code GRACE_Name[]="Amazing Grace "; uchar code JOY_Name[]="Ode To Joy "; uchar code HAPPY_Name[]="Happy Birthday "; void Timer0_Initialize(); void Delay_1ms(uchar ms); void Delay(uchar); void Key_Scan(char *numz,uchar *kz); uchar Busy_Check(); void LCD_Write_Command(uchar cmd); void LCD_Initialize(); void Show_String(uchar x,uchar y,uchar *str); void main() { uchar m,m1,k=0; //定義臨時變量 char num=0; char *numz; uchar *kz; uchar *p[3]; uchar *q[3]; numz=# kz=&k; p[0]=GRACE;p[1]=JOY;p[2]=HAPPY; q[0]=GRACE_Name;q[1]=JOY_Name;q[2]=HAPPY_Name; Timer0_Initialize(); LCD_Initialize(); while(Key1); Delay_1ms(5); while(Key1); while(1) { while(*(p[num]+k)!=0) //判斷取得的音符碼是否為結束碼 { beat=*(p[num]+k)&0x0f; //取節(jié)拍碼 m=_crol_(*(p[num]+k),4)&0x0f; //取音調碼 if(m!=0) //判斷取得的音調碼是否為0 { //不是,根據(jù)取得的音調碼計算T0初值 m1=--m*2+1; m=m*2; tl=TL0=TABLE[m1]; th=TH0=TABLE[m]; TR0=1; //啟動T0 } else //取得的音符碼為0,則停止T0 TR0=0; Delay(beat); k++; Show_String(0,0,q[num]); Show_String(0,1,q[num]+16); Key_Scan(numz,kz); } num++; if(num>2) num=0; k=0; } } /************************** T0初始化函數(shù) ****************************/ void Timer0_Initialize() { TMOD=0x01; IE=0x82; } /************************* T0中斷服務函數(shù) ***************************/ void timer0() interrupt 1 using 1 { TL0=tl;TH0=th; //重裝定時初值 SPEAK=~SPEAK; //蜂鳴器控制端口電平取反 } /************************ 四分之一拍延時函數(shù) ************************/ void Delay_Beat() { uint i; for(i=0;i<20000;i++); }
/************************** 節(jié)拍延時函數(shù) ****************************/ void Delay(uchar tt) { uchar i; for(i=0;i<tt;i++) Delay_Beat(); } /***************************1ms延時函數(shù) ****************************/ void Delay_1ms(uchar ms) { int i; while(ms--) for(i=125;i>0;i--); } /**************************按鍵掃描函數(shù)******************************/ void Key_Scan(char *numz,uchar *kz) { bit flag; if(!Key0) { Delay_1ms(5); if(!Key0) { (*numz)--; if(*numz<0) *numz=2; *kz=0; } } else if(!Key2) { Delay_1ms(5); if(!Key2) { (*numz)++; if(*numz>2) *numz=0; *kz=0; } } else if(!Key3) { Delay_1ms(5); if(!Key3) { TR0=0; flag=1; while(flag) { if(!Key1) { Delay_1ms(5); if(!Key1) { flag=0; TR0=1; } } } } } while((!Key0)||(!Key1)||(!Key2)); } /*******************檢查1602是否處于忙狀態(tài)函數(shù)**********************/ uchar Busy_Check() { uchar LCD_Status; RS=0; RW=1; E=1; Delay_1ms(1); //為什么延時1ms呢? LCD_Status=P0; E=0; return LCD_Status; } /************************向1602寫入命令函數(shù)*************************/ void LCD_Write_Command(uchar cmd) { while((Busy_Check()&0x80)==0x80); //如果1602忙 RS=0; RW=0; E=0; P0=cmd; E=1; Delay_1ms(1); E=0; } /************************向1602寫入數(shù)據(jù)函數(shù)*************************/ void LCD_Write_Data(uchar dat) { while((Busy_Check()&0x80)==0x80); RS=1; RW=0; E=0; P0=dat; E=1; Delay_1ms(1); E=0; } /*************************初始化1602液晶函數(shù)************************/ void LCD_Initialize() { LCD_Write_Command(0x38); //設置1602液晶功能,8位數(shù)據(jù)接口, //兩行顯示,5*10點陣字符 Delay_1ms(1); LCD_Write_Command(0x01); //清屏 Delay_1ms(1); LCD_Write_Command(0x06); //輸入方式選擇指令,數(shù)據(jù)讀寫后AC自動+1, //輸出顯示保持不變 Delay_1ms(1); LCD_Write_Command(0x0c); //開顯示,關光標,關閃爍 Delay_1ms(1); } /****************在坐標點X、Y上寫入一個字符串函數(shù)*******************/ void Show_String(uchar x,uchar y,uchar *str) { uchar i=0; if(y==0) LCD_Write_Command(0x80|x); if(y==1) LCD_Write_Command(0xc0|x); for(i=0;i<16;i++) { LCD_Write_Data(*(str+i)); } }
|