- /*
- 此程序為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
復制代碼 |