本帖最后由 学习51单片机 于 2014-11-22 18:37 编辑
求教八路抢答器怎样让按下抢答键后开始60秒倒计时
#include <reg51.h>
#include<intrins.h> //包含_nop_()函数定义的头文件
#include<math.h>
#include<absacc.h>
typedef unsigned char uchar; //无符号字符型
typedef unsigned int uint16; //无符号整型
sbit KEY1 = P1^0; //抢答键1S1
sbit KEY2 = P1^1; //抢答键2S2
sbit KEY3 = P1^2; //抢答键3S3
sbit KEY4 = P1^3; //抢答键4S4
sbit KEY5 = P1^4; //抢答键5S5
sbit KEY6 = P1^5; //抢答键6S6
sbit KEY7 = P1^6; //抢答键7S7
sbit KEY8 = P1^7; //抢答键8S8
sbit BEEP = P3^6; //蜂鸣器
sbit LED1 = P2^0; //第一个数码管共阴极
sbit LED3 = P2^1; //第三个数码管共阴极
sbit LED4 = P2^2; //第四个数码管共阴极
sbit LED2 = P2^5; //第二个数码管共阴极
sbit StartKEY = P3^0; //开始抢答键
sbit answerKEY = P3^1; //开始答题键
uchar StartKEYDown; //抢答键按下标志位
uchar KeyDown ; //已有按键按下标志位
uchar ClearShake; //按键消除抖动计时
uint16 BuzzerAlarm; //蜂鸣器报警1秒钟
uchar ScanningFlag; //数码管动态扫描控制标志位
uchar ContestTimeCnt; //为抢答时间计时
uchar AnswerTimeCnt; //为答题时间计时
uchar AnswerKEYDown; //答题键按下标志位
uchar AlarmFlag; //已报警过标志位
uchar ContestOverTime; //抢答时间到标志位
uchar AnswerOverTime; //答题时间到标志位
uchar ContestKeyDown; //抢答键已按下过标志位用来控制系统的清除
uchar NoAnswer; //没人回答正确报警已经输出过
uchar AlarmControl; //抢答倒计时还剩10秒钟报警输出
uchar AlarmOutput; //选手按下抢答键时报警输出控制
#define ContestTime 30 //抢答时间30秒钟
#define AnswerTime 60 //答题时间60秒钟
const uchar SheetLed[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00,0xff}; //0 1 2 3 4 5 6 7 8 9 不显
//const uchar SheetLed[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
/*void Delay(uint16 i)
{
while(i--);
} */
void InitWindow(void)
{
LED1 = 1; //初始化的时候所有数码管都不选通
LED3 = 1; //相当于数码管全部不点亮
LED4 = 1;
}
/***********按键扫描程序***************/
void KeyCheck(void)
{
if(StartKEY == 0) //抢答键按下
if(ClearShake == 5) //定时器中断时间2ms按键消除抖动2*5=10ms
{
StartKEYDown = 1; //抢答器按下标志位抢答键按下后开放选手的按键功能否则按下无效
BEEP = 0; //抢答键按下蜂鸣器报警通知选手
BuzzerAlarm = 0;//计时清零蜂鸣器报警一秒钟后关闭
ContestTimeCnt = 0;
AnswerTimeCnt = 0;
ContestKeyDown = 1;
KeyDown = 0;
AnswerKEYDown = 0;
NoAnswer = 0;
AlarmFlag = 0;
ContestOverTime = 0;
AlarmOutput = 0;
}
if(KeyDown != 0) //有选手按下抢答键否则答题键无效
if(answerKEY == 0) //答题键按下
if(ClearShake == 5)
{
AnswerKEYDown = 1;
BEEP = 0;
}
if(BuzzerAlarm == 500) //1000ms时间到
{
if(StartKEYDown == 1)//抢答键已被按下选手开始抢答
{
BEEP = 1; //关闭报警输出
BuzzerAlarm = 0; //计时清零
if(KeyDown == 0) //没有选手按下抢答键
if(ContestOverTime == 0) //倒计时没到30秒钟可以继续计时
ContestTimeCnt++; //没有选手按下抢答键抢答时间继续倒计时否则停止
if(AnswerKEYDown == 1) //答题键按下
//BuzzerAlarm = 0; //计时清零
// ContestTimeCnt=0;
if(AnswerOverTime == 0)//答题时间没到60秒钟可以继续计时
AnswerTimeCnt++;
if(ContestTimeCnt == 30) //30秒钟时间到
{
//ContestTimeCnt = 0;
ContestOverTime = 1;
if(KeyDown == 0) //没有选手按下抢答键
if(AlarmFlag == 0)//系统还没报过警
{
BEEP = 0; //报警输出
AlarmFlag = 1; //已报警标志位
}
}
if(AnswerTimeCnt == 60) //答题时间时间到
if(NoAnswer == 0)
{
AnswerOverTime = 1;
BEEP = 0;
NoAnswer = 1;
}
}
}
if(KeyDown == 0)
if(ContestTimeCnt > 20)
{
if((ContestTime - ContestTimeCnt) == 0)
BEEP = 1;
else
BEEP = 0;
}
if(AnswerTimeCnt > 55)
if((AnswerTime - AnswerTimeCnt) == 0)
BEEP = 1;
else
BEEP = 0;
if(AlarmFlag != 1)//30秒倒计时没到可以继续抢答
if(KeyDown == 0) //没有选手按下抢答键继续扫描
{
if(KEY1 == 0) //抢答键1按下
if(ClearShake == 5)
KeyDown = 1; //一旦检测到有一个按键按下停止扫描其它按键
if(KEY2 == 0) //抢答键2按下
if(ClearShake == 5)
KeyDown = 2;
if(KEY3 == 0)
if(ClearShake == 5)
KeyDown = 3; //抢答键3按下
if(KEY4 == 0)
if(ClearShake == 5)
KeyDown = 4; //抢答键4按下
if(KEY5 == 0)
if(ClearShake == 5)
KeyDown = 5; //抢答键5按下
if(KEY6 == 0)
if(ClearShake == 5)
KeyDown = 6; //抢答键6按下
if(KEY7 == 0)
if(ClearShake == 5)
KeyDown = 7; //抢答键7按下
if(KEY8 == 0)
if(ClearShake == 5)
KeyDown = 8; //抢答键8按下
}
else
{
if(AlarmOutput == 0)
{
BEEP = 0; //报警输出
AlarmOutput = 1;
}
}
if(ClearShake > 5)
ClearShake = 0; //每个按键的消抖计时统一清零
}
/***********数码管显示程序******************/
void LedShow(void)
{
if(StartKEYDown == 1)//抢答键已被按下选手开始抢答
{
if(ScanningFlag == 0)//控制数码管轮流显示
{
LED1 = 1;
LED3 = 0; //选中第3个数码管显示抢答倒计时十位
LED4 = 1;
P0 = SheetLed[(ContestTime - ContestTimeCnt)/10]; //动态扫描时间为2ms
ScanningFlag = 1;
}
else if(ScanningFlag == 1)
{
LED1 = 1;
LED3 = 1;
LED4 = 0;
P0 = SheetLed[(ContestTime - ContestTimeCnt)%10];
ScanningFlag = 2;
}
else if(ScanningFlag == 2)
{
if(AnswerKEYDown == 1)
{
//P0 = 0xff;
LED1 = 1;
LED4 = 1;
LED3 = 0; //答题倒计时十位
P0 = SheetLed[(AnswerTime-AnswerTimeCnt)/10];
}
ScanningFlag = 3;
}
else if(ScanningFlag == 3)
{
if(AnswerKEYDown == 1)
{
LED1 = 1;
LED3 = 1;
LED4 = 0; //答题倒计时个位
P0 = SheetLed[(AnswerTime-AnswerTimeCnt)%10];
}
ScanningFlag = 4;
}
else if(ScanningFlag == 4)
{
ScanningFlag = 0;
switch(KeyDown)
{
case 0:
LED3 = 1;
LED4 = 1;
LED1 = 0;
P0 = SheetLed[10];//没有选手按下按键第一个数码管不显示
break;
case 1:
LED3 = 1;
LED4 = 1;
LED1 = 0;
P0 = SheetLed[1];
break;
case 2:
LED3 = 1;
LED4 = 1;
LED1 = 0;
P0 = SheetLed[2];
break;
case 3:
LED3 = 1;
LED4 = 1;
LED1 = 0;
P0 = SheetLed[3];
break;
case 4:
LED3 = 1;
LED4 = 1;
LED1 = 0;
P0 = SheetLed[4];
break;
case 5:
LED3 = 1;
LED4 = 1;
LED1 = 0;
P0 = SheetLed[5];
break;
case 6:
LED3 = 1;
LED4 = 1;
LED1 = 0;
P0 = SheetLed[6];
break;
case 7:
LED3 = 1;
LED4 = 1;
LED1 = 0;
P0 = SheetLed[7];
break;
case 8:
LED3 = 1;
LED4 = 1;
LED4 = 1;
LED1 = 0;
P0 = SheetLed[8];
break;
}
}
}
}
/**********定时器0初始化函数*****************/
void Init_timer()
{
TMOD=0x01; //0000 0001 定时器0在模式1下工作16位计数
TH0=63536/256; //定时器0初值 定时2000us
TL0=63536%256;
ET0=1; //使能定时器0中断
EA=1; //使能总中断
TR0=1; //开始计时
}
/****************************************************************************
* 名称 timer0()
* 功能 定时器1每2000us中断一次。
* 入口参数
****************************************************************************/
void timer0(void) interrupt 1
{
EA =0; //关总中断
TR0=0; //关定时器中断
TMOD=0x01; //0000 0001 定时器0在模式1下工作16位计数
TH0=63536/256; //重新装初值
TL0=63536%256;
TR0=1; //开中断
EA=1;
ClearShake++;
BuzzerAlarm++;
LedShow(); //数码管显示
}
void main(void)
{
Init_timer();//定时器初始化
InitWindow();
for(;;)
{
KeyCheck();
}
}
|