找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2|回复: 0
打印 上一主题 下一主题
收起左侧

基于单片机的八路抢答器程序

[复制链接]
跳转到指定楼层
楼主
ID:1172609 发表于 2026-6-4 14:16 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本程序是一个基于51单片机(STC89C52/AT89S52)的八路抢答器系统。系统支持6名参赛选手(编号1~6)、1个主持人控制端(开始键)和1个设置键,具备抢答计时、选手编号显示、声光提示等完整功能。

核心功能
功能描述
主持人控制按下"开始"键(KEY7)启动一轮抢答
6路抢答选手16号按键(KEY1KEY6),先按先得
倒计时显示4位数码管显示剩余时间和选手编号
声光报警蜂鸣器提示音 + LED状态指示
抢答锁定一旦有选手抢答,锁定其他选手按键
回答计时抢答成功后给予20秒回答时间

引脚详细说明P2口 — 输出控制口
引脚符号方向有效电平功能描述
P2.0BEEP输出高电平蜂鸣器驱动,发声提示
P2.1LED3输出低电平LED指示灯3
P2.2LED2输出低电平LED指示灯2
P2.3LED1输出低电平LED指示灯1(超时报警)
P2.4DIG1输出低电平第1位数码管位选
P2.5DIG2输出低电平第2位数码管位选
P2.6DIG3输出低电平第3位数码管位选
P2.7DIG4输出低电平第4位数码管位选

P0口 — 数码管段选
引脚符号功能
P0.0~P0.7duanPore共阴数码管段选(a,b,c,d,e,f,g,dp),高电平有效
P1口 — 选手按键输入
引脚符号功能
P1.0KEY11号选手抢答键
P1.1KEY22号选手抢答键
P1.2KEY33号选手抢答键
P1.3KEY44号选手抢答键
P1.4KEY55号选手抢答键
P1.5KEY66号选手抢答键

P3口 — 控制按键
引脚符号功能
P3.2KEY7主持人"开始"键
P3.3KEY8设置键(预留,代码中未使用)
关键技术参数汇总
参数数值
系统时钟12 MHz(假设)
机器周期1 μs
定时器0中断周期10 ms
1秒计数阈值100次 × 10ms
抢答倒计时5 秒
回答倒计时20 秒
按键消抖延时10 ms
数码管扫描间隔5 ms(每位)
数码管刷新率≈ 50 Hz(每秒25轮完整扫描)
蜂鸣器提示时长300 ms

单片机源程序如下:
  1. #include <reg52.h>

  2. //------------------------- 引脚定义 --------------------------//
  3. sbit BEEP = P2^0;        //蜂鸣器控制引脚,高电平有效

  4. sbit LED1 = P2^3;        //LED1,控制引脚,低电平有效
  5. sbit LED2 = P2^2;        //LED2,控制引脚,低电平有效
  6. sbit LED3 = P2^1;        //LED3,控制引脚,低电平有效

  7. //数码管引脚定义
  8. #define duanPore        P0                //数码管段控制端口,高电平有效
  9. sbit DIG1 = P2^4;                        //数码管第1位位选控制端口,低电平有效
  10. sbit DIG2 = P2^5;                        //数码管第2位位选控制端口,低电平有效
  11. sbit DIG3 = P2^6;                        //数码管第3位位选控制端口,低电平有效
  12. sbit DIG4 = P2^7;                        //数码管第4位位选控制端口,低电平有效

  13. //按键引脚定义
  14. sbit KEY1 = P1^0;                //1号选手
  15. sbit KEY2 = P1^1;                //2号选手
  16. sbit KEY3 = P1^2;                //3号选手
  17. sbit KEY4 = P1^3;                //4号选手
  18. sbit KEY5 = P1^4;                //5号选手
  19. sbit KEY6 = P1^5;                //6号选手
  20. sbit KEY7 = P3^2;                //主持人键
  21. sbit KEY8 = P3^3;                //设置键



  22. //---------------------- 全局变量定义 --------------------//

  23. //数码管段码表,适用于共阴数码管
  24. unsigned char code tab_duan[18] =
  25. {
  26.         0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,        //0~9
  27.         0x77,0x7c,0x39,0x5e,0x79,0x71,                //A~F
  28.         0x40,0x00                                                        //'-',关闭显示
  29. };
  30. unsigned char dat_buf[4] = {17, 17, 0, 5};        //显示数据缓存区,默认上电显示"  05"
  31. int time = 5;                                //倒计时时间
  32. unsigned char i = 0;
  33. unsigned int count = 0;                //计数缓存变量
  34. bit flag_lock = 1;                         //键盘锁定标志,1:不锁定,0:锁定




  35. //------------------------------- 函数声明 ------------------------------------//
  36. void DelayMs(unsigned int ms);                //延时函数,单位:ms
  37. void dig_scan(unsigned char *dat);
  38. unsigned char KeyScan(void);                //独立按键扫描
  39. void InitTimer0(void);                                //定时器0初始化
  40. void alarm(void);                //报警函数
  41. void AnswerTask(void);        //抢答任务




  42. /* 主函数 */
  43. void main(void)
  44. {
  45.         BEEP = 0;                        //上电默认关闭蜂鸣器
  46.         LED1 = 1;
  47.         InitTimer0();                //定时器0初始化        

  48.         while(1)
  49.         {
  50.                 if(KeyScan() == 7)        //如果主持人键按下,则进行抢答
  51.                 {
  52.                         alarm();                //蜂鸣器响一声
  53.                         AnswerTask();        //进行抢答任务
  54.                 }

  55.                 dig_scan(dat_buf);        //测试数码管显示        
  56.         }
  57. }

  58. /* 延时函数,单位:ms */
  59. void DelayMs(unsigned int ms)
  60. {
  61.         unsigned char a,b,c;

  62.         while(--ms)
  63.         {
  64.             for(c=1;c>0;c--)
  65.                 for(b=142;b>0;b--)
  66.                     for(a=2;a>0;a--);        
  67.         }
  68. }

  69. /* 数码管显示扫描 */
  70. void dig_scan(unsigned char *dat)
  71. {
  72.         /* 动态扫描处理 */
  73.         switch(i)
  74.         {
  75.                 case 0:
  76.                 {
  77.                         duanPore = tab_duan[dat[0]];        //显示第1位数码管内容        
  78.                         DIG1 = 0;
  79.                         break;
  80.                 }
  81.                 case 1:
  82.                 {
  83.                         duanPore = tab_duan[dat[1]];        //显示第2位数码管内容        
  84.                         DIG2 = 0;                                                //选通第2位数码管
  85.                         break;
  86.                 }
  87.                 case 2:
  88.                 {
  89.                         duanPore = tab_duan[dat[2]];        //显示第3位数码管内容        
  90.                         DIG3 = 0;                                                //选通第3位数码管
  91.                         break;
  92.                 }
  93.                 case 3:
  94.                 {
  95.                         duanPore = tab_duan[dat[3]];        //显示第4位数码管内容        
  96.                         DIG4 = 0;                                                //选通第4位数码管
  97.                         break;
  98.                 }
  99.                 default: break;        
  100.         }
  101.         DelayMs(5);                //扫描延时10ms,根据实际情况适当修改改延时时间
  102.         DIG1 = 1;                        //消隐
  103.         DIG2 = 1;
  104.         DIG3 = 1;
  105.         DIG4 = 1;
  106.         ++i;                                //扫描变量循环
  107.         if(i > 3)
  108.                 i = 0;        
  109. }

  110. /* 独立按键扫描 */
  111. unsigned char KeyScan(void)
  112. {
  113.         if(KEY1 == 0)                //如果按键1按下
  114.         {
  115.                 DelayMs(10);        //延时10ms去除按键抖动        
  116.                 if(KEY1 == 0)        //再确认一次按键按下,表示到这按键已经稳定了
  117.                         return 1;        //输出按键值1
  118.         }
  119.         if(KEY2 == 0)                //如果按键2按下
  120.         {
  121.                 DelayMs(10);        //延时10ms去除按键抖动        
  122.                 if(KEY2 == 0)        //再确认一次按键按下,表示到这按键已经稳定了
  123.                         return 2;        //输出按键值2
  124.         }
  125.         if(KEY3 == 0)                //如果按键3按下
  126.         {
  127.                 DelayMs(10);        //延时10ms去除按键抖动        
  128.                 if(KEY3 == 0)        //再确认一次按键按下,表示到这按键已经稳定了
  129.                         return 3;        //输出按键值3
  130.         }
  131.         if(KEY4 == 0)                //如果按键4按下
  132.         {
  133.                 DelayMs(10);        //延时10ms去除按键抖动        
  134.                 if(KEY4 == 0)        //再确认一次按键按下,表示到这按键已经稳定了
  135.                         return 4;        //输出按键值4
  136.         }
  137.         if(KEY5 == 0)                //如果按键5按下
  138.         {
  139.                 DelayMs(10);        //延时10ms去除按键抖动        
  140.                 if(KEY5 == 0)        //再确认一次按键按下,表示到这按键已经稳定了
  141.                         return 5;        //输出按键值5
  142.         }
  143.         if(KEY6 == 0)                //如果按键6按下
  144.         {
  145.                 DelayMs(10);        //延时10ms去除按键抖动        
  146.                 if(KEY6 == 0)        //再确认一次按键按下,表示到这按键已经稳定了
  147.                         return 6;        //输出按键值6
  148.         }
  149.         if(KEY7 == 0)                //如果按键7按下
  150.         {
  151.                 DelayMs(10);        //延时10ms去除按键抖动        
  152.                 if(KEY7 == 0)        //再确认一次按键按下,表示到这按键已经稳定了
  153.                         return 7;        //输出按键值7
  154.         }
  155.         if(KEY8 == 0)                //如果按键8按下
  156.         {
  157.                 DelayMs(10);        //延时10ms去除按键抖动        
  158.                 if(KEY8 == 0)        //再确认一次按键按下,表示到这按键已经稳定了
  159.                         return 8;        //输出按键值8
  160.         }
  161.         
  162.         return 0;                        //无按键按下输出0
  163. }

  164. /* 定时器0初始化 */
  165. void InitTimer0(void)
  166. {
  167.     TMOD = 0x01;        //配置定时器0为工作模式1,16位定时器
  168.     TH0 = (65536 - 10000) / 256;        //定时10ms
  169.     TL0 = (65536 - 10000) % 256;
  170.     EA = 1;                        //打开总中断
  171.     ET0 = 1;                //打开定时器0中断
  172.     TR0 = 0;                //上电默认关闭定时器0
  173. }
  174. /* 定时器0中断服务函数,10ms进一次中断 */
  175. void Timer0Interrupt(void) interrupt 1
  176. {
  177.     TH0 = (65536 - 10000) / 256;        //定时10ms,重新装载计数值
  178.     TL0 = (65536 - 10000) % 256;
  179.            
  180.         ++count;
  181.         if(count > 100)                                 //1s时间计算:10ms * 100 = 1s
  182.         {
  183.                 count = 0;                                        //计数值清零
  184.                 --time;                                                //倒计时时间减一次
  185.                 if(time <= 0)                                //如果倒计时结束,则关闭定时器0,停止倒计时,并声光报警和锁定键盘
  186.                 {
  187.                         TR0 = 0;                                //关闭定时器0
  188.                         BEEP = 1;                                //声光报警
  189.                         LED1 = 0;
  190.                         flag_lock = 0;                        //锁定键盘                                
  191.                 }                                
  192.         }
  193. }
  194. /* 报警函数 */
  195. void alarm(void)
  196. {
  197.         BEEP = 1;                //蜂鸣器响一下
  198.         DelayMs(300);        //延时300ms
  199.         BEEP = 0;
  200. }
  201. /* 实现抢答任务 */
  202. void AnswerTask(void)
  203. {
  204.         unsigned char key_val;                //按键值缓存

  205.         time = 5;                                        //倒计时5s
  206.         TR0 = 1;                                        //启动定时器0,开始倒计时
  207.         while(1)
  208.         {
  209.                 if(flag_lock == 1)
  210.                 {
  211.                         key_val = KeyScan();                //获取按键值
  212.                         switch(key_val)
  213.                         {
  214.                                 case 1:
  215.                                 {
  216.                                         dat_buf[0] = key_val;        //第1位数码管显示1号
  217.                                         dat_buf[1] = 16;                //显示'-'
  218.                                         time = 20;                                //倒计时20s,选手回答时间
  219.                                         alarm();                                //蜂鸣器响一下
  220.                                         flag_lock = 0;                        //锁定键盘
  221.                                         break;
  222.                                 }
  223.                                 case 2:
  224.                                 {
  225.                                         dat_buf[0] = key_val;        //第2位数码管显示2号
  226.                                         dat_buf[1] = 16;                //显示'-'
  227.                                         time = 20;                                //倒计时20s,选手回答时间
  228.                                         alarm();                                //蜂鸣器响一下
  229.                                         flag_lock = 0;
  230.                                         break;
  231.                                 }
  232.                                 case 3:
  233.                                 {
  234.                                         dat_buf[0] = key_val;        //第3位数码管显示3号
  235.                                         dat_buf[1] = 16;                //显示'-'
  236.                                         time = 20;
  237.                                         alarm();                                //蜂鸣器响一下
  238.                                         flag_lock = 0;
  239.                                         break;
  240.                                 }
  241.                                 case 4:
  242.                                 {
  243.                                         dat_buf[0] = key_val;        //第4位数码管显示4号
  244.                                         dat_buf[1] = 16;                //显示'-'
  245.                                         time = 20;
  246.                                         alarm();                                //蜂鸣器响一下
  247.                                         flag_lock = 0;
  248.                                         break;
  249.                                 }
  250.                                 case 5:
  251.                                 {
  252.                                         dat_buf[0] = key_val;        //第5位数码管显示5号
  253.                                         dat_buf[1] = 16;                //显示'-'
  254.                                         time = 20;
  255.                                         alarm();                                //蜂鸣器响一下
  256.                                         flag_lock = 0;
  257.                                         break;
  258.                                 }
  259.                                 case 6:
  260.                                 {
  261.                                         dat_buf[0] = key_val;        //第6位数码管显示6号
  262.                                         dat_buf[1] = 16;                //显示'-'
  263.                                         time = 20;
  264.                                         alarm();                                //蜂鸣器响一下
  265.                                         flag_lock = 0;
  266.                                         break;
  267.                                 }
  268.                                 default: break;
  269.                         }
  270.                 }
  271.                   
  272.                 dat_buf[2] = time / 10;                //取出倒计时的十位数
  273.                 dat_buf[3] = time % 10;                //取出倒计时的个位数
  274.                 dig_scan(dat_buf);                        //数码管显示内容
  275.         }
  276. }
复制代码

keil代码: 1.【单片机实训】抢答器程序设计(已完成基本要求).zip (49.03 KB, 下载次数: 0)
电路原理图:无
仿真:无

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表