文章目录

  • 设计要求
  • 电路原理图
    • 硬件原理
      • 时钟信号(晶振)
      • 矩阵按键与独立按键
  • 代码解析

设计要求

  1. 同时为16支参赛队提供抢答功能,抢答成功后应能通过数码管显示出参赛队号数,同时点亮发光二极管示意抢答成功。
  2. 加入独立开关,可启动10秒倒计时功能,通过数码管显示出倒计时时间(倒计时状态下抢答功能不起作用,反之亦然)。

电路原理图

硬件原理

时钟信号(晶振)


单片机晶振部位电路,详情请参考《51单片机入门——单片机最小系统》,在此项目中我们选择 11.0592 MHz的晶振。

矩阵按键与独立按键


在该项目中矩阵按键用于选手的抢答器,独立按键用于主持人复位重置抢答。

代码解析

矩阵按键部分代码:
keyboard.c

#include "KEYBOARD.H"uchar keySta[4][4] = {//矩阵按键的当前状态 1为高电平 ,0为低电平{1 , 1 , 1 , 1} , {1 , 1 , 1 , 1} , {1 , 1 , 1 , 1} , {1 , 1 , 1 , 1}
};uchar ledChar[16] = { //共阳极数码管显示字符转换表0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};/* 按键驱动函数,检测按键动作,调度相应动作函数*/
void KeyDriver()
{uchar i , j;static char backup[4][4] = {{1 , 1 , 1 , 1} , {1 , 1 , 1 , 1} , {1 , 1 , 1 , 1} , {1 , 1 , 1 , 1}};for (i = 0 ; i < 4 ; i ++){for (j = 0 ; j < 4 ; j ++){if (keySta[i][j] != backup[i][j]) //检测按键动作{if (backup[i][j] != 0)     //按键按下时执行动作{P0 = ~ledChar[i*4+j];LED1 = 1;}backup[i][j] = keySta[i][j];  //备份按键状态}}}
}/* 按键扫描函数 , 在定时中断中调用,推荐1ms*/
void KeyScan()
{uchar i;static uchar keyout = 0;   // 矩阵按键扫描输出索引static uchar keybuf[4][4] = {  // 矩阵按键扫描缓冲区{0xff , 0xff , 0xff , 0xff} , {0xff , 0xff , 0xff , 0xff} , {0xff , 0xff , 0xff , 0xff} , {0xff , 0xff , 0xff , 0xff} };// 将一行的4个按键值移入缓冲区keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN1;keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN2;keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN3;keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN4; // 消抖后更新按键状态for (i = 0 ; i < 4 ; i ++) //每行4个按键,所以循环4次{if ((keybuf[keyout][i] & 0x0f) == 0x00){  //连续 4 次扫描值为 0,即 4*4ms 内都是按下状态时,可认为按键已稳定的按下keySta[keyout][i] = 0;}else if ((keybuf[keyout][i] & 0x0f) == 0x0f){    //连续 4 次扫描值为 1,即 4*4ms 内都是弹起状态时,可认为按键已稳定的弹起keySta[keyout][i] = 1;}}//执行下一次的扫描输出keyout ++;   //输出索引递增keyout = keyout & 0x03; //索引值加到 4 即归零switch(keyout)   //根据索引,释放当前输出引脚,拉低下次的输出引脚{case 0: KEY_OUT4 = 1; KEY_OUT1 = 0; break;case 1: KEY_OUT1 = 1; KEY_OUT2 = 0; break;case 2: KEY_OUT2 = 1; KEY_OUT3 = 0; break;case 3: KEY_OUT3 = 1; KEY_OUT4 = 0; break;default: break;}
}

keyborad.h

#ifndef _KEY_BOARD_H_
#define _KEY_BOARD_H_#include<reg52.h>typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long ulong;sbit KEY_OUT1 = P2^7;
sbit KEY_OUT2 = P2^6;
sbit KEY_OUT3 = P2^5;
sbit KEY_OUT4 = P2^4;
sbit KEY_IN1 = P2^3;
sbit KEY_IN2 = P2^2;
sbit KEY_IN3 = P2^1;
sbit KEY_IN4 = P2^0;sbit KEY1 = P3^0;
sbit LED1 = P3^1;extern uchar ledChar[16];void KeyDriver();
void KeyScan();#endif

主函数代码:

#include <reg52.h>
#include "KEYBOARD.H"uchar T0RH = 0; // T0 重载值的高字节
uchar T0RL = 0; // T0 重载值的低字节bit a = 0; // 独立按键索引位
bit countdownRunning = 1; // 倒计时运行标志uchar integerPart = 10; //计数void ConFigTimer0(uchar ms);
void KeyControl();
void CountdownDisplay();void main()
{   P0 = ~ledChar[0]; // 初始化数码管ConFigTimer0(2); // 定时2msEA = 1; // 开启总中断while(1){if ((LED1 != 1) && (countdownRunning == 0))KeyDriver();KeyControl();CountdownDisplay();   }
}/* 倒计时复位函数 */
void CountdownReset()
{countdownRunning = 1; //重启integerPart = 10;//初始计数值LED1 = 0;
}/* 倒计数函数 */
void CountdownCount()
{if (countdownRunning){if (integerPart != 0)integerPart --;elsecountdownRunning = 0;      }
}/* 倒计时显示函数 */
void CountdownDisplay()
{if (countdownRunning == 1){LED1 = 0;P0 = ~ledChar[integerPart];}
}/* 复位函数 */
void KeyControl()
{if (KEY1 == 0 && a == 0){a = 1 ;  } if (KEY1 == 1 && a == 1){CountdownReset();a = 0; }
}/* 配置并启动T0 ,11.0592MHz */
void ConFigTimer0(uchar ms)
{ulong tmp ; //临时变量tmp = 11059200 / 12; //定时器计数频率tmp = (tmp * ms) / 1000; //计算所需的计数值tmp = 65536 - tmp; //计算定时器重载值tmp += 2;  //补偿中断响应延时造成的误差    T0RH = (uchar)(tmp >> 8); //定时器重载值拆分为高低字节T0RL = (uchar)tmp;TMOD &= 0xF0; //清零 T0 的控制位  TMOD |= 0x01; //配置 T0 为模式 1TH0 = T0RH; //加载 T0 重载值TL0 = T0RL;ET0 = 1; //使能 T0 中断TR0 = 1; //启动 T0
}/* T0 中断服务函数,用于按键状态的扫描并消抖,倒计时的时间计算 */
void InterruptTimer0() interrupt 1
{uint t;TH0 = T0RH;TL0 = T0RL;KeyScan();t ++;if (t > 500){CountdownCount(); //调用倒计数函数t = 0;}
}

关于这个程序有1点值得提一下:定时器配置函数ConFigTimer0(uchar ms),虽然这样在程序里通过计算得出初值(重载值)增加了些许代码,但它换来的是便利性和编程效率,因为只要你完成这个函数,之后所有需要用定时器定时 x 毫秒的场合,你都可以直接把函数拿过去,用所需要的毫秒数作为实参调用它即可,不需要在用计算器埋头算一通了,是不是很值呢。

51单片机入门——16路抢答器相关推荐

  1. 【单片机系列】基于51单片机的16路抢答器

     1.功能介绍    抢答器是一种应用非常广泛的设备,在各种竞赛.抢答场合中,它能迅速.客观的分辨出最先获得发言权的选手.早期的抢答器只有几个三极管.可控硅.发光管等组成,能通过发光管的指示辨认出选手 ...

  2. 单片机六位抢答器c语言程序,八路电子抢答器(基于51单片机的8路抢答器设计C语言程序)...

    哥,你还有AT89C51单片机8路抢答器的资料吗 哥,你还有AT89C51单片机8路抢答器的资料吗 AT89C51单片机8路抢答器的资料 源程序如下 #include #define uchar un ...

  3. 51单片机的四路抢答器c语言,用51单片机制作4路抢答器

    此抢答器具有限时抢答,超时无效的特点,并可以对主持人未喊开始而提前抢答的犯规情况作出判断. 由于用了单片机,所以电路很简单.懒得写译码程序,也不想做驱动电路.干脆直接用了一片74LS48译码驱动器来驱 ...

  4. 基于51单片机的8路抢答器proteus仿真 汇编语言程序设计

    硬件设计 上一篇讲了基于C语言的抢答器,下边讲一下基于汇编语言的抢答器. 仿真图: 程序设计 OK EQU 20H ;抢答开始标志位RING EQU 22H ;响铃标志位 DATA0 EQU 36H ...

  5. 基于51单片机的8八路抢答器设计

    基于51单片机的8路抢答器 具体功能: (1)主持人进行复位,依次显示8位选手的分数,8位选手分数显示结束后主持人方可按下开始按键: (2)主持人按下抢答开始按键,抢答者才可以开始抢答,数码管抢答倒计 ...

  6. 基于51单片机8位竞赛抢答器_倒计时可调+LED跑马灯

    基于51单片机8位竞赛抢答器_倒计时可调+LED跑马灯仿真设计 (程序+proteus仿真+报告) Proteus仿真版本:proteus 7.8 程序编译器:keil 4/keil 5 编程语言:C ...

  7. 基于51单片机的八路竞赛抢答器设计

    目录 基于51单片机的八路抢答器设计 1.主要功能 2.仿真图 3.测试图 4.程序源码 5.资源获取 基于51单片机的八路抢答器设计 1.主要功能 利用STC89C52单片机及外围接口实现的抢答系统 ...

  8. 单片机设计_8路抢答器(AT89C51)

    想要更多项目私wo!!! 一.电路设计 此电路由AT89C51最小系统.四位数码管.蜂鸣器电路和按键模块组成. 运行原理: 该抢答器电路可同时进行八路优先抢答.按键按下后,蜂鸣器发声,同时数码管 显示 ...

  9. 单片机流星灯_基于51单片机的16路流星灯程序

    本程序仅供学习交流用,不得用于任何商业用途 程序改进思路:可以加入流星下落速度调整,即下文的 staytime 可以用数组替换 参考数组 226,160,130,113,101,92,85,80,75 ...

最新文章

  1. numpy中的ndim、shape、dtype、astype
  2. Python:lambda表达式的两种应用场景
  3. Python3经典100道练习题003
  4. http://mirrors.aliyuncs.com/centos/7/extras/x86_64/repodata/repomd.xml: [Errno 12] Timeout on http:/
  5. iOS 设置不同环境对应不同icon
  6. 遗传所屠强研究组开发Decode-seq方法显著提高差异表达基因分析的准确性
  7. ajax head带参数两次请求
  8. iOS 10.3下解决Fiddler代理抓包ssl证书信任问题
  9. 软件工程概论--课后作业1
  10. 企业微信API全局错误码 enum枚举类
  11. reader java_Java Reader 类
  12. nb信号和4g信号_工业级NB-IoT和4G DTU区别分析
  13. 计算机符串长度的函数,常用字符串长度计算函数
  14. 掌控你的信息流:在自己的VPS上部署RSSHub
  15. 计算机怎么设置加密文件,电脑文件夹怎么设置密码 电脑文件夹加密的3种方法...
  16. “看来少宇这家伙身上有着惊天的秘密啊
  17. php压力比例混合器图片,教你认识各种泡沫比例混合器
  18. origin作图中的图中图(将原图中的某个区域放大)
  19. python中文开发环境_python中文开发环境
  20. 假设检验:如何理解单侧、双侧检验的拒绝域

热门文章

  1. 全网最全fiddler使用教程和fiddler如何抓包(fiddler手机抓包)-笔者亲测
  2. JavaScript在线客服留言代码
  3. 基于matlab的单相pwm逆变电路的仿真研究,基于Matlab的单相双极性spwm逆变电路仿真报告...
  4. 常数多项式、零次多项式和零多项式的差别
  5. 蓝牙协议HFP(Hands-Free Profile)电话免提协议 Connection management 连接管理HFP SLC 的建立跟释放
  6. 技术解读 一维码,二维码,zxing
  7. 17-截图screenshot
  8. QA特辑 | 看了这场直播,我找到了设备指纹“从不说谎”的原因
  9. ProE 应用技巧30则
  10. 推荐:E都市三维地图, 酷!