13.3.2 程序设计 - 51CTO.COM

来源:百度文库 编辑:神马文学网 时间:2024/04/29 13:17:07
原文地址:http://book.51cto.com/art/200811/96259.htm
抢答器工作过程如下。
首先主持人选定倒计时时间,单片机扫描U3以获取此信息。如果没有人为设置,默认为10s。
在按下抢答按键之前,3个数码管全部显示"0"。
按下抢答按键之后,蜂鸣器响一声,单片机开始倒计时,数码管U6和U7显示倒计时时间,数码管U5显示"0"。
如果有竞赛者率先在规定时间内按键,则蜂鸣器响一声,数码管U5显示该竞赛者的编号,U6和U7停止更新。
如果在主持人未按下抢答按键的时候有选手抢答,则此时蜂鸣器响一声,U5显示犯规者的编号,U6和U7显示"FF"以指示有人犯规。
如果在规定时间内无人按键,则U5显示"0",U6和U7显示"EE"以指示无人按键。
无论是在规定时间内有人按键、在规定时间内无人按键或者是有人犯规,都需要主持人再按一下抢答按键,之后单片机根据U3状态决定倒计时时间,3个数码管全部显示"0",恢复到初始状态,准备下一轮抢答。
程序流程如图13.7所示。
 
(点击查看大图)图13.7  四路抢答器程序流程图
程序如例13-4所示。
【例13-4】用8051单片机控制的四路抢答器程序。限于篇幅,这里没有给出显示程序,参见12.2.2节中例12-5。
#include
typedef unsigned char uchar;
sbit LE=P1^4;
sbit KEY5=P3^7;
sbit DIN=P2^4;       //定义P2.5控制MAX7219的串行数据输入端
sbit LOAD=P2^3;       //定义P2.4控制MAX7219的载入使能端
sbit CLK=P2^2;       //定义P2.3控制MAX7219的时钟信号
sbit BUZ=P0^1;
#define TIMER_HBYTE -50000/256   //定时50ms
#define TIMER_LBYTE -50000%256
uchar intr_counter;      //设定的时间用需要产生的中断次数表示
uchar bdata byte;      //在bdata区定义一个变量,便于位操作
sbit byte_7=byte^7;
bit foul_flg;       //是否有人犯规标志
bit time_over_flg;      //是否倒计时超时标志
bit key_flg;       //是否有人在规定时间内按键标志
void max7219_reset(void);    //初始化MAX7219
void write_reg(uchar,uchar);   //向控制寄存器写数据
void write_digit(uchar,uchar);   //向字型寄存器写数据
void send_data(uchar);     //底层的硬件驱动
uchar set_time(void);     //函数功能:设置倒计时时间
bit control_key(void);     //函数功能:检测主持人是否按键
uchar get_key_num(void);    //函数功能:检测哪个参赛者按键
void display_time(void);    //函数功能:显示倒计时剩余时间
void foul_handle(uchar);    //函数功能:犯规处理
void key_handle(uchar);     //函数功能:按键处理
void time_over_handle(void);   //函数功能:超时处理
void init_t0(void);      //函数功能:初始化T0定时器
void delay_20ms(void);     //函数功能:延时20ms,按键去抖动
void buz_on(void)      //函数功能:蜂鸣器响500ms
void main(void)
{
uchar key_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;     //主持人按键后进入下一轮
}
}
}
}
bit control_key(void)     //检测主持人是否按键
{
if(KEY5==1)       //如果KEY5为高,说明没有按键
return 1;      //返回1,表示没有按键动作
else         //如果KEY5为低,说明可能有按键动作
delay_20ms();     //延时20ms,去抖动
if(KEY5==1)       //如果20ms后KEY5变为高电平,是干扰
return 1;      //返回1
else         //如果20ms后仍为低电平,确认有按键动作
return 0;      //返回0
}
uchar set_time(void)     //根据设置决定倒计时时间
{
uchar intr_counter;
if(P3^6==0) intr_counter=200;  //10s
else if(P3^5==0) intr_counter=160; //8s
else if (P3^4==0) intr_counter=120; //6s
else if (P3^3==0) intr_counter=80; //4s
else intr_counter=200;    //如果没有设置,默认为10s
return intr_counter;
}
uchar get_key_num()      //检测哪个参赛者按键
{
uchar key_state=0;
key_state=P1;
key_state&=0x0f;      //读取P1端口的低4位
if(key_state==0x0f)     //若均为高电平,说明无人按键
return 0;      //返回1
else
{
key_state^=0xff;
if(key_state&0x01) return 1;  //如果KEY1被按下,返回1
else if(key_state&0x02) return 2; //如果KEY2被按下,返回2
else if(key_state&0x04) return 3; //如果KEY3被按下,返回3
else return 4;     //如果KEY4被按下,返回4
}
}
void foul_handle(uchar key_number)  //犯规处理
{
write_digit(DIGIT0,key_number);  //显示犯规者号码
write_digit(DIGIT1,0x0f);   //显示"FF"
write_digit(DIGIT2,0x0f);
buz_on();       //蜂鸣器响
}
void time_over_handle(void)    //超时处理
{
write_digit(DIGIT0,0x0);   //显示"0"
write_digit(DIGIT1,0x0e);   //显示"EE"
write_digit(DIGIT2,0x0e);
buz_on();       //蜂鸣器响
}
void key_handle(uchar key_number)  //按键处理
{
write_digit(DIGIT0,key_number);  //显示按键者号码
buz_on();
}
void display_time(void)     //显示倒计时剩余时间
{
uchar number;
write_digit(DIGIT0,LED_code[0]);
number=int_counter/20;    //秒数
write_digit(DIGIT1,number/10);  //秒数的十位数字
write_digit(DIGIT2,number%10);  //秒数的个位数字
}
void buz_on(void)
{
uchar i;
BUZ=0;        //开蜂鸣器
for(i=1;i<=25;i++)     //延时500ms
delay_20ms;
BUZ=1;        //关蜂鸣器
}
void init_t0(void)
{
TMOD=0x01;       //T0选择工作方式1,16位定时器
TH0=TIMER_HBYTE;      //定时时间为50ms
TL0=TIMER_LBYTE;
EA=1;        //使能CPU中断
ET0=1;        //使能T0溢出中断
TR0=1;        //T0运行
}
void isr_t0(void) interrupt 1   //T0中断服务函数
{
TH0=TIMER_HBYTE;      //定时时间为50ms
TL0=TIMER_LBYTE;
intr_counter--;      //中断次数
if(intr_counter==0)     //倒计时时间到
{
time_over_flg=1;     //设置超时标志
TR0=0;//禁止T0运行
}
}
void delay_20ms(void)     //延时20ms
{}
void max7219_reset(void)    //初始化MAX7219
{}
void write_reg(uchar reg,uchar sdata) //写入命令
{}
void write_digit(uchar digit,uchar number) //显示数字
{}
void send_data(uchar byte)    //MAX7219的驱动程序
{}