基于51单片机的4路抢答器

/*
此程序为4人抢答器。
抢答者4人对应,K1-4的按钮
裁判可操作Ks,Kr,Kc,Ka4个按钮
Ks:按下就进入抢答倒计时
Kr:按下复位,准备下次抢答
Kc,Ka:用于调整倒计时。
在复位之前使用,且当前的操作是对复位之后的倒计时有用
保证没有人按下除了Kc,Ka之外的按钮。
最大设置为1分钟,最小10s
按一次Kc加1s
操作步骤:按下Kr,后要按住Ka不松的状态按Kc加时间,然后再次按下Kr

显示器第一行显示倒计时的时间
例如:countdown:10s
显示器第二行显示违规者和抢答成功者的对应按钮
例如:error:0 win:2 表示:无人违规,2号抢答成功
例如:error:2 win:0 表示:有人违规,2号违规
*/

#include “reg52.h”
#include “lcd.h”

#define uchar unsigned char
#define uint unsigned int

sbit K1=P1^0;
sbit K2=P1^1;
sbit K3=P1^2;
sbit K4=P1^3;
sbit Ks=P3^0; //按下就进入抢答倒计时
sbit Kr=P3^2; //按下复位,准备下次抢答
sbit Kc=P3^3; //按下调整倒计时,注意事项见timeset()
sbit Ka=P3^4; //配合Kc
sbit beep=P3^7;
sbit led=P3^1;

uchar fallflag=0,sflag=0,jflag=0,sjflag=0;
uchar win,time=10; //time为倒计时秒数,num为程序中控制倒计时的变量,win为抢答成功的按钮
uchar num,numf; //numf为配合num来显示lcd

uchar Disp1[16]="countdown:00s ";
uchar Disp2[16]="error:0 win:0 ";

void judge();
void search();

void delay(uchar ms)
{
uchar y;
for(;ms>0;ms–)
for(y=120;y>0;y–);
}

void T0_Init()
{
TMOD=0X11;
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;
TH1=(65536-1000)/256;
TL1=(65536-1000)%256;
ET0=1;
ET1=1;
TR0=1; //定时器0开
TR1=0; //定时器1关
EA=1;
}
/lcd1602显示程序/
void display(uchar date1,uchar date2)
{
uchar i,a;
LcdInit();
Disp1[10]=num/10+‘0’;
Disp1[11]=num%10+‘0’;
Disp2[6]=date1+‘0’;
Disp2[12]=date2+‘0’;
for(i=0;i<16;i++)
{
LcdWriteData(Disp1[i]);
}
LcdWriteCom(0x80+0x40);
for(a=0;a<16;a++)
{
LcdWriteData(Disp2[a]);
}
}

/*
开始准备抢答,开始倒计时
/
void Ks_Scan()
{
if(Ks0)
{
delay(10);
if(Ks
0)
{
TR1=1; //开启倒计时
sjflag=1; //开启犯规判断
while(num!=0) //如果在期间有人抢答,fallflag=1,此程序执行完后,后续程序会判犯规
{
if(numnumf-1)
{
numf=numf-1;
display(0,0); //不能显示num=0时
}
}
sflag=1; //抢答开始
if(sjflag
0) //有人犯规
{
sflag=0;
}
sjflag=0; //关闭犯规判断
display(0,0); //显示num=0时
beep=0; //蜂鸣
}
while(!Ks);
}
}
/

复位
/
void restoration()
{
if(Kr0)
{
delay(10);
if(Kr
0)
{
sflag=0;
sjflag=0;
jflag=0;
win=0;
fallflag=0;
TR1=0;
num=time;
numf=num;
beep=1;
led=1;
display(0,0); //清除显示屏
}
while(!Kr);
}
}
/

在复位之前使用,且当前的操作是对复位之后的倒计时有用
保证没有人按下除了Kc,Ka之外的按钮。
最大设置为1分钟,最小10s
按一次Kc加1s
操作步骤:按下Kr,后要按住Ka不松的状态按Kc加时间,然后再次按下Kr
*/
void timeset() //改变抢答时间
{
uchar a=0;
if(Ka0)
{
delay(10);
if(Ka
0)
{
while(!Ka)
{
if(Kc0)
{
delay(10);
if(Kc
0)
{
a++;
}
while(!Kc);
}
}
time=time+a;
}
}
if(time>=60)
{
time=10;
}
}

void main()
{
T0_Init();
while(1)
{
Ks_Scan();
if((sflag0)&(fallflag0)) //没开始没人抢答
{
timeset();
}
if((sflag0)&(fallflag!=0)) //有人违规抢答
{
led=0; //亮灯警告
beep=1; //关闭蜂鸣
display(fallflag,0); //显示有人犯规,并显示犯规按钮,根据fallflag
}
if((sflag
1)&(fallflag0)) //无人违规
{
while(jflag
0)
{
judge();
}
judge(); //防止jflag=1时,judge()没执行
beep=1; //关闭蜂鸣
display(0,win); //显示抢答成功按钮,根据win
}
restoration(); //复位
}
}

/不停的扫描k1-4的状态,每隔1ms扫描一次/
void timer0() interrupt 1
{
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;
search();
}

void timer1() interrupt 3
{
static i;
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;
i++;
if(i1000)
{
i=0;
num–;
//display(0,0); //为什么此时加上这个程序就报warning
if(num
0) //放在内部保证定时器的准确性
{
TR1=0;
}
}
}

//先丢后面的代码

/*
配合定时器0使用
如果k1-4有按键按下,fallflag=1
*/
void search()
{
if((K10)&(sjflag1)) //按下Ks开始后(sjflag=1)如果有人按了K1就会进入程序
{
delay(10);
if(K10)
{
fallflag=1;
sjflag=0; //互锁,并配合Ks_Scan()中的犯规判断语句
}
while(!K1);
}
if((K2
0)&(sjflag1))
{
delay(10);
if(K2
0)
{
fallflag=2;
sjflag=0;
}
while(!K2);
}
if((K30)&(sjflag1))
{
delay(10);
if(K30)
{
fallflag=3;
sjflag=0;
}
while(!K3);
}
if((K4
0)&(sjflag1))
{
delay(10);
if(K4
0)
{
fallflag=4;
sjflag=0;
}
while(!K4);
}
}

void judge()
{
if((K10)&(jflag0))
{
delay(10);
if((K10)&(jflag0))
{
win=1;
jflag=1; //锁住其他按钮
}
while(!K1);
}
if((K20)&(jflag0))
{
delay(10);
if((K20)&(jflag0))
{
win=2;
jflag=1; //锁住其他按钮
}
while(!K2);
}
if((K30)&(jflag0))
{
delay(10);
if((K30)&(jflag0))
{
win=3;
jflag=1; //锁住其他按钮
}
while(!K3);
}
if((K40)&(jflag0))
{
delay(10);
if((K40)&(jflag0))
{
win=4;
jflag=1; //锁住其他按钮
}
while(!K4);
}
}

以下是“lcd.c”
#include “lcd.h”

/*******************************************************************************

  • 函 数 名 : Lcd1602_Delay1ms
  • 函数功能 : 延时函数,延时1ms
  • 输 入 : c
  • 输 出 : 无
  • 说 名 : 该函数是在12MHZ晶振下,12分频单片机的延时。
    *******************************************************************************/

void Lcd1602_Delay1ms(uint c) //误差 0us
{
uchar a,b;
for (; c>0; c–)
{
for (b=199;b>0;b–)
{
for(a=1;a>0;a–);
}
}

}

/*******************************************************************************

  • 函 数 名 : LcdWriteCom

  • 函数功能 : 向LCD写入一个字节的命令

  • 输 入 : com

  • 输 出 : 无
    *******************************************************************************/
    #ifndef LCD1602_4PINS //当没有定义这个LCD1602_4PINS时
    void LcdWriteCom(uchar com) //写入命令
    {
    LCD1602_E = 0; //使能
    LCD1602_RS = 0; //选择发送命令
    LCD1602_RW = 0; //选择写入

      LCD1602_DATAPINS = com;     //放入命令
      Lcd1602_Delay1ms(1);                //等待数据稳定
    
      LCD1602_E = 1;                  //写入时序
      Lcd1602_Delay1ms(5);          //保持时间
      LCD1602_E = 0;
    

}
#else
void LcdWriteCom(uchar com) //写入命令
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 0; //选择写入命令
LCD1602_RW = 0; //选择写入

    LCD1602_DATAPINS = com;        //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
    Lcd1602_Delay1ms(1);

    LCD1602_E = 1;         //写入时序
    Lcd1602_Delay1ms(5);
    LCD1602_E = 0;

    LCD1602_DATAPINS = com << 4; //发送低四位
    Lcd1602_Delay1ms(1);

    LCD1602_E = 1;         //写入时序
    Lcd1602_Delay1ms(5);
    LCD1602_E = 0;

}
#endif
/*******************************************************************************

  • 函 数 名 : LcdWriteData

  • 函数功能 : 向LCD写入一个字节的数据

  • 输 入 : dat

  • 输 出 : 无
    *******************************************************************************/
    #ifndef LCD1602_4PINS
    void LcdWriteData(uchar dat) //写入数据
    {
    LCD1602_E = 0; //使能清零
    LCD1602_RS = 1; //选择输入数据
    LCD1602_RW = 0; //选择写入

      LCD1602_DATAPINS = dat; //写入数据
      Lcd1602_Delay1ms(1);
    
      LCD1602_E = 1;   //写入时序
      Lcd1602_Delay1ms(5);   //保持时间
      LCD1602_E = 0;
    

}
#else
void LcdWriteData(uchar dat) //写入数据
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 1; //选择写入数据
LCD1602_RW = 0; //选择写入

    LCD1602_DATAPINS = dat;        //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
    Lcd1602_Delay1ms(1);

    LCD1602_E = 1;          //写入时序
    Lcd1602_Delay1ms(5);
    LCD1602_E = 0;

    LCD1602_DATAPINS = dat << 4; //写入低四位
    Lcd1602_Delay1ms(1);

    LCD1602_E = 1;          //写入时序
    Lcd1602_Delay1ms(5);
    LCD1602_E = 0;

}
#endif
/*******************************************************************************

  • 函 数 名 : LcdInit()
  • 函数功能 : 初始化LCD屏
  • 输 入 : 无
  • 输 出 : 无
    *******************************************************************************/
    #ifndef LCD1602_4PINS
    void LcdInit() //LCD初始化子程序
    {
    LcdWriteCom(0x38); //开显示
    LcdWriteCom(0x0c); //开显示不显示光标
    LcdWriteCom(0x06); //写一个指针加1
    LcdWriteCom(0x01); //清屏
    LcdWriteCom(0x80); //设置数据指针起点
    }
    #else
    void LcdInit() //LCD初始化子程序
    {
    LcdWriteCom(0x32); //将8位总线转为4位总线
    LcdWriteCom(0x28); //在四位线下的初始化
    LcdWriteCom(0x0c); //开显示不显示光标
    LcdWriteCom(0x06); //写一个指针加1
    LcdWriteCom(0x01); //清屏
    LcdWriteCom(0x80); //设置数据指针起点
    }
    #endif

以下是“lcd.h”
#ifndef _LCD_H
#define _LCD_H
/**********************************
当使用的是4位数据传输的时候定义,
使用8位取消这个定义
**********************************/
//#define LCD1602_4PINS

/**********************************
包含头文件
**********************************/
#include

//—重定义关键词—//
#ifndef uchar
#define uchar unsigned char
#endif

#ifndef uint
#define uint unsigned int
#endif

/**********************************
PIN口定义
**********************************/
#define LCD1602_DATAPINS P2
sbit LCD1602_E=P0^7;
sbit LCD1602_RW=P0^6;
sbit LCD1602_RS=P0^5;

/**********************************
函数声明
**********************************/
/在51单片机12MHZ时钟下的延时函数/
void Lcd1602_Delay1ms(uint c); //误差 0us
/LCD1602写入8位命令子函数/
void LcdWriteCom(uchar com);
/LCD1602写入8位数据子函数/
void LcdWriteData(uchar dat) ;
/LCD1602初始化子程序/
void LcdInit();

#endif

原理图奉上:
基于51单片机的4路抢答器_第1张图片
如果此单片机仿真有问题请修改
void timer1() interrupt 3中的if(i1000)改为i15左右的数值。
至于为什么小编能力有限,无法解决

文件下载地址:https://download.csdn.net/download/thibaul/11175630

你可能感兴趣的:(基于51单片机的4路抢答器)