抢答器正常情况下使用很ok,并且可以调节倒计时时间于LCD1602显示。
非正常情况下,会有些漏洞存在,感兴趣的朋友可以进一步完善。
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
- //有倒计时功能的八路抢答器C语言程序:
- #include<reg52.h>
- #define LCDPORT P0 //LCD数据线
- #define KEY P3 //八路抢答按键
- typedef unsigned char uchar;
- typedef unsigned int uint;
- sbit begin=P1^1; //开始键
- sbit set=P1^2; //设置时间键
- sbit add=P1^3;
- sbit dec=P1^4;
- sbit rst=P1^5; //复位键
- sbit light=P1^6; //开始指示灯
- sbit speaker=P1^7; //控制蜂鸣器
- sbit lcdrs=P2^0;
- sbit lcdrw=P2^1;
- sbit lcden=P2^2;
- uchar code table[]="00:15"; //初始值的设定
- uint aa=0,bb=0,cc=0,dd=0; //用于计数
- uchar start; //开始标志
- uchar stop; //结束标志
- uchar reset; //复位标志
- uchar miao=15;
- uchar fen=0;
- bit lockflag=0; //锁定标志,标志着已经有人抢答成功
- bit spflag=0; //开始声响标示
- bit ovflag=0; //超时声响标志
- /****延时z毫秒*******/
- void delay(uint z)
- {
- uchar x,y;
- for(x=z;x>0;x--)
- for(y=250;y>0;y--); //晶振为12MHZ:4*250*z=z ms
- }
- /***液晶写地址******/
- void write_com(uchar com)
- {
- lcdrs=0;
- lcdrw=0;
- P0=com;
- lcden=1;
- delay(3);
- lcden=0;
- }
- /****液晶写数据******/
- void write_data(uchar date)
- {
- lcdrs=1;
- lcdrw=0;
- P0=date;
- lcden=1;
- delay(3);
- lcden=0;
- }
- /***液晶初始化********/
- void lcd_init()
- {
- uchar num;
- write_com(0X38); //初始化
- write_com(0X0c); //打开光标 0x0c不显示光标,0x0e光标不闪,0x0f光标闪
- write_com(0X06); //清显示
- write_com(0X80); //显示第一行,第二行为(0x80+0x40)
- for(num=0;num<5;num++)
- {
- write_data(table[num]);
- delay(5);
- }
- }
- /******定时器初始化*******/
- void timer_init()
- {
- TMOD=0x11; //工作方式的选择
- TH0=(65536-50000)/256;
- TL0=(65536-50000)%256; //50ms
- ET0=1;
- TH1=(65536-500)/256;
- TL1=(65536-500)%256; //0.5ms
- ET1=1;
- EA=1;
- TR0=0;
- TR1=0;
- }
- /*****显示分*****/
- void display1(uchar fen)
- {
- uchar shi,ge;
- shi=fen/10;
- ge=fen%10;
- write_com(0X80);
- write_data(0X30+shi); //这里要注意,显示的是ASCII码!
- write_data(0X30+ge);
- }
- /*****显示秒*******/
- void display(uchar miao)
- {
- uchar shi,ge;
- shi=miao/10;
- ge=miao%10;
- write_com(0X80+3) ;
- write_data(0X30+shi); //这里要注意,显示的是ASCII码!
- write_data(0X30+ge);
- }
- /******定时器0的中断服务程序******/
- //倒计时
- void timer0() interrupt 1
- {
- TH0=(65536-50000)/256;
- TL0=(65536-50000)%256;
- aa++;
- if(aa==20) //20*50ms=1s
- {
- aa=0;
- miao--;
- if(miao==0)
- {
- if(fen==0)
- {
- stop=1; //时间到了,抢答超时
- TR0=0; //关闭定时器
- light=1; //把灯也关了
- TR1=1; //开启定时器1,响声
- ovflag=1; //超时标志
- }
- else
- {
- fen--;
- miao=59;
- }
- }
- display(miao); //更新显示数据
- display1(fen);
- }
- }
- /*****键盘扫描程序********/
- uchar keyscan()
- {
- uchar keyn;
- if(KEY!=0xff)
- {
- delay(5); //延时5ms作消抖处理
- if(KEY!=0xff) //确认有按键按下
- {
- switch(KEY)
- {
- case 0xfe:keyn=0;break;
- case 0xfd:keyn=1;break;
- case 0xfb:keyn=2;break;
- case 0xf7:keyn=3;break;
- case 0xef:keyn=4;break;
- case 0xdf:keyn=5;break;
- case 0xbf:keyn=6;break;
- case 0x7f:keyn=7;break;
- }
- while(KEY!=0xff); //等待松手
- }
- }
- if(begin==0)
- {
- delay(5); //延时5m作消抖处理
- if(begin==0)
- {
- keyn=8;
- while(!begin);
- }
- }
- if(set==0)
- {
- delay(5); //延时5m作消抖处理
- if(set==0)
- {
- while(!set);
- delay(5);
- while(!set);
- bb++;
- }
- }
- if(bb==1)
- {
- write_com(0x80+4);
- write_com(0x0f);
- }
- if(bb==2)
- {
- write_com(0x80+1);
- write_com(0x0f);
- }
- if(add==0)
- {
- delay(5); //延时5m作消抖处理
- if(add==0)
- {
- while(!add);
- delay(5);
- while(!add);
- //修改秒,增加1
- if(bb==1)
- {
- uchar ge,shi;
- miao++;
- shi=miao/10;
- ge=miao%10;
- //秒的修整
- if(miao==60)
- {
- ge=0;
- shi=0;
- }
- //显示修整值
- miao=shi*10+ge;
- display(miao);
- write_com(0x80+4);//把光标位置移回来
- }
- //修改分钟,加一
- if(bb==2)
- {
- uchar ge,shi;
- fen++;
- shi=fen/10;
- ge=fen%10;
- if(fen==60)
- {
- ge=0;
- shi=0;
- }
- fen=shi*10+ge;
- display1(fen);
- write_com(0x80+1);
- }
- }
- }
- if(dec==0)
- {
- delay(5); //延时5m作消抖处理
- if(dec==0)
- {
- while(!dec);
- delay(5);
- while(!dec);
- if(bb==1)
- {
- uchar ge,shi;
- miao--;
- shi=miao/10;
- ge=miao%10;
- if(miao==-1)
- {
- shi=5;
- ge=9;
- }
- miao=shi*10+ge;
- display(miao);
- write_com(0x80+4);
- }
- //修改分钟
- if(bb==2)
- {
- uchar ge,shi;
- fen--;
- shi=fen/10;
- ge=fen%10;
- if(fen==-1)
- {
- shi=5;
- ge=9;
- }
- fen=shi*10+ge;
- display1(fen);
- write_com(0x80+1);
- }
- }
- }
- if(bb==3)
- {
- bb=0;
- write_com(0x0c);
- }
- if(rst==0)
- {
- delay(5); //延时5m作消抖处理
- if(rst==0)
- {
- keyn=9;
- while(!rst);
- }
- }
- return(keyn);
- }
- /*******定时器1的中断服务程序*******/
- //喇叭声响
- void timer1() interrupt 3
- {
- TH1=(65536-500)/256;
- TL1=(65536-500)%256; //重装初值
- if(spflag) //开始时先响500ms
- {
- speaker=!speaker;
- dd++;
- if(dd>1000) //0.5ms*1000=500ms
- {
- dd=0;
- TR1=0; //停止定时器
- spflag=0;
- }
- }
- if(ovflag) //超时声响
- {
- dd++;
- if(dd%4==0){speaker=!speaker;}
- if(dd>3000)
- {
- dd=0;
- TR1=0;
- // ovflag=0;
- }
- }
- }
- void restart()
- {
- uchar num;
- start=0;
- TR0=0; //关闭定时器才能停止计时
- TR1=0;
- miao=0;
- fen=0;
- spflag=0;
- ovflag=0;
- lockflag=0; //各种标志清零
- P1=0XFF;
- P3=0XFF;
- miao=15;
- fen=0;
- lcd_init();
- timer_init();
- write_com(0x80+0x40);
- write_data(' ');
- }
- void main()
- {
- uchar a;
- lcd_init();
- timer_init();
- while(1)
- {
- a=25;
- a=keyscan();
- if(a!=25)
- {
- if(a==8) //按下开始键
- {
- start=1; //第一次按下就要开始抢答
- light=0; //灯亮表示开始
- spflag=1; //标志开始的声响
- EA=1; //启动定时器
- TR0=1;
- TR1=1;
- }
- while(start) //已经按下开始键后才作下面处理
- {
- a=keyscan();
- if(a>=0&&a<8&&lockflag==0&&ovflag==0)
- {
- write_com(0x80+0x40) ;
- write_data(0x30+a);
- TR0=0; //关闭定时器停止计时
- lockflag=1; //锁定
- start=0;
- }
- if(lockflag==1)start=0;
- }
- if(a==9)restart(); //按下复位键
- }
- }
- }
复制代码
所有资料51hei提供下载:
有倒计时功能的八路抢答器.zip
(57.34 KB, 下载次数: 49)
|