单片机源程序如下:
#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; //定义节拍和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; //取节拍码 m=_crol_(*(p[num]+k),4)&0x0f; //取音调码 if(m!=0) //判断取得的音调码是否为0 { //不是,根据取得的音调码计算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初始化函数 ****************************/ void Timer0_Initialize() { TMOD=0x01; IE=0x82; } /************************* T0中断服务函数 ***************************/ void timer0() interrupt 1 using 1 { TL0=tl;TH0=th; //重装定时初值 SPEAK=~SPEAK; //蜂鸣器控制端口电平取反 } /************************ 四分之一拍延时函数 ************************/ void Delay_Beat() { uint i; for(i=0;i<20000;i++); }
/************************** 节拍延时函数 ****************************/ void Delay(uchar tt) { uchar i; for(i=0;i<tt;i++) Delay_Beat(); } /***************************1ms延时函数 ****************************/ void Delay_1ms(uchar ms) { int i; while(ms--) for(i=125;i>0;i--); } /**************************按键扫描函数******************************/ 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是否处于忙状态函数**********************/ 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写入命令函数*************************/ 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写入数据函数*************************/ 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液晶函数************************/ void LCD_Initialize() { LCD_Write_Command(0x38); //设置1602液晶功能,8位数据接口, //两行显示,5*10点阵字符 Delay_1ms(1); LCD_Write_Command(0x01); //清屏 Delay_1ms(1); LCD_Write_Command(0x06); //输入方式选择指令,数据读写后AC自动+1, //输出显示保持不变 Delay_1ms(1); LCD_Write_Command(0x0c); //开显示,关光标,关闪烁 Delay_1ms(1); } /****************在坐标点X、Y上写入一个字符串函数*******************/ 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)); } }
|