标题:
基于51单片机的4人抢答器代码
[打印本页]
作者:
18181974358
时间:
2019-4-30 19:37
标题:
基于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(Ks==0)
{
delay(10);
if(Ks==0)
{
TR1=1; //开启倒计时
sjflag=1; //开启犯规判断
while(num!=0) //如果在期间有人抢答,fallflag=1,此程序执行完后,后续程序会判犯规
{
if(num==numf-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(Kr==0)
{
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(Ka==0)
{
delay(10);
if(Ka==0)
{
while(!Ka)
{
if(Kc==0)
{
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((sflag==0)&(fallflag==0)) //没开始没人抢答
{
timeset();
}
if((sflag==0)&(fallflag!=0)) //有人违规抢答
{
led=0; //亮灯警告
beep=1; //关闭蜂鸣
display(fallflag,0); //显示有人犯规,并显示犯规按钮,根据fallflag
}
if((sflag==1)&(fallflag==0)) //无人违规
{
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(i==1000)
{
i=0;
num--;
//display(0,0); //为什么此时加上这个程序就报warning
if(num==0) //放在内部保证定时器的准确性
{
TR1=0;
}
}
}
//先丢后面的代码
/*
配合定时器0使用
如果k1-4有按键按下,fallflag=1
*/
void search()
{
if((K1==0)&(sjflag==1)) //按下Ks开始后(sjflag=1)如果有人按了K1就会进入程序
{
delay(10);
if(K1==0)
{
fallflag=1;
sjflag=0; //互锁,并配合Ks_Scan()中的犯规判断语句
}
while(!K1);
}
if((K2==0)&(sjflag==1))
{
delay(10);
if(K2==0)
{
fallflag=2;
sjflag=0;
}
while(!K2);
}
if((K3==0)&(sjflag==1))
{
delay(10);
if(K3==0)
{
fallflag=3;
sjflag=0;
}
while(!K3);
}
if((K4==0)&(sjflag==1))
{
delay(10);
if(K4==0)
{
fallflag=4;
sjflag=0;
}
while(!K4);
}
}
void judge()
{
if((K1==0)&(jflag==0))
{
delay(10);
if((K1==0)&(jflag==0))
{
win=1;
jflag=1; //锁住其他按钮
}
while(!K1);
}
if((K2==0)&(jflag==0))
{
delay(10);
if((K2==0)&(jflag==0))
{
win=2;
jflag=1; //锁住其他按钮
}
while(!K2);
}
if((K3==0)&(jflag==0))
{
delay(10);
if((K3==0)&(jflag==0))
{
win=3;
jflag=1; //锁住其他按钮
}
while(!K3);
}
if((K4==0)&(jflag==0))
{
delay(10);
if((K4==0)&(jflag==0))
{
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 <reg52.h>
//---重定义关键词---//
#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
复制代码
作者:
YHY232
时间:
2019-5-6 08:20
感觉不错哦,谢谢大佬分享
作者:
da'da'l'k
时间:
2020-6-20 22:23
写的很详细了,谢谢分享
作者:
静谧零度
时间:
2020-6-21 10:39
有仿真图吗?
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1