
# Arduino 

当我们拿到Arduino开发板时，首先我们要安装Arduino IDE和驱动，相关文件我们可以在官网上找到，以下链接是包含各种系统、各种版本的Arduino IDE和驱动任你选择。

<https://www.arduino.cc/en/Main/OldSoftwareReleases#1.5.x>

下面我们介绍下Arduino-1.5.6 版本IDE在Windows系统的安装方法。

下载下来的文件是一个arduino-1.5.6-r2-windows.zip的压缩文件夹，解压出来到硬盘。

双击Arduino-1.5.6 .exe文件

![](media/fa71c56663f756e7fb7ec2ad2514a865.png)

然后

![](media/bc56b067fdcc39f37308104166be5bfb.png)

然后

![](media/7765ebba748d098ae1805f048a7f212b.png)

等待安装完成.点击close，安装完成。

![](media/395497018845b1dd50695e66966104fb.png)

1.5.6版本安装后的样子。

![](media/af93a6fc21845eb546398e38e8c70d20.png)

接下来是开发板驱动的安装，这次我们安装的是Keyes UNO R3开发板的驱动，Keyes 2560 R3开发板安装驱动方法和这个类似，驱动文件可以用同一个文件。

不同的系统，安装驱动的方法也有一些细小的区别，下面我们介绍在WIN 7系统安装驱动的方法。

第一次Keyes UNO R3开发板连接电脑时，点击计算机--属性--设备管理器，显示如下图。

![](media/994912547c9fd3db1ded9082e3e9055a.png)

点击 Unknown device 安装驱动，如下图。

![](media/385e7e462164e18617ffb64e2639eef9.png)

进入下图，选择

![](media/4ac540068115dc72ad8b18664da2e968.png)

找到Arduino安装位置的drivers文件夹

![](media/bc3d1f7561d2a4f4ca4ec415bcfad426.png)

点击“Next”，今天下图选择，开始安装驱动

![](media/884877f8017764e0caf124af3d90261b.png)

安装驱动完成，出现下图点击Close。

![](media/e50c6960af08edb0b4833bad2d77e085.png)

这样驱动就装好了。点击计算机--属性--设备管理器，我们可看见如下图。

![](media/43cc43168705bb10bb3154d6cc18999e.png)

## Arduino IDE的使用方法

Keyes UNO R3
开发板的USB驱动安装成功之后，我们可以在Windows设备管理器中找到相应的串口。

下面示范第一个程序的烧写，串口监视器中显示“Hello World！”。

测试代码为：


```
int val;                      // 定义一个整型变量val，用于存储串口读取的值  
int ledpin = 13;              // 定义LED引脚为数字口13  

void setup()                  // 初始化函数  
{  
    Serial.begin(9600);       // 初始化串口通信，波特率9600  
    pinMode(ledpin, OUTPUT);  // 设置LED引脚为输出模式  
}  

void loop()                   // 主循环函数  
{  
    val = Serial.read();      // 读取串口数据并赋值给val  

    if (val == 'R')           // 如果接收到字符'R'  
    {  
        digitalWrite(ledpin, HIGH);  // 点亮LED  
        delay(500);                  // 延时500ms  
        digitalWrite(ledpin, LOW);  // 熄灭LED  
        delay(500);                  // 延时500ms  
        Serial.println("Hello World!");  // 串口打印"Hello World!"  
    }  
}  
```


我们打开Arduino 的软件，编写一段程序让Keyes UNO R3开发板接受到我们发的指令就显示“Hello World！”字符串；我们再借用一下Keyes UNO R3 开发板上的 D13的指示灯，让Keyes UNO R3开发板接受到指令时指示灯闪烁一下，再显示“Hello World！”。

打开Arduino 的软件，设置板，如下。

![](media/43d9c16b238cfa52845c3a1b553cc630.png)

设置COM端口，如下

![](media/025e24eacb26620c8831c8a3571412f6.png)

点击![](media/eb385c638a1aa0b63971a8871b1bb907.png)编译程序，检查程序是否错误；点击![](media/027da150683195e85b2f0dcdd879e0c1.png)上传程序；Keyes UNO R3 开发板设置OK后右下脚显示如下图，和设备管理器中显示一致。

![](media/add2f4f32678fe555861ae1763488afd.png)

上传成功，输入R，点击发送，Keyes UNO R3 开发板上的 D13的指示灯闪烁一次，串口监视器中显示 Hello World! 如下图

![](media/fa8f2de13c41710b9dbbfde0833eca74.png)

那么恭喜你，你的第一个程序已经成功了！！！

## 实验课程

### 实验一 LED 闪烁实验

实验说明

LED 闪烁实验是比较基础的实验之一，上一个“ Hello World！”实验里已经利用到了Arduino 自带的LED，这次我们利用其他I/O口和外接直插LED 灯来完成这个实验。

实验器材

开发板\*1

USB线\*1

LED\*1

220Ω 电阻\*1

面包板\*1

正标线若干

接线图

连接Keyes UNO R3

![](media/624dcc2b2969142b1996316d8d3e1c6e.jpeg)

连接Keyes 2560 R3

![](media/62db77daee892e9d8fea02436fc10625.jpeg)

测试代码

```
int led = 2;                // 定义数字口2为LED控制引脚  

void setup()                // 初始化函数  
{  
    pinMode(led, OUTPUT);   // 设置LED引脚为输出模式  
}  

void loop()                 // 主循环函数  
{  
    digitalWrite(led, HIGH);  // 点亮LED  
    delay(2000);              // 延时2000ms（2秒）  
    digitalWrite(led, LOW);   // 熄灭LED  
    delay(2000);              // 延时2000ms（2秒）  
}  
```

测试结果

下载完程序就可以看到我们的IO口外接小灯在闪烁了，这样我们的实验现象为LED不停闪烁，间隔大约为两秒。

### 实验二 呼吸灯实验

实验说明

上一课程中我们只是控制LED的亮和灭，那么我们可以怎么控制LED的亮度呢？本课程中我们把LED接到PWM口中，然后通过改变PWM数值，调节LED亮度，使LED逐渐变亮，和逐渐变暗，从而达到呼吸灯的效果。

实验器材

开发板\*1

USB线\*1

LED\*1

220Ω 电阻\*1

面包板\*1

正标线若干

接线图

连接Keyes UNO R3

![](media/bcf09fd19775fcb089d265f0da3e8b87.jpeg)

连接Keyes 2560 R3

![](media/817a98a86960c00a0bef5271d5dfdd75.jpeg)

测试代码

```
int ledPin = 3;              // 定义数字口3为LED控制引脚（支持PWM调光）  

void setup()                 // 初始化函数  
{  
    pinMode(ledPin, OUTPUT); // 设置LED引脚为输出模式  
}  

void loop()                  // 主循环函数  
{  
    // LED逐渐变亮（0 → 255）  
    for (int a = 0; a <= 255; a++)  
    {  
        analogWrite(ledPin, a);  // PWM输出亮度值（0最暗，255最亮）  
        delay(10);              // 延时10ms，控制渐变速度  
    }  

    // LED逐渐变暗（255 → 0）  
    for (int a = 255; a >= 0; a--)  
    {  
        analogWrite(ledPin, a);  // PWM输出亮度值  
        delay(10);              // 延时10ms，控制渐变速度  
    }  

    delay(1000);               // 循环间隔1秒  
}  
```

测试结果

下载完程序就可以看到我们的IO口外接小灯显示出呼吸灯的效果，小灯先逐渐变亮，后逐渐变暗，循环交替。

### 实验三 广告灯实验

实验说明

在生活中我们经常会看到一些由各种颜色的led灯组成的广告牌，广告牌上各个位置上癿led灯不断的变话,形成各种效果。本节实验就是利用led灯编程模拟广告灯效果。

实验器材

开发板\*1

USB线\*1

LED\*5

220Ω 电阻\*5

面包板\*1

正标线若干

接线图

连接Keyes UNO R3

![](media/99d924bde4bc07721a23e6bbe0bfeba3.jpeg)

连接Keyes 2560 R3

![](media/38a14526f475e0bdf8c29d6cf82063bf.jpeg)

测试代码

```
int BASE = 2; //第一个 LED 接的 I/O 口

int NUM = 5; //LED 的总数

void setup()
{
    for (int i = BASE; i < BASE + NUM; i ++)
    {
        pinMode(i, OUTPUT); //设定数字I/O口为输出
    }
}

void loop()
{
    for (int i = BASE; i < BASE + NUM; i ++)
    {
        digitalWrite(i, HIGH); //设定数字I/O口输出为"高"，即逐渐开灯
        delay(200); //延迟
    }

    for (int i = BASE; i < BASE + NUM; i ++)
    {
        digitalWrite(i, LOW); //设定数字I/O口输出为"低"，即逐渐关灯
        delay(200); //延迟
    }
}
```

测试结果

下载完程序就可以看到我们的IO口外接小灯先逐渐变亮，然后逐渐变暗，循环交替。

### 实验四 按键控制LED实验

实验说明

I/O 口的意思即为INPUT 接口和OUTPUT接口，到目前为止我们设计的小灯实验都还只是应用到Arduino 的I/O口的输出功能，这个实验我们来尝试一下使用Arduino的I/O口的输入功能即为读取外接设备的输出值，我们用一个按键和一个LED小灯完成一个输入输出结合使用的实验，让大家能简单了解I/O 的作用。

实验器材

开发板 \*1

USB线\*1

LED\*1

轻触按键\*1

220Ω 电阻\*1

10KΩ 电阻\*1

面包板\*1

正标线若干

接线图

连接Keyes UNO R3

![](media/24e0c6835efc64707cff8d092d6e417e.jpeg)

连接Keyes 2560 R3

![](media/94fe40846870703c39c0fbf4b0ccce87.jpeg)

测试代码

```
int ledPin = 11; //定义数字口11  

int inputPin = 3; //定义数字口3  

void setup()  
{  
    pinMode(ledPin, OUTPUT); //将ledPin设置为输出  
    pinMode(inputPin, INPUT); //将inputPin设置为输入  
}  

void loop()  
{  
    int val = digitalRead(inputPin);  
    //设置数字变量val，读取到数字口3的数值，并赋值给 val  

    if (val == LOW) //当val为低电平时，LED变暗  
    {  
        digitalWrite(ledPin, LOW); // LED变暗  
    }  
    else  
    {  
        digitalWrite(ledPin, HIGH); // LED亮起  
    }  
}  
```

测试结果

下载完程序，上电后，当按键按下时小灯亮起，否则小灯不亮。

### 实验五 抢答器实验

实验说明

完成上面的实验以后相信已经有很多朋友可以独立完成这个实验了，我们可以模拟抢答器实验。实验中我们利用4个按键控制3个小灯，一个按键用做复位按键；另外3个按键对应3个小灯，用于抢答。

实验器材

开发板\*1

USB线\*1

keyes 插件RGB模块\*1

轻触按键\*4

10KΩ 电阻\*4

面包板\*1

正标线若干

接线图

连接Keyes UNO R3

![](media/d290eec0bf31feebd56f1d9875b2ad22.jpeg)

连接Keyes 2560 R3

![](media/00d7ef3d185b442c4868a0bafa761453.jpeg)

测试代码

```
int redled = 8;    //红色LED 输出
int yellowled = 7; //黄色LED输出
int greenled = 6;  //绿色LED输出
int redpin = 5;    //红色按键引脚
int yellowpin = 4; //黄色按键引脚
int greenpin = 3;  //绿色按键引脚
int restpin = 2;   //复位按键引脚定义

int red;
int yellow;
int green;

void setup()
{
    pinMode(redled, OUTPUT);
    pinMode(yellowled, OUTPUT);
    pinMode(greenled, OUTPUT);
    pinMode(redpin, INPUT);
    pinMode(yellowpin, INPUT);
    pinMode(greenpin, INPUT);
}

void loop() //按键循环扫描。
{
    red = digitalRead(redpin);
    yellow = digitalRead(yellowpin);
    green = digitalRead(greenpin);

    if(red == LOW)
        RED_YES();
    if(yellow == LOW)
        YELLOW_YES();
    if(green == LOW)
        GREEN_YES();
}

void RED_YES() //一直执行红灯亮，直到复位键按下，结束循环
{
    while(digitalRead(restpin) == 1)
    {
        digitalWrite(redled, HIGH);
        digitalWrite(greenled, LOW);
        digitalWrite(yellowled, LOW);
    }
    clear_led();
}

void YELLOW_YES() //一直执行黄灯亮，直到复位键按下，结束循环
{
    while(digitalRead(restpin) == 1)
    {
        digitalWrite(redled, LOW);
        digitalWrite(greenled, LOW);
        digitalWrite(yellowled, HIGH);
    }
    clear_led();
}

void GREEN_YES() //一直执行绿灯亮，直到复位键按下，结束循环
{
    while(digitalRead(restpin) == 1)
    {
        digitalWrite(redled, LOW);
        digitalWrite(greenled, HIGH);
        digitalWrite(yellowled, LOW);
    }
    clear_led();
}

void clear_led() //清除LED
{
    digitalWrite(redled, LOW);
    digitalWrite(greenled, LOW);
    digitalWrite(yellowled, LOW);
}
```

测试结果

下载完程序，上电后，一个简单的抢答器就做好了。

### 实验六 电位器调控灯光亮度实验

实验说明

在第二课程中我们直接通过PWM口控制灯的亮度，从而达到呼吸灯的效果。在这课程中我们通过一个电位器，利用电位器调节PWM值，从而控制灯的亮度。

实验器材

开发板\*1

USB线\*1

LED\*1

220Ω 电阻\*1

可调电位器\*1

面包板\*1

正标线若干

接线图

连接Keyes UNO R3

![](media/64d9aff067dd321147ff853657a16806.jpeg)

连接Keyes 2560 R3

![](media/425382a4cb985b88e699413bbce8e65a.jpeg)

测试代码

```
int ledpin = 11; //定义数字接口11（PWM 输出）

void setup()
{
    pinMode(ledpin, OUTPUT); //定义数字接口11 为输出
    Serial.begin(9600); //设置波特率为9600
}

void loop()
{
    int val = analogRead(0); //读取模拟口A0口的值
    val = map(val, 0, 1023, 0, 255); //从0-1023映射到0-255
    Serial.println(val); //显示val 变量
    analogWrite(ledpin, val); // 打开LED 并设置亮度
    delay(100); //延时0.1 秒
}
```

测试结果

下载完程序后。我们可以通过旋转可调电位器控制小灯的亮度，打开串口监视器，设置波特率为9600，就可看到调节LED亮度的PWM值。

### 实验七 感光灯实验

实验说明

完成以上的各种实验后，我们对Arduino的应用也应该有一些认识和了解了，在基本的数字量输入输出和模拟量输入以及PWM的产生都掌握以后，我们就可以开始进行一些传感器的应用了。

本次实验我们先进行一个较为简单的光敏电阻的使用实验。光敏电阻既然是可以根据光强改变阻值的元件，自然也需要模拟口读取模拟值了，本实验可以借鉴电位器调控灯光亮度实验，将电位计换做光敏电阻实现当光强不同时LED小灯的亮度也会有相应的变化。

实验器材

开发板\*1

USB线\*1

LED\*

220Ω 电阻\*1

10KΩ 电阻\*1

光敏电阻\*1

面包板\*1

正标线若干

接线图

连接Keyes UNO R3

![](media/0a23d778060815ad2a49255d509e125e.jpeg)

连接Keyes 2560 R3

![](media/7bf5ddf21e26908abb79a3443ecfed62.jpeg)

测试代码

```
int ledpin = 11; //定义数字接口11（PWM 输出）

void setup()
{
    pinMode(ledpin, OUTPUT); //定义数字接口11 为输出
    Serial.begin(9600); //设置波特率为9600
}

void loop()
{
    int val = analogRead(0); //读取模拟口A0口的值
    Serial.println(val); //显示val 变量
    val = map(val, 0, 1023, 0, 255); //从0-1023映射到0-255
    analogWrite(ledpin, 255 - val); // 打开LED 并设置亮度
    delay(10); //延时0.01 秒
}
```

测试结果

下载完程序后，光敏电阻感应到灯光越亮，小灯越暗；光敏电阻感应到灯光越暗，小灯越亮。打开串口监视器，设置波特率为9600，就可看到光敏电阻感应到外界光强所得的模拟值。

### 实验八 有源蜂鸣器实验

实验说明

蜂鸣器可分为有源蜂鸣器和无源蜂鸣器两种。本课程中主要用到了有源蜂鸣器，有源蜂鸣器内部有一简单的振荡电路，能将恒定的直流电转化成一定频率的脉冲信号。实验中中我们只需要给蜂鸣器输入一个高电平信号，蜂鸣器响起。

实验器材

开发板\*1

USB线\*1

有源蜂鸣器\*1

面包板\*1

正标线若干

接线图

连接Keyes UNO R3

![](media/b9c82991ba660244213212640071fe35.jpeg)

连接Keyes 2560 R3

![](media/c9b654f6b5b473d52af6a8410bf0a736.jpeg)

测试代码

```
int buzzer = 2; //定义数字口2

void setup()
{
    pinMode(buzzer, OUTPUT); //设置buzzer为输出
}

void loop()
{
    digitalWrite(buzzer, HIGH); //开启buzzer
    delay(1000); //延迟1S
    digitalWrite(buzzer, LOW); //关闭buzzer
    delay(1000); //延迟1S
}
```

测试结果

下载完程序后，我们可以听到蜂鸣器响1秒，停止响起1秒，循环交替。

### 实验九 无源蜂鸣器实验

实验说明

蜂鸣器可分为有源蜂鸣器和无源蜂鸣器两种。本课程中主要用到了无源蜂鸣器，无源蜂鸣器内部不带振荡源，直流信号无法令其鸣叫，须用方波驱动。

实验器材

开发板 \*1

USB线\*1

无源蜂鸣器\*1

面包板\*1

正标线若干

接线图

连接Keyes UNO R3

![](media/433d781ed9b9e8df18cb7eae170699df.jpeg)

连接Keyes 2560 R3

![](media/ee920cdef474104e679d12da6535dfbc.jpeg)

测试代码

code 1:

```
int buzzer = 3; //定义数字口3

void setup()
{
    pinMode(buzzer, OUTPUT); //将buzzer设置为输出
}

void loop()
{
    unsigned char i, j; //定义变量i，j
    
    while(1)
    {
        for(i = 0; i < 80; i++) // 输出一个频率的声音
       {
            digitalWrite(buzzer, HIGH);
            delay(1); //延迟1ms
            digitalWrite(buzzer, LOW);
            delay(1); //延迟1ms
       }
    
      for(i = 0; i < 100; i++) // 输出另一个频率的声音
      {
            digitalWrite(buzzer, HIGH);
            delay(2); //延迟2ms
            digitalWrite(buzzer, LOW);
            delay(2); //延迟2ms
      }
    }
}
```

code 2:

```
#define D0 -1
#define D1 262
#define D2 293
#define D3 329
#define D4 349
#define D5 392
#define D6 440
#define D7 494
#define M1 523
#define M2 586
#define M3 658
#define M4 697
#define M5 783
#define M6 879
#define M7 987
#define H1 1045
#define H2 1171
#define H3 1316
#define H4 1393
#define H5 1563
#define H6 1755
#define H7 1971
// 列出全部D调的频率

#define WHOLE 1
#define HALF 0.5
#define QUARTER 0.25
#define EIGHTH 0.25
#define SIXTEENTH 0.625
// 列出所有节拍

int tune[] = // 根据简谱列出各频率
{
    M3,M3,M4,M5,
    M5,M4,M3,M2,
    M1,M1,M2,M3,
    M3,M2,M2,
    M3,M3,M4,M5,
    M5,M4,M3,M2,
    M1,M1,M2,M3,
    M2,M1,M1,
    M2,M2,M3,M1,
    M2,M3,M4,M3,M1,
    M2,M3,M4,M3,M2,
    M1,M2,D5,D0,
    M3,M3,M4,M5,
    M5,M4,M3,M4,M2,
    M1,M1,M2,M3,
    M2,M1,M1
};

float durt[] = // 根据简谱列出各节拍
{
    1,1,1,1,
    1,1,1,1,
    1,1,1,1,
    1+0.5,0.5,1+1,
    1,1,1,1,
    1,1,1,1,
    1,1,1,1,
    1+0.5,0.5,1+1,
    1,1,1,1,
    1,0.5,0.5,1,1,
    1,0.5,0.5,1,1,
    1,1,1,1,
    1,1,1,1,
    1,1,1,0.5,0.5,
    1,1,1,1,
    1+0.5,0.5,1+1,
};

int length;
int tonepin = 3; // 使用3号接口

void setup()
{
    pinMode(tonepin, OUTPUT);
    length = sizeof(tune) / sizeof(tune[0]); // 计算长度
}

void loop()
{
    for(int x = 0; x < length; x++)
    {
        tone(tonepin, tune[x]);
        delay(500 * durt[x]); // 根据节拍调节延时
        noTone(tonepin);
    }
    delay(2000); // 每遍播放完后暂停2秒
}
```

测试结果

实验中我们提供了两个例程，上传例程1代码后，蜂鸣器会发出两种不同的声音，实验中，两种声音循环交替。上传例程2中代码后，蜂鸣器会想响起《欢乐颂》的曲子。

### 实验十 火焰报警实验

实验说明

火焰传感器是机器人专门用来搜寻火源的传感器，本传感器对火焰特别灵敏。火焰传感器利用红外线对火焰非常敏感的特点，使用特制的红外线接收管来检测火焰，然后把火焰的亮度转化为高低变化的电平信号。

实验中，我们把火焰的亮度转化为高低变化的电平信号输入到UNO板中，然后控制蜂鸣器的响起。

实验器材

开发板\*1

USB线\*1

有源蜂鸣器\*1

火焰传感器\*1

10KΩ 电阻\*1

面包板\*1

正标线若干

接线图

连接Keyes UNO R3

![](media/39bab4acf4f7a981e7e4a6d596318f5b.jpeg)

连接Keyes 2560 R3

![](media/1f10c7f8353ce8c40e3b7d130908b332.jpeg)

测试代码

```
int flame = 7;  // 定义火焰传感器接口为数字7接口
int Beep = 9;   // 定义蜂鸣器接口为数字9接口

void setup()
{
    pinMode(Beep, OUTPUT);  // 定义Beep为输出接口
    pinMode(flame, INPUT);  // 定义flame为输入接口
}

void loop()
{
    int val = digitalRead(flame);  // 读取火焰传感器
    
    if(val == HIGH)  // 当检测到火焰时（数字口7为高电平）
    {
        digitalWrite(Beep, HIGH);  // 蜂鸣器鸣响
    }
    else
    {
        digitalWrite(Beep, LOW);   // 关闭蜂鸣器
    }
    
    delay(500);  // 检测间隔500ms
}
```

测试结果

下载完程序后，我们可以模拟在有火焰时报警的情况，在没有火焰时一切正常，当有火焰时立刻报警做出提示。

### 实验十一 温馨水杯实验

实验说明

LM35 是很常用且易用的温度传感器元件，将LM35温度传感器接到开发板上，通过算法可将读取的模拟值转换为实际的温度。

本实验中我们还外接了3个指示灯，在代码中我没设置在不同的温度范围，亮起不同颜色的指示灯。根据这个，我们完全可以做个温馨水杯，通过指示灯，我们就可以知道杯子里的水的冷热情况。

实验器材

开发板 \*1

USB线\*1

LM35DZ\*1

LED\*3

220Ω 电阻\*3

面包板\*1

正标线若干

接线图

连接Keyes UNO R3

![](media/5cd6a10517ac3f4907ed064b95cb0c7b.jpeg)

连接Keyes 2560 R3

![](media/a22dfcbc6dee7d51c6acd687e76df8e7.jpeg)

测试代码

```
void setup() 
{
    Serial.begin(9600);  // 初始化串口通信，波特率9600
    pinMode(12, OUTPUT); // 设置12号引脚为输出模式
    pinMode(11, OUTPUT); // 设置11号引脚为输出模式
    pinMode(10, OUTPUT); // 设置10号引脚为输出模式
}

void loop() 
{
    int vol = analogRead(A0) * (5.0 / 1023.0*100);  // 读取A0模拟值并转换为温度值
    Serial.print("Tep:");  // 串口打印温度标签（注意原代码拼写为"Tep"）
    Serial.print(vol);     // 输出温度数值
    Serial.println("C");   // 输出温度单位（摄氏度）

    // 温度状态判断
    if (vol<28)  // 当温度低于28度时
    {
        digitalWrite(12, HIGH);  // 开启12号引脚（低温指示灯）
        digitalWrite(11, LOW);   // 关闭11号引脚
        digitalWrite(10, LOW);   // 关闭10号引脚
    }
    else if (vol>=28 && vol<=30)  // 当温度在28-30度之间时
    {
        digitalWrite(12, LOW);    // 关闭12号引脚
        digitalWrite(11, HIGH);   // 开启11号引脚（正常温度指示灯）
        digitalWrite(10, LOW);    // 关闭10号引脚
    }
    else if (vol>30)  // 当温度高于30度时
    {
        digitalWrite(12, LOW);    // 关闭12号引脚
        digitalWrite(11, LOW);    // 关闭11号引脚
        digitalWrite(10, HIGH);   // 开启10号引脚（高温指示灯）
    }
}
```

测试结果

下载完程序后，打开串口监视器，设置波特率为9600，就可看到当前的温度。当温度大于30摄氏度时，红色指示灯亮起，其他指示灯熄灭；当温度大于等于28摄氏度且小于等于30摄氏度时，红色指示灯熄灭，黄色指示灯亮起；当温度小于28摄氏度时，黄色指示灯熄灭，蓝色指示灯亮起。

### 实验十二 魔术光杯实验

实验说明

倾斜开关的工作原理是当开关一端低于水平位置倾斜，开关寻通；当另一端低于水平位置倾斜，开关停止。魔术光杯实验原理是利用 PWM调光的原理，两个LED的亮度发生变化。

这个实验中倾斜开关提供数字信号，触发 PWM的调节，通过程序的设计，我们就能看到类似于两组装满光的杯子倒来倒去的效果了。

实验器材

开发板\*1

USB线\*1

LED\*2

倾斜开关\*2

220Ω 电阻\*2

10KΩ 电阻\*2

面包板\*1

正标线若干

接线图

连接Keyes UNO R3

![](media/fb3ca0c279b9333896ade41f26a36941.jpeg)

连接Keyes 2560 R3

![](media/c3444798cdb4d79bb906264e42565616.jpeg)

测试代码

```
int LedPinA = 5;            // 定义数字口5（PWM输出控制LED）
int LedPinB = 6;            // 定义数字口6（PWM输出控制LED）
int ButtonPinA = 7;         // 定义数字口7（按钮A输入）
int ButtonPinB = 4;         // 定义数字口4（按钮B输入）

int buttonStateA = 0;       // 存储按钮A的状态
int buttonStateB = 0;       // 存储按钮B的状态
int brightnessA = 0;        // LEDA亮度初始值（0-255）
int brightnessB = 255;      // LEDB亮度初始值（0-255）

void setup()                // 初始化函数
{
    Serial.begin(9600);     // 初始化串口通信（波特率9600）
    
    pinMode(LedPinA, OUTPUT);  // 设置数字口5为输出模式
    pinMode(LedPinB, OUTPUT);  // 设置数字口6为输出模式
    pinMode(ButtonPinA, INPUT);  // 设置数字口7为输入模式
    pinMode(ButtonPinB, INPUT);  // 设置数字口4为输入模式
}

void loop()                 // 主循环函数
{
    // 按钮A控制LEDB亮度
    buttonStateA = digitalRead(ButtonPinA);  // 读取按钮A状态
    
    if (buttonStateA == HIGH && brightnessA != 255)  // 按下按钮A且亮度未达最大值
    {
        brightnessA++;       // 亮度增加
        delay(10);          // 延时10ms（防抖+渐变效果）
    }
    
    if (buttonStateA == LOW && brightnessA != 0)     // 松开按钮A且亮度未达最小值
    {
        brightnessA--;       // 亮度减少
        delay(10);          // 延时10ms
    }
    
    analogWrite(LedPinB, brightnessA);  // 输出PWM信号控制LEDB亮度
    Serial.print(brightnessA);          // 串口打印LEDB亮度值
    Serial.print(" ");                  // 打印空格分隔数据

    // 按钮B控制LEDA亮度
    buttonStateB = digitalRead(ButtonPinB);  // 读取按钮B状态
    
    if (buttonStateB == HIGH && brightnessB != 0)    // 按下按钮B且亮度未达最小值
    {
        brightnessB--;       // 亮度减少
        delay(10);          // 延时10ms
    }
    
    if (buttonStateB == LOW && brightnessB != 255)   // 松开按钮B且亮度未达最大值
    {
        brightnessB++;       // 亮度增加
        delay(10);          // 延时10ms
    }
    
    analogWrite(LedPinA, brightnessB);  // 输出PWM信号控制LEDA亮度
    Serial.println(brightnessB);        // 串口打印LEDA亮度值并换行
    
    delay(5);               // 主循环延时5ms（降低CPU占用）
```

测试结果

按照上图接好线，烧录好代码，上电后，将两个倾斜开关同时倾斜一边，一个LED逐渐变暗，同时另一个逐渐变亮，最终一个LED完全熄灭，一个LED最亮；在串口监视器中看到对应具体数值变化，如下图。当倾斜另一边中，现象一样，方向相反。

![](media/6608de7728812e94c0b8c112d09f2879.png)

### 实验十三 红外遥控解码实验

实验说明

通用红外遥控系统由发射和接收两大部分组成。本实验中发射部分就是遥控器，接收部分就是红外接收
VS1838B。红外接收
VS1838B是集接收、放大、解调一体的器件，它内部IC就已经完成了解调，输出的就是数字信号。

![](media/fe1441e8140e067e2d67b03eef452565.png)

实验器材

开发板\*1

USB线\*1

红外遥控\*1

红外接收 VS1838B\*1

面包板\*1

正标线若干

接线图

连接Keyes UNO R3

![](media/2bf4d7d28fca36cda7d5c197378ea920.jpeg)

连接Keyes 2560 R3

![](media/de83e49d53cc09f7c493e3ca1591d836.jpeg)

测试代码

```
#include <IRremote.h>        // 引入红外遥控库

int RECV_PIN = 11;           // 定义红外接收器连接的数字口11
IRrecv irrecv(RECV_PIN);     // 创建红外接收对象
decode_results results;      // 存储解码结果的结构体

void setup()                 // 初始化函数
{
    Serial.begin(9600);      // 初始化串口通信（波特率9600）
    irrecv.enableIRIn();     // 启动红外接收功能
}

void loop()                  // 主循环函数
{
    if (irrecv.decode(&results))  // 检测是否接收到红外信号
    {
        Serial.println(results.value, HEX);  // 以16进制格式输出红外编码
        irrecv.resume();     // 准备接收下一个红外信号
    }
}
```

测试结果

下载完程序，上电后，红外遥控对准红外接收传感器发送信号，我们可以在串口监视器总看到相应按键的编码，如下图。

![](media/6e224d6fbf7a702f322424b19ae3a985.png)

![](media/a958f197b17d1b147340419615e0e40c.png)

### 实验十四 一位数码管显示实验

实验说明

数码管是一种半导体发光器件，其基本单元是发光二极管。数码管按段数分为七段数码管和八段数码管，八段数码管比七段数码管多一个发光二极管单元（多一个小数点显示），本实验所使用的是八段数码管。数码管共有七段显示数字的段，还有一个显示小数点的段。当让数码管显示数字时，只要将相应的段点亮即可。

实验器材

开发板 \*1

USB线\*1

一位数码管\*1

220Ω 电阻\*8

面包板\*1

正标线若干

接线图

连接Keyes UNO R3

![](media/e8ada6e0c1fda411c08c666ca7c9ccd6.jpeg)

连接Keyes 2560 R3

![](media/29ae65fe5c7eda6809ac597efb59d487.jpeg)

测试代码

```
//设置控制各段的数字IO 脚
int a=7;//定义数字接口7 连接a 段数码管
int b=6;// 定义数字接口6 连接b 段数码管
int c=5;// 定义数字接口5 连接c 段数码管
int d=10;// 定义数字接口11 连接d 段数码管
int e=11;// 定义数字接口10 连接e 段数码管
int f=8;// 定义数字接口8 连接f 段数码管
int g=9;// 定义数字接口9 连接g 段数码管
int dp=4;// 定义数字接口4 连接dp 段数码管

void digital_1(void) //显示数字1
{
    unsigned char j;
    digitalWrite(c,HIGH);//给数字接口5 引脚高电平，点亮c 段
    digitalWrite(b,HIGH);//点亮b 段
    for(j=7;j<=11;j++)//熄灭其余段
        digitalWrite(j,LOW);
    digitalWrite(dp,LOW);//熄灭小数点DP 段
}

void digital_2(void) //显示数字2
{
    unsigned char j;
    digitalWrite(b,HIGH);
    digitalWrite(a,HIGH);
    for(j=9;j<=11;j++)
        digitalWrite(j,HIGH);
    digitalWrite(dp,LOW);
    digitalWrite(c,LOW);
    digitalWrite(f,LOW);
}

void digital_3(void) //显示数字3
{
    unsigned char j;
    digitalWrite(g,HIGH);
    digitalWrite(d,HIGH);
    for(j=5;j<=7;j++)
        digitalWrite(j,HIGH);
    digitalWrite(dp,LOW);
    digitalWrite(f,LOW);
    digitalWrite(e,LOW);
}

void digital_4(void) //显示数字4
{
    digitalWrite(c,HIGH);
    digitalWrite(b,HIGH);
    digitalWrite(f,HIGH);
    digitalWrite(g,HIGH);
    digitalWrite(dp,LOW);
    digitalWrite(a,LOW);
    digitalWrite(e,LOW);
    digitalWrite(d,LOW);
}

void digital_5(void) //显示数字5
{
    unsigned char j;
    for(j=7;j<=9;j++)
        digitalWrite(j,HIGH);
    digitalWrite(c,HIGH);
    digitalWrite(d,HIGH);
    digitalWrite(dp,LOW);
    digitalWrite(b,LOW);
    digitalWrite(e,LOW);
}

void digital_6(void) //显示数字6
{
    unsigned char j;
    for(j=7;j<=11;j++)
        digitalWrite(j,HIGH);
    digitalWrite(c,HIGH);
    digitalWrite(dp,LOW);
    digitalWrite(b,LOW);
}

void digital_7(void) //显示数字7
{
    unsigned char j;
    for(j=5;j<=7;j++)
        digitalWrite(j,HIGH);
    digitalWrite(dp,LOW);
    for(j=8;j<=11;j++)
        digitalWrite(j,LOW);
}

void digital_8(void) //显示数字8
{
    unsigned char j;
    for(j=5;j<=11;j++)
        digitalWrite(j,HIGH);
    digitalWrite(dp,LOW);
}

void setup()
{
    int i;//定义变量
    for(i=4;i<=11;i++)
        pinMode(i,OUTPUT);//设置4～11 引脚为输出模式
}

void loop()
{
    while(1)
    {
        digital_1();//显示数字1
        delay(2000);//延时2s
        digital_2();//显示数字2
        delay(1000); //延时1s
        digital_3();//显示数字3
        delay(1000); //延时1s
        digital_4();//显示数字4
        delay(1000); //延时1s
        digital_5();//显示数字5
        delay(1000); //延时1s
        digital_6();//显示数字6
        delay(1000); //延时1s
        digital_7();//显示数字7
        delay(1000); //延时1s
        digital_8();//显示数字8
        delay(1000); //延时1s
    }
}
```

测试结果

下载完程序后，数码管循环显示1～8 数字。

### 实验十五 74HC595驱动一位数码管实验

实验说明

上一个实验中我们直接把用开发板控制一位数码管，需要占用了较多的数字口，本实验中我们添加了一个74HC595芯片控制一位数码管，只需要用3个数字口就可以控制8个LED灯，具体设置方法可以参照以下表格。


||Q7|Q6|Q5|Q4|Q3|Q2|Q1|Q0||
|-|-|-|-|-|-|-|-|-|-|
||a|b|c|d|e|f|g|dp||
|0|1|1|1|1|1|1|0|0|252|
|1|0|1|1|0|0|0|0|0|96|
|2|1|1|0|1|1|0|1|0|218|
|3|1|1|1|1|0|0|1|0|242|
|4|0|1|1|0|0|1|1|0|102|
|5|1|0|1|1|0|1|1|0|182|
|6|1|0|1|1|1|1|1|0|190|
|7|1|1|1|0|0|0|0|0|224|
|8|1|1|1|1|1|1|1|0|254|
|9|1|1|1|1|0|1|1|0|246|

</tbody>
</table>

实验器材

开发板\*1

USB线\*1

74HC595\*1

一位数码管\*1

220Ω 电阻\*8

面包板\*1

正标接线若干

接线图

连接Keyes UNO R3

![](media/af348aa0d2de9a605c00413265e92663.jpeg)

连接Keyes 2560 R3

![](media/da8dce755fb531be7e00100d53f7ac04.jpeg)

测试代码

```
int latchPin = 4;
int clockPin = 5;
int dataPin = 2; //这里定义了那三个脚

void setup ()
{
    pinMode(latchPin,OUTPUT);
    pinMode(clockPin,OUTPUT);
    pinMode(dataPin,OUTPUT); //让三个脚都是输出状态
}

void loop()
{
    int a[10]={
        246,254,224,190,182,102,242,218,96,252}; 
        //定义功能数组，数组依次为数码管得定义
    
    for(int x=9; x>-1 ;x-- ) //倒数功能循环
    {
        digitalWrite(latchPin,LOW);
        shiftOut(dataPin,clockPin,MSBFIRST,a[x]); //显示数组a[x]
        digitalWrite(latchPin,HIGH);
        delay(1000);
    }
}
```

测试结果

下载完程序后，数码管循环显示0～9 数字。

### 实验十六 舵机控制实验

实验说明

舵机是一种位置伺服的驱动器，主要是由外壳、电路板、无核心马达、齿轮与位置检测

器所构成。舵机有很多规格，但所有的舵机都有外接三根线，分别用棕、红、橙三种颜

色进行区分，由于舵机品牌不同，颜色也会有所差异，棕色为接地线，红色为电源正极

线，橙色为信号线。

![](media/4b15604cd8a82aeb39497c7544b39f93.emf)

舵机的转动的角度是通过调节PWM（脉冲宽度调制）信号的占空比来实现的，标准PWM

（脉冲宽度调制）信号的周期固定为20ms（50Hz），理论上脉宽分布应在1ms到2ms

之间，但是，事实上脉宽可由0.5ms 到2.5ms 之间，脉宽和舵机的转角0°～180°相

对应。有一点值得注意的地方，由于舵机牌子不同，对于同一信号，不同牌子的舵机旋

转的角度也会有所不同。

![](media/c29c393165eaf0cba523e46d53d1b958.emf)

实验器材

开发板\*1

USB线\*1

舵机\*1

正标线若干

接线图

连接Keyes UNO R3

![](media/dd0a6f36d61f07a112ff6f3d9a659946.jpeg)

连接Keyes 2560 R3

![](media/227313ebcf705c614ef9ceaa5b634197.jpeg)

测试代码

程序A：

```
int servopin=9;      //定义数字接口9 连接伺服舵机信号线
int myangle;         //定义角度变量
int pulsewidth;      //定义脉宽变量
int val;

void servopulse(int servopin,int myangle)  //定义一个脉冲函数
{
    pulsewidth=(myangle*11)+500;           //将角度转化为500-2480 的脉宽值
    digitalWrite(servopin,HIGH);           //将舵机接口电平至高
    delayMicroseconds(pulsewidth);         //延时脉宽值的微秒数
    digitalWrite(servopin,LOW);            //将舵机接口电平至低
    delay(20-pulsewidth/1000);
}

void setup()
{
    pinMode(servopin,OUTPUT);              //设定舵机接口为输出接口
    Serial.begin(9600);                    //连接到串行端口，波特率为9600
    Serial.println("servo=o_seral_simple ready");
}

void loop()  //将0 到9 的数转化为0 到180 角度，并让LED 闪烁相应数的次数
{
    val=Serial.read();                     //读取串行端口的值
    if(val>='0'&&val<='9')
    {
        val=val-'0';                       //将特征量转化为数值变量
        val=val*(180/9);                   //将数字转化为角度
        Serial.print("moving servo to ");
        Serial.print(val,DEC);
        Serial.println();
        for(int i=0;i<=50;i++)             //给予舵机足够的时间让它转到指定角度
        {
            servopulse(servopin,val);      //引用脉冲函数
        }
    }
}
```

程序B：

```
#include <Servo.h>  

Servo myservo;        //定义舵机变量名

void setup()
{
    myservo.attach(9); //定义舵机接口（9、10 都可以，缺点只能控制2 个）
}

void loop()
{
    myservo.write(90); //设置舵机旋转的角度
}
```

测试结果

程序A 结果：

在串口监视器中输入数字点击发送，舵机转动到所对应的角度数的位置，并将角度打印显示到屏幕上。

程序B结果：

舵机自己转动到90度位置。

### 实验十七 四位数码管显示数字实验

实验说明

在实验十五中我们使用开发板驱动一个一位数码管，本实验我们使用开发板驱动一个共阴四位数码管。驱动数码管限流电阻肯定是必不可少的，限流电阻有两种接法，一种是在d1-d4阴极接，总共接4颗。这种接法好处是需求电阻比较少，但是会产生每一位上显示不同数字亮度会不一样，1最亮，8最暗。另外一种接法就是在其他8个引脚上接，这种接法亮度显示均匀，但是用电阻较多。本次实验使用8颗220Ω电阻。

四位数码管总共有12个引脚，小数点朝下正放在面前时，左下角为1,其他管脚顺序为逆时针旋转。左上角为最大的12号管脚。

![](media/2d04173569ee9e6c055296916c1748be.jpg)

四位数码管原理图如下

![](media/9d2a9bfdac6e2a6a3956de68b11e62b0.jpg)

实验器材

开发板\*1

USB线\*1

四位数码管\*1

220Ω 电阻\*8

面包板\*1

正标线若干

接线图

连接Keyes UNO R3

![](media/47b9f26e49f7adb9b46652ec823a98a2.jpeg)

连接Keyes 2560 R3

![](media/38011e914609fffd909b4e6dfd36fbee.jpeg)

测试代码

```
// 数码管段选引脚定义（a-g, dp）
int a = 1;
int b = 2;
int c = 3;
int d = 4;
int e = 5;
int f = 6;
int g = 7;
int dp = 8;

// 数码管位选引脚定义（4位数码管）
int d4 = 9;
int d3 = 10;
int d2 = 11;
int d1 = 12;

// 全局变量定义
long n = 1230;  // 初始显示值（未使用）
int x = 100;    // 变量（未使用）
int del = 55;   // 时钟微调参数（未使用）

void setup()
{
    // 初始化所有引脚为输出模式
    pinMode(d1, OUTPUT);
    pinMode(d2, OUTPUT);
    pinMode(d3, OUTPUT);
    pinMode(d4, OUTPUT);
    pinMode(a, OUTPUT);
    pinMode(b, OUTPUT);
    pinMode(c, OUTPUT);
    pinMode(d, OUTPUT);
    pinMode(e, OUTPUT);
    pinMode(f, OUTPUT);
    pinMode(g, OUTPUT);
    pinMode(dp, OUTPUT);
}

/////////////////////////////////////////////////////////////
void loop()
{
    // 计数器变量初始化
    int a=0;  // 千位
    int b=0;  // 百位
    int c=0;  // 十位
    int d=0;  // 个位
    unsigned long currentMillis = millis();
    
    // 主计数循环
    while(d>=0)
    {
        // 每秒更新一次显示
        while(millis()-currentMillis<1000)
        {
            // 动态扫描显示4位数码管
            Display(1,a);  // 显示千位
            Display(2,b);  // 显示百位
            Display(3,c);  // 显示十位
            Display(4,d);  // 显示个位
        }
        currentMillis = millis();
        
        // 数字递增逻辑
        d++;
        if (d>9)  // 个位进位
        {
            c++;
            d=0;
        }
        if (c>9)  // 十位进位
        {
            b++;
            c=0;
        }
        if (b>9)  // 百位进位
        {
            a++;
            b=0;
        }
        if (a>9)  // 千位归零
        {
            a=0;
            b=0;
            c=0;
            d=0;
        }
    }
}

///////////////////////////////////////////////////////////////
// 位选函数（选择要显示的数码管位）
void WeiXuan(unsigned char n)
{
    switch (n)
    {
        case 1:  // 选择第1位
            digitalWrite(d1, LOW);
            digitalWrite(d2, HIGH);
            digitalWrite(d3, HIGH);
            digitalWrite(d4, HIGH);
            break;
        case 2:  // 选择第2位
            digitalWrite(d1, HIGH);
            digitalWrite(d2, LOW);
            digitalWrite(d3, HIGH);
            digitalWrite(d4, HIGH);
            break;
        case 3:  // 选择第3位
            digitalWrite(d1, HIGH);
            digitalWrite(d2, HIGH);
            digitalWrite(d3, LOW);
            digitalWrite(d4, HIGH);
            break;
        case 4:  // 选择第4位
            digitalWrite(d1, HIGH);
            digitalWrite(d2, HIGH);
            digitalWrite(d3, HIGH);
            digitalWrite(d4, LOW);
            break;
        default:  // 默认关闭所有位选
            digitalWrite(d1, HIGH);
            digitalWrite(d2, HIGH);
            digitalWrite(d3, HIGH);
            digitalWrite(d4, HIGH);
            break;
    }
}

// 数字0-9的显示函数（共阴极数码管）
void Num_0()  // 显示数字0
{
    digitalWrite(a, HIGH);
    digitalWrite(b, HIGH);
    digitalWrite(c, HIGH);
    digitalWrite(d, HIGH);
    digitalWrite(e, HIGH);
    digitalWrite(f, HIGH);
    digitalWrite(g, LOW);
    digitalWrite(dp, LOW);
}

void Num_1()  // 显示数字1
{
    digitalWrite(a, LOW);
    digitalWrite(b, HIGH);
    digitalWrite(c, HIGH);
    digitalWrite(d, LOW);
    digitalWrite(e, LOW);
    digitalWrite(f, LOW);
    digitalWrite(g, LOW);
    digitalWrite(dp, LOW);
}

void Num_2()  // 显示数字2
{
    digitalWrite(a, HIGH);
    digitalWrite(b, HIGH);
    digitalWrite(c, LOW);
    digitalWrite(d, HIGH);
    digitalWrite(e, HIGH);
    digitalWrite(f, LOW);
    digitalWrite(g, HIGH);
    digitalWrite(dp, LOW);
}

void Num_3()  // 显示数字3
{
    digitalWrite(a, HIGH);
    digitalWrite(b, HIGH);
    digitalWrite(c, HIGH);
    digitalWrite(d, HIGH);
    digitalWrite(e, LOW);
    digitalWrite(f, LOW);
    digitalWrite(g, HIGH);
    digitalWrite(dp, LOW);
}

void Num_4()  // 显示数字4
{
    digitalWrite(a, LOW);
    digitalWrite(b, HIGH);
    digitalWrite(c, HIGH);
    digitalWrite(d, LOW);
    digitalWrite(e, LOW);
    digitalWrite(f, HIGH);
    digitalWrite(g, HIGH);
    digitalWrite(dp, LOW);
}

void Num_5()  // 显示数字5
{
    digitalWrite(a, HIGH);
    digitalWrite(b, LOW);
    digitalWrite(c, HIGH);
    digitalWrite(d, HIGH);
    digitalWrite(e, LOW);
    digitalWrite(f, HIGH);
    digitalWrite(g, HIGH);
    digitalWrite(dp, LOW);
}

void Num_6()  // 显示数字6
{
    digitalWrite(a, HIGH);
    digitalWrite(b, LOW);
    digitalWrite(c, HIGH);
    digitalWrite(d, HIGH);
    digitalWrite(e, HIGH);
    digitalWrite(f, HIGH);
    digitalWrite(g, HIGH);
    digitalWrite(dp, LOW);
}

void Num_7()  // 显示数字7
{
    digitalWrite(a, HIGH);
    digitalWrite(b, HIGH);
    digitalWrite(c, HIGH);
    digitalWrite(d, LOW);
    digitalWrite(e, LOW);
    digitalWrite(f, LOW);
    digitalWrite(g, LOW);
    digitalWrite(dp, LOW);
}

void Num_8()  // 显示数字8
{
    digitalWrite(a, HIGH);
    digitalWrite(b, HIGH);
    digitalWrite(c, HIGH);
    digitalWrite(d, HIGH);
    digitalWrite(e, HIGH);
    digitalWrite(f, HIGH);
    digitalWrite(g, HIGH);
    digitalWrite(dp, LOW);
}

void Num_9()  // 显示数字9
{
    digitalWrite(a, HIGH);
    digitalWrite(b, HIGH);
    digitalWrite(c, HIGH);
    digitalWrite(d, HIGH);
    digitalWrite(e, LOW);
    digitalWrite(f, HIGH);
    digitalWrite(g, HIGH);
    digitalWrite(dp, LOW);
}

void Clear() // 清空数码管显示
{
    digitalWrite(a, LOW);
    digitalWrite(b, LOW);
    digitalWrite(c, LOW);
    digitalWrite(d, LOW);
    digitalWrite(e, LOW);
    digitalWrite(f, LOW);
    digitalWrite(g, LOW);
    digitalWrite(dp, LOW);
}

// 数字选择函数
void pickNumber(unsigned char n)
{
    switch (n)
    {
        case 0: Num_0(); break;
        case 1: Num_1(); break;
        case 2: Num_2(); break;
        case 3: Num_3(); break;
        case 4: Num_4(); break;
        case 5: Num_5(); break;
        case 6: Num_6(); break;
        case 7: Num_7(); break;
        case 8: Num_8(); break;
        case 9: Num_9(); break;
        default: Clear(); break;
    }
}

// 数码管显示函数
void Display(unsigned char x, unsigned char Number)
{
    WeiXuan(x);      // 选择显示位
    pickNumber(Number); // 显示数字
    delay(1);        // 短暂延时
    Clear();         // 清除显示（消隐）
}
```

测试结果

下载完程序后，数码管首先显示“0000”数值，显示跳动，每跳动一下数码管显示数值加1。当显示数值为超过“9999”后，显示数值再次变为“0000”，循环显示。

### 实验十八 1602液晶显示实验

实验说明

本次试验使用keyes UNO R3
直接驱动1602液晶显示文字。1602液晶在应用中非常广泛，它的显示容量为16×2个字符，芯片工作电压为4.5～5.5V。1602液晶在接keyes UNO R3
控制板显示文字时有两种接线法，分别为4位接法和8位接法，本实验中都会有相关说明介绍。

实验器材

开发板\*1

USB线\*1

1602 LCD\*1

可调电位器\*1

面包板\*1

正标线若干

接线图

连接Keyes UNO R3

四位接法

![](media/705ffaa005ddcd6b2552ca07e91a7a0d.jpeg)

八位接法

![](media/c58f8bc4e9103a3d44c67c32b0544f0c.jpg)

连接Keyes 2560 R3

四位接法

![](media/2746513e4d3eca53c5eed70ab2f9e9c2.jpeg)

八位接法

![](media/c58f8bc4e9103a3d44c67c32b0544f0c.jpg)

测试代码

四位接法

```
/*
  LiquidCrystal Library - Hello World
  
  演示16x2 LCD显示器的使用。LiquidCrystal库适用于所有兼容
  Hitachi HD44780驱动器的LCD显示器。这类显示器通常具有16针接口
  
  本示例在LCD上显示"Hello World!"和"Hello keyes!"
  
  电路连接：
  * LCD RS引脚 -> 数字引脚2
  * LCD Enable引脚 -> 数字引脚3
  * LCD D4引脚 -> 数字引脚4
  * LCD D5引脚 -> 数字引脚5
  * LCD D6引脚 -> 数字引脚6
  * LCD D7引脚 -> 数字引脚7
  * LCD R/W引脚 -> 接地
  * LCD VSS引脚 -> 接地
  * LCD VCC引脚 -> 5V
  * 10K电位器：
     - 两端分别接+5V和地
     - 中间引脚接LCD VO引脚
*/

// 包含LCD库
#include <LiquidCrystal.h>

// 初始化库，指定接口引脚
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

void setup() {
  // 设置LCD的列数和行数（16列2行）
  lcd.begin(16, 2);
  
  // 在LCD上打印消息
  lcd.setCursor(2,0);    // 设置光标位置(列,行)
  lcd.print("Hello, world!");
  lcd.setCursor(2,1);
  lcd.print("Hello, keyes!");
}

void loop() {
  // 空循环
}

/* 以下是八位接法的实现代码 */

// 定义引脚（八位并行接口）
int DI = 12;    // 数据/指令选择
int RW = 11;    // 读/写选择
int DB[] = {3, 4, 5, 6, 7, 8, 9, 10}; // 使用数组定义数据总线引脚
int Enable = 2; // 使能引脚

// 写命令函数
void LcdCommandWrite(int value) {
  int i = 0;
  digitalWrite(DI, LOW);  // 写命令模式
  digitalWrite(RW, LOW);  // 写模式
  
  // 向数据总线写入值（注意信号顺序反转）
  for (i=DB[0]; i <= DI; i++) {
    digitalWrite(i,value & 0x01);
    value >>= 1;
  }
  
  // 产生使能脉冲
  digitalWrite(Enable,LOW);
  delayMicroseconds(1);
  digitalWrite(Enable,HIGH);
  delayMicroseconds(1);
  digitalWrite(Enable,LOW);
  delayMicroseconds(1);
}

// 写数据函数
void LcdDataWrite(int value) {
  int i = 0;
  digitalWrite(DI, HIGH); // 写数据模式
  digitalWrite(RW, LOW);
  
  for (i=DB[0]; i <= DB[7]; i++) {
    digitalWrite(i,value & 0x01);
    value >>= 1;
  }
  
  // 产生使能脉冲
  digitalWrite(Enable,LOW);
  delayMicroseconds(1);
  digitalWrite(Enable,HIGH);
  delayMicroseconds(1);
  digitalWrite(Enable,LOW);
  delayMicroseconds(1);
}

// 初始化函数（八位接口）
void setup(void) {
  int i = 0;
  // 设置所有引脚为输出模式
  for (i=Enable; i <= DI; i++) {
    pinMode(i,OUTPUT);
  }
  
  delay(100); // 短暂延时等待LCD上电
  
  // LCD初始化序列
  LcdCommandWrite(0x38); // 8位接口，2行显示，5x7点阵
  delay(64);
  LcdCommandWrite(0x38);
  delay(50);
  LcdCommandWrite(0x38);
  delay(20);
  
  LcdCommandWrite(0x06); // 输入模式设置：增量，不移位
  delay(20);
  
  LcdCommandWrite(0x0E); // 显示控制：开显示，显示光标，不闪烁
  delay(20);
  
  LcdCommandWrite(0x01); // 清屏，光标归位
  delay(100);
  
  LcdCommandWrite(0x80); // 设置DDRAM地址
  delay(20);
}

// 主循环（八位接口）
void loop(void) {
  LcdCommandWrite(0x01); // 清屏
  delay(10);
  
  LcdCommandWrite(0x80+2); // 设置光标位置第一行第3列
  delay(10);
  
  // 逐字符写入"Hello, world!"
  LcdDataWrite('H');
  LcdDataWrite('e');
  LcdDataWrite('l');
  LcdDataWrite('l');
  LcdDataWrite('o');
  LcdDataWrite(',');
  LcdDataWrite(' ');
  LcdDataWrite('w');
  LcdDataWrite('o');
  LcdDataWrite('r');
  LcdDataWrite('l');
  LcdDataWrite('d');
  LcdDataWrite('!');
  delay(10);
  
  LcdCommandWrite(0xc0+2); // 设置光标位置第二行第3列
  delay(10);
  
  // 逐字符写入"Hello, keyes!"
  LcdDataWrite('H');
  LcdDataWrite('e');
  LcdDataWrite('l');
  LcdDataWrite('l');
  LcdDataWrite('o');
  LcdDataWrite(',');
  LcdDataWrite(' ');
  LcdDataWrite('k');
  LcdDataWrite('e');
  LcdDataWrite('y');
  LcdDataWrite('e');
  LcdDataWrite('s');
  LcdDataWrite('!');
  LcdDataWrite(' ');
  
  delay(5000); // 显示5秒
}
```

测试结果

无论是四位接法还是八位接法，接好线，烧录程序上电后，通过旋转电位器调节背光，即可在1602 LCD上看到设置的显示字符。四位接法和八位接法显示一样，第一行显示
"Hello, world!"字符，第二行显示"Hello, keyes!"字符。

### 实验十九 超声波测距显示实验

实验说明

本实验中我们主要用到了超声波传感器和1602 LCD。实验中我们通过超声波测到超声波与前方障碍物的距离，然后在1602 LCD上显示测试结果。

实验器材

开发板 \*1

USB线\*1

1602 LCD\*1

可调电位器\*1

超声波传感器\*1

面包板\*1

正标线若干

杜邦线若干

接线图

连接Keyes UNO R3

![](media/a3aa6c3f2b62104bc65c88ccf71b18eb.jpeg)

连接Keyes 2560 R3

![](media/256d52c2b4a2086548a12e252ffde9db.jpeg)

测试代码

```
#include <LiquidCrystal.h>

// 超声波传感器引脚定义
#define echoPin 3   // 回声信号接收引脚
#define trigPin 2   // 触发信号输出引脚
#define LEDPin 13   // 板载LED指示灯引脚

// 初始化LCD对象（RS, E, D4, D5, D6, D7）
LiquidCrystal lcd(4, 5, 6, 7, 8, 9);

// 距离测量范围设置
int maximumRange = 200;  // 最大测量距离（厘米）
int minimumRange = 0;    // 最小测量距离（厘米）

// 测量变量
long duration, distance; // 持续时间和计算得到的距离

void setup() 
{
    // 初始化各引脚模式
    pinMode(trigPin, OUTPUT);
    pinMode(echoPin, INPUT);
    pinMode(LEDPin, OUTPUT);  // 用于距离超出范围指示
    
    // LCD显示屏初始化
    lcd.begin(16, 2);
    lcd.setCursor(0,0);
    lcd.print("The distance is:");
}

void loop() 
{
    /* 超声波测距过程 */
    // 发送10μs的触发脉冲
    digitalWrite(trigPin, LOW);
    delayMicroseconds(2);
    digitalWrite(trigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);
    
    // 测量回声脉冲宽度
    duration = pulseIn(echoPin, HIGH);
    
    // 计算距离（声速340m/s，换算为58.2μs/cm）
    distance = duration/58.2;
    
    // 距离有效性判断
    if (distance >= maximumRange || distance <= minimumRange)
    {
        /* 超出有效范围时的处理 */
        lcd.setCursor(0,1);
        lcd.print("-1 ");  // 显示-1表示超出范围
        digitalWrite(LEDPin, HIGH);  // 点亮LED指示异常
    }
    else 
    {
        /* 正常距离显示处理 */
        Serial.println(distance);  // 串口输出距离值
        
        // 根据距离值位数调整LCD显示格式
        if(distance<10)
        {
            lcd.setCursor(0,1);
            lcd.print(distance);
            lcd.setCursor(1,1);
            lcd.print("  ");  // 清空后两位
        }
        
        if((distance >=10)&&(distance<100))
        {
            lcd.setCursor(0,1);
            lcd.print(distance);
            lcd.setCursor(2,1);
            lcd.print(" ");  // 清空最后一位
        }
        
        if(distance>100)
        {
            lcd.setCursor(0,1);
            lcd.print(distance);  // 三位数完整显示
        }
        
        digitalWrite(LEDPin, LOW);  // 关闭LED指示
    }
    
    // 每次测量间隔50ms
    delay(50);
}
```

测试结果

按照上图接好线，烧录好代码，旋转电位器调节好背光后，1602 LCD显示"The distance is:"字符；测试超声波与前方障碍物的距离，测试到数据，则在1602 LCD上显示该数据，若没测试到数据，那么就在1602 LCD上显示”-1”字符。

### 实验二十 1302时钟显示实验

实验说明

上一实验中我们在1602 LCD上显示超声波距离，这一实验程也是将1602 LCD做显示器。这个实验相当于我们自制一个时钟，时钟上包含年、月、日、星期、小时、分钟、秒。初始时间在代码中设置，时钟自动行走，在1602 LCD显示。

实验器材

开发板\*1

USB线\*1

1602 LCD\*1

可调电位器\*1

1302时钟传感器\*1

面包板\*1

正标线若干

杜邦线若干

接线图

连接Keyes UNO R3

![](media/6f2c276066d55e5cb20c7d53f34594da.jpeg)

连接Keyes 2560 R3

![](media/c91c6fbb0b67121713bac6955b616666.jpeg)

测试代码

```
#include <stdio.h>                      // 标准输入输出头文件
#include <string.h>                     // 字符串操作头文件
#include <DS1302.h>                     // DS1302实时时钟库
#include <Wire.h>                       // I2C通信库
#include <LiquidCrystal.h>              // LCD液晶显示屏库

LiquidCrystal lcd(5, 6, 7, 8, 9, 10);  // 初始化LCD引脚(RS,EN,D4,D5,D6,D7)

/* 设置数字I/O引脚连接 */
uint8_t CE_PIN = 4;                     // RST复位引脚
uint8_t IO_PIN = 3;                     // DAT数据引脚 
uint8_t SCLK_PIN = 2;                   // CLK时钟引脚

/* 创建缓冲区 */
char buf[50];                           // 完整日期时间缓冲区
char bf[50];                            // 星期和年份缓冲区
char bu[50];                            // 时间缓冲区
char uf[50];                            // 月份和日期缓冲区
char day[10];                           // 星期名称缓冲区

/* 创建DS1302对象 */
DS1302 rtc(CE_PIN, IO_PIN, SCLK_PIN);   // 实例化DS1302对象

void print_time()
{
    /* 从芯片获取当前时间和日期 */
    Time t = rtc.time();                 // 获取当前时间结构体

    /* 设置星期名称 */
    memset(day, 0, sizeof(day));         // 清空星期缓冲区
    switch (t.day)
    {
        case 1:
            strcpy(day, "Sunday ");      // 星期日
            break;
        case 2:
            strcpy(day, "Monday ");      // 星期一
            break;
        case 3:
            strcpy(day, "Tuesday ");     // 星期二
            break;
        case 4:
            strcpy(day, "Wednesday");    // 星期三
            break;
        case 5:
            strcpy(day, "Thursday ");    // 星期四
            break;
        case 6:
            strcpy(day, "Friday ");     // 星期五
            break;
        case 7:
            strcpy(day, "Saturday ");   // 星期六
            break;
    }

    /* 格式化日期时间并存入缓冲区 */
    snprintf(buf, sizeof(buf), "%s %04d-%02d-%02d %02d:%02d:%02d",
             day,
             t.yr, t.mon, t.date,
             t.hr, t.min, t.sec);

    snprintf(bf, sizeof(bf), "%s %04d",
             day, t.yr);
    lcd.setCursor(0,0);                 // 设置光标位置(第一行开头)
    lcd.print(bf);                      // 显示星期和年份

    snprintf(bu, sizeof(bu), "%02d:%02d:%02d",
             t.hr, t.min, t.sec);
    
    lcd.setCursor(0,1);                 // 设置光标位置(第二行开头)
    lcd.print(bu);                      // 显示时分秒

    snprintf(uf, sizeof(uf), "%02d-%02d",
             t.mon, t.date);
    lcd.setCursor(11,1);                // 设置光标位置(第二行第11列)
    lcd.print(uf);                      // 显示月-日
}

void setup()
{
    lcd.begin(16, 2);                   // 初始化16x2 LCD显示屏

    /* 通过关闭写保护和清除时钟停止标志初始化芯片 */
    rtc.write_protect(false);           // 禁用写保护
    rtc.halt(false);                    // 清除时钟停止标志

    /* 创建时间对象设置日期时间 */
    Time t(2017,7,24,10,12,22,2);       // 创建时间对象(年,月,日,时,分,秒,星期)

    /* 设置芯片日期时间 */
    rtc.time(t);                        // 写入RTC时间
}

/* 循环每秒打印时间 */
void loop()
{
    print_time();                       // 调用时间显示函数
    delay(1000);                        // 延时1秒
}
```

测试结果

按照上图接好线，烧录好代码，旋转电位器调节好背光后，1602 LCD显示当前初始时间，然后时钟开始走动。

### 实验二十一 人体红外感应实验

实验说明

和上面两个实验一样，这个实验也是用1602 LCD做显示器。实验中，我们用到了人体红外热释电传感器，当检测到有人有附近移动时，在1602 LCD显示对应字符，当没有检测到人体在附件移动时，1602 LCD显示另一对应字符。

实验器材

开发板\*1

USB线\*1

1602 LCD\*1

可调电位器\*1

人台红外热释电传感器\*1

面包板\*1

正标线若干

杜邦线若干

接线图

连接Keyes UNO R3

![](media/38933e8434f68fc7a85cf6fe08d4c1d1.jpeg)

连接Keyes 2560 R3

![](media/47f2e716fee2ddaaee4ffb7449c52a63.jpeg)

测试代码

```
#include <LiquidCrystal.h>

LiquidCrystal lcd(3, 4, 5, 6, 7, 8);

byte sensorPin = 2;          //定义数字口2
byte indicator = 13;         //定义数字口13

void setup()
{
    pinMode(sensorPin, INPUT);  //设置数字口2位输入
    pinMode(indicator, OUTPUT); //设置数字口13为输出
    lcd.begin(16, 2);
}

void loop()
{
    byte state = digitalRead(sensorPin);  //读取到数字口2的数值赋值给state
    digitalWrite(indicator, state);       //控制数值口13的状态

    if(state == 1)                        //当数值口2位高电平时，串口监视器输出对应字符，并自动换行
    {
        lcd.setCursor(0, 0);
        lcd.print("Somebody is ");
        lcd.setCursor(0, 1);
        lcd.print("in this area! ");
    }
    else if(state == 0)
    {
        lcd.setCursor(0, 0);
        lcd.print("No one! ");
        lcd.setCursor(0, 1);
        lcd.print("No one! ");
    }
}
```

按照上图接好线，烧录好代码，旋转电位器调节好背光后，当检测到有人有附近移动时，在1602 LCD第一行显示显示"Somebody is "字符，第二行显示"in this area!"字符；当没有检测到人体在附件移动时，1602 LCD两行都显示"No one!"字符。

### 实验二十二 温湿度显示实验

实验说明

和上面实验一样，这个实验也是用1602 LCD做显示器。这个实验中我们主要用到了DHT11温湿度传感器和1602 LCD。DHT11温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器，它应用专用的数字模块采集技术和温湿度传感技术，确保产品具有极高的可靠性和卓越的长期稳定性。

实验中我们DHT11温湿度传感器测试出当前环境中的温度和湿度，然后在1602 LCD 显示测试结果。

实验器材

开发板\*1

USB线\*1

1602 LCD\*1

可调电位器\*1

DHT11温湿度传感器\*1

面包板\*1

正标线若干

杜邦线若干

接线图

连接Keyes UNO R3

![](media/86d74cbccfe29339e7abbe91b48a72ac.jpeg)

连接Keyes 2560 R3

![](media/4fe2a1786ab6147d484945ba6f174ab5.jpeg)

测试代码

```
#include <dht11.h>                      // DHT11温湿度传感器库
#include <LiquidCrystal.h>              // LCD液晶显示屏库

// 初始化LCD引脚(RS,EN,D4,D5,D6,D7)
LiquidCrystal lcd(3, 4, 5, 6, 7, 8);   

dht11 DHT;                              // 创建DHT11对象
#define DHT11_PIN 2                     // DHT11数据引脚定义

void setup()
{
    lcd.begin(16, 2);                   // 初始化16x2 LCD显示屏
    
    // 在LCD上打印固定信息
    lcd.setCursor(0,0);                 // 设置光标位置(第一行开头)
    lcd.print("Humidity (%):");         // 显示"湿度(%)"
    
    lcd.setCursor(0,1);                 // 设置光标位置(第二行开头)
    lcd.print("Temp (C):");             // 显示"温度(℃)"
}

void loop()
{
    int chk;                            // 传感器状态检查变量
    chk = DHT.read(DHT11_PIN);         // 读取DHT11传感器数据
    
    // 检查传感器状态
    switch (chk)
    {
        case DHTLIB_OK:                 // 读取成功
            break;
        case DHTLIB_ERROR_CHECKSUM:    // 校验和错误
            break;
        case DHTLIB_ERROR_TIMEOUT:     // 读取超时
            break;
        default:                       // 其他错误
            break;
    }
    
    // 显示传感器数据
    lcd.setCursor(13,0);               // 设置湿度显示位置(第一行第13列)
    lcd.print(DHT.humidity);           // 显示湿度值
    
    lcd.setCursor(9,1);                // 设置温度显示位置(第二行第9列)
    lcd.print(DHT.temperature);        // 显示温度值
    
    delay(1000);                       // 延时1秒
}
```

测试结果

按照上图接好线，烧录好代码，旋转电位器调节好背光后，1602 LCD显示当前环境中的温度和湿度值。

### 实验二十三 摇杆模块数据显示实验

实验说明

和上面实验一样，这个实验也是用1602 LCD做显示器。这个实验中我们主要用到了摇杆模块和1602 LCD。摇杆模块5V供电，信号端X,Y接模拟口，原始状态下读出电压为2.5V左右，当随箭头方向按下，读出电压值随着增加，最大到5V，箭头相反方向按下，读出电压值减少，最小为0V；信号端B接数字口，原始状态下输出0，按下输出1。

实验中我们读取摇杆模块X、Y、B三个接口数值，然后在1602 LCD显示测试结果。

实验器材

开发板\*1

USB线\*1

1602 LCD\*1

可调电位器\*1

摇杆模块\*1

面包板\*1

正标线若干

杜邦线若干

接线图

连接Keyes UNO R3

![](media/fe6859b9e397a7979a807ed8a407d7bb.jpeg)

连接Keyes 2560 R3

![](media/16010d9d33d585f147c4c9f0418a7059.jpeg)

测试代码

```
#include <LiquidCrystal.h>              // LCD液晶显示屏库

// 初始化LCD引脚(RS,EN,D4,D5,D6,D7)
LiquidCrystal lcd(3, 4, 5, 6, 7, 8);   

int JoyStick_X = 1;                     // 定义摇杆X轴模拟口A1
int JoyStick_Y = 0;                     // 定义摇杆Y轴模拟口A0
int JoyStick_Z = 2;                     // 定义摇杆Z轴数字口2

void setup()
{
    pinMode(JoyStick_Z, INPUT);         // 将JoyStick_Z设置为输入模式
    lcd.begin(16, 2);                   // 初始化16x2 LCD显示屏
    
    // 在LCD上打印固定标签
    lcd.setCursor(0,0);                 // 设置光标位置(第一行开头)
    lcd.print("X:");                    // 显示X轴标签
    
    lcd.setCursor(8,0);                 // 设置光标位置(第一行第8列)
    lcd.print("Y:");                    // 显示Y轴标签
    
    lcd.setCursor(0,1);                 // 设置光标位置(第二行开头)
    lcd.print("Z:");                    // 显示Z轴标签
}

void loop()
{
    int x,y,z;                          // 定义摇杆值变量
    
    // 读取并显示X轴数值
    x = analogRead(JoyStick_X);         // 读取A1模拟口数值
    if(x < 10)
    {
        lcd.setCursor(2,0);             // 设置光标位置(第一行第2列)
        lcd.print(x);                   // 显示个位数
        lcd.setCursor(3,0);             // 设置光标清除位置
        lcd.print(" ");                // 清除多余数字
    }
    else if((x >= 10) && (x < 100))
    {
        lcd.setCursor(2,0);
        lcd.print(x);                   // 显示两位数
        lcd.setCursor(4,0);
        lcd.print(" ");
    }
    else if((x >= 100) && (x < 1000))
    {
        lcd.setCursor(2,0);
        lcd.print(x);                   // 显示三位数
        lcd.setCursor(5,0);
        lcd.print(" ");
    }
    else if(x >= 1000)
    {
        lcd.setCursor(2,0);
        lcd.print(x);                   // 显示四位数
    }
    delay(100);                         // 延时100ms

    // 读取并显示Y轴数值
    y = analogRead(JoyStick_Y);         // 读取A0模拟口数值
    if(y < 10)
    {
        lcd.setCursor(10,0);            // 设置光标位置(第一行第10列)
        lcd.print(y);
        lcd.setCursor(11,0);
        lcd.print(" ");
    }
    else if((y >= 10) && (y < 100))
    {
        lcd.setCursor(10,0);
        lcd.print(y);
        lcd.setCursor(12,0);
        lcd.print(" ");
    }
    else if((y >= 100) && (y < 1000))
    {
        lcd.setCursor(10,0);
        lcd.print(y);
        lcd.setCursor(13,0);
        lcd.print(" ");
    }
    else if(y >= 1000)
    {
        lcd.setCursor(2,0);
        lcd.print(y);
    }
    delay(100);

    // 读取并显示Z轴数值
    z = digitalRead(JoyStick_Z);        // 读取数字口2数值
    lcd.setCursor(2,1);                 // 设置光标位置(第二行第2列)
    lcd.print(z);                       // 显示开关状态(0/1)
    delay(100);                         // 延时100ms
}
```

测试结果

下载完程序后，上电后，通过电位器调节1602 LCD背光后，我们可以在1602 LCD上看、

到摇杆模块X、Y、Z方向对应的的数值。

### 实验二十四 继电器控灯实验

实验说明

继电器模块是一种用于低电控制高电，保护电路的模块。本实验用到的5V单路继电器模块高电平有效，它有控制指示灯，吸合亮，断开不亮。实验中我们通过控制继电器从而控制一个LED的亮灭。

实验器材

开发板\*1

USB线\*1

5V 单路继电器模块\*1

LED\*1

220Ω 电阻\*1

面包板\*1

正标线若干

杜邦线若干

接线图

连接Keyes UNO R3

![](media/c09612dd3e0dbf0700aba6dbfcb5a595.jpeg)

连接Keyes 2560 R3

![](media/46d12c11c177ead23cf49a4f92c1d3b6.jpeg)

测试代码

```
int Relay = 3;  //定义数字口3  

void setup()  
{  
    pinMode(Relay, OUTPUT);  //将Relay设置为输出  
}  

void loop()  
{  
    digitalWrite(Relay, HIGH);  //打开继电器  
    delay(2000);                //延时2S  
    digitalWrite(Relay, LOW);   //关闭继电器  
    delay(2000);                //延时2S  
}  
```

### 实验二十五 水蒸气检测显示实验

实验说明

和上面实验一样，这个实验也是用1602 LCD做显示器。这个实验中我们主要用到了水滴水蒸气传感器和1602 LCD。水滴水蒸气传感器是一个模拟传感器，可以制作简单的雨水探测器与液位开关。当传感器表面的湿度上升，输出电压将增大。

实验中我们读取水滴水蒸气传感器信号端的模拟值，然后在1602 LCD显示测试结果。

实验器材

开发板\*1

USB线\*1

1602 LCD\*1

可调电位器\*1

水滴水蒸气传感器\*1

面包板\*1

正标线若干

杜邦线若干

接线图

连接Keyes UNO R3

![](media/2a6ff2e869c6332cdb991b6791e40a97.jpeg)

连接Keyes 2560 R3

![](media/3ac66ec29b2fd4799493c55d0556ebaf.jpeg)

测试代码

```
#include <LiquidCrystal.h>              // LCD液晶显示屏库头文件

// 初始化LCD引脚(RS,EN,D4,D5,D6,D7)
LiquidCrystal lcd(3, 4, 5, 6, 7, 8);   

void setup() 
{
    lcd.begin(16, 2);                   // 初始化16列2行的LCD显示屏
    
    // 在LCD第一行打印标题
    lcd.setCursor(0,0);                 // 设置光标位置(第一行开头)
    lcd.print("Sensor value:");         // 显示"传感器值:"
}

void loop() 
{
    int value = analogRead(A0);         // 读取A0模拟口的数值
    
    // 根据数值位数调整显示位置
    if(value < 10)                      // 数值小于10的情况
    {
        lcd.setCursor(0,1);             // 设置光标位置(第二行开头)
        lcd.print(value);               // 显示数值
        lcd.setCursor(1,1);             // 设置清除位置
        lcd.print(" ");                 // 清除多余数字
    }
    
    if((value >= 10) && (value < 100))  // 数值在10-99之间
    {
        lcd.setCursor(0,1);
        lcd.print(value);
        lcd.setCursor(2,1);
        lcd.print(" ");
    }
    
    if((value >= 100) && (value < 1000)) // 数值在100-999之间
    {
        lcd.setCursor(0,1);
        lcd.print(value);
        lcd.setCursor(3,1);
        lcd.print(" ");
    }
    
    if(value >= 1000)                   // 数值大于等于1000
    {
        lcd.setCursor(2,0);             // 注意：这里显示在第一行第2列
        lcd.print(value);
    }
    
    delay(100);                         // 延时100毫秒
}
```

测试结果

下载完程序后，上电后，通过电位器调节1602 LCD背光后，我们可以在1602 LCD上看

到水滴水蒸气传感器信号端的模拟值。

### 实验二十六 声控灯实验

实验说明

麦克风声音传感器是专门用来检测声音的传感器。传感器有S端是模拟输出，是麦克风的电压信号实时输出，通过电位器可调节信号增益。实验中，我通过传感器检测声音大小，从而控制一个LED亮灭。

实验器材

开发板\*1

USB线\*1

麦克风声音传感器\*1

LED\*1

220Ω 电阻\*1

面包板\*1

正标线若干

杜邦线若干

接线图

连接Keyes UNO R3

![](media/14643d220c05590eb11e45d74c40a503.jpeg)

连接Keyes 2560 R3

![](media/22717e9792b9462ff6d2ea5345132b30.jpeg)

测试代码

```
int MIC = 0;  //定义声音传感器为模拟0 接口  
int LED = 9;  //定义LED接口为数字9 接口  
int val = 0;  //定义数字变量  

void setup()  
{  
    pinMode(LED, OUTPUT);  //定义LED 为输出接口  
    pinMode(MIC, INPUT);   //定义声音传感器为输入接口  
    Serial.begin(9600);    //设定波特率为9600  
}  

void loop()  
{  
    val = analogRead(MIC);  //读取声音传感器的模拟值  
    Serial.println(val);    //输出模拟值，并将其打印出来  

    if(val >= 300)         //当模拟值大于300 时LED亮起  
    {  
        digitalWrite(LED, HIGH);  
    }  
    else  
    {  
        digitalWrite(LED, LOW);  
    }  

    delay(500);  
}  
```

测试结果

下载完程序后，我们可以检测声音大小，输出模拟值，声音越大，输出越大。当声音大小到达一定数值时，LED亮起，否则LED熄灭。

### 实验二十七 步进电机实验

实验说明

步进电机是一种将电脉冲转化为角位移的执行机构。通俗一点讲：当步进驱动器接收到

一个脉冲信号，它就驱动步进电机按设定的方向转动一个固定的角度（及步进角）。你

可以通过控制脉冲个数来控制角位移量，从而达到准确定位的目的；同时你也可以通过

控制脉冲频率来控制电机转动的速度和加速度，从而达到调速的目的。

下面这个就是本次实验使用的步进电机  
![](media/ffd29f7fe6040ad38e1edebc8597be31.png)  
减速步进电机

直径：28mm

电压：5V

步进角度：5.625 x 1/64

减速比：1/64

5线4相 可以用普通uln2003芯片驱动，也可以接成2相使用

该步进电机空载耗电在50mA以下，带64倍减速器，输出力矩比较大，可以驱动重负

载，极适合开发板使用。注意：此款步进电机带有64倍减速器，与不带减速器的步进

电机相比，转速显得较慢，为方便观察，可在输出轴处粘上一片小纸板。

![](media/73bd016226e3e794a06c599a6e11cd2c.png)

步进电机(五线四相）驱动板(UL2003)试验板

![](media/c16005aed5b06a748a5bd5bafd96cd46.jpg)

实验器材

开发板\*1

USB线\*1

减速步进电机\*1

UL2003\*1

杜邦线若干

接线图

连接Keyes UNO R3

![](media/1e62403cec5848271792558fa0306471.jpeg)

连接Keyes 2560 R3

![](media/8b38bdb611eb88cb18f0e41b9418ab8d.jpeg)

测试代码

```
#include <Stepper.h>

// 这里设置步进电机旋转一圈是多少步
#define STEPS 100

// 设置步进电机的步数和引脚
Stepper stepper(STEPS, 11, 10, 9, 8);

// 定义变量用来存储历史读数
int previous = 0;

void setup()
{
    // 设置电机每分钟的转速为90步
    stepper.setSpeed(90);
}

void loop()
{
    // 获取传感器读数
    int val = analogRead(0);
    
    // 移动步数为当前读数减去历史读数
    stepper.step(val - previous);
    
    // 保存历史读数
    previous = val;
}
```

测试结果

按照上图接好线，烧录好代码，上电后，5V步进电机转动，转动速度很慢。

### 实验二十八 姿态传感器实验

实验说明

APDS-9930 在单个 8 引脚封装内提供 I2C 接口兼容的环境亮度传感器 (ALS, Ambient Light Sensor) 和带有红外 LED的接近传感器，其中环境亮度传感器使用双光二极管来近似 0.01 lux照度下低流明性能的人眼视觉反应，提供的高灵敏度使得器件可以在深色玻璃后运作。接近传感器经过完全调校可进行100毫米物体检测，免除终端设备和次组件的工厂校准需求。从明亮的阳光照射到黑暗的房间，接近检测功能都能运作良好。模块中加入微光学透镜提供红外能量的高效率传送和接收，可降低总体功耗。另外，内部状态机可使器件进入低功耗模式，带来极低的平均功耗。

本实验只是简单的测试下这个传感器的基本功能。

实验器材

开发板\*1

USB线\*1

keyes 9930 接近和非接触式手势检测RGB和姿态传感器\*1

杜邦线若干

接线图

连接Keyes UNO R3

![](media/3d79aa9a0f05e9354f54f1b413eefd94.jpeg)

连接Keyes 2560 R3

![](media/9aeb9d40b6f00649049b01a19f060a3f.jpeg)

测试代码

```
#define DUMP_REGS                       // 定义寄存器调试模式

#include <Wire.h>                       // I2C通信库
#include <APDS9930.h>                   // APDS-9930传感器库

// 引脚定义
#define APDS9930_INT 2                  // 中断引脚(必须使用中断引脚)
#define LED_PIN 13                      // LED指示灯引脚

// 常量定义
#define PROX_INT_HIGH 600               // 接近中断高阈值
#define PROX_INT_LOW 0                  // 接近中断低阈值

// 全局变量
APDS9930 apds = APDS9930();             // 创建APDS-9930对象
float ambient_light = 0;                // 环境光强度值
uint16_t ch0 = 0;                       // 通道0光强度
uint16_t ch1 = 1;                       // 通道1光强度
uint16_t proximity_data = 0;            // 接近检测数据
volatile bool isr_flag = false;         // 中断标志位

void setup() 
{
    // 初始化LED引脚
    pinMode(LED_PIN, OUTPUT);           // 设置LED为输出模式
    pinMode(APDS9930_INT, INPUT);       // 设置中断引脚为输入模式

    // 初始化串口通信
    Serial.begin(9600);                 // 设置串口波特率9600
    Serial.println();
    Serial.println(F("------------------------------"));
    Serial.println(F("APDS-9930 - ProximityInterrupt"));
    Serial.println(F("------------------------------"));

    // 初始化中断服务程序
    attachInterrupt(digitalPinToInterrupt(APDS9930_INT), interruptRoutine, FALLING);

    // 初始化APDS-9930传感器
    if (apds.init()) 
    {
        Serial.println(F("APDS-9930 initialization complete"));
    }
    else 
    {
        Serial.println(F("Something went wrong during APDS-9930 init!"));
    }

    // 设置接近传感器增益
    if (!apds.setProximityGain(PGAIN_2X)) 
    {
        Serial.println(F("Something went wrong trying to set PGAIN"));
    }

    // 设置接近中断阈值
    if (!apds.setProximityIntLowThreshold(PROX_INT_LOW)) 
    {
        Serial.println(F("Error writing low threshold"));
    }
    if (!apds.setProximityIntHighThreshold(PROX_INT_HIGH)) 
    {
        Serial.println(F("Error writing high threshold"));
    }

    // 启动接近传感器(启用中断)
    if (apds.enableProximitySensor(true)) 
    {
        Serial.println(F("Proximity sensor is now running"));
    }
    else 
    {
        Serial.println(F("Something went wrong during sensor init!"));
    }

    // 启动光传感器(不启用中断)
    if (apds.enableLightSensor(false)) 
    {
        Serial.println(F("Light sensor is now running"));
    }
    else 
    {
        Serial.println(F("Something went wrong during light sensor init!"));
    }

#ifdef DUMP_REGS
    /* 寄存器调试输出 */
    uint8_t reg;
    uint8_t val;
    for (reg = 0x00; reg <= 0x19; reg++) 
    {
        if ((reg != 0x10) && (reg != 0x11))
        {
            apds.wireReadDataByte(reg, val);
            Serial.print(reg, HEX);
            Serial.print(": 0x");
            Serial.println(val, HEX);
        }
    }
    apds.wireReadDataByte(0x1E, val);
    Serial.print(0x1E, HEX);
    Serial.print(": 0x");
    Serial.println(val, HEX);
#endif
}

void loop() 
{
    // 检测中断标志
    if (isr_flag) 
    {
        // 读取接近值并输出
        if (!apds.readProximity(proximity_data)) 
        {
            Serial.println("Error reading proximity value");
        }
        else 
        {
            Serial.print("Proximity detected! Level: ");
            Serial.print(proximity_data);
            Serial.print(" ");
        }

        // 读取光强度值(环境光,通道0,通道1)
        if (!apds.readAmbientLightLux(ambient_light) || !apds.readCh0Light(ch0) || !apds.readCh1Light(ch1)) 
        {
            Serial.println(F("Error reading light values"));
        }
        else 
        {
            Serial.print(F("Ambient: "));
            Serial.print(ambient_light);
            Serial.print(F(" Ch0: "));
            Serial.print(ch0);
            Serial.print(F(" Ch1: "));
            Serial.println(ch1);
        }

        // LED指示灯闪烁
        digitalWrite(LED_PIN, HIGH);    // 点亮LED
        delay(300);                     // 保持300ms
        digitalWrite(LED_PIN, LOW);     // 关闭LED

        // 清除中断标志和中断状态
        isr_flag = false;
        if (!apds.clearProximityInt()) 
        {
            Serial.println("Error clearing interrupt");
        }
    }
}

// 中断服务程序
void interruptRoutine() 
{
    isr_flag = true;                    // 设置中断标志
}
```

测试结果

打开串口监视器，显示如下图。

![](media/9d02169f800388120e1e9745e6f4995c.png)

### 实验二十九 震动检测传感器实验

实验说明

震动检测传感器是基于压电陶瓷片的模拟震动传感器，是利用压电陶瓷给电信号产生震动的反变换过程，当压电陶瓷片震动时就会产生电信号。它可与Arduino专用传感器扩展板结合使用，Arduino模拟口能感知微弱的震动电信号，可实现与震动有相关的互动作品，比如电子鼓互动作品。

这个实验中，我们将模拟电压陶瓷震动传感器依照程序接入Arduino UNO控制器模拟口A0，观察当震动程度不同时，串口的输出值。

实验器材

开发板\*1

USB线\*1

震动检测传感器\*1

杜邦线若干

接线图

连接Keyes UNO R3

![](media/f93e1a1a601e6d819d75cfc9fae1eee9.jpeg)

连接Keyes 2560 R3

![](media/24be91a9b7235e8655f55492055d85f0.jpeg)

测试代码

```
void setup()
{
    Serial.begin(9600);             //打开串口，设置串口波特率为 9600bps
}

void loop()
{
    int val;
    val = analogRead(0);            //将模拟压电陶瓷震动传感器连接到模拟接口 0
    
    Serial.print("Vibration is ");
    Serial.println(val, DEC);       //通过串口打印读取到的模拟值
    
    delay(100);
}
```

测试结果

当你检测到不同程度震动时，反馈回此时的测量值。如下图所示，此图是当将震动传

感器贴到 A4 纸中央上，绷直 A4 纸，敲击 A4一边，串口反馈回来的数据示意图。

![](media/da8ceb016664a169fdedf038f3446075.png)

## 相关资料链接地址

[https://pan.baidu.com/s/1pKIxC2B](https://pan.baidu.com/s/1pKIxC2B)





