单片机8位抢答器源程序

功能如下:显示抢答、回答时间倒计时,能够调节抢答、回答时间,能够报警犯规抢答,可以计分,可以实现软复位

使用AT89S52 单片机。四位数码管(为啥我没有选择用液晶,因为我觉得液晶做的抢答器根本不具有实用性)。我所认为的实用性是做出来的东西是能够使用的而不是模型。同时我的8个按键都是分开来做的,也是实用性的考虑

/*八路抢答器-----能够显示抢答、回答时间倒计时,能够调节抢答、回答时间,能够报警犯规抢答,可以计分,可以实现软复位*/

/*欢迎交流*/

#include<reg52.h>

#define uchar unsigned char

#define uint unsigned int

sbit fmq=P3^6;

sbit Key_Start=P3^4;//开始键,时间设置时+

sbit Key_Stop=P3^5;//停止键,时间设置时-

sbit Key_Restart=P3^0;//复位键

sbit Key_set_Q=P3^2;//抢答时间设置键

sbit Key_set_H=P3^3;//回答时间设置键

sbit led=P3^7;//抢答LED提示

uchar code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff,0xc6,0xf0,0xb6};//段码表

uchar code table_char[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xc7,0xc0,0x92,0x86,0xbf,0xb7,0xff,0xb9,0x8f};//0-9 L O S E -

uchar  table_score[9]={0,50,50,50,50,50,50,50,50};//记分数组,初设值50分

void delay(uint z);//延时函数声明

void init();//初始化函数声明

void display(uchar XuanShou,uchar time);//显示数字函数声明

void display_char(uchar char_1,uchar char_2,uchar char_3,uchar char_4 );//显示字符函数声明

void display_set(uchar char_1,uchar time,uchar char_2);//时间设置闪动显示函数声明

void display_score(uchar xs_num);//分数查询显示函数

void beep();//蜂鸣器函数

void beep_last();//蜂鸣器特殊报警

void LED();//提示灯函数

uchar QiangDa_time,HuiDa_time,QiangDa_time_temp=20,HuiDa_time_temp=30;//抢答时间、回答时间变量

uchar count_0,count_1;//定时中计数用的

uint shan_count=0;//闪动显示计数用

void main()

{

 uchar AnJian,ShuJu,XuanShou_num;

Top:init();//初始化

 XuanShou_num=1;//为分数查询做好准备

 while(1)

 {

  display(10,0);//显示一杠

  ShuJu=P1;

  if(ShuJu!=0xff)//犯规抢答!!

  {

//   delay(10);

//   if(ShuJu!=0xff)

//   {

    AnJian=ShuJu;

    switch(AnJian)//取出选手编号

    {

     case 0xfe : XuanShou_num=1;break;//1111 1110

     case 0xfd : XuanShou_num=2;break;//1111 1101

     case 0xfb : XuanShou_num=3;break;//1111 1011

     case 0xf7 : XuanShou_num=4;break;//1111 0111

     case 0xef : XuanShou_num=5;break;//1110 1111

     case 0xdf : XuanShou_num=6;break;//1101 1111

     case 0xbf : XuanShou_num=7;break;//1011 1111

     case 0x7f : XuanShou_num=8;break;//0111 1111

     default : goto LOSE;//无法显示了,有两个以上的键同时按下了!!不过这种概率相当小

    }

    while(1)

    {

     display_char(13,14,14,XuanShou_num);//闪动显示犯规选手并且报警

     if(shan_count==50)

     {

      beep();

     }

     if(Key_Stop==0)

     {

      delay(10);

      if(Key_Stop==0)

      {

       beep();

       table_score[XuanShou_num]--;//扣分

      }

     }

     while(!Key_Stop)

     {

      display_char(14,14,1,16);//按键不放开的情况下显示-1

      shan_count=1;//调用的是闪动显示函数,但是不让其闪动

     }

     if(Key_Restart==0)

     {

      delay(10);

      if(Key_Restart==0)

      {

       beep();

       goto Top;//热复位

      }

     }

    }

//   }

  }

  if(Key_Start==0)

  {

   delay(10);

   if(Key_Start==0)//主持人按下抢答键,抢答正式开始!

   {

    QiangDa_time=QiangDa_time_temp;

    HuiDa_time=HuiDa_time_temp;

    beep();

    TR1=1;//抢答时间开始倒计时

    break;//跳出犯规抢答查询循环

   }

  }

//一下为查分程序测试

   if(Key_Stop==0)

   {

    delay(10);

   if(Key_Stop==0)//进入分数查询显示

   {

    beep();

    while(!Key_Stop);

    while(1)

    {

     display_score(XuanShou_num);

     if(Key_Start==0)

     {

      delay(10);

      if(Key_Start==0)

      {

       XuanShou_num++;

       if(XuanShou_num==9) XuanShou_num=1;

      }

     }

     while(!Key_Start);//等待按键释放

     if(Key_Stop==0)

     {

      delay(10);

      if(Key_Stop==0)

      {

       XuanShou_num--;

       if(XuanShou_num==0) XuanShou_num=8;

      }

     }

     while(!Key_Stop);//等待按键释放

       if(Key_Restart==0)

     {

      delay(10);

      if(Key_Restart==0)

      {

       beep();

       goto Top;//热复位

      }

     }

    }

   }

   }

 }

 while(1) //查询是否有按键按下,进入抢答循环

 {

  display(10,QiangDa_time);//显示抢答倒计时

  if(QiangDa_time==0)

  {

//   beep();

   TR1=0;//关闭定时器1

LOSE:  while(1)

   {

    display_char(10,11,12,13); //显示lose 字符

    if(Key_Restart==0)

    {

     delay(10);

     if(Key_Restart==0)//热复位键,从头开始下一轮

     {

      beep();

      goto Top;

     }

    }

   }

  }

  ShuJu=P1;//把P1口的数据送给变量

  if(ShuJu!=0xff)//有按键按下

  {

//   delay(10);

//   if(ShuJu!=0xff)//确定有按键按下

//   {

     AnJian=ShuJu;//传递数据扫描值

//     TR0=1;//启动定时器0

     TR1=0;//关闭定时器1

     break;//不再进行查询是否有按键按下了

//   }

  }

 }

 switch(AnJian)//取出选手编号

 {

  case 0xfe : XuanShou_num=1;beep();LED();break;//1111 1110

  case 0xfd : XuanShou_num=2;beep();LED();break;//1111 1101

  case 0xfb : XuanShou_num=3;beep();LED();break;//1111 1011

  case 0xf7 : XuanShou_num=4;beep();LED();break;//1111 0111

  case 0xef : XuanShou_num=5;beep();LED();break;//1110 1111

  case 0xdf : XuanShou_num=6;beep();LED();break;//1101 1111

  case 0xbf : XuanShou_num=7;beep();LED();break;//1011 1111

  case 0x7f : XuanShou_num=8;beep();LED();break;//0111 1111

  default : goto LOSE;//无法显示了,有两个以上的键同时按下了!!不过这种概率相当小

 }

 TR0=1;//启动定时器0(在这里启动比在前面好)

 while(1)

 {

  display(XuanShou_num,HuiDa_time);//显示选手编号和回答倒计时

  if(HuiDa_time==0)

  {

   TR0=0;//关闭定时器0

   goto LOSE;//跳到显示lose字符那里

  }

  if(Key_Stop==0)

  {

   delay(30);

   if(Key_Stop==0)//停止键按下

   {

    beep();

    TR0=0;//关闭定时器0,选手开始回答

    while(!Key_Stop);

    while(1) //在显示选手回答倒计时时只有在stop按键按下时,才可按复位键

    {

     display(XuanShou_num,HuiDa_time);//显示选手编号和回答倒计时

     if(Key_Start==0)

     {

      delay(10);

      if(Key_Start==0)

      {

       beep();

       table_score[XuanShou_num]++;//加分

      }

     }

     while(!Key_Start)

     {

      display_char(17,18,1,16);//按键不放开的情况下显示+1

      shan_count=1;//调用的是闪动显示函数,但是不让其闪动

     }

     if(Key_Stop==0)

     {

      delay(10);

      if(Key_Stop==0)

      {

       beep();

       table_score[XuanShou_num]--;//扣分

      }

     }

     while(!Key_Stop)

     {

      display_char(14,14,1,16);//按键不放开的情况下显示-1

      shan_count=1;//调用的是闪动显示函数,但是不让其闪动

     }

     if(Key_Restart==0)

     {

      delay(10);

      if(Key_Restart==0)//热复位键,从头开始下一轮

      {

       beep();

       goto Top;

      }

     }

    }

   }

  }

//  else

/*  if(Key_Restart==0)

  {

   delay(10);

   if(Key_Restart==0)//热复位键,从头开始下一轮

   {

    beep();

    goto Top;

   }

  } */

 }

 

}

void delay(uint z)//1ms基准延时

{

 uint x,y;

 for(x=z;x>0;x--)

  for(y=110;y>0;y--);

}

void init()//初始化函数

{

// P1=0xff

 EA=1;//开总中断;

 TMOD=0x11;//定时器工作方式1,16位定时计数器

 TH0=(65536-50000)/256;//50us

 TL0=(65536-50000)%256;

 ET0=1;//开定时器0中断(暂时不启动定时器)

// TMOD=0x01;//定时器工作方式1,16位定时计数器

 TH1=(65536-50000)/256;//50us

 TL1=(65536-50000)%256;

 ET1=1;//开定时器0中断(暂时不启动定时器)

 EX0=1;//启动外中断0

 EX1=1;//启动外中断1

 P1=0xff;//读P1口的数据要先置1准备

 count_0=0;//定时器中的计数清零

 count_1=0;

 shan_count=0;

}

void display(uchar XuanShou,uchar time)//显示数字的函数

{

  P2=0x7f;//0111 1111最后一位数码管亮

  P0=table[XuanShou];//选手编号

  delay(1);

  P2=0x7f;//0111 1111

  P0=0xff;//消余辉

  delay(1);

 

  P2=0xdf;//1101 1111

  P0=table[time%10];//时间的个位

  delay(1);

  P2=0xdf;//0111 1111

  P0=0xff;//消余辉

  delay(1);

 

  P2=0xef;// 1110 1111

  P0=table[time/10];//时间的十位

  delay(1);

  P2=0xef;//0111 1111

  P0=0xff;//消余辉

  delay(1);

}

void display_char(uchar char_1,uchar char_2,uchar char_3,uchar char_4 )//闪动!显示字符的函数

{

 shan_count++;

 if(shan_count==150) shan_count=0;

  if(shan_count>0&&shan_count<50)

  {

  P2=0x7f;//0111 1111

  P0=table_char[char_4];

  delay(1);

  P2=0x7f;//0111 1111

  P0=0xff;

  delay(1);

 

  P2=0xbf;//1011 1111

  P0=table_char[char_3];

  delay(1);

  P2=0xbf;//1011 1111

  P0=0xff;

  delay(1);

 

  P2=0xdf;//1101 1111

  P0=table_char[char_2];

  delay(1);

  P2=0xdf;//1101 1111

  P0=0xff;

  delay(1);

 

  P2=0xef;//1110 1111

  P0=table_char[char_1];

  delay(1);

  P2=0xef;//1110 1111

  P0=0xff;

  delay(1);

 }

 else

 {

   P2=0x7f;//0111 1111

  P0=0xff;

  delay(1);

  P2=0xbf;//

  P0=0xff;

  delay(1);

  P2=0xdf;//

  P0=0xff;

  delay(1);

  P2=0xef;//

  P0=0xff;

  delay(1);

 }

}

void display_set(uchar char_1,uchar time,uchar char_2)//时间设置的闪动显示

{

 shan_count++;

 if(shan_count==120) shan_count=0;

  if(shan_count>0&&shan_count<40)

  {

   P2=0x7f;//0111 1111最后一位数码管亮

  P0=table[char_2];//显示一个符号

  delay(1);

  P2=0x7f;//0111 1111

  P0=0xff;//消余辉

  delay(1);

  P2=0xbf;//1011 1111

  P0=table[time%10];//时间的个位

  delay(1);

  P2=0xbf;//1011 1111

  P0=0xff;//消余辉

  delay(1);

 

  P2=0xdf;//1101 1111

  P0=table[time/10];//时间的十位

  delay(1);

  P2=0xdf;//1101 1111

  P0=0xff;//消余辉

  delay(1);

 

  P2=0xef;// 1110 1111

  P0=table[char_1];//显示一个符号

  delay(1);

  P2=0xef;//1110 1111

  P0=0xff;//消余辉

  delay(1);

  }

  else

  {

   P2=0x7f;//0111 1111

  P0=table[char_2];

  delay(1);

  P2=0xbf;//

  P0=0xff;

  delay(1);

  P2=0xdf;//

  P0=0xff;

  delay(1);

  P2=0xef;//

  P0=table[char_1];

  delay(1);

  }

}

void display_score(uchar xs_num)//分数查询显示函数

{

  P2=0x7f;//0111 1111最后一位数码管亮

  P0=table[(table_score[xs_num]%10)];//分数的个位

  delay(1);

  P2=0x7f;//0111 1111

  P0=0xff;//消余辉

  delay(1);

  P2=0xbf;//1011 1111

  P0=table[(table_score[xs_num]/10)];//分数的十位

  delay(1);

  P2=0xbf;//1011 1111

  P0=0xff;//消余辉

  delay(1);

 

  P2=0xdf;//1101 1111

  P0=table_char[15];//间隔符号

  delay(1);

  P2=0xdf;//1101 1111

  P0=0xff;//消余辉

  delay(1);

 

  P2=0xef;// 1110 1111

  P0=table[xs_num];//选手编号

  delay(1);

  P2=0xef;//1110 1111

  P0=0xff;//消余辉

  delay(1);

}

void beep() //有源蜂鸣器函数

{

  fmq=0;

  delay(80);

  fmq=1;

}

void beep_last()//最后一声特殊声调

{

  fmq=0;

  delay(300);

  fmq=1;

}

void LED()

{

 led=0;

 delay(150);

 led=1;

}

void T0_time() interrupt 1//定时器0中断函数_回答时间

{

 TH0=(65536-50000)/256;//50ms

 TL0=(65536-50000)%256;//马上重装初值,以免有误差

 if(count_0==20)

 {

  count_0=0;

  HuiDa_time--;

  if(HuiDa_time<=5)

  {

   if(HuiDa_time==0)

   {

    beep_last();//最后一声特殊警告

   }

   beep();

  }

 }

 count_0++;

 

}

void T1_time() interrupt 3//定时器1中断函数_抢答时间

{

 TH1=(65536-50000)/256;//50us

 TL1=(65536-50000)%256;//马上重装初值,这样在后面调用beep()函数时就不会影响定时器的准确计时了

 if(count_1==20)

 {

  count_1=0;

  QiangDa_time--;

   if(QiangDa_time<=5)

  {

   if(QiangDa_time==0)

   {

    beep_last();//最后一声警告

   }

   else

   beep();

  }

 }

 count_1++; 

}

void EX0_set_QiangDa_time() interrupt 0 //外中断0,设置抢答时间

{

 delay(10);//消抖一下

 if(Key_set_Q==0)

 {

  beep();

  while(1)

  {

//   display(11,QiangDa_time_temp);

//   delay(100);//闪动效果

   display_set(12,QiangDa_time_temp,13);//调用时间设置闪动显示函数,效果为 [时间]

   if(Key_Start==0)//时间+1键

   {

     delay(10);

     if(Key_Start==0)

     {

      QiangDa_time_temp++;

     if(QiangDa_time_temp==100)

     {

      QiangDa_time_temp=1;

     }

     }

   }

   while(!Key_Start);//等待按键释放

//   else

   if(Key_Stop==0)//时间-1键

   {

     delay(10);

     if(Key_Stop==0)

     {

      QiangDa_time_temp--;

     if(QiangDa_time_temp==0)

     {

      QiangDa_time_temp=99;

     }

     }

   }

   while(!Key_Stop);//等待按键释放

//   else

   if(Key_Restart==0)

   {

    if(Key_Restart==0)

    {

     beep();

     break;

    }

   }

  }

 }

}

void EX1_set_HuiDa_time() interrupt 2 //外中断1,设置回答时间

{

 delay(10);//消抖一下

 if(Key_set_H==0)

 {

  beep();

  while(1)

  {

   display_set(12,HuiDa_time_temp,13);//调用时间设置闪动显示函数,效果为 [时间]

   if(Key_Start==0)//时间+1键

   {

     delay(10);

     if(Key_Start==0)

     {

      HuiDa_time_temp++;

     if(HuiDa_time_temp==100)

     {

      HuiDa_time_temp=1;

     }

     }

   }

   while(!Key_Start);//等待按键释放

//   else

   if(Key_Stop==0)//时间-1键

   {

     delay(10);

     if(Key_Stop==0)

     {

      HuiDa_time_temp--;

     if(HuiDa_time_temp==0)

     {

      HuiDa_time_temp=99;

     }

     }

   }

   while(!Key_Stop);//等待按键释放

//   else

   if(Key_Restart==0)

   {

    if(Key_Restart==0)

    {

     beep();

     break;

    }

   }

  }

 }

}