|
本程序是一個基于51單片機(STC89C52/AT89S52)的八路搶答器系統。系統支持6名參賽選手(編號1~6)、1個主持人控制端(開始鍵)和1個設置鍵,具備搶答計時、選手編號顯示、聲光提示等完整功能。
核心功能| 功能 | 描述 | | 主持人控制 | 按下"開始"鍵(KEY7)啟動一輪搶答 | | 6路搶答 | 選手16號按鍵(KEY1KEY6),先按先得 | | 倒計時顯示 | 4位數碼管顯示剩余時間和選手編號 | | 聲光報警 | 蜂鳴器提示音 + LED狀態指示 | | 搶答鎖定 | 一旦有選手搶答,鎖定其他選手按鍵 | | 回答計時 | 搶答成功后給予20秒回答時間
| 引腳詳細說明P2口 — 輸出控制口| 引腳 | 符號 | 方向 | 有效電平 | 功能描述 | | P2.0 | BEEP | 輸出 | 高電平 | 蜂鳴器驅動,發聲提示 | | P2.1 | LED3 | 輸出 | 低電平 | LED指示燈3 | | P2.2 | LED2 | 輸出 | 低電平 | LED指示燈2 | | P2.3 | LED1 | 輸出 | 低電平 | LED指示燈1(超時報警) | | P2.4 | DIG1 | 輸出 | 低電平 | 第1位數碼管位選 | | P2.5 | DIG2 | 輸出 | 低電平 | 第2位數碼管位選 | | P2.6 | DIG3 | 輸出 | 低電平 | 第3位數碼管位選 | | P2.7 | DIG4 | 輸出 | 低電平 | 第4位數碼管位選 |
P0口 — 數碼管段選| 引腳 | 符號 | 功能 | | P0.0~P0.7 | duanPore | 共陰數碼管段選(a,b,c,d,e,f,g,dp),高電平有效 | P1口 — 選手按鍵輸入| 引腳 | 符號 | 功能 | | P1.0 | KEY1 | 1號選手搶答鍵 | | P1.1 | KEY2 | 2號選手搶答鍵 | | P1.2 | KEY3 | 3號選手搶答鍵 | | P1.3 | KEY4 | 4號選手搶答鍵 | | P1.4 | KEY5 | 5號選手搶答鍵 | | P1.5 | KEY6 | 6號選手搶答鍵 |
P3口 — 控制按鍵| 引腳 | 符號 | 功能 | | P3.2 | KEY7 | 主持人"開始"鍵 | | P3.3 | KEY8 | 設置鍵(預留,代碼中未使用)
| 關鍵技術參數匯總| 參數 | 數值 | | 系統時鐘 | 12 MHz(假設) | | 機器周期 | 1 μs | | 定時器0中斷周期 | 10 ms | | 1秒計數閾值 | 100次 × 10ms | | 搶答倒計時 | 5 秒 | | 回答倒計時 | 20 秒 | | 按鍵消抖延時 | 10 ms | | 數碼管掃描間隔 | 5 ms(每位) | | 數碼管刷新率 | ≈ 50 Hz(每秒25輪完整掃描) | | 蜂鳴器提示時長 | 300 ms
|
單片機源程序如下:
- #include <reg52.h>
- //------------------------- 引腳定義 --------------------------//
- sbit BEEP = P2^0; //蜂鳴器控制引腳,高電平有效
- sbit LED1 = P2^3; //LED1,控制引腳,低電平有效
- sbit LED2 = P2^2; //LED2,控制引腳,低電平有效
- sbit LED3 = P2^1; //LED3,控制引腳,低電平有效
- //數碼管引腳定義
- #define duanPore P0 //數碼管段控制端口,高電平有效
- sbit DIG1 = P2^4; //數碼管第1位位選控制端口,低電平有效
- sbit DIG2 = P2^5; //數碼管第2位位選控制端口,低電平有效
- sbit DIG3 = P2^6; //數碼管第3位位選控制端口,低電平有效
- sbit DIG4 = P2^7; //數碼管第4位位選控制端口,低電平有效
- //按鍵引腳定義
- sbit KEY1 = P1^0; //1號選手
- sbit KEY2 = P1^1; //2號選手
- sbit KEY3 = P1^2; //3號選手
- sbit KEY4 = P1^3; //4號選手
- sbit KEY5 = P1^4; //5號選手
- sbit KEY6 = P1^5; //6號選手
- sbit KEY7 = P3^2; //主持人鍵
- sbit KEY8 = P3^3; //設置鍵
- //---------------------- 全局變量定義 --------------------//
- //數碼管段碼表,適用于共陰數碼管
- unsigned char code tab_duan[18] =
- {
- 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f, //0~9
- 0x77,0x7c,0x39,0x5e,0x79,0x71, //A~F
- 0x40,0x00 //'-',關閉顯示
- };
- unsigned char dat_buf[4] = {17, 17, 0, 5}; //顯示數據緩存區,默認上電顯示" 05"
- int time = 5; //倒計時時間
- unsigned char i = 0;
- unsigned int count = 0; //計數緩存變量
- bit flag_lock = 1; //鍵盤鎖定標志,1:不鎖定,0:鎖定
- //------------------------------- 函數聲明 ------------------------------------//
- void DelayMs(unsigned int ms); //延時函數,單位:ms
- void dig_scan(unsigned char *dat);
- unsigned char KeyScan(void); //獨立按鍵掃描
- void InitTimer0(void); //定時器0初始化
- void alarm(void); //報警函數
- void AnswerTask(void); //搶答任務
- /* 主函數 */
- void main(void)
- {
- BEEP = 0; //上電默認關閉蜂鳴器
- LED1 = 1;
- InitTimer0(); //定時器0初始化
- while(1)
- {
- if(KeyScan() == 7) //如果主持人鍵按下,則進行搶答
- {
- alarm(); //蜂鳴器響一聲
- AnswerTask(); //進行搶答任務
- }
- dig_scan(dat_buf); //測試數碼管顯示
- }
- }
- /* 延時函數,單位:ms */
- void DelayMs(unsigned int ms)
- {
- unsigned char a,b,c;
- while(--ms)
- {
- for(c=1;c>0;c--)
- for(b=142;b>0;b--)
- for(a=2;a>0;a--);
- }
- }
- /* 數碼管顯示掃描 */
- void dig_scan(unsigned char *dat)
- {
- /* 動態掃描處理 */
- switch(i)
- {
- case 0:
- {
- duanPore = tab_duan[dat[0]]; //顯示第1位數碼管內容
- DIG1 = 0;
- break;
- }
- case 1:
- {
- duanPore = tab_duan[dat[1]]; //顯示第2位數碼管內容
- DIG2 = 0; //選通第2位數碼管
- break;
- }
- case 2:
- {
- duanPore = tab_duan[dat[2]]; //顯示第3位數碼管內容
- DIG3 = 0; //選通第3位數碼管
- break;
- }
- case 3:
- {
- duanPore = tab_duan[dat[3]]; //顯示第4位數碼管內容
- DIG4 = 0; //選通第4位數碼管
- break;
- }
- default: break;
- }
- DelayMs(5); //掃描延時10ms,根據實際情況適當修改改延時時間
- DIG1 = 1; //消隱
- DIG2 = 1;
- DIG3 = 1;
- DIG4 = 1;
- ++i; //掃描變量循環
- if(i > 3)
- i = 0;
- }
- /* 獨立按鍵掃描 */
- unsigned char KeyScan(void)
- {
- if(KEY1 == 0) //如果按鍵1按下
- {
- DelayMs(10); //延時10ms去除按鍵抖動
- if(KEY1 == 0) //再確認一次按鍵按下,表示到這按鍵已經穩定了
- return 1; //輸出按鍵值1
- }
- if(KEY2 == 0) //如果按鍵2按下
- {
- DelayMs(10); //延時10ms去除按鍵抖動
- if(KEY2 == 0) //再確認一次按鍵按下,表示到這按鍵已經穩定了
- return 2; //輸出按鍵值2
- }
- if(KEY3 == 0) //如果按鍵3按下
- {
- DelayMs(10); //延時10ms去除按鍵抖動
- if(KEY3 == 0) //再確認一次按鍵按下,表示到這按鍵已經穩定了
- return 3; //輸出按鍵值3
- }
- if(KEY4 == 0) //如果按鍵4按下
- {
- DelayMs(10); //延時10ms去除按鍵抖動
- if(KEY4 == 0) //再確認一次按鍵按下,表示到這按鍵已經穩定了
- return 4; //輸出按鍵值4
- }
- if(KEY5 == 0) //如果按鍵5按下
- {
- DelayMs(10); //延時10ms去除按鍵抖動
- if(KEY5 == 0) //再確認一次按鍵按下,表示到這按鍵已經穩定了
- return 5; //輸出按鍵值5
- }
- if(KEY6 == 0) //如果按鍵6按下
- {
- DelayMs(10); //延時10ms去除按鍵抖動
- if(KEY6 == 0) //再確認一次按鍵按下,表示到這按鍵已經穩定了
- return 6; //輸出按鍵值6
- }
- if(KEY7 == 0) //如果按鍵7按下
- {
- DelayMs(10); //延時10ms去除按鍵抖動
- if(KEY7 == 0) //再確認一次按鍵按下,表示到這按鍵已經穩定了
- return 7; //輸出按鍵值7
- }
- if(KEY8 == 0) //如果按鍵8按下
- {
- DelayMs(10); //延時10ms去除按鍵抖動
- if(KEY8 == 0) //再確認一次按鍵按下,表示到這按鍵已經穩定了
- return 8; //輸出按鍵值8
- }
-
- return 0; //無按鍵按下輸出0
- }
- /* 定時器0初始化 */
- void InitTimer0(void)
- {
- TMOD = 0x01; //配置定時器0為工作模式1,16位定時器
- TH0 = (65536 - 10000) / 256; //定時10ms
- TL0 = (65536 - 10000) % 256;
- EA = 1; //打開總中斷
- ET0 = 1; //打開定時器0中斷
- TR0 = 0; //上電默認關閉定時器0
- }
- /* 定時器0中斷服務函數,10ms進一次中斷 */
- void Timer0Interrupt(void) interrupt 1
- {
- TH0 = (65536 - 10000) / 256; //定時10ms,重新裝載計數值
- TL0 = (65536 - 10000) % 256;
-
- ++count;
- if(count > 100) //1s時間計算:10ms * 100 = 1s
- {
- count = 0; //計數值清零
- --time; //倒計時時間減一次
- if(time <= 0) //如果倒計時結束,則關閉定時器0,停止倒計時,并聲光報警和鎖定鍵盤
- {
- TR0 = 0; //關閉定時器0
- BEEP = 1; //聲光報警
- LED1 = 0;
- flag_lock = 0; //鎖定鍵盤
- }
- }
- }
- /* 報警函數 */
- void alarm(void)
- {
- BEEP = 1; //蜂鳴器響一下
- DelayMs(300); //延時300ms
- BEEP = 0;
- }
- /* 實現搶答任務 */
- void AnswerTask(void)
- {
- unsigned char key_val; //按鍵值緩存
- time = 5; //倒計時5s
- TR0 = 1; //啟動定時器0,開始倒計時
- while(1)
- {
- if(flag_lock == 1)
- {
- key_val = KeyScan(); //獲取按鍵值
- switch(key_val)
- {
- case 1:
- {
- dat_buf[0] = key_val; //第1位數碼管顯示1號
- dat_buf[1] = 16; //顯示'-'
- time = 20; //倒計時20s,選手回答時間
- alarm(); //蜂鳴器響一下
- flag_lock = 0; //鎖定鍵盤
- break;
- }
- case 2:
- {
- dat_buf[0] = key_val; //第2位數碼管顯示2號
- dat_buf[1] = 16; //顯示'-'
- time = 20; //倒計時20s,選手回答時間
- alarm(); //蜂鳴器響一下
- flag_lock = 0;
- break;
- }
- case 3:
- {
- dat_buf[0] = key_val; //第3位數碼管顯示3號
- dat_buf[1] = 16; //顯示'-'
- time = 20;
- alarm(); //蜂鳴器響一下
- flag_lock = 0;
- break;
- }
- case 4:
- {
- dat_buf[0] = key_val; //第4位數碼管顯示4號
- dat_buf[1] = 16; //顯示'-'
- time = 20;
- alarm(); //蜂鳴器響一下
- flag_lock = 0;
- break;
- }
- case 5:
- {
- dat_buf[0] = key_val; //第5位數碼管顯示5號
- dat_buf[1] = 16; //顯示'-'
- time = 20;
- alarm(); //蜂鳴器響一下
- flag_lock = 0;
- break;
- }
- case 6:
- {
- dat_buf[0] = key_val; //第6位數碼管顯示6號
- dat_buf[1] = 16; //顯示'-'
- time = 20;
- alarm(); //蜂鳴器響一下
- flag_lock = 0;
- break;
- }
- default: break;
- }
- }
-
- dat_buf[2] = time / 10; //取出倒計時的十位數
- dat_buf[3] = time % 10; //取出倒計時的個位數
- dig_scan(dat_buf); //數碼管顯示內容
- }
- }
復制代碼
keil代碼:
1.【單片機實訓】搶答器程序設計(已完成基本要求).zip
(49.03 KB, 下載次數: 0)
2026-6-4 14:08 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
電路原理圖:無
仿真:無
|