/*****************************************************************************
程 序 名:51AVR实验板配套程序 - 6路抢答器
开发环境:Keil
编 写 者:www.01mcu.net
功能简述:用按键和数码管组成抢答器
硬件说明:数码管的千位、百位显示抢答限时倒计数秒;
数码管个位显示路号,
K1-K6对应于抢答队按钮
K8为开始按钮
蜂鸣器接单片机P3.5
由于按键和数码显示公用P1,程序要分时扫描进行
晶体为12MHz
使用说明:按K8抢答开始,K1-K6为抢答键,预置抢答时限为10秒,用户可以改动
完成日期:2008.06.24
******************************************************************************/
#include <reg51.h>
sbit ls1=P0^2; //个位公共极
sbit ls2=P0^3; //十位公共极
sbit ls3=P0^4; //百位公共极
sbit ls4=P0^5; //千位公共极
sbit key=P0^6; //键盘公共极
sbit star=P1^7; //开始按键K8
sbit spk=P0^0; //蜂鸣器
unsigned char ST; //抢答标志,=0抢答结束;=1抢答开始;
unsigned char keyval; //读取的键值
#define Dat P1 //数据输出端
unsigned char mSec,Sec; //计时用
unsigned char qw,bw,sw,gw; //显存
unsigned char tab[]=
{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf}; //共阳
//0 1 2 3 4 5 6 7 8 9 -
//初始化--------------------------
Init()
{
TMOD=0x01; //T0=定时方式1
//定时器设置
TH0=0x3C;TL0=0xb0; //该值在12MHz时为50mS中断1次
//TR0=1; //使用时启动定时
ET0=1;
EA=1;
}
//发生子程序----------------------------
Sound(unsigned char F,unsigned char L)
{//t是声音的频率,L是声音的长度;具体数据根据晶体和实验决定
unsigned char f;unsigned int l;
for(l=0;l<L;l++)
{
spk=0;
for(f=0;f<F;f++);
spk=1;
for(f=0;f<F;f++);
}
}
//定时0中断--------------------------
void Timer0(void) interrupt 1
{
TH0=0x3c;
TL0=0xb0; //50mS中断一次
mSec++;
if(mSec>=20) //20次=1S
{mSec=0;
Sec--;
if(Sec==0)
{ST=0; //抢答自动到时
TR0=0; //停止
Sound(60,2000); //长声
gw=0; //自动到时,清除对号
}
}
}
//延时----------------------------
Delay(unsigned char t)
{
while(t--);
}
//显示----------------------------
void Display()
{
unsigned char j;
qw=Sec/10;
bw=Sec%10;
for(j=0;j<10;j++)
{
Dat=tab[gw];
ls1=0;
Delay(10);
ls1=1;
Dat=tab[0x0a]; //永远显示 '-'
ls2=0;
Delay(10);
ls2=1;
Dat=tab[bw];
ls3=0;
Delay(10);
ls3=1;
Dat=tab[qw];
ls4=0;
Delay(10);
ls4=1;
}
Dat=0xff; //由于公用P1,不用时要释放P1
}
//--键盘扫描程序--------------------------------------
Scankey()
{unsigned char i;
key=0; //拉低键盘公共线
if(Dat!=0xff) //有按键按下
{i=~Dat; //读取键盘状态,因为键盘按下位=0,抬起=1,所以这里取反便于下面分析
switch(i)
{
case 0x01: gw=0x01; //K1,键值显示在个位
TR0=0; //关定时
Sound(100,250); //长声
ST=0;
break;
case 0x02: gw=0x02; //K2
TR0=0; //关定时
Sound(100,250); //长声
ST=0;
break;
case 0x04: gw=0x03; //K3
TR0=0; //关定时
Sound(100,250); //长声
ST=0;
break;
case 0x08: gw=0x04; //K4
TR0=0; //关定时
Sound(100,250); //长声
ST=0;
break;
case 0x10: gw=0x05; //K5
TR0=0; //关定时
Sound(100,250); //长声
ST=0;
break;
case 0x20: gw=0x06; //K6
TR0=0; //关定时
Sound(100,250); //长声
ST=0;
break;
default: break; //其它双键按下不处理,
}
}
key=1; //释放键盘公共线
}
//--主程序---------------------------------------------------------
main()
{
unsigned int i;
Init(); //初始化
Dat=0xff;
ST=0;
for(i=0;i<300;i++) Display(); //开始显示
spk=1;
gw=0; //平常对号显示"0"
while(1)
{
if(ST==0)
{key=0;
star=1;
if(star==0)
{keyval=0;
Sound(100,50); //短一声
TH0=0x3c;
TL0=0xb0;
mSec=gw=0; //清计时时间、上次获胜对号
Sec=10; //预置抢答时限 !!! 你可以自行设置1-99秒限时时间
TR0=1; //开始计时
ST=1; //抢答开始
}
key=1;
}
if(ST==1) Scankey(); //抢答开始后才允许扫描键盘
if(TR0==0) Sec=0; //不在抢答期,时间显示0
Display();
}
}