/*
此程序为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(Ks0)
{
TR1=1; //开启倒计时
sjflag=1; //开启犯规判断
while(num!=0) //如果在期间有人抢答,fallflag=1,此程序执行完后,后续程序会判犯规
{
if(numnumf-1)
{
numf=numf-1;
display(0,0); //不能显示num=0时
}
}
sflag=1; //抢答开始
if(sjflag0) //有人犯规
{
sflag=0;
}
sjflag=0; //关闭犯规判断
display(0,0); //显示num=0时
beep=0; //蜂鸣
}
while(!Ks);
}
}
/
复位
/
void restoration()
{
if(Kr0)
{
delay(10);
if(Kr0)
{
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(Ka0)
{
while(!Ka)
{
if(Kc0)
{
delay(10);
if(Kc0)
{
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((sflag1)&(fallflag0)) //无人违规
{
while(jflag0)
{
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(num0) //放在内部保证定时器的准确性
{
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((K20)&(sjflag1))
{
delay(10);
if(K20)
{
fallflag=2;
sjflag=0;
}
while(!K2);
}
if((K30)&(sjflag1))
{
delay(10);
if(K30)
{
fallflag=3;
sjflag=0;
}
while(!K3);
}
if((K40)&(sjflag1))
{
delay(10);
if(K40)
{
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”
/*******************************************************************************
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
/*******************************************************************************
以下是“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
原理图奉上:
如果此单片机仿真有问题请修改
void timer1() interrupt 3中的if(i1000)改为i15左右的数值。
至于为什么小编能力有限,无法解决
文件下载地址:https://download.csdn.net/download/thibaul/11175630