- /*
- 此程序为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
复制代码 |