基于MCS51单片机四路抢答器.docx
《基于MCS51单片机四路抢答器.docx》由会员分享,可在线阅读,更多相关《基于MCS51单片机四路抢答器.docx(12页珍藏版)》请在冰豆网上搜索。
基于MCS51单片机四路抢答器
基于MCS-51单片机的四路抢答器
抢答器是为智力竞赛参赛者答题时进行抢答而设计的一种优先判决器电路,广泛应用于各种知识竞赛、文娱活动等场合。
能够实现抢答器功能的方式有多种,可以采用前期的模拟电路、数字电路或模拟与数字电路相结合的方式,但这种方式制作过程复杂,而且准确性与可靠性不高,成品面积大,安装、维护困难。
本节介绍一种利用8051单片机作为核心部件进行逻辑控制及信号产生的四路抢答器。
硬件设计
硬件电路应能完成以下功能:
参加竞赛者对主持人提出的问题要在最短的时间作出判断,并按下抢答按键回答问题。
当第一个人按下按键后,则在显示器上显示此竞赛者的并进行声音提示,同时电路将其他抢答按键封锁,使其不起作用。
若有人在可以抢答之前按键,应该有违规提示。
电路应该具有倒计时功能,倒计时时间可以设置并显示,在规定时间没有人抢答则本题作废。
回答完或超时后,由主持人将所有按键恢复,重新开始下一轮。
完成上述功能的电路包括时间设定开关、声光显示、按键控制以及按键锁存等部分,如图所示。
各电路模块的功能如下。
· 单片机部分:
通过读取P3.7~P3.3的状态决定倒计时时间;通过读取P1.3~P1.0的状态读取按键情况;通过P2.4~P2.2控制显示模块以显示按键者的和倒计时所剩时间;通过P0.1控制蜂鸣器。
· 时间设定模块:
以拨码开关U3作为倒计时时间的选择信号。
若P3.7通过U3接地,倒计时时间为10s;若P3.6通过U3接地,倒计时时间为8s,若P3.5通过U3接地,倒计时时间为6s,若P3.4通过U3接地,倒计时时间为4s。
判断时P3.7优先级最高,P3.4优先级最低。
· 按键模块:
KEY1~KEY4的信息可以直接传输到P1.3~P1.0。
单片机一旦检测到有按键按下,立即将P1.4置为低电平,将按键信息锁存,以免后来的按键对其产生影响。
KEY1~KEY4为抢答按键,KEY5为主持人控制按键。
· 数码管显示模块:
数码管显示模块由一片MAX7219和3个数码管组成。
其中U5用来显示按键者的编号,U6、U7在倒计时时显示还有多长时间,如果有人犯规抢答,U6~U7显示“FF”。
· 蜂鸣器模块:
蜂鸣器在主持人发出可以抢答信号、有人按下抢答按键和倒计时时间到等3种情况下发出蜂鸣声。
程序设计
抢答器工作过程如下。
· 首先主持人选定倒计时时间,单片机扫描U3以获取此信息。
如果没有人为设置,默认为10s。
· 在按下抢答按键之前,3个数码管全部显示“0”。
· 按下抢答按键之后,蜂鸣器响一声,单片机开始倒计时,数码管U6和U7显示倒计时时间,数码管U5显示“0”。
· 如果有竞赛者率先在规定时间按键,则蜂鸣器响一声,数码管U5显示该竞赛者的编号,U6和U7停止更新。
· 如果在主持人未按下抢答按键的时候有选手抢答,则此时蜂鸣器响一声,U5显示犯规者的编号,U6和U7显示“FF”以指示有人犯规。
· 如果在规定时间无人按键,则U5显示“0”,U6和U7显示“EE”以指示无人按键。
· 无论是在规定时间有人按键、在规定时间无人按键或者是有人犯规,都需要主持人再按一下抢答按键,之后单片机根据U3状态决定倒计时时间,3个数码管全部显示“0”,恢复到初始状态,准备下一轮抢答。
程序流程如图所示。
图 四路抢答器程序流程图
程序如例1所示。
【例1】用8051单片机控制的四路抢答器程序。
限于篇幅,这里没有给出显示程序,参见节中例
#include
typedefunsignedcharuchar;
sbitLE=P1^4;
sbitKEY5=P3^7;
sbitDIN=P2^4; //定义P2.5控制MAX7219的串行数据输入端
sbitLOAD=P2^3; //定义P2.4控制MAX7219的载入使能端
sbitCLK=P2^2; //定义P2.3控制MAX7219的时钟信号
sbitBUZ=P0^1;
#defineTIMER_HBYTE-50000/256 //定时50ms
#defineTIMER_LBYTE-50000%256
ucharintr_counter; //设定的时间用需要产生的中断次数表示
ucharbdatabyte; //在bdata区定义一个变量,便于位操作
sbitbyte_7=byte^7;
bitfoul_flg; //是否有人犯规标志
bittime_over_flg; //是否倒计时超时标志
bitkey_flg; //是否有人在规定时间按键标志
voidmax7219_reset(void); //初始化MAX7219
voidwrite_reg(uchar,uchar); //向控制寄存器写数据
voidwrite_digit(uchar,uchar); //向字型寄存器写数据
voidsend_data(uchar); //底层的硬件驱动
ucharset_time(void); //函数功能:
设置倒计时时间
bitcontrol_key(void); //函数功能:
检测主持人是否按键
ucharget_key_num(void); //函数功能:
检测哪个参赛者按键
voiddisplay_time(void); //函数功能:
显示倒计时剩余时间
voidfoul_handle(uchar); //函数功能:
犯规处理
voidkey_handle(uchar); //函数功能:
按键处理
voidtime_over_handle(void); //函数功能:
超时处理
voidinit_t0(void); //函数功能:
初始化T0定时器
voiddelay_20ms(void); //函数功能:
延时20ms,按键去抖动
voidbuz_on(void) //函数功能:
蜂鸣器响500ms
voidmain(void)
{
ucharkey_number;
max7219_reset(); //初始化MAX7219
while
(1)
{
foul_flg=0; //设置初始环境
time_over_flg=0;
TR0=0; //禁止T0运行
write_digit(DIGIT0,LED_code[0x0]);//上电后3个数码管全部显示0
write_digit(DIGIT1,LED_code[0x0]);
write_digit(DIGIT2,LED_code[0x0]);
while((control_key()==1)&&(foul_flg==0))
//如果主持人没有按键
{
key_number=getkey_num(); //检查是否有人犯规
if(key_number==0) //如果没有,进行下一次循环
continue;
else //如果有人犯规
{
foul_handle(); //犯规处理
foul_flg=1; //设置犯规标志
}
}
if(foul_flg==1) //如果有人犯规
{
while(control_key()==1); //等待主持人按键以进入下一轮
continue; //主持人按键后进入下一轮
}
else //如果没有人犯规,必定是主持人允许答题
{
intr_counter=set_time(); //读取倒计时时间
init_t0(); //定时器T0开始计时
buz_on(); //蜂鸣器响500ms
while(time_over_flg==0&&key_flg==0)
{
key_number=getkey_num(); //在规定时间检查是否有按键
if(key_number!
=0) //如果有
{
key_handle(key_number);//按键处理
key_flg=1; //设置有人按键答题标志
TR0=0; //停止T0运行
}
else //否则循环检测
{
display_time(); //并显示剩余时间
continue;
}
}
if(key_flg==1) //如果有人在规定时间答题
{
while(control_key==1);//等待主持人按键以进入下一轮
continue; //主持人按键后进入下一轮
}
else //倒计时时间到仍无人按键
{
time_over_handle(); //超时处理
while(control_key==1);//等待主持人按键以进入下一轮
continue; //主持人按键后进入下一轮
}
}
}
}
bitcontrol_key(void) //检测主持人是否按键
{
if(KEY5==1) //如果KEY5为高,说明没有按键
return1; //返回1,表示没有按键动作
else //如果KEY5为低,说明可能有按键动作
delay_20ms(); //延时20ms,去抖动
if(KEY5==1) //如果20ms后KEY5变为高电平,是干扰
return1; //返回1
else //如果20ms后仍为低电平,确认有按键动作
return0; //返回0
}
ucharset_time(void) //根据设置决定倒计时时间
{
ucharintr_counter;
if(P3^6==0)intr_counter=200; //10s
elseif(P3^5==0)intr_counter=160; //8s
elseif(P3^4==0)intr_counter=120; //6s
elseif(P3^3==0)intr_counter=80; //4s
elseintr_counter=200; //如果没有设置,默认为10s
returnintr_counter;
}
ucharget_key_num() //检测哪个参赛者按键
{
ucharkey_state=0;
key_state=P1;
key_state&=0x0f; //读取P1端口的低4位
if(key_state==0x0f) //若均为高电平,说明无人按键
return0; //返回1
else
{
key_state^=0xff;
if(key_state&0x01)return1; //如果KEY1被按下,返回1
elseif(key_state&0x02)return2; //如果KEY2被按下,返回2
elseif(key_state&0x04)return3; //如果KEY3被按下,返回3
elsereturn4; //如果KEY4被按下,返回4
}
}
voidfoul_handle(ucharkey_number) //犯规处理
{
write_digit(DIGIT0,key_number); //显示犯规者
write_digit(DIGIT1,0x0f); //显示“FF”
write_digit(DIGIT2,0x0f);
buz_on(); //蜂鸣器响
}
voidtime_over_handle(void) //超时处理
{
write_digit(DIGIT0,0x0); //显示“0”
write_digit(DIGIT1,0x0e); //显示“EE”
write_digit(DIGIT2,0x0e);
buz_on(); //蜂鸣器响
}
voidkey_handle(ucharkey_number) //按键处理
{
write_digit(DIGIT0,key_number); //显示按键者
buz_on();
}
voiddisplay_time(void) //显示倒计时剩余时间
{
ucharnumber;
write_digit(DIGIT0,LED_code[0]);
number=int_counter/20; //秒数
write_digit(DIGIT1,number/10); //秒数的十位数字
write_digit(DIGIT2,number%10); //秒数的个位数字
}
voidbuz_on(void)
{
uchari;
BUZ=0; //开蜂鸣器
for(i=1;i<=25;i++) //延时500ms
delay_20ms;
BUZ=1; //关蜂鸣器
}
voidinit_t0(void)
{
TMOD=0x01; //T0选择工作方式1,16位定时器
TH0=TIMER_HBYTE; //定时时间为50ms
TL0=TIMER_LBYTE;
EA=1; //使能CPU中断
ET0=1; //使能T0溢出中断
TR0=1; //T0运行
}
voidisr_t0(void)interrupt1 //T0中断服务函数
{
TH0=TIMER_HBYTE; //定时时间为50ms
TL0=TIMER_LBYTE;
intr_counter--; //中断次数
if(intr_counter==0) //倒计时时间到
{
time_over_flg=1; //设置超时标志
TR0=0;//禁止T0运行
}
}
voiddelay_20ms(void) //延时20ms
{}
voidmax7219_reset(void) //初始化MAX7219
{}
voidwrite_reg(ucharreg,ucharsdata) //写入命令
{}
voidwrite_digit(uchardigit,ucharnumber) //显示数字
{}
voidsend_data(ucharbyte) //MAX7219的驱动程序
{}