美文网首页我爱编程Arduino与物联网
第四章 抢答器的制作(Arduino边做边学:从点亮Led到物联

第四章 抢答器的制作(Arduino边做边学:从点亮Led到物联

作者: 创客创未来 | 来源:发表于2018-05-25 10:54 被阅读396次

    本系列文章为作者原创,未经作者书面同意,不得转载!

    我们在电视综艺节目里面经常看到多个选手抢答问题(其实我并不常看这种“娱乐奶嘴”节目,我也不建议你们看),一般每个选手前面都有一个抢答器,谁先按下抢答器按键,谁前面的灯就会点亮,然后就可以回答主持人提出的问题。
    如何制作一个抢答器 ?


    我们的第三个项目就是做一个抢答器,抢答器的使用一般是这样的:在主持人和每位选手前面都有一个抢答按钮,同时每位选手前面还有一盏灯,当主持人开始提问时,这时主持人会按一下自己前面的按钮,让系统准备就绪,所有选手面前的灯会闪动几次,表示马上要开始抢答了,然后主持人开始提问,选手在这过程中可以按下按钮抢答问题,第一个按下按钮的选手前面的灯会点亮,之后按下按钮的选手前面的灯不再点亮。

    1 本章您将学到

    在这个项目中,您将学到的:

    • 学会使用按键开关
    • 学习读取数字输入信号
    • 学会Arduino程序设计中的选择结构及其实现

    2 工具和组件

    2.1 工具列表

    本项目不需要额外的工具。

    2.2 元器件列表

    元器件 型号 数量 备注
    主控板 arduino Uno 1
    LED灯 3 红黄绿各一个
    电阻 220欧姆 3
    电阻 10K欧姆 4
    按键开关 3
    面包板 1
    杜邦线 12
    数据线 Uno数据线 1

    2.3 工具和元器件介绍

    2.3.1 按键开关

    按键开关是我们在项目中第一次使用,我们简单介绍一下:

    按键之类的开关有好几种,有两针脚、四针脚、六针脚等,两针脚很单纯,就是按下后两个针脚会接通,四针脚或六针脚的话,实际上要看说明,了解哪些脚位是连通,而哪些是由开关控制。以本次项目使用的的四针脚开关为例,脚位突出的一边在按键按下前彼此不连通,而与对面脚位是连通的,见下面的按键开关示意图:

    按键 02.jpg button01.png

    按键开关工作原理:在按键没有按下时,四针脚开关中的1、2脚连通,3、4脚联通;当按键按下时,所有针脚全部连通,如下图所示:

    button02.png

    我们在购买按键开关时记得同时购买按键和按键帽,按键帽可以直接扣在按键上,有各种不同颜色的按键帽,通过按键帽跟按键的搭配,能够对按键进行区分标识,还有就是看起来也舒服多了(当然裸奔也不影响功能):

    006.jpg

    下图是扣上按键帽后的按键开关的样子:

    005.jpg

    3 电路设计

    3.1 电路图

    根据我们的项目需求,设计电路图如下:


    电路图.png

    为了区分主持人和选手,我们把主持人的按键开关放在了最左边。

    3.2 电路原理

    三盏灯的连接就不多介绍了,上一章中有详细的介绍,这里主要介绍一下按键开关的电路连接。
    为了便于说明按键开关的电路连接,我们去掉了电路中的其它部分,单独只看一个按键开关的电路连接,它是这样的:


    电路图-按键开关.png

    这个电路看起来还是比较简单的,在按键没有按下时,13引脚的输入状态是0(低电平),当按键按下后,由于跟5V高电平引脚连通,13引脚的输入状态变成1(高电平)。

    在上面的电路中,我们使用了一个下拉电阻(10K欧姆),对于这个电阻的作用,可能有些朋友会有些迷惑,其实在有些电路中还有一种与之功能类似的电阻叫做上拉电阻(功能类似,但作用相反),这里我们介绍一下这两种电阻的作用。

    3.2.1 上拉电阻/下拉电阻

    下面是上拉电阻和下拉电阻的定义:

    上拉电阻:用于当输入端无确定电平(开路)时,将输入确定到逻辑1上,否则这个悬空的输入端,可能由于干扰之类的,被拉到逻辑0。

    下拉电阻:用于当输入端无确定电平(开路)时,将输入确定到逻辑0上,否则这个悬空的输入端,可能由于干扰之类的,被拉到逻辑1。

    怎么样,这个定义是不是说得很清晰、很明白了?看了后,你是不是觉得云里雾里的。

    好,别着急,俗话说“一图解千言”,我们还是上几张图来说明问题,图片来源:youtube视频截图。


    上拉电阻 1.png

    不好意思,忘了讲了,图片中的文字是英文的,为了让小朋友能看明白,我还是来翻译一下:
    左边的逻辑电路兄弟(单片机)的输入引脚:嗨,请给我一个确定的“0”,或者“1”的逻辑信号(就是低电平或者高电平信号)。
    但是右边的兄弟:输入引脚接的是一个开关,正处在悬空状态(“断开”的状态),所以右侧兄弟的回答是:“对不起,我可能是逻辑“0”,嗯,可能是悬空的!”

    这样的回答显然不能让左侧的兄弟满意,因为你的回答太犹豫了,太没有确定性了,让人没法相信你。所以,如下图,左侧的兄弟显然很着急:“什么?!在这种情况下,我该怎么办?”

    所以说:找个靠谱的队友有多么重要!

    上拉电阻 2.png

    显然右侧的兄弟已经意识到了这一点,它开始让自己变得靠谱起来,它增加了一个电阻,电阻另一端接在高电平VCC(逻辑1)上。

    好吧,看看这时开关闭合和断开的状态:


    上拉电阻 3.png

    左侧的兄弟这时候可以得到非常明确的信号“0”,或者“1”了,“哇,它再也不是悬空的状态了,谢谢你,电阻兄弟,我的朋友!”

    你现在是不是有点明白了,还没明白?没关系,再看一遍,其实我也是看了几遍才明白的!

    我们来总结一下:

    单片机的管脚输入需要有明确的信号,也就是要么高电平,要么低电平。通常我们认为,你的输入脚如果和VCC相接,那肯定是高电平;和GND相接,那肯定是低电平。然而还有一种状态你可能忽视了,就是管脚悬空的时候。
    管脚悬空的时候,由于电路中的电磁感应,可以在管脚上随机地感应出时高时低的电平,这就使得在单片机看来,你在随机地输入1或0。这显然也不是你所需要了。你所需要的是明确的高或低电平。这时候电阻来帮忙了。
    如果这个电阻的一端连在了VCC上,那这个电阻就是所谓的“上拉电阻”,它可以帮助管脚肯定处于高电平。bingo!问题解决!
    如果这个电阻的一端连在了GND上,那这个电阻就是所谓的“下拉电阻”,它可以帮助管脚肯定处于低电平。bingo!问题解决!上拉电阻和下拉电阻的目的是帮助电路消灭因为感应电压带来的随机高低电平。

    4 程序设计

    我们已经完成了电路部分的设计,下面就要开始进行程序设计了,不过在开始进行主程序编写之前,我们还要做件事情:

    • 要先了解一下Arduino程序设计中的判断结构和相应的控制语句,本项目中需要用到。

    4.1 Arduino程序设计中的判断结构

    程序中的判断结构要求程序设计者指定要由程序评估或测试的一个或多个条件,以及条件为真时要执行的语句(必需的)和条件为假时要执行的语句(可选的)。

    以下是Arduino编程语言中判断结构的一般形式:


    判断结构.png

    Arduino编程语言提供了几种类型的判断语句:

    • if 语句
    • if... else 语句
    • switch 语句

    我们今天主要介绍 if 语句和 if..else 语句:

    4.1.1 if 语句

    if 语句由一个布尔表达式后跟一个或多个语句组成。

    语法:

    Arduino中 if 语句的语法:

    if(boolean_expression)  //括号中为布尔表达式
    {
       // 如果布尔表达式为真将执行的语句
    }
    

    如果布尔表达式为 true,则 if 语句内的代码块(可以是一条语句,也可以是多条语句,如果是多条语句,则必须放在大括号内,作为一个语句块)将被执行。如果布尔表达式为 false,则 if 语句结束后的第一组代码(闭括号后)将被执行。

    if 后面小括号里求值的表达式,需要以下操作符:
    比较运算操作符:

    • x == y(x 等于 y)
    • x != y(x 不等于 y)
    • x < y(x 小于 y)
    • x > y(x 大于 y)
    • x <= y(x 小于等于 y)
    • x >= y(x 大于等于 y)

    警告:
    请注意赋值运算符和比较运算符。

    • 两个“=”表示的是比较运算符运算符,如 if (x == 10),作用是判断x是否和10相等,如果相等,则布尔表达式( x==10 )为真,程序开始执行 if 后面语句块,否则为假,程序跳过 if 后面的语句快。
    • 一个“=”表示的是赋值运算符,如 if (x = 10),作用是将10 赋值给 x,而 该布尔表达式 (x = 10)永远为真,应为在Arduino中,非 0 值永远为真,这时候不管发生什么,程序都将执行 if 后面的语句块,同时 x 也被赋值为 10。显然这都不是我们期待的结果。

    流程图:

    if 流程图.jpg

    示例

    if (x > 120) digitalWrite(LEDpin, HIGH); 
    
    if (x > 120)
    digitalWrite(LEDpin, HIGH); 
    
    if (x > 120){ digitalWrite(LEDpin, HIGH); } 
    
    if (x > 120){ 
      digitalWrite(LEDpin1, HIGH);
      digitalWrite(LEDpin2, HIGH); 
    }                                 
    

    以上所有书写方式都正确,请注意语句必须以英文分号 “;” 结束。

    4.1.2 if...else 语句

    if...else 是比 if 更为高级的判断流程控制语句,它可以进行多次条件判断。比如,检测模拟输入的值,当它小于500时该执行哪些操作,大于或等于500时执行另外的操作。

    语法

    if...else 语句的语法:

    if (boolean_expression)   //括号中为布尔表达式
    {
      // 如果布尔表达式为真将执行的语句
    }
    else
    {
      // 如果布尔表达式为假将执行的语句
    }
    

    流程图

    if else.png

    示例

    if (temperature >= 70) //第一个布尔表达式
    {
      //危险,关闭系统
    }
    else if (temperature >= 60 && temperature < 70) //第二个布尔表达式
    {
      //警告,用户需要注意
    }
    else
    {
      //安全
    }
    

    这段示例代码中,第一个布尔表达式首先对 温度变量 temperature 进行判断,当其大于等于70时,危险,需要关闭系统(代码中并没有给出执行的语句,只作为示意);如果第一个布尔表达式为假,则第二个布尔表达式再对 temperature 进行判断,当其小于70,但大于等于60时,系统会进行告警;如果前两个布尔表达式都为假,则执行最后一个 else 后的语句块。

    4.2 主程序设计

    /*
     *名称:抢答器
     *功能:
     *作者:YXK
     *时间:2018.5.28 
     */
    
    //定义LED灯的引脚
    const int redLed = 12;
    const int yellowLed = 11;
    const int blueLed = 10;
    
    //定义按键开关引脚
    const int redButton = 7; 
    const int yellowButton = 6; 
    const int blueButton = 5;
    const int startButton = 13; 
    
    int r=0,y=0,b=0,s=0;  //定义三个变量存储三个按键开关的状态
    bool ready = false;   //定义一个变量用于记录抢答器是否就绪的状态
    
    void setup() {
      // put your setup code here, to run once:
      // 定义引脚输入输出状态
      pinMode(redLed, OUTPUT);
      pinMode(yellowLed, OUTPUT);
      pinMode(blueLed, OUTPUT);
      pinMode(redButton, INPUT);
      pinMode(yellowButton, INPUT);
      pinMode(blueButton, INPUT);
      pinMode(startButton, INPUT);
    
      //将LED灯的初始化状态设定为熄灭
      digitalWrite(redLed, LOW);
      digitalWrite(yellowLed, LOW);
      digitalWrite(blueLed, LOW);
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
      // 读取四个按键开关的状态
         r = digitalRead(redButton);
         y = digitalRead(yellowButton);
         b = digitalRead(blueButton);
         s = digitalRead(startButton);
    
         if(s==1){  //如果主持人按下开始抢答按钮,选手前面的LED闪烁3次
           for(int i=0;i<3;i++){
            digitalWrite(redLed, HIGH);
            digitalWrite(yellowLed, HIGH);
            digitalWrite(blueLed, HIGH);
            delay(500);
            digitalWrite(redLed, LOW);
            digitalWrite(yellowLed, LOW);
            digitalWrite(blueLed, LOW);
            delay(500);
          }
          ready = true;
         }
    
         //当抢答器处于就绪状态时
         //红色按键按下
         if(ready && r==1){
          digitalWrite(redLed, HIGH);
          ready = false;
          }
    
          //黄色按键按下
         if(ready && y==1){
          digitalWrite(yellowLed, HIGH);
          ready = false;
          }
    
          //蓝色按键按下
          if(ready && b==1){
          digitalWrite(blueLed, HIGH);
          ready = false;
          }       
    }
    

    说明:主程序中有一个 for 循环控制语句,这部分内容后续章节会有介绍,在本项目中,您只需要知道它的功能即可:就是让所有选手前面的灯闪烁三次。

    5 安装调试

    根据电路图,最后做出来的效果是这个样子的:


    最终图.jpg

    左边的白色按钮是主持人用的复位按钮,右边分别时选手面前的灯和按键。

    我们只是用面包板搭建了模拟系统,其实如果时间充裕,可以为每位选手做单独做一个抢答器,每个上面有一个按钮和一个LED灯,具体的设计大家可以发挥想象,那样看起来就更接近真实了。

    比方说,网上有兄弟做出来的效果是这个样子的:


    效果1.png

    电路都是差不多的,只是形式不同,有空的朋友可以多动动手,让自己的电子制作看起来更加实用或者漂亮,呵呵,这也很重要哦!

    6 总结扩展

    这个项目实际上并不复杂,电路设计和主程序代码都还有改进的空间,但为了初学者理解,我们并没有引入相对复杂的设计。

    随着学习的深入,有兴趣的朋友可以对其进行改进,如,简化电路的设计(如:采用内部下拉电阻),或者让程序看起来更加简洁并且适应性更好(如考虑增加选手的情况)。

    另外也可以增加一个显示模块,让主持人可以轻易的看到抢答的结果,当然这个需要我们一步一步的学习后再来考虑改进,呵呵,想法+努力,你就是最棒的!

    如果您喜欢本文,您可以点击一下下面的喜欢按钮,您也可以关注我,谢谢您的支持!

    相关文章

      网友评论

        本文标题:第四章 抢答器的制作(Arduino边做边学:从点亮Led到物联

        本文链接:https://www.haomeiwen.com/subject/asyyjftx.html