### 第3课 台灯

#### 3.1 项目介绍

常见的台灯，用到了LED灯和按键。通过按按键来控制灯的开与关。

按键按下，我们的单片机读取到低电平，松开读取到高电平。在这一实验课程中，我们利用按键和黄色LED做一个扩展，当按键按下时即读取到低电平时点亮黄色LED灯，松开按键时即读取到高电平时熄灭黄色LED灯，这样就可以通过一个模块控制另一个模块了。

#### 3.2 模块相关资料

![](media/button-schematic-diagram.png)

附原理图，按键有四个引脚，其中1和3是相连的，2和4是相连的，在我们未按下按键时，13与24是断开的，信号端S读取的是被4.7K的上拉电阻R1所拉高的高电平，而当我们按下按键时，13和24连通。信号端S连接到了GND，此时读取到的电平为低电平，即按下按键，传感器信号端为低电平；松开按键时，信号端为高电平。

#### 3.3 实验组件

|![](media/esp32.png)|![](media/yellow-led2.png)|![](media/button.png)|![](media/3p.png)|![](media/usb.png)|
|-|-|-|-|-|
|ESP32 Plus主板 *1|黄色LED模块 *1|按键 *1|3P线 *2|USB线 *1|

#### 3.4 模块接线图

木板房子⑦处(左侧)按键1和黄色LED的控制引脚：

|木板房子⑦处(左侧)按键1（S引脚）|io4|
|-|-|
|黄色LED灯（S引脚）|io12|

⚠️ **特别注意：智能家居已经组装好了，这里不需要把按键模块和LED模块拆下来又重新组装和接线，这里再次提供接线图，是为了方便您编写代码！**

![](media/pjt3.png)


#### 3.5 读取按钮值的实验代码1

读取木板房子⑦处(左侧)按键的状态值，在串口监视器中显示出来，这样就可以直观的看到按键的状态值，即可得到0或1两种状态值。

```c
/*  
 * 项目: button
 * 描述: 读取按键的高低电平
 * 编译IDE：ARDUINO IDE
 * 作者: http//www.keyes-robot.com
*/
#define btn1 4

void setup() {
  Serial.begin(9600);
  pinMode(btn1, INPUT);
}

void loop() {
  boolean btn1_val = digitalRead(btn1);
  Serial.print("button1 = ");
  Serial.println(btn1_val);
  delay(100);
}
```

#### 3.6 实验结果1

按照接线图接好线，外接电源，选择好正确的开发板板型（ESP32 Dev Module）和 适当的串口端口（COMxx），然后单击按钮![](media/cou0.png)上传示例代码至ESP32主控板。示例代码上传成功后，上电后，点击打开arduino IDE的串口监视器，设置波特率为9600，如下图操作。

![](media/ide4.png)

再按下木板房子⑦处(左侧)按键1就可以看到按键状态值的改变，如下图。

![](media/button-value.png)

#### 3.7 代码流程图

![](media/project03.png)

#### 3.8 台灯的实验代码2 

计算木板房子⑦处(左侧)按键1被点击的次数，然后再对计算的次数进行对2求余数，可以看到打印的数字。

```c
/*  
 * 项目: button_led
 * 描述: 按键控制LED
 * 编译IDE：ARDUINO IDE
 * 作者: http//www.keyes-robot.com
*/
#define btn1 4
#define led_y 12
int btn_count = 0; // 按键计数器

void setup() 
{
  Serial.begin(9600);
  pinMode(btn1, INPUT);
  pinMode(led_y, OUTPUT);
}

void loop() 
{
  boolean btn1_val = digitalRead(btn1);
  if(btn1_val == 0) // 按下按钮
  {
    delay(10);  // 脱扣延迟10ms
    if(btn1_val == 0) // 确认按钮仍按下
    {
      boolean btn_state = 1;
      while(btn_state == 1) // 循环直到松开按钮
      {
        boolean btn_val = digitalRead(btn1);
        if(btn_val == 1)  // 松开按钮
        {
          btn_count++;    // 增量压计数器
          Serial.println(btn_count);
          btn_state = 0;  // 退出循环
        }
      }
    }
    boolean value = btn_count % 2; // 模运算（0或1）
    if(value == 1)
    {
      digitalWrite(led_y, HIGH); // 打开LED
    }
    else
    {
      digitalWrite(led_y, LOW); // 关闭LED
    }
  }
}
```

#### 3.9 实验结果2

按照接线图接好线，外接电源，选择好正确的开发板板型（ESP32 Dev Module）和 适当的串口端口（COMxx），然后单击按钮![](media/cou0.png)上传示例代码至ESP32主控板。示例代码上传成功后，打开串口监视器，设置波特率为9600，打印出木板房子⑦处(左侧)按键1被点击的次数，并且点击一次木板房子⑦处(左侧)按键1，LED灯就亮，再点击一次，LED关闭。

![Img](../../media/image-03.gif)

![](media/button-value2.png)

#### 3.10 代码说明

digitalRead(button):读取按键的数字电平，高HIGH或者低LOW。如果该引脚未连接任何东西，则digitalRead（）可以返回HIGH或LOW（并且可以随机更改）

if..else..语句：当if后面（）的逻辑判断为真时，执行大括号里的代码；否则执行else后面{}里的代码。