|
本程序是一个基于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)
电路原理图:无
仿真:无
|