《基于开源Arduino的数字系统设计》实验报告
Pomegranate20 一个小学生

课程情况概述

小组成员及课堂分工

姓名 学号 分工
刘诺鸿 2022303984
金徐辉

课程总目标

  1. 了解 Arduino 的基本原理和使用方法。
  2. 掌握使用 Arduino 进行数字系统设计的方法。
  3. 提高动手能力和实践能力。
  4. 培养团队协作精神。

实验一、太空船控制器

1. 实验目的

设计并制作一个 70 年代科幻电影中出现的“太空飞船控制中心”。 制作一块有开关和灯的控制面板, 通过按下开关改变灯的状态。通过 Arduino 的代码配置输入管脚检测开关闭合状态,配置输出引脚输出高低电压。学习掌握 Arduino 数字接口的相关知识。

2. 实验器材

实验材料名称 数量
Arduino UNO 1
面包板 1
开关 1
LED 灯 3
220 Ω 电阻 3
10 kΩ 电阻 1

3. 硬件电路及连接说明

1

连接面包板和 Arduino 的 5V 和地。放置两个红色 LED 和一个绿色 LED 在面包板上。将每个 LED 的负极(短引线)通过 220 欧姆电阻器连接到地。连接绿色 LED 的阳极(长引线)到管脚 3。分别连接两个红色 LED 的阳极到管脚 4和 5。放置一个开关在面包板上。一端连接到电源,另一端连接到 Arduino 的数字管脚 2。在开关连接到 Arduino 的那个管脚上增加一个 10 K 欧姆的电阻到地。

注意:连接 LED 灯时,要注意正负极。

4. 实验原理

Arduino 的数字管脚只能读取两种状态:有电压没有电压 。这种类型的输入一般叫数字信号输入。有电压和没有电压一般使用 HIGH (高电平)和 LOW (低电平)来表示(有时也用真假,数字1和0来表示高电平和低电平)。 HIGH 代表“有电压”。 LOW 代表“没有电压”。当想让一个输出管脚输出 HIGH ,需要使用digitalWrite()这个函数。当运行后,这个数字管脚与地之间有 5 V 的电压(电位差)。当让一个输出管脚输出 LOW ,则会关闭输出。

Arduino 的数字式管脚既可以作为输入,也可以作为输出。可以在代码中根据函数来配置它们。当管脚是输出时,可以使用它打开像LED这样的器件。如果配置管脚作为输入,能检查开关是否被按下。因为管脚 0 和 1 已经被用来和计算机通信,最好从管脚2开始使用。

5. 实验代码

graph TD;
    A(开始) --> B[初始化引脚模式]
    B --> C[读取按键状态]
    C --> D{按键被按下?}
    D -- 否 --> E[绿色LED点亮]
    E --> F[红色LED1熄灭]
    F --> G[红色LED2熄灭]
    G --> C
    D -- 是 --> H[执行相关亮灭操作]
    H --> C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
int switchState = 0; // 定义并初始化一个整型变量 switchState,用于存储按键状态

void setup() {
// 设置引脚模式
pinMode(3, OUTPUT); // 将引脚3设置为输出模式,用于控制绿色LED
pinMode(4, OUTPUT); // 将引脚4设置为输出模式,用于控制红色LED
pinMode(5, OUTPUT); // 将引脚5设置为输出模式,用于控制红色LED
pinMode(2, INPUT); // 将引脚2设置为输入模式,用于读取按键状态
}

void loop() {
// 读取按键状态
switchState = digitalRead(2); // 将引脚2的数字状态(按键状态)读取到 switchState 变量中

// 根据按键状态控制LED灯的亮灭
if (switchState == LOW) { // 如果按键没有被按下
digitalWrite(3, HIGH); // 点亮绿色LED(引脚3)
digitalWrite(4, LOW); // 熄灭红色LED(引脚4)
digitalWrite(5, LOW); // 熄灭红色LED(引脚5)
} else { // 如果按键被按下
digitalWrite(3, LOW); // 熄灭绿色LED(引脚3)
digitalWrite(4, LOW); // 熄灭红色LED(引脚4)
digitalWrite(5, HIGH); // 点亮红色LED(引脚5)
delay(250); // 延时四分之一秒

// 控制LED的闪烁
digitalWrite(4, HIGH); // 点亮红色LED(引脚4)
digitalWrite(5, LOW); // 熄灭红色LED(引脚5)
delay(250); // 延时四分之一秒
}
}//返回loop函数开始位置

6. 实验结果

f7d74864ed75a476c97bfd09f1bd0b9d

实验二、爱情传感器

1. 实验目的

当遇见女神/男神心跳加速,体温上升;测量你手指的温度,按照高于环境温度的程度依次亮起 LED 灯;了解测温传感器 TMP36 (温度传感器的输出电压按照摄氏温度的一定比例变化);学习掌握 Arduino 实现 A/D 转换的知识。

2. 实验器材

实验材料名称 数量
Arduino UNO 1
面包板 1
温度传感器 TMP36 1
LED 灯 3
220 Ω 电阻 3

3. 硬件电路及连接说明

2

将每个LED的负极(短引线)通过一个220欧姆的电阻器连接到地。分别连接LED的阳极到管脚2至4,其在工程中充当指示器。将 TMP36 放置在面包板上,保持圆形那面背对Arduino,如图 2所示。连接平面那边的左侧引线到电源,右侧引线到地。连接中间的引线到 Arduino 的 A0 管脚。这是模拟输入管脚 0 。

注意:LED 灯的正负极、TMP36 的引脚对应位置。

4. 实验原理

即使Arduino是一个数字工具,它也能够从模拟传感器获取例如温度或光照强度等测量信息。要实现这一点,我们需要使用Arduino内置的模数转换器(ADC)。模拟引脚 A0 至 A5 能够提供0至1023范围内的数值,这些数值可以对应映射到0伏至5伏的电压范围内。

我们将使用一个温度传感器来测量皮肤的温度。这种传感器会根据检测到的温度变化输出不同的电压值。它具有三个引脚:一个连接到地线,另一个连接到电源,第三个则输出一个变化的电压至 Arduino 。在这个项目中,我们将读取传感器的输出电压,并利用这个电压来控制 LED 的亮灭,以此表示温度的变化。市面上有多种类型的温度传感器,其中 TMP36 因其输出电压与摄氏度温度成正比的特性而非常方便使用。

Arduino IDE内置了一个名为串口监视器的工具,它允许我们从微控制器接收反馈信息。通过串口监视器,我们可以获取传感器状态的实时信息,并了解在代码运行过程中电路的工作情况。

5. 实验代码

graph TD;
    A(开始) --> B[初始化串口通信]
    B --> C[设置引脚2到引脚4为输出,
并置为低电平]
    C --> E[读取、打印传感器值]
    E --> G[转换为电压值]
    G --> I[转化为温度值]
    I --> J{温度区间}
    J -- <20℃ --> K[熄灭所有LED]
    J -- 20℃-22℃ --> L[点亮LED1]
    L --> M[熄灭LED2和LED3]
    J -- 22℃-24℃ --> N[点亮LED1和LED2]
    N --> O[熄灭LED3]
    J -- >24℃ --> P[点亮所有LED]
    K --> Q[延时1ms]
    M --> Q
    O --> Q
    P --> Q
    Q --> E
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
const int sensorPin = A0;  // 定义传感器连接的引脚为A0
const float baselineTemp = 20.0; // 定义基准温度为20.0摄氏度

void setup() {
Serial.begin(9600); // 初始化串口通信,波特率为9600
for (int pinNumber = 2; pinNumber < 5; pinNumber++) { // 循环设置引脚2到引脚4为输出,并置为低电平
pinMode(pinNumber, OUTPUT);
digitalWrite(pinNumber, LOW);
}
}

// loop函数会一直循环执行
void loop() {
int sensorVal = analogRead(sensorPin); // 读取传感器的值
Serial.print("Sensor Value:"); // 打印文本
Serial.print(sensorVal); // 打印传感器的值
float voltage = (sensorVal / 1024.0) * 5.0; // 将传感器值转换为电压值
Serial.print(", Volts:"); // 打印文本
Serial.print(voltage); // 打印电压值
Serial.print(", degrees c:"); // 打印文本
// 将电压值转换为以摄氏度为单位的温度值
float temperature = (voltage-0.5) * 100;
Serial.println(temperature); // 打印温度值并换行

// 根据温度值控制LED的状态,温度每升高2度,就多亮1个LED灯(温度区间左闭右开)
if (temperature < baselineTemp) { // 如果温度低于基准温度(<20℃)
digitalWrite(2, LOW); // 将引脚2置为低电平,灯灭
digitalWrite(3, LOW); // 将引脚3置为低电平,灯灭
digitalWrite(4, LOW); // 将引脚4置为低电平,灯灭
} else if (temperature >= baselineTemp + 2 && temperature < baselineTemp + 4) { // 如果温度在基准温度加2到基准温度加4之间(22~24℃)
digitalWrite(2, HIGH); // 将引脚2置为高电平,灯亮
digitalWrite(3, LOW); // 将引脚3置为低电平,灯灭
digitalWrite(4, LOW); // 将引脚4置为低电平,灯灭
} else if (temperature >= baselineTemp + 4 && temperature < baselineTemp + 6) { // 如果温度在基准温度加4到基准温度加6之间(24~26℃)
digitalWrite(2, HIGH); // 将引脚2置为高电平,灯亮
digitalWrite(3, HIGH); // 将引脚3置为高电平,灯亮
digitalWrite(4, LOW); // 将引脚4置为低电平,灯灭
} else if (temperature >= baselineTemp + 6) { // 如果温度高于基准温度加6(>26℃)
digitalWrite(2, HIGH); // 将引脚2置为高电平,灯亮
digitalWrite(3, HIGH); // 将引脚3置为高电平,灯亮
digitalWrite(4, HIGH); // 将引脚4置为高电平,灯亮
}
delay(1); // 延时1毫秒
}

6. 实验结果

087094b29cb62b863dee238ab014ac4

实验三、混色灯

1. 实验目的

测量红绿蓝三原色的亮度值;根据测量得出的亮度值来改变红绿蓝 LED 的亮度。了解混色光敏电阻-光线传感器、RGB 三色 LED 管;通过改变电压的高低,实现 LED 亮度的改变;学习了解 PWM ,即脉冲宽度调制。

2. 实验器材

实验材料名称 数量
Arduino UNO 1
面包板 1
4 引线 LED(RGB) 1
光敏电阻 3
220 Ω 电阻 3
10 kΩ 电阻 3

3. 硬件电路及连接说明

6

在面包板上布置三个光敏电阻,确保它们的两个引脚分别位于面包板的两侧,如图所示。将光敏电阻的一个引脚连接到电源,另一个引脚通过一个10千欧姆的电阻连接到地。这个电阻与光敏电阻串联,它们共同构成一个分压器。根据欧姆定律,连接点的电压会按照它们电阻的比例进行分配。当光敏电阻表面受到的光照发生变化时,其电阻值也会随之变化,进而导致连接点的电压发生变化。将光敏电阻与电阻同一侧的引脚通过导线连接到模拟引脚 0、1和2 。

分别用三种颜色的塑料片覆盖在光敏电阻的表面。将红色塑料片覆盖在连接到A0引脚的光敏电阻上,绿色塑料片覆盖在连接到A1引脚的光敏电阻上,蓝色塑料片覆盖在连接到A2引脚的光敏电阻上。每种塑料片只允许与其颜色相对应的特定波长的光线通过,例如红色塑料片只允许红光通过,绿色塑料片只允许绿光通过,蓝色塑料片只允许蓝光通过。这样就可以检测出照射在传感器上的光的组成。

注意:将 LED 最长的引线插入面包板并连接到地,将另外三条引线分别通过220欧姆的电阻对应接到数字引脚9、10和11。

4. 实验原理

Arduino不能改变输出管脚的电压,它只能输出 5V。 因此我们将需要使用一个称为脉冲宽度调制( PWM )的技术来改变LED的亮度。PWM 在一个固定的周期内快速地改变输出管脚的高低电平,其改变速度比人眼所能观察到的要快得多。它和电影工作的原理是相似的,即利用快速变化的静止图片来创造运动的错觉。

迅速地改变管脚的电平可以实现我们改变输出电压的目的,进而调整 LED 的亮度。在一个周期中管脚电压高电平的时间所占的比例被称为占空比。Arduino Uno 有6个管脚可以被用来作为 PWM (数字管脚3,5,6,9,10和17)。在这个项目中,我们将使用光敏电阻(一种根据照射到它们表面的光强度来改变自身电阻的传感器)作为输入。如果我们将光敏电阻的一端连接到 Arduino 上,我们将可以通过检查管脚上的电压值来测试光敏电阻的阻值变化。

该实验中所使用的 4引线 LED 具有4条引线,是一个共阴极 RGB LED。它内部包含独立的红色、绿色和蓝色发光元件,以及一个共用的地线(负极)。通过调整 Arduino 的 PWM (脉冲宽度调制)引脚(通过220欧姆的电阻接到阳极)与阴极之间的电压,可以控制LED三种颜色光线的亮度。

5. 实验代码

graph TD;
    A(开始) --> B[初始化串行通信]
    B --> C[设置LED引脚
为输出模式]
    C --> D[读取红绿蓝
三个传感器的值]
    D --> I[输出原始传感器数值]
    I --> J[将传感器值缩小四倍]
    J --> L[输出映射后的传感器值,
设置LED亮度]
    L --> D
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//定义引脚变量,光敏电阻上放对应颜色的塑料片来充当传感器
const int greenLEDPin = 9; // 绿色LED的数字引脚
const int redLEDPin = 11; // 红色LED的数字引脚
const int blueLEDPin = 10; // 蓝色LED的数字引脚
const int redSensorPin = A0; // 红色光线传感器的模拟引脚
const int greenSensorPin = A1; // 绿色光线传感器的模拟引脚
const int blueSensorPin = A2; // 蓝色光线传感器的模拟引脚
//电压值变量
int redValue = 0; // 存储红色值的变量
int greenValue = 0; // 存储绿色值的变量
int blueValue = 0; // 存储蓝色值的变量
int redSensorValue = 0; // 存储红色光线传感器读数的变量
int greenSensorValue = 0; // 存储绿色光线传感器读数的变量
int blueSensorValue = 0; // 存储蓝色光线传感器读数的变量

void setup() {
Serial.begin(9600); // 初始化串行通信,设置波特率为9600
pinMode(greenLEDPin, OUTPUT); // 设置绿色LED引脚为输出模式
pinMode(redLEDPin, OUTPUT); // 设置红色LED引脚为输出模式
pinMode(blueLEDPin, OUTPUT); // 设置蓝色LED引脚为输出模式
}

// 主循环,会一直运行
void loop() {
redSensorValue = analogRead(redSensorPin); // 读取红色光线传感器值
delay(5); // 延迟5毫秒
greenSensorValue = analogRead(greenSensorPin); // 读取绿色光线传感器值
delay(5); // 延迟5毫秒
blueSensorValue = analogRead(blueSensorPin); // 读取蓝色光线传感器值
Serial.print("Raw Sensor Values \t Red:"); // 输出原始传感器数值,红色部分
Serial.print(redSensorValue); // 输出红色光线传感器数值
Serial.print("\t Green:"); // 输出原始传感器数值,绿色部分
Serial.print(greenSensorValue); // 输出绿色光线传感器数值
Serial.print("\t Blue:"); // 输出原始传感器数值,蓝色部分
Serial.println(blueSensorValue); // 输出蓝色光线传感器数值并换行

redValue = redSensorValue / 4; // 将红色光线传感器值缩小四倍
greenValue = greenSensorValue / 4; // 将绿色光线传感器值缩小四倍
blueValue = blueSensorValue / 4; // 将蓝色光线传感器值缩小四倍
//打印新的映射值(即上面缩小后所得的值)
Serial.print("Mapped Sensor Values \t Red:"); // 输出映射后的光线传感器数值,红色部分
Serial.print(redValue); // 输出映射后的红色数值
Serial.print("\t Green:"); // 输出映射后的光线传感器数值,绿色部分
Serial.print(greenValue); // 输出映射后的绿色数值
Serial.print("\t Blue:"); // 输出映射后的光线传感器数值,蓝色部分
Serial.println(blueValue); // 输出映射后的蓝色数值并换行
//设置LED光线亮度
analogWrite(redLEDPin, redValue); // 控制红色LED亮度
analogWrite(greenLEDPin, greenValue); // 控制绿色LED亮度
analogWrite(blueLEDPin, blueValue); // 控制蓝色LED亮度
}

6. 实验结果

image-20240623235851511

实验四、心情指示器

1. 实验目的

根据可变电位器的值来改变舵机的旋转角度;了解一种分压器件:可变电位器;掌握 Arduino 实现舵机控制的方法。

2. 实验器材

实验材料名称 数量
Arduino UNO 1
面包板 1
100µf 电容器 2
可变电位器 1
舵机 1

3. 硬件电路及连接说明

5

将 Arduino 的5V和地(GND)连接到面包板的一侧。在面包板上放置一个可变电位器,并将电位器的一个引脚连接到5V,另一个引脚连接到地(GND)。

舵机具有三根引线:一根是电源线(通常为红色),一根是地线(通常为黑色),第三根是控制线(通常为白色),它将接收来自Arduino的控制信号。将三个公端排针插入舵机线路的母端(参考图3),并将这些排针连接到面包板上,确保每个引脚位于不同的行。将 5V 连接到红色导线,地连接到黑色导线,同时将白色导线连接到数字引脚9。

当舵机启动时,它会比正常运行时消耗更多的电流,这可能导致板子上的电压下降。为了使可能发生的所有电压波动更加平稳,可以在公端排针右侧的电源和地之间并联一个100μF电容器(如图1所示)。同样,我们也可以在电位器的电源和地之间并联一个电容器。这些电容器用于减少或分离其他电路造成的波动,因此被称为去耦电容。

注意:连接电容时,要注意正负极(长正短负),否则可能会爆炸。

4. 实验原理

舵机是一种特殊的马达,不是整周旋转,而是移动到一个具体位置并且固定那里,直到其再次接收到移动的指令。舵机通常只转动 180 度(半圈)。电位器是一种分压器,当转动其旋钮时,可以改变中间引脚上的电压比例,从而经过映射,能够调整模拟信号输入引脚0的电压。利用这个原理,可以实现对于舵机位置的控制。

在制作彩色混合灯时,我们可以通过对发光二极管(LED)进行脉冲宽度调制(PWM)来控制其亮度。同样,舵机也需要接收脉冲信号来指示它们应该转动到哪个角度。这些脉冲信号以固定的间隔发送,但其宽度会在1000微秒到2000微秒之间变化。

我们可以编写代码来生成这些脉冲,而且 Arduino 软件提供了 Servo 库,使得控制舵机变得更加简单。由于舵机的转动范围限制在180度,而模拟信号的输入范围是0到1023,因此我们需要使用一个名为map()的函数来调整从电位器读取的值,以适应这个范围。

5. 实验代码

graph TD;
    A(开始) --> B[初始化舵机和串行通信]
    B --> C[读取模拟输入引脚值]
    C --> D[输出模拟输入值]
    D --> E[将输入值映射到角度]
    E --> F[输出角度值]
    F --> G[将舵机转到映射角度]
    G --> H[延迟15ms]
    H --> C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <Servo.h> // 导入 Servo 库,用于控制舵机
Servo myServo; // 创建 Servo 库的对象 myServo
int const potPin = A0; // 声明并初始化常量 potPin,用于存储模拟输入的引脚 A0
int potVal; // 声明变量 potVal,用于存储模拟输入的数值
int angle; // 声明变量 angle,用于存储舵机的角度

void setup(){
myServo.attach(9); // 将舵机连接到数字引脚 9
Serial.begin(9600); // 初始化串行通信,波特率为 9600
}
//在loop()函数中,读取模拟信号输入值并且把它打印到串口监视器。
void loop(){
potVal = analogRead(potPin); // 读取模拟输入引脚 A0 的数值,并存储到变量 potVal 中
Serial.print("potVal:"); // 输出字符 "potVal:"
Serial.print(potVal); // 输出变量 potVal 的值
angle = map(potVal, 0, 1023, 0, 179); // 将 potVal 的值从范围 [0, 1023] 按比例映射到 [0, 179],并存储到变量 angle 中
Serial.print(",angle:"); // 输出字符 ",angle:"
Serial.println(angle); // 输出变量 angle 的值,并换行
myServo.write(angle); // 将舵机转到角度 angle
delay(15); // 延迟 15 毫秒
}

6. 实验结果

fdf7389b6304ce085d3f -small-original

实验五、电动纸风车

1. 实验目的

使用开关控制马达的开启,按下开启,松开停止;学习驱动马达电机、判断直接使用 IO 口是否可行;了解控制大功率用电器的常用解决方案:嵌入式处理器的 IO 口通常只有几十毫安,无法直接驱动马达,需使用继电器或者晶体管,由单片机的 IO 口控制继电器或晶体管的通断;了解马达断电后的反向电动势,可通过反向并联一个二极管消除,连接感性负载时注意反向电动势的影响。

2. 实验器材

实验材料名称 数量
Arduino UNO 1
面包板 1
10 kΩ 电阻 1
按键开关 1
马达 1
9V电源 1
晶体管 1
二极管 1

3. 硬件电路及连接说明

3

首先,通过Arduino将电源和地连接到面包板上。然后,在面包板上增加一个瞬时开关,并将开关的一端连接到电源,另一端连接到Arduino的数字管脚2。在开关的输出端添加一个10KΩ的下拉电阻,连接到地。

当我们在电路中使用不同电压的电源时,需要将它们的地线连接在一起,以形成一个共地。将9V电池夹固定在面包板上,并使用跳线将电池的地线和面包板的地线相连,如示意图1所示。接着,将电机的空闲引脚连接到9V电源。

接下来,将晶体管放置在面包板上。确保在查看元件时,晶体管的金属片朝向我们。将Arduino的数字管脚9连接到晶体管的左侧管脚,这个管脚称为栅极。栅极上的电压变化会影响晶体管其他两个管脚之间的电路连接。将电机的一端连接到晶体管的中间管脚,这个管脚称为漏极。当 Arduino 向栅极提供电压以激活晶体管时,漏极将与第三个管脚(称为源极)导通。将源极连接到地。

然后,将电机的电源线连接到电机和面包板上。最后增加的元件是二极管。二极管是一个具有单向导电性的元件。注意二极管的一端带有条纹,这是二极管的负极(或阴极),另一端是正极(或阳极)。将二极管的阳极连接到电机的地线,阴极连接到电机的电源线。如示意图1所示,这看起来可能不正确,但实际上是为了防止电机产生的所有反向电压进入我们的电路。请记住,反向电压的方向与我们提供的电压方向相反。

注意:连接 二极管时,要注意正负极。要注意共地。

4. 实验原理

晶体管是一种半导体器件,它允许我们使用Arduino的微小电流输出来控制较大的电流和高电压电源。尽管晶体管有多种类型,但它们的基本原理是相同的。可以将晶体管想象成一个数字开关。当向晶体管的栅极管脚提供电压时,它将控制源极和漏极之间的电路连接。这样,我们就可以使用Arduino来控制大电流或高电压的电机了。

电机是一种利用电磁感应原理工作的装置。电磁感应是通过改变导线中的电流来在导线周围产生变化磁场的过程。当电机通电时,内部的铜线圈就会产生一个磁场。这个磁场使得传动轴旋转起来。

5. 实验代码

graph TD;
A(开始) --> B[设置 motorPin 为输出]
B --> C[设置 switchPin 为输入]
C --> D[读取开关状态到 switchState]
D --> E{switchState == HIGH?}
E -- 是 --> F[启动电机]
E -- 否 --> G[关闭电机]
F & G --> H[等待一段时间]
H --> D
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const int switchPin = 2; // 声明一个常量整型变量 switchPin,其值为 2,表示开关引脚连接到 Arduino 的第 2 号引脚
const int motorPin = 10; // 声明一个常量整型变量 motorPin,其值为 9,表示电机引脚连接到 Arduino 的第 9 号引脚
int switchState = 0; // 声明一个整型变量 switchState,用于存储开关的状态,初始化为 0

void setup() {
pinMode(motorPin, OUTPUT); // 设置 motorPin 引脚为输出模式,用于控制电机
pinMode(switchPin, INPUT); // 设置 switchPin 引脚为输入模式,用于读取开关状态
}

void loop() {
switchState = digitalRead(switchPin); // 读取开关引脚的状态,将状态值存储到 switchState 变量中

if (switchState == HIGH) { // 如果开关状态为高电平(即开关打开)
digitalWrite(motorPin, HIGH); // 将电机引脚输出高电平,启动电机

} else { // 如果开关状态为低电平(即开关关闭)
digitalWrite(motorPin, LOW); // 将电机引脚输出低电平,关闭电机
}
}

6. 实验结果

66710e5ec89cd97daca0d0d35cd1547f

实验六、幻影箱

1. 实验目的

在互联网、电视甚至电影出现之前,一些早期的动态影像是通过一种称为幻影箱(Phantascope)的工具制作的。幻影箱利用一系列细微差别的静态图像来创造运动的错觉。这些图像通常被放置在一个带有裂缝的圆柱形筒体上。当筒体旋转时,通过裂缝观察对面的静态图案,会产生一种图案在移动的错觉。裂缝的作用是防止图像变得模糊,而筒体的旋转则让图像看起来像是在动。最初,这些新奇的设备是手动旋转的,或者使用一个手摇装置来驱动。

在本次实验中,我们使用一个开关来控制电机的启动和旋转方向;使用一个电位器来调节电机的转速;通过调整电压的大小来控制电机的转速;利用 PWM(脉冲宽度调制)输出来控制转速;通过改变电压的极性来控制电机的旋转方向;使用晶体管来控制电机的启动和电压极性;最后,使用H桥芯片 L293D 来驱动电机,这个芯片包含了驱动晶体管和反向二极管。

2. 实验器材

实验材料名称 数量
Arduino UNO 1
面包板 1
10 kΩ 电阻 1
9V电源 1
马达 1
电位器 1
H 桥芯片 1
瞬时开关 2

3. 硬件电路及连接说明

4

首先,我们将面包板的电源和地连接到Arduino。接下来,我们在面包板上增加两个瞬时开关,并将每个开关的一侧连接到电源。在每个开关的输出端串联一个10KΩ的电阻至地。连接到Arduino管脚4的开关用于控制电机的旋转方向,而连接到管脚5的开关控制电机的电源。

然后,我们将一个电位器连接到面包板。电位器的一端连接到5V,另一端连接到地。中间的管脚连接到Arduino的模拟输入管脚0,这将用于控制电机的转速。将H桥放置在面包板上,确保它横跨面包板的中线(具体细节参见图2)。H桥的管脚1连接到Arduino的数字管脚9,这是H桥的使能管脚。接收到5V电压时,它将驱动电机;接收到0V电压时,它将停止电机。我们可以使用这个管脚来调整H桥的电压,进而调整电机的转速。H桥的管脚2连接到Arduino的数字管脚3,管脚7连接到数字管脚2。这些管脚用于与H桥通信,指示电机的旋转方向。如果管脚3为低电平且管脚2为高电平,电机将朝一个方向旋转。如果管脚2为低电平且管脚3为高电平,电机将朝相反方向旋转。如果两个管脚同时为高电平或低电平,电机将停止转动。H桥从管脚16获取电源,请将它连接到面包板的SV。将管脚4和管脚5连接到地。电机连接到H桥的管脚3和6。这两个管脚将根据发送到管脚2和7的信号来导通或关断。

最后,我们将一个未连接电池的电池夹插入面包板上的其他电源网格。将Arduino的地连接到电池的地上。H桥的管脚8连接到电池电源,这是H桥驱动电机的能量来源。

注意:共地连接、芯片方向(观察缺口位置)。

4. 实验原理

在这个项目中,我们将亲手制作自己的幻影箱。我们将用一个电机来驱动它旋转。

为了让这个系统更加高级,我们会增添一些控制功能:一个开关用于控制电机的旋转方向,另一个开关用于控制电机的电源供应,还有一个电位器用来调节电机的转速。在电动纸风车项目中,电机只能单向旋转。如果我们改变电机的电源和地线,电机就会反向旋转。然而,手动改变电机的旋转方向在实际操作中并不方便,因此我们将使用一种名为H桥的装置来实现这一功能。H桥是一种集成电路芯片(IC)。集成电路是一种将大量电路集成在一个小封装内的器件。它们便于安装,并且能够简化复杂的电路设计。

我们可以通过 IC 外部的引脚来访问其内部的电路。不同的 IC 有不同的引脚数量,但并非所有引脚都会在电路中使用。有时,使用数字而非功能来标识这些引脚更为方便。观察 IC 时,有凹槽的一面是顶部。我们可以通过从左上角开始,沿着U型方向计数来识别引脚编号。

5. 实验代码

graph TD;
    A(开始) --> B[初始化设置]
    B --> C{主循环}
    C --> D[读取电机开关状态]
    D --> E[读取电机方向开关状态]
    E --> F[读取电位器输入值]
    F --> G{电机开关状态改变?}
    G -- 是 --> H{电机开关打开?}
    H -- 是 --> I[切换电机使能状态]
    H -- 否 --> J[保持电机使能状态]
    G -- 否 --> J
    J --> K{电机方向开关状态改变?}
    K -- 是 --> L{电机方向开关被触发?}
    L -- 是 --> M[切换电机方向]
    L -- 否 --> N[保持电机方向]
    K -- 否 --> N
    N --> O{电机方向}
    O -- 正向 --> P[设置控制引脚1高电平, 引脚2低电平]
    O -- 反向 --> Q[设置控制引脚1低电平, 引脚2高电平]
    P & Q --> R{电机使能状态}
    R -- 开启 --> S[调节电机速度]
    R -- 关闭 --> T[关闭电机]
    S & T --> U[更新上次开关状态]
    U --> V[更新上次方向状态]
    V --> C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
const int controlPin1 = 2;  // 定义控制电机方向的引脚1
const int controlPin2 = 3; // 定义控制电机方向的引脚2
const int enablePin = 9; // 定义电机使能引脚
const int directionSwitchPin = 4; // 定义电机方向开关引脚
const int onOffSwitchStateSwitchPin = 5; // 定义电机开关状态开关引脚
const int potPin = A0; // 定义电位器输入引脚
int onOffSwitchState = 0; // 存储电机开关状态
int previousOnOffSwitchState = 0; // 存储上一个电机开关状态
int directionSwitchState = 0; // 存储电机方向开关状态
int previousDirectionSwitchState = 0; // 存储上一个电机方向开关状态
int motorEnabled = 0; // 存储电机使能状态
int motorSpeed = 0; // 存储电机速度
int motorDirection = 1; // 存储电机方向,默认为正向

void setup() {
pinMode(directionSwitchPin, INPUT); // 设置电机方向开关引脚为输入模式
pinMode(onOffSwitchStateSwitchPin, INPUT); // 设置电机开关状态开关引脚为输入模式
pinMode(controlPin1, OUTPUT); // 设置控制电机方向引脚1为输出模式
pinMode(controlPin2, OUTPUT); // 设置控制电机方向引脚2为输出模式
pinMode(enablePin, OUTPUT); // 设置电机使能引脚为输出模式
digitalWrite(enablePin, LOW); // 将电机使能引脚初始化为低电平
}

void loop() {
onOffSwitchState = digitalRead(onOffSwitchStateSwitchPin); // 读取电机开关状态
delay(1); // 等待1毫秒,防止读取到不稳定的值
directionSwitchState = digitalRead(directionSwitchPin); // 读取电机方向开关状态
motorSpeed = analogRead(potPin) / 4; // 读取电位器输入值,并将其映射到0-255范围内

if (onOffSwitchState != previousOnOffSwitchState) { // 如果电机开关状态改变
if (onOffSwitchState == HIGH) { // 如果电机开关打开
motorEnabled = !motorEnabled; // 切换电机使能状态
}
}

if (directionSwitchState != previousDirectionSwitchState) { // 如果电机方向开关状态改变
if (directionSwitchState == HIGH) { // 如果电机方向开关处于高电平(被触发)
motorDirection = !motorDirection; // 切换电机方向
}
}

if (motorDirection == 1) { // 如果电机方向为正向
digitalWrite(controlPin1, HIGH); // 设置控制电机方向引脚1为高电平
digitalWrite(controlPin2, LOW); // 设置控制电机方向引脚2为低电平
} else { // 否则(电机方向为反向)
digitalWrite(controlPin1, LOW); // 设置控制电机方向引脚1为低电平
digitalWrite(controlPin2, HIGH); // 设置控制电机方向引脚2为高电平
}

if (motorEnabled == 1) { // 如果电机使能状态为开启
analogWrite(enablePin, motorSpeed); // 控制电机使能引脚输出对应的PWM信号,调节电机速度
} else { // 否则(电机使能状态为关闭)
analogWrite(enablePin, 0); // 将电机使能引脚输出PWM信号设置为0,关闭电机
}

previousDirectionSwitchState = directionSwitchState; // 更新上一个电机方向开关状态
previousOnOffSwitchState = onOffSwitchState; // 更新上一个电机开关状态
}

6. 实验结果

c5a93a9d2f7d6732f57aed905b55b85b

实验七、触摸感应灯

1. 实验目的

本项目旨在通过 CapacitiveSensor 库实现电容式触摸按键的构建,并利用该按键控制LED灯的亮灭。 CapacitiveSensor 库由Paul Badger 编写,能够测量人体与金属物体接触时的电容变化。电容是衡量物体存储电荷能力的一种物理量,而本项目中,Arduino的两个管脚——发送管脚和接收管脚——将用于检测人体靠近时电容的变化。

2. 实验器材

实验材料名称 数量
Arduino UNO 1
面包板 1
220 Ω 电阻 1
10 M Ω 电阻 1
LED 1
触摸传感器^1 1

3. 硬件电路及连接说明

image-vmake (3)

连接一个 LED 到管脚 12 ,然后将负极通过一个 220Ω 的电阻连接到地。连接数字管脚 2 和 4 到面包板。这两个管脚中间连接一个 1MΩ 的电阻。从面包板上与管脚 2 相同的那行接出一条 8-10 厘米以上的导线,另外一端什么都不接。这将成为您的触摸传感器。

注意:连接 LED 灯时,要注意正负极。 在这个项目中没有必要为您的面包板提供 5V 电源。数字管脚为传感器提供电流。

4. 实验原理

电容式触摸按键基于人体电场效应,当人体接近金属物体时,人体会吸收部分电荷,从而影响Arduino管脚达到相同状态所需的时间。将Arduino的发送管脚和接收管脚连接至金属物体,如铝板,以形成电容式触摸传感器。本项目将采用电容式触摸按键电路,与电阻式触摸按键相比,电容式具有实现多点触控的优势,尽管其精度相对较低。当电容式触摸按键被人体接触时,Arduino将检测到电容的变化,并据此控制LED灯的亮灭状态:触摸时亮灯,未触摸时灭灯。在软件层面,我们将使用”CapacitiveSensor”库来读取电容值,并根据读数控制LED灯的状态。

5. 实验代码

graph TD;
    A[开始] --> B[初始化设置]
    B --> C{主循环}
    C --> D[通过电容传感器获取电容值]
    D --> E[在串口上打印传感器读数]
    E --> F{电容值大于阈值?}
    F -- 是 --> G[点亮LED]
    F -- 否 --> H[关闭LED]
    G & H --> I[延迟10毫秒]
    I --> C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <CapacitiveSensor.h> // 导入 CapacitiveSensor 库,用于电容传感器
CapacitiveSensor capSensor = CapacitiveSensor(4, 2);
// 创建一个 CapacitiveSensor 对象,将 4 号引脚连接到发送端,2 号引脚连接到接收端

int threshold =1000; // 设置阈值为 1000

const int ledPin = 12; // 将 12 号引脚定义为 LED 控制引脚

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

void loop() {
long sensorValue = capSensor.capacitiveSensor(30); // 通过电容传感器获取电容值,30 是想要读取的采样数量
Serial.println(sensorValue); // 在串口上打印传感器读数

if (sensorValue > threshold) { // 如果电容值大于阈值
digitalWrite(ledPin, HIGH); // 点亮 LED
} else { // 如果小于阈值
digitalWrite(ledPin, LOW); // 关闭 LED
}
delay(10); // 延迟 10 毫秒
}

6. 实验结果

ecbd976652989b98778e -small-original

实验八、水晶球

1. 实验目的

随机在液晶屏上显示预先定义的字符,每晃动一下变化一次,利用倾斜开关或者加速度计实现对晃动的感知;将液晶视为一个存储器件,实现液晶屏的显示;通过数据总线写入即可显示字符;使用 LiquidCrystal 库实现复杂的数据写入操作。

2. 实验器材

实验材料名称 数量
Arduino UNO 1
面包板 1
倾斜开关 1
220 Ω 电阻 1
10 kΩ 电阻 1
电位器 1
LCD 屏 1

3. 硬件电路及连接说明

image-vmake (2)

这个电路并不复杂,但涉及许多导线。在搭建电路时,我们要保持谨慎,确保连接正确。首先,将电源和地连接到旁边的面包板上。然后,放置一个倾斜开关到面包板上,并将一端连接到 5V 。另一端通过一个 10KΩ 的电阻连接到地,同时连接到 Arduino 的管脚6。我们将管脚6作为数字输入使用,这与我们在其他项目中的做法相同。

寄存器选择(RS)管脚控制字符将显示在屏幕上的哪个位置。读写管脚(R/W)决定屏幕的读写模式。在这个项目中,我们使用写模式。使能(EN)管脚通知 LCD 它将接收到一个指令。数据管脚(D0-D7)用来向屏幕发送字符数据。我们只需要使用4个数据管脚(D4-D7)。最后,有一个管脚用来调节显示的对比度。我们将使用一个电位器来控制它。

Arduino 软件自带的 LiquidCrystal 库处理这些管脚的所有写入操作,并简化了显示字符的编码过程。LCD的两个外部管脚(Vss和LED-)需要连接到地。同时,将R/W管脚连接到地,这将设置屏幕为写模式。将LCD的电源供应管脚(Vcc)直接连接到5V。将LED+管脚通过一个220Ω的电阻连接到电源。

接线方面:Arduino数字管脚2连接到LCD的 D7 ,数字管脚3连接到LCD的 D6 ,数字管脚4连接到LCD的 D5 ,数字管脚5连接到LCD的 D4 。这些数据管脚用来告诉屏幕显示什么字符。将LCD的 EN 管脚连接到Arduino的管脚 11 。将LCD的RS管脚连接到Arduino的管脚 12 ,这个管脚使能写入 LCD 。

在面包板上放置一个电位器,一端连接到电源,另一端连接到地。中间的管脚连接到LCD的 V0 管脚。这将允许我们改变屏幕的对比度。

4. 实验原理

LCD通过改变两个极化滤光片之间的液晶的电子属性来工作。滤光片仅允许特定种类的光通过。当滤光片之间的液晶被加压ben后,它将开始进入半固体状态。这个新状态的方向和极化滤光片的方向不同,将会阻止光线通过,因此创造了在屏幕上看到的字符。本项目中使用的LCD屏幕16列2行,能够显示32个字符的东西。它有非常多的管脚。这些管脚被用来供电和通信,以便它知道在屏幕上显示什么,不过您不需要连接所有管脚。管脚连接方式见图。

img

利用倾斜开关(内部带有一颗滚珠)控制电路的通断,当开关高于水平位置倾斜时开关导通,低于水平位置时开关断开。

5. 实验代码

graph TD;
    A(开始) --> B[初始化设置]
    B --> C{主循环}
    C --> D[读取开关状态]
    D --> E{开关状态改变?}
    E -- 否 --> F[保持当前显示]
    E -- 是 --> G{开关状态为低电平?}
    G -- 否 --> F
    G -- 是 --> H[生成随机数reply]
    H --> I[清除LCD显示]
    I --> J[显示'The ball says:'']
    J --> K{reply值}
    K -- 0 --> L[显示'Yes']
    K -- 1 --> M[显示'Most likely']
    K -- 2 --> N[显示'Certainly']
    K -- 3 --> O[显示'Outlook good']
    K -- 4 --> P[显示'Unsure']
    K -- 5 --> Q[显示'Ask again']
    K -- 6 --> R[显示'Doubtful']
    K -- 7 --> S[显示'No']
    L & M & N & O & P & Q & R & S --> T[更新上次开关状态]
    T --> C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <LiquidCrystal.h>  // 导入 LiquidCrystal(即液晶) 库 

LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // 使用 LiquidCrystal 库创建 lcd 对象,指定引脚 12、11、5、4、3、2

const int switchPin = 6; // 定义开关接收的引脚为 6
int switchState = 0; // 初始化开关状态变量为 0
int preSwitchState = 0; // 初始化上一次开关状态变量为 0
int reply; // 声明变量 reply,用于存储回复信息

void setup() {
lcd.begin(16, 2); // 初始化 LCD 显示器,设置列数为 16,行数为 2
pinMode(switchPin, INPUT); // 设置开关引脚为输入模式
lcd.print("Ask the"); // 在第一行显示 "Ask the"
lcd.setCursor(0, 1); // 设置光标位置为第二行开头
lcd.print("Crystal Ball"); // 在第二行显示 "Crystal Ball"
}

void loop() {
switchState = digitalRead(switchPin); // 读取开关状态并保存到 switchState 变量中
if (switchState != preSwitchState) { // 如果当前开关状态与上一次不同
if (switchState == LOW) { // 如果当前开关状态为低电平(按下)
reply = random(8); // 生成一个随机数,范围在 0 到 7 之间,并保存到 reply 变量中
lcd.clear(); // 清除 LCD 显示内容
lcd.setCursor(0, 0); // 设置光标位置为第一行开头
lcd.print("The ball says:"); // 在第一行显示 "The ball says:"
lcd.setCursor(0, 1); // 设置光标位置为第二行开头
switch (reply) { // 根据 reply 的值进行不同的处理
case 0: //reply = 0 时
lcd.print("Yes"); // 在第二行显示 "Yes"
break;
case 1: //reply = 1 时
lcd.print("Most likely"); // 在第二行显示 "Most likely"
break;
case 2: //reply = 2 时
lcd.print("Certainly"); // 在第二行显示 "Certainly"
break;
case 3: //reply = 3 时
lcd.print("Outlook good"); // 在第二行显示 "Outlook good"
break;
case 4: //reply = 4 时
lcd.print("Unsure"); // 在第二行显示 "Unsure"
break;
case 5: //reply = 5 时
lcd.print("Ask again"); // 在第二行显示 "Ask again"
break;
case 6: //reply = 6 时
lcd.print("Doubtful"); // 在第二行显示 "Doubtful"
break;
case 7: //reply = 7 时
lcd.print("No"); // 在第二行显示 "No"
break;
}
}
}
preSwitchState = switchState; // loop()函数中做的最后一件事是更新上一次开关状态为当前状态,也就是将switchstate变量的值赋给prevSwitchstate变量。
//这可以在下个1oop循环中跟踪开关的状态变化。
}

6. 实验结果

1b3640a04b6c0a8e6a95518038c50c4c
 评论