电子贺卡仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机电子贺卡源程序如下:
- #include<reg52.h>
- #include<intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- sbit SPEAK=P2^7; //定义蜂鸣器输出端口
- sbit CS1=P2^4;
- sbit CS2=P2^3;
- sbit RS=P2^2;
- sbit RW=P2^1;
- sbit E=P2^0;
- sbit L1=P1^0;
- sbit L2=P1^1;
- uchar code HZ0[]={
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- .................
- ...............
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
- };
- void delayus(uchar delay)
- {
- uchar i;
- for(i=0;i<=delay;i++)
- _nop_();
- }
- void check_busy()
- {
- uchar a=0;
- for(a=0;a<200;a++); //此处为延时,一段时间后确保处于空闲状态
- //此处为状态查询,查询忙状态,没有使用成功,以后再调试
- /*RW=1;
- RS=0;
- E=1;
- while(1)
- {
- E=1;
- if(!(P0&0x80))
- break;
- a++;
- if(a>10)
- break;
-
- }
- E=1;*/
- }
- void write_cmd(uchar inst)
- {
- check_busy();
- RS=0;
- RW=0;
- E=1;
- P3=inst;
- E=0;
- _nop_();
- }
- void write_data(uchar dat)
- {
- check_busy();
- RS=1;
- RW=0;
- E=1;
- P3=dat;
- E=0;
- _nop_();
- }
- void LCD_Init()
- {
- write_cmd(0x30);//30H--基本指令操作?
- delayus(4);
- write_cmd(0x0c);//开显示,关光标,不闪烁。
- delayus(10);
- write_cmd(0x01);//清除显示
- delayus(10);
- write_cmd(0x06);//光标的移动方向左,DDRAM的地址计数器(AC)加1。
- delayus(10);
- }
- void set_xy(uchar x,uchar y) //x为行,y为列
- {
- if(y>=64) //列地址大于等于64时右屏显示?
- {
- CS2=0; //低电平选择
- CS1=1; //写右屏是左屏关闭,不然两边会同时显示
- y=y-64;
- }
- else //列地址小于64时左屏显示
- {
- CS1=0; //同上
- CS2=1;
- }
- write_cmd(0x40|y); //写列地址
- _nop_();
- write_cmd(0xb8|x); //写行地址?
- }
- //显示函数
- void disp_hz(uchar *p)
- {
- uchar i;
- for(i=0;i<128;i++)
- {
- set_xy(0,i);
- write_data(p[i]);
- set_xy(1,i);
- write_data(p[i+128]);
- set_xy(2,i);
- write_data(p[i+256]);
- set_xy(3,i);
- write_data(p[i+384]);
- set_xy(4,i);
- write_data(p[i+512]);
- set_xy(5,i);
- write_data(p[i+640]);
- set_xy(6,i);
- write_data(p[i+768]);
- set_xy(7,i);
- write_data(p[i+896]);
- set_xy(8,i);
- write_data(p[i+1024]);
- }
- }
- void disp_zf(uchar R,uchar L,uchar *p)
- {
- uchar i;
- for(i=0;i<8;i++)
- {
- set_xy(2*R,8*L+i);
- write_data(p[i]);
- set_xy(2*R+1,8*L+i);
- write_data(p[i+8]);
- }
- }
- uchar beat,tl,th,key=0,k=0,temp; //定义节拍和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};
- void Timer0_Initialize();
- void delay_10ms();
- void Delay(uchar);
- void Key_Scan();
- uint a[4]={0,1,2,3};
- void main()
- {
- uchar m,m1; //定义临时变量
- uchar *p[3];
- uchar beat=0;
- p[0]=GRACE;
- p[1]=JOY;
- p[2]=HAPPY;
- Timer0_Initialize();
- while(1)
- {
- Key_Scan();
- if(key!=3)
- TR0=1;
- switch(key)
- {
- P1=0xff;
- case 0:
- disp_hz(HZ0 );
- temp=key;
- TR0=1;
- while(*(p[key]+k)!=0) //判断取得的音符码是否为结束码
- {
- beat=*(p[key]+k)&0x0f; //取节拍码
- m=_crol_(*(p[key]+k),4)&0x0f; //取音调码
- if(beat!=0)
- { //判断取得的音调码是否为0 { //不是,根据取得的音调码计算T0初值
- m1=--m*2+1;
- m=m*2;
- tl=TL0=TABLE[m1];
- th=TH0=TABLE[m];
-
- }
- else
- { //取得的节拍码为0,则停止T0
- TR0=0;
- }
- Delay(beat);
- k++;
- Key_Scan();
- delay_10ms();
- if(temp!=key)break;
- }
- TR0=0;
- k=0;
- break;
-
- case 1:
- disp_hz(HZ1 );
- temp=key;
- TR0=1;
- while(*(p[key]+k)!=0) //判断取得的音符码是否为结束码
- {
- beat=*(p[key]+k)&0x0f; //取节拍码
- m=_crol_(*(p[key]+k),4)&0x0f; //取音调码
- if(beat!=0)
- { //判断取得的音调码是否为0 { //不是,根据取得的音调码计算T0初值
- m1=--m*2+1;
- m=m*2;
- tl=TL0=TABLE[m1];
- th=TH0=TABLE[m];
-
- }
- else
- { //取得的节拍码为0,则停止T0
- TR0=0;
- }
- Delay(beat);
- k++;
- Key_Scan();
- delay_10ms();
- if(temp!=key)break;
- }
- TR0=0;
- k=0;
- break;
-
- case 2:
- disp_hz(HZ2 );
- temp=key;
- TR0=1;
- while(*(p[key]+k)!=0) //判断取得的音符码是否为结束码
- {
- beat=*(p[key]+k)&0x0f; //取节拍码
- m=_crol_(*(p[key]+k),4)&0x0f; //取音调码
- if(beat!=0)
- { //判断取得的音调码是否为0 { //不是,根据取得的音调码计算T0初值
- m1=--m*2+1;
- m=m*2;
- tl=TL0=TABLE[m1];
- th=TH0=TABLE[m];
-
- }
- else
- { //取得的节拍码为0,则停止T0
- TR0=0;
- }
- Delay(beat);
- k++;
- Key_Scan();
- delay_10ms();
- if(temp!=key)break;
- }
- TR0=0;
- k=0;
- break;
- case 3:
- TR0=0;break;
- }
- }
- }
-
-
-
- void Timer0_Initialize()
- {
- EA=1;
- ET0=1;
- TMOD=0x01;
- TR0=1;
- }
- 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();
- }
- void delay_10ms()
- {
- int i;
- for(i=0;i<200;i++);
- }
- void Key_Scan()
- {
- uchar i,temp1;
- P1=0xfb;
- for(i=0;i<=1;i++)
- {
- if(L1==0)
- {
- if(i==0)
- key=a[i];
- else
- key=a[i+1];
-
- }
- if(L2==0)
- {
- if(i==0)
- key=a[i+1];
- else
- key=a[i+2];
- }
-
- delay_10ms();
- temp1=P1;
- temp1=temp1|0x03;
- temp1=temp1<<1;
- temp1=temp1|0x03;
- P1=temp1;
- }
- }
复制代码
Keil代码与Proteus仿真下载:
仿真和程序.7z
(108.6 KB, 下载次数: 22)
|