五、Arduino项目实践
1. LED控制实例
在此实例中,我们将使用Arduino进行最基本的操作之一——点亮和关闭一个LED灯 。我们将学习如何使用数字输出来控制LED,以及如何通过编写代码来让LED闪烁 。
1.1 LED灯结构组成
LED 灯(发光二极管)是一种半导体光源,主要结构包括以下部分:
- 外壳:通常由塑料或玻璃制成,用于保护内部元件。
- 发光材料:LED 最核心的部分,由特殊半导体材料制成,例如:常见的 InGaN(氮化铟镓)或 AlInGaP(铝铟镓磷)。
- 芯片:用于产生光的发光二极管芯片。
- 引线:提供电连接的金属引线。
- 焊点:将LED 芯片与引线连接在一起的焊接点。
- 电极:负责连接半导体材料与外部电路,通常由金属制成。
- 反射腔:用于增强发光效果的一个结构,将发出的光反射到正面。
1.2 LED 灯发光原理
LED(发光二极管)发光原理基于半导体特性。在半导体中,存在着两类载流子:电子(n型半导体)和空穴(p型半导体)。当n型与p型半导体材料接触时,会在交界处形成一个层结。当施加适当的电压时,层结中空穴和电子可重组并释放能量。这个能量以光子的形式释放出来,产生光。
1.3 LED 灯驱动原理
LED 驱动指的是通过稳定的电源为 LED 提供合适的电流和电压,使其正常工作点亮。LED 驱动方式主要有恒流和恒压两种。限定电流的恒流驱动是最常见的方式,因为 LED 灯对电流敏感,电流大于其额定值可能导致损坏。恒流驱动保证了稳定的电流,从而确保了 LED 安全。 LED 灯的驱动比较简单,只需要给将对应的正负极接到单片机的正负极即可驱动。LED的接法也分有两种,灌入电流和输出电流。
- 灌入电流指的是LED的供电电流是由外部提供电流,将电流灌入我们的MCU; 风险是当外部电源出现变化时,可能会导致MCU的引脚被烧坏。
- 输出电流指的是由MCU提供电压电流,将电流输出给LED;如果使用 MCU的GPIO 直接驱动 LED,则驱动能力较弱,可能无法提供足够的电流驱动 LED。
需要注意的是LED 灯的颜色不同,对应的电压也不同 。电流不可过大,通常需要接入220欧姆到10K欧姆左右的限流电阻 ,限流电阻的阻值越大,LED的亮度越暗。
1.4 LED灯原理图
在开发板的原理图中,使用的是输出电流接法,但是输出的电流提供方,由开发板上的一个LM358芯片提供。
LM358是一款广泛使用的双通道运算放大器(op-amp)。它通常用于各种电子电路中,提供放大信号的功能。每个LM358芯片含有两个独立的运算放大器,这两个放大器在一个单一的IC封装内,并且能够独立运作。它因其高性价比、稳定性好、易于使用以及广泛的工作电压范围等优点而受到青睐。
以下电路我们以比较器的角度看待。在比较器配置中,运算放大器不是用来提供精确增益的线性放大,而是用作开关,这意味着它的输出只有两种状态:高电平(通常接近供电电压)或低电平(接近接地电压)。
在电路中,LM358被用作比较器,比较器的工作原理是:
- 当正相输入端(5脚+)的电压 高于 反相输入端(6脚-)时,运算放大器的输出(7脚)将会是高电平。
- 当正相输入端(5脚+)的电压 低于 反相输入端(6脚-)时,运算放大器的输出(7脚)将会是低电平。
而以下原理图中,反相输入端(6脚-)通过连接到输出端(7脚)形成了正反馈回路。对于比较器配置,这种连接形式会创建形成一个带迟滞的开关,这意味着输出状态的改变需要输入端之间有一个明显的电压差,这有助于稳定输出,防止噪声或输入端电压震荡造成的频繁切换。(关于正反馈电路这里不再介绍,请自行百度)
在实际应用中,LM358的这个配置将导致当GPIO输出电平高于输出端和反相输入端连接点电压时,LED会亮 ;当GPIO输出电平低于这个点电压时,LED就会熄灭 。由于存在迟滞,实际的熄灭电平可能会比亮灯时的电平稍微低一些。
原理图中的SCK为GPIO13,通过LED灯的驱动原理可以知道,我们只要控制开发板的GPIO13引脚输出高电平,即可点亮LED;
1.5 API介绍
在arduino中,可以通过调用 pinMode(pin, mode);
函数设置GPIO13引脚为输出模式,再通过 digitalWrite(pin, value);
函数设置GPIO13引脚输出高电平或者低电平即可;
1.6 设置引脚模式
pinMode()
是 Arduino 编程语言中的一个函数,用于设置指定引脚的工作模式。它的语法如下:
pinMode(pin,mode);
其中,pin
是要设置的引脚号;mode
是要设置的工作模式,模式可以是以下之一:
- INPUT: 将指定引脚设置为输入模式,用于接收外部信号或传感器数据。在此模式下,引脚会读取外部信号的电平。需要注意的是,在此模式下,引脚可能会处于悬空状态,导致不稳定的读数。为解决此问题,可以使用外部上拉或下拉电阻或者改为使用内置的上拉电阻(见下文)。
- INPUT_PULLUP: 将引脚设置为内置上拉输入模式。在此模式下,引脚连接到一个内部的上拉电阻,它会将悬空引脚保持在高电平状态。当外部电平为低电平时,读数会切换到LOW。
- OUTPUT: 将指定引脚设置为输出模式,用于发送电信号或控制外部设备。在此模式下,引脚可以输出高电平(HIGH)或低电平(LOW)。可用于驱动LED、继电器等外部设备。
- INPUT_PULLDOWN: 将引脚设置为内置下拉输入模式,在此模式下,Arduino会在输入端接入一个将引脚连接到地的电阻,以确保输入端始终处于低电平状态。当外部电路未连接或者处于高阻状态时,Arduino输入引脚会仍然保持在低电平状态。
使用 pinMode
函数的示例代码如下:
// 设置引脚 6 为输出模式
pinMode(6, OUTPUT);
// 设置引脚 2 为输入模式
pinMode(2, INPUT);
2
3
4
在以上示例中,第一个代码行将引脚 GPIO6 设置为输出模式,可以将其用作控制外部设备的引脚。第二个代码行将引脚 GPIO2 设置为输入模式,可以将其用作接收外部传感器的信号的引脚。
1.7 设置引脚输出
digitalWrite()
是 Arduino 编程语言中用于设置数字引脚电平的函数。它用来将数字引脚设置为 HIGH 或 LOW。当引脚设置为 OUTPUT 模式时,使用该函数可以改变引脚电平从而影响连接到该引脚的组件。
函数的语法为:
digitalWrite(pin, value);
这里:
pin
: 是你想要写入的数字引脚编号;value
: 是你要设置的电平,可以是HIGH
或LOW
。其中HIGH
表示高电平,LOW
表示低电平。
例如:
pinMode(13, OUTPUT); // 设置 13 引脚为输出模式
digitalWrite(13, HIGH); // 将数字 13 引脚输出设置为 HIGH(高电平)
2
在以上的示例中,第一行代码设置了 13 号引脚(GPIO13)为输出模式,然后第二行代码就可以将 13 号引脚的电平设置为 HIGH,这样在 13 号引脚上就会有3.3V 的电压输出。
要注意的是,如果没有首先使用
pinMode()
函数将引脚设置为 OUTPUT,调用digitalWrite()
函数可能不会产生任何效果。
❓数字引脚是什么?
数字引脚是微控制器(不限于 Arduino)或其他电子设备中的一种输入/输出(I/O)引脚。顾名思义,数字引脚处理的是二进制的,离散的电平,通常分为 HIGH(高电平,如 5V 或 3.3V)和 LOW(低电平,如 0V 或接地)。这些引脚的主要目的是与其他数字设备或组件进行通信、控制或检测。
1.8 Arduino编程步骤
- 打开Arduino IDE(集成开发环境)。
- 连接Arduino开发板到计算机的USB端口。
- 在IDE编写以下代码:
// 定义连接LED正极的Arduino引脚
const int ledPin = 13;
// setup函数在Arduino板重新启动时或者上电时运行
void setup()
{
// 设置ledPin引脚的模式为输出模式
pinMode(ledPin, OUTPUT);
}
// loop函数在setup运行之后持续循环运行
void loop()
{
// 打开LED
digitalWrite(ledPin, HIGH);
// 等待1000毫秒(1秒)
delay(1000);
// 关闭LED
digitalWrite(ledPin, LOW);
// 等待1000毫秒(1秒)
delay(1000);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- 在IDE中选择正确的Arduino板型和端口。注意,端口不是完全一样的,大家请根据自己开发板的端口进行连接,可以通过反复插拔确定是哪一个端口。
- 上传代码到Arduino板中(使用IDE的上传按钮)。
1.9 实例操作结果
当Arduino板接上电源并成功上传上述程序之后,该实例中的LED将开始以1秒间隔闪烁。即LED将点亮1秒钟,然后熄灭1秒钟,这个过程会不断重复。
这个简单的实验是学习电子和编程知识的良好开端,许多复杂的项目都是从像这样控制LED灯开始的。
2. 数字输入与输出实例
在本实例中,我们将实现一个简单的项目:当按下按钮时,一个LED灯会亮起。这个项目将教会你如何配置Arduino的数字输入和输出,并将展示如何在实际项目中使用它们。
材料清单
- 1 x ColorEasyDuino开发板
- 1 x 面包板
- 1 x LED灯
- 1 x 220Ω电阻
- 1 x 按钮
- 2 x 10kΩ电阻(用于按钮的上拉电阻,非必须,但是推荐)
- 跳线若干
2.1 独立按键基础知识
独立按键是一种简单的输入设备,广泛应用于各种电子设备中,用于实现基本的用户交互。它们的工作原理通常基于一个简单的机械开关,当按下按键时触发某些操作。独立按键可以有多种尺寸、形状和颜色,便于用户辨识和使用。
2.2 独立按键结构组成
独立按键的主要结构组成包括:按钮、外壳、弹簧、触点、导电片和引脚。由一个弹性体(如弹簧或金属片)和一个按键帽组成。当按键被用户按下时,弹性体会缩短,使按键帽压缩,使按钮顶部变得接近或触摸基底。当用户松开按钮时,弹性体恢复原状,按键返回初始位置。所以当按键未被按下时,通常触点是分开的,电路是断开的。当按下按键时,导电片触碰到触点,从而形成一个闭合电路。
2.3 独立按键驱动原理
独立按键驱动是为了让微控制器能识别按键的状态,而微控制器正好可以识别高电平和低电平,所以大多数的按键都是通过给按键的一端接入高电平,一端接入GPIO;或者是给按键的一端接入低电平,一端接入GPIO。通过检测连接按键的引脚有没有发生电平变化,就可以知道按键是否按下。
2.4 消抖措施
由于机械按键在闭合和分开时可能产生的机械振动(相当于弹簧),导致开关状态在短时间内多次变换,这就是按键抖动现象。消抖措施主要分为软件消抖和硬件消抖:
- 软件消抖:主要是通过编程的方法,设定一个延迟或计时器,确保在一定的时间内只读取一次按键状态,避免抖动对程序的影响。
- 硬件消抖:在按键电路中加入元器件如电阻、电容组成的RC低通滤波器,对按键信号进行平滑处理,降低抖动的影响。
2.5 硬件连接
步骤1:连接LED
- 将LED的长脚(阳极正极)插入面包板的一个槽。
- 将220Ω电阻一端连接到LED的短脚(阴极负极),并将另一端连接到Arduino的GND接口。
- 使用跳线将LED的长脚(阳极)连接到Arduino的数字输出口,例如D13。
步骤2:连接按键
- 将按钮的一个针脚连接到GND。
- 将另一个针脚连接到Arduino的一个数字输入口,例如D2。
- (可选)为了确保当按钮未被按下时输入是高电平,您可以添加一个10kΩ电阻作为上拉电阻,连接按钮的这个针脚(不是连接GND的那个)到+5V。
注意:如果你的Arduino板具备内置上拉电阻功能,可以在软件中启用,以避免物理上拉电阻的需求。
将以上的接线图转换为原理图进行说明。
在上面的原理图中,将按键右侧一端通过上拉电阻R1接到的5V的高电平上,另一端接到引脚GPIO2上,另一侧全部接到了GND(低电平)。将开发板的按键电路简化,得到下图。
开发板一上电,GPIO2引脚就会因为R1这个上拉电阻变为高电平,所以当按键没有按下的时候,GPIO2引脚默认为高电平;当按键按下时,因为按键闭合,GPIO2通过按键接到了GND上,同时因为有R1的存在,没有产生短路,所以GPIO2变为了低电平;
2.6 API介绍
以下是一个通用的独立按键驱动流程:
- 初始化微控制器的GPIO为输入功能 。
- 检测按键状态(定时轮询或中断触发)。
- 如有抖动现象,应用消抖措施。
- 根据按键状态执行相应的程序代码。
- 在操作完成后等待下一次按键触发。
❓什么是定时轮询或中断触发?
- 定时轮询也叫顺序检测,它是一种扫描式的按键驱动方式,在一个循环的代码中循环的检测按键状态。当检测到按键闭合时,就进行相应操作。
- 中断触发主要利用微控制器的中断功能,当按键状态发生变化时,微控制器会立即响应,停止当前任务并执行按键响应程序。这种方式对实时性要求较高。
❓我们知道可以通过代码读取按键引脚上的电平,判断按键是否按下。但是如何编写读取的代码呢?
digitalRead()
是 Arduino 编程中用于从数字引脚读取电平状态的函数。当引脚设置为输入模式(INPUT
或 INPUT_PULLUP
)时,你可以使用这个函数来读取该引脚的当前电平状态。 digitalRead()
函数只有一个参数:
- 引脚编号(Pin number):这是你要读取的数字引脚的编号。
digitalRead() 函数返回的值为 HIGH
(高电平)或 LOW
(低电平)。 以一个使用了 digitalRead()
的示例为例:
int buttonState = digitalRead(2);
在此例子中,我们从编号为2的引脚上(GPIO2)读取值。返回的值存储在变量buttonState
中,它将会是HIGH
或者LOW
,分别表示在该引脚上读取的电平是高还是低。
2.7 Arduino编程步骤
- 打开Arduino IDE(集成开发环境)。
- 连接Arduino开发板到计算机的USB端口。
- 在IDE编写以下代码:
// 定义连接到LED和按钮的引脚
const int buttonPin = 2; // 按钮连接到数字引脚2
const int ledPin = 13; // LED连接到数字引脚13
// 变量track button状态
int buttonState = 0;
void setup() {
// 初始化LED引脚为输出模式
pinMode(ledPin, OUTPUT);
// 初始化按钮引脚为输入模式
pinMode(buttonPin, INPUT_PULLUP);
// 如果没有使用物理上拉电阻,请启用内部上拉电阻
}
void loop() {
// 读取按钮的状态
buttonState = digitalRead(buttonPin);
// 如果检测到按钮被按下
if (buttonState == LOW) {
// 打开LED
digitalWrite(ledPin, HIGH);
} else {
// 否则关闭LED
digitalWrite(ledPin, LOW);
}
}
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
- 在IDE中选择正确的Arduino板型和端口。
- 上传代码到Arduino板中(使用IDE的上传按钮)。
- 一旦代码上传完成,你可以试着按下按钮看到LED的响应。
2.8 实例操作结果
当Arduino板接上电源并成功上传上述程序之后,该实例中当我们按下按键时,LED会亮起,松开按键时,LED会熄灭。
3. 时间操作实例
在Arduino编程中,精确和有效地管理时间是实现各种功能的关键。无论是在简单的LED闪烁示例中添加延时,还是在更复杂的项目中进行任务调度,时间管理都扮演着至关重要的角色。本章旨在提供一个详细的时间操作指南,涵盖从基本的延时到复杂的非阻塞时间管理技术。
3.1 延时的作用
在Arduino或其他微控制器的编程中,延时被广泛使用,主要有以下一些原因:
- 处理硬件
许多硬件都需要一些时间来响应某个命令。例如,如果在一个程序中你启动一个电动机然后立即检查其状态,你可能会得到一个错误的读数,因为电动机可能还没有足够的时间开始旋转。此时你需要使用 delay() 函数让系统等待一段时间,使得电动机有足够的时间响应。 - 用户交互
我们常常需要在用户交互中实现延迟效果。例如,在蜂鸣器播放音乐时,音符之间需要一段沉默的时间。或者,在闪烁LED灯的情况下,"开"和"关"状态之间需要延时以控制闪烁的速度。 - 节省能源
在一些应用中,比如电池供电的系统,如果不在需要的时候长期保持系统的高速运转,那么电池的寿命会大大缩短。在此情况下,我们可以让系统在一段时间后进入待机或低功耗模式,直到下一个处理周期到来。 - 定时操作
在许多项目中,我们常常需要实现一些特定时间点的操作。例如,在自动灌溉系统中,我们可能需要在每天的特定时间点进行灌溉。在间隔测量中,我们可能每隔一段时间采集一次数据。
尽管延时函数在很多情况下非常有用,但也需要注意其阻塞性质。过度依赖阻塞延时可能会导致程序对其他事件的响应不及时。为了更好的在Arduino上进行多任务编程,我们还可以学习一些非阻塞延时的编程技术。
❓什么是阻塞延时?
阻塞延时是在程序执行过程中,当某个操作或函数需要一定时间才能完成时,程序会暂停执行直至该操作完成,这段时间程序被阻塞了。阻塞延时可能会导致程序运行速度变慢或出现假死现象。
举个例子,假设你想要煮开水来泡茶。通常情况下,你会将水壶放在炉灶上加热,等待水烧开后才能使用。在这个过程中,存在阻塞延时。
当你将水壶放在炉灶上加热时,程序可以看作是“等待”水烧开的操作。在这个等待过程中,你不能立即得到热水来泡茶,需要耐心等待水煮沸。期间,你无法做其他与烧水无关的事情,因为你需要留意水壶,并等待时机。即便家里着火了,你也还是在等待烧水。
在Arduino中,时间操作常见的有两种机制: 使用delay()
函数实现简单的延时,以及使用millis()
或micros()
来进行非阻塞延时。下面将详细介绍这些机制以及如何在Arduino项目中运用它们。
3.2 使用delay()
函数
delay()
函数会使Arduino暂停指定的毫秒数。 在这段时间内,程序不会执行任何其他代码,即这是一个阻塞操作。 这个函数很适合简单的程序和小型项目,但是它不适应需要同时执行多个任务的情况。
语法:
delay(milliseconds);
参数:milliseconds
: 程序中断的时间,以毫秒为单位。
示例使用delay()
:
// 定义连接LED正极的Arduino引脚
const int ledPin = 13;
// setup函数在Arduino板重新启动时或者上电时运行
void setup()
{
// 设置ledPin引脚的模式为输出模式
pinMode(ledPin, OUTPUT);
}
// loop函数在setup运行之后持续循环运行
void loop()
{
// 打开LED
digitalWrite(ledPin, HIGH);
// 等待1000毫秒(1秒)
delay(1000);
// 关闭LED
digitalWrite(ledPin, LOW);
// 等待1000毫秒(1秒)
delay(1000);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
在此示例中,每隔1秒LED就亮灭一次。
3.3 使用millis()
进行非阻塞性操作
millis()
函数返回自Arduino板启动(或最后一次复位)以来的毫秒数 。这个函数的返回值是一个unsigned long
数据类型。
使用millis()
的优点:
- 在等待的过程中可以执行其他代码。
- 避免了
delay()
导致的阻塞性质。
示例使用millis()
进行定时:
unsigned long previousMillis = 0; // 保存上次更新的时间
const long interval = 1000; // 设置间隔时间(1秒)
void setup() {
}
void loop() {
unsigned long currentMillis = millis(); // 获取当前时间
if (currentMillis - previousMillis >= interval) { // 检查是否已过1秒
previousMillis = currentMillis; // 保存当前时间
// 在这里执行定时的操作
}
// 在这里可以加入其他的代码,这些代码会在两次定时操作之间执行
}
2
3
4
5
6
7
8
9
10
11
12
13
14
在上述示例中,我们使用millis()
来跟踪时间间隔。如果当前时间和最后一次记录的时间相差1秒或以上,程序就执行定时操作并更新previousMillis
变量。
3.4 使用micros()
得到更精确的时间
与millis()
类似,micros()
函数返回自程序开始以来的微秒数 ,但精度更高。
注意:
micros()
函数返回的时间值在70分钟后会溢出并重新开始。
示例:
void setup() {
Serial.begin(9600);
}
void loop() {
unsigned long timeMicros = micros();
// 执行操作...
// 然后可以使用timeMicros来判断所花费的微秒时间
}
2
3
4
5
6
7
8
3.5 计时函数的注意点
- 由于
millis()
和micros()
使用的数据类型为unsigned long
,时间会在大约50天(millis()
)或70分钟(micros()
)后溢出(回到0)。编程时需要考虑这种情况。 - 在执行时间较长的操作时,应避免使用
delay()
,因为它会阻塞程序执行其他代码。在需要程序响应的场合,使用基于millis()
的非阻塞延时会更加合适。
以上就是Arduino时间控制功能的详细介绍。掌握这些函数可以帮助你编写出响应更快、更可靠、更复杂的Arduino应用程序。大家可以自行参试使用上面的三个方法,去控制LED亮灭1秒的时间。
4. 模拟输入与输出实例
在这个实例中,我们将使用一个可变电阻器(例如电位器)作为模拟输入,以读取模拟值(电压),并使用PWM控制LED作为模拟输出来调整其亮度。
材料清单
- 1 x 开发板
- 1 x 面包板
- 1 x LED灯
- 1 x 220Ω电阻
- 1 x 10kΩ电位器
- 跳线若干
4.1 模拟输入介绍
模拟输入是Arduino和许多其他微控制器能力的核心特性之一 。与数字输入不同,模拟输入可以读取从传感器或其他设备发出的变化的电压值 ,而不仅仅是简单的高(通常为5V或3.3V)和低(0V)状态。
我们开发板的主控配备了一个内建的模拟数字转换器(ADC),引出了6个模拟输入引脚(A0至A5)。每个模拟输入引脚都可以读取范围在0V至5V之间的连续电压值,并将其转换为一个介于0到1023之间的数字值(假设是一个10位的ADC)。这个过程被称为模拟到数字转换。
下面是一些模拟输入的关键点:
- 分辨率: 开发板的10位ADC提供了2^10 = 1024个不同的电压水平。这意味着它可以区分1/1024的分辨率或约4.88毫伏(Vref/1024)的变化,其中Vref通常是5V,是根据开发板的供电电压不同而不同。
- 电压参考: 默认情况下,模拟输入的参考电压是5V(在5V供电的Arduino板上),但是这个值可以通过编程改变为其他值或使用外部参考。
- 读取值: 使用analogRead(pin)函数可以读取模拟引脚的电压值,参数pin是你想要读取的模拟引脚编号(比如A0、A1等)。
- 应用: 模拟输入引脚可以用来读取多种类型的传感器数据,比如温度、湿度、光照强度、声音强度、位置(使用电位计)等。
模拟输入有助于创建交互式和响应外部环境变化的项目。它们是实现物理世界数据采集的关键部分,并且在制定数据驱动决策的系统中起着至关重要的作用。
在编程时,记住模拟输入读取过程可能需要一些时间,而在高速或频繁地读取数据时,这可能会对系统性能产生影响。然而,在许多情况下,模拟读数速度对于大多数传统的传感器应用都是足够的。
4.2 模拟输出介绍
模拟输入允许我们从各种传感器读取连续值,而模拟输出 是指能够产生一系列值而不只是0和1(开或关) 。尽管这样,实际上大多数微控制器,包括Arduino,都不能直接产生真正的模拟电压输出。相反,它们使用脉冲宽度调制(PWM)来模拟模拟输出。
脉冲宽度调制(PWM)
脉冲宽度调制(PWM)是一种模拟信号控制方法,其中微控制器通过变化信号在一定时间周期内的高电平时间比例来模拟模拟输出。 这个比例通常被称为占空比 。这种方法能够通过快速切换计算机的数字引脚(开/关)并控制信号的占空比来近似连续电压级。
举个例子: 想象你有一个LED和一个开关,你以肉眼看不清的速度,快速反复地开关一次,这样LED灯就会亮一半时间,暗一半时间。如果你快速地进行这个操作,对于观察者来说,LED就像是以半亮度持续亮着。这就是PWM的基本原理。如果你把大部分时间保持开关为关闭状态,那么LED会显得更暗;相反,如果你把开关大部分时间保持为打开状态,LED会显得更亮。这就是PWM调节占空比来控制亮度的过程。
与模拟输出相关的关键点:
- 占空比: 占空比表示多长时间信号是高(通常5V或3.3V),相对于整个周期来说。举例来说,如果PWM信号的占空比为50%,那么信号是一半时间高电平,一半时间低电平。
- 频率: PWM信号的频率是指完整周期的重复次数。例如,Arduino板上的PWM频率通常在约490Hz左右。
- 应用: PWM输出可以用在诸如LED亮度调节、电机速度控制、加热元件温度管理以及其他需要变化电压的场合。
- 函数: 在Arduino 中,
analogWrite(pin, value)
函数用于设置PWM输出,其中pin
是指定的PWM输出引脚,value
是介于0到255之间的值,表示占空比的相对量(0表示0%,255表示100%)。
注意事项:
- 虽然PWM可以模拟模拟输出,但这并不是真正的连续模拟信号。因而,对于一些特定应用(例如产生精确的音频信号),可能会要求真正的模拟输出,这时就需要使用外部模拟数字转换器(DAC)。
- 由于PWM信号本质上仍然是数字信号(高频的“开”和“关”),对于某些应用来说,可能需要一个低通滤波器来平滑输出信号,使其更接近真正的模拟信号,特别是当用在不希望有PWM噪声的精细控制时。
- 只有特定的Arduino引脚能够产生PWM信号。通常这些引脚会在Arduino板上用“~”符号标记。
模拟输出(通过PWM)是微控制器用于模拟电压级别连续变化的一个非常有效的方法。这一技术极大扩展了微控制器处理模拟信号和应对复杂任务的能力。
4.3 硬件连接
步骤1:连接LED
- 将LED的长脚(阳极)插入面包板的一个槽。
- 使用一端连接到LED短脚(阴极)的220Ω电阻,并将另一端连接到Arduino的GND口。
- 使用跳线将LED的长脚(阳极)连接到Arduino的任意PWM数字输出口,例如D9。
注意:注意端口选择,PWM输出针脚通常标记有"~"符号。
步骤2:连接电位器
- 将电位器的一端连接到+5V。
- 将另一端连接到GND。
- 将电位器的中间引脚(滑动触点)连接到Arduino的任意模拟输入口,例如A0。
模拟输入口只引出了A0~A5
4.4 软件设置
打开Arduino IDE并输入以下代码:
// 定义电位器连接到的模拟输入引脚
const int potPin = A0;
// 定义LED连接到的数字引脚,需要支持PWM
const int ledPin = 9;
void setup() {
// 初始化LED引脚为输出模式
pinMode(ledPin, OUTPUT);
}
void loop() {
// 读取电位器的值(0到1023之间)
int potValue = analogRead(potPin);
// 将读取的模拟值映射到PWM范围(0到255之间)
int ledBrightness = map(potValue, 0, 1023, 0, 255);
// 设置LED的亮度
analogWrite(ledPin, ledBrightness);
// 为了看到亮度变化,这里延迟100毫秒
delay(100);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
在以上的代码中,有一行陌生的代码。
c// 将读取的模拟值映射到PWM范围(0到255之间) int ledBrightness = map(potValue, 0, 1023, 0, 255);
1
2在Arduino中,
map()
函数用于将一个数字从一个范围映射到另一个范围。
以下是其中每个参数的含义:
a.potValue
是当前从模拟输入读取的值,它可能来源于比如一个电位计(旋转角度传感器)或其他模拟传感器。
v.0
是potValue
可能的最低值,对应于模拟输入的最小电压(通常是0V)。
c.1023
是potValue
可能的最高值,对应于模拟输入的最大电压(在10位ADC中,这>通常是5V或3.3V情况下的最大数字表示)。
d.0
是映射后的范围的最低值,这是你希望potValue
的最小值所映射的值。
e.255
是映射后的范围的最高值,这是你希望potValue
的最大值所映射的值。
因此,这行代码的作用是将从模拟输入引脚读取的值(假定在0到1023之间)映射到一个0到255之间的值。这通常用于将10位的模拟输入值转换为适用于PWM输出(使用analogWrite
)的8位值,因为analogWrite
接受从0到255的值来表示PWM的占空比。这个映射过程是线性的,意味着如果potValue
是512,映射后的值将大约是128,因为512大约是1023的一半,同样128是255的一半。
- 将上面的代码复制并粘贴到Arduino IDE中。
- 连接你的Arduino板到电脑。
- 在IDE中选择正确的板和端口。
- 上传代码到你的Arduino板。
4.5 实例操作结果
在上传完成后,旋转电位器,你应该可以看到LED的亮度随之变化。通过旋转电位器,电位器中点的电压变化,这种变化通过模拟输入读取并转换为数字值。然后,这个数字值经过映射和调整,以PWM信号的形式输出到LED,从而改变其亮度。
5. 中断服务实例
Arduino中的中断是一种强大的特性,允许微控制器在指定事件发生时立即暂停当前的任务,执行一个所谓的中断服务程序(Interrupt Service Routine, ISR) 。完成这个特殊功能后,微控制器会返回到原来被打断的地方继续执行。这对于响应快速事件(例如,外部设备输入)是非常有用的。
5.1 中断基本概念
在微处理器或微控制器的世界中,中断是一种特殊的事件,它会打断和暂时挂起当前正在执行的程序,以便处理一个特定的状况或者事件。例如按下按钮、到达定时器时间或收到序列口数据。中断是一个非常重要的计算机系统概念,它通过异步的方式对这些特定情况做出响应。这里举一个例子,比如我们正在敲代码,突然有一个电话打过来,这时我们停止敲代码转而去接电话,然后在电话聊完事情之后继续敲代码。这里面的电话就相当于一个中断,打断我们当前做的事情,接电话聊事情就相当于中断需要去执行的事情,也就是中断服务程序。
中断可以分为硬件中断和软件中断两种类型 。
硬件中断通常由外部设备的物理事件引发,如按下按钮、达到定时器的时间、或数据到达串行端口。当这些事件发生时,微处理器会立即暂停其当前的任务,并跳转到一个预先定义的中断服务程序(ISR)来响应该事件。
软件中断则是由软件指令引发,通常用于更复杂的处理任务。像操作系统的系统调用就使用了软件中断。
5.2 外部中断介绍
在数字输入与输出章节,我们在做按键实验时,虽然能实现读取 GPIO口输入功能,但代码是一直在检测IO输入口的变化,如果我们后续加入了大量的代码,就需要花费很长的时间才能轮询到按键检测部分,因此效率不高。特别是在一些特定的场合,比如某个按键,可能 1 天才按下一次去执行相关功能,这样我们就浪费大量时间来实时检测按键的情况。为了解决这样的问题,我们引入外部中断概念。顾名思义,就是当按键被按下(产生中断)时,才去执行相关功能。这大大节省了 CPU 的资源,因此中断在实际项目中应用非常普遍。
外部中断是硬件中断的一种,它由微控制器外部的事件引发。微控制器的某些引脚被设计为对特定事件的发生做出响应,例如按钮的按压、传感器的信号改变等。这些指定的引脚通常被称为“外部中断引脚”。
在发生外部中断事件时,当前在执行的程序会被立即停止,然后跳转到对应的中断服务程序(ISR)进行处理。处理完毕后,程序会返回到被中断的地方继续执行。
对于嵌入式系统、实时系统来说,外部中断的使用是非常重要的,能帮助系统对外部事件进行即时响应,大大提高了系统的效率和实时性。
Arduino开发板子通常只有2个外部中断,分别连接到数字引脚2和3。使用attachInterrupt()
函数来定义一个中断,并关联到一个ISR。
5.3 外部中断的作用和优势
中断功能在Arduino开发中具有以下作用和优势:
- 实时响应外部事件:中断功能可以让你的Arduino在检测到外部事件触发时立即作出响应。这些外部事件可以是来自传感器、按钮、开关、接收到的信号等等。通过外部中断,就可以实时地捕捉到这些事件并执行相应的操作,而无需频繁地轮询或等待。
- 节省计算资源:外部中断允许你将处理外部事件的任务转移给芯片的硬件,从而节省了处理器的计算资源。相比于软件轮询方式,外部中断可以降低对处理器的负担,使其可以更有效地利用其它资源进行更复杂的任务。
- 精确的事件捕捉:中断功能能够以非常精确的方式捕捉外部事件的触发。你可以通过配置中断触发方式(如上升沿、下降沿、任意电平、低电平保持、高电平保持等)来适应不同的外部事件,并在事件发生时立即中断当前程序的执行,转而执行中断服务函数(ISR)。
- 高优先级处理:外部中断可以设置为高优先级处理,优先于当前正在执行的程序。这对于需要立即响应的重要事件非常有用,如紧急通知、传感器检测等。当外部事件触发时,处理器将立即转移到中断服务函数执行,确保及时、准确地处理相关操作,避免对处理程序的延迟。
总之,中断功能给的Arduino项目提供了实时响应、节省计算资源、精确事件捕捉、高优先级处理和多路中断处理等优势。它为我们提供了更加灵活、高效的方式来处理外部事件,并帮助构建更强大、可靠的应用。
5.4 硬件连接
步骤1:连接LED
- 将LED的长脚(阳极正极)插入面包板的一个槽。
- 将220Ω电阻一端连接到LED的短脚(阴极负极),并将另一端连接到Arduino的GND接口。
- 使用跳线将LED的长脚(阳极)连接到Arduino的数字输出口,例如D13。
步骤2:连接按键
- 将按钮的一个针脚连接到GND。
- 将另一个针脚连接到Arduino的一个外部中断引脚,2脚或者3脚。
- (可选)为了确保当按钮未被按下时输入是高电平,您可以添加一个10kΩ电阻作为上拉电阻,连接按钮的这个针脚(不是连接GND的那个)到+5V。
5.5 API介绍
Arduino Uno这类板子通常只有2个外部中断,分别连接到数字引脚2和3。使用attachInterrupt()
函数来定义一个中断,并关联到一个ISR。
语法:
attachInterrupt(interruptNum, ISR, mode);
参数说明:
interruptNum
: 这是外部中断号,Arduino开发板只有两个引脚支持,分别是GPIO2(中断号0),GPIO3(中断号1)。对于大多数Arduino板,可以直接使用digitalPinToInterrupt(pin)
宏将数字引脚pin
转换为相应的中断号。ISR
:中断触发时调用的函数。mode
:指定何种类型的引脚状态改变会触发中断。常用模式有:LOW
:引脚为低电平时触发(不推荐,因为会持续触发中断)。CHANGE
:引脚电平改变时触发。RISING
:引脚电平上升(从低到高)过程中触发。FALLING
:引脚电平下降(从高到低)过程中触发。
arduino的外部中断有上升沿触发、下降沿触发、低电平触发、电平改变触发模式。
上升沿和下降沿触发如下:
当引脚设置为外部中断引脚后,检测到引脚出现设置的触发模式时,就会进入中断回调函数中执行相应程序;
5.6 Arduino编程步骤
- 打开Arduino IDE(集成开发环境)。
- 连接Arduino开发板到计算机的USB端口。
- 在IDE编写以下代码:
const int buttonPin = 2; // 外部中断引脚连接到数字2
const int LEDPin = 13; // 调试LED连接到数字13
volatile bool buttonPressed = false; // 使用 volatile 关键字修饰共享变量
bool led_flag = false;//LED状态
void setup()
{
pinMode(buttonPin, INPUT_PULLUP); // 设置内部上拉电阻输入
pinMode(LEDPin , OUTPUT); // 设置输出模式
//开启引脚2的中断模式,中断触发后执行函数handleInterrupt,触发方式下降沿
attachInterrupt(digitalPinToInterrupt(buttonPin), handleInterrupt, FALLING);
}
void loop()
{
if( buttonPressed == true )
{
digitalWrite(LEDPin, led_flag=!led_flag);
buttonPressed = false; // 重置状态标志
}
// 执行其他任务
}
void handleInterrupt()
{
buttonPressed = true; // 更新共享变量以反映按钮被按下
}
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
- 在IDE中选择正确的Arduino板型和端口。
- 上传代码到Arduino板中(使用IDE的上传按钮)。
- 一旦代码上传完成,你可以试着按下按钮看到LED的响应。
注意事项
根据上面的示例中使用的中断回调函数 button_ISR() 进行说明。
在 Arduino 中使用中断需要注意一下几点:
a. 尽量保证中断程序内容少
b. 避免在中断处理函数中使用阻塞函数(如 delay()
),使用非阻塞的延迟方法来处理需要延迟的操作(micros()
函数),以保证中断的正常执行和系统的稳定性。这是因为 delay()
函数会阻塞整个系统,包括中断的正常执行。当中断触发时,处理函数应该尽快执行完毕,以确保及时响应并避免中断积压;
c. 与主程序共享的变量要加上 volatile
关键字;
d. 在 Arduino 中使用中断时,应尽量避免在中断处理函数中使用 Serial
串口对象的打印函数。当在中断处理函数中使用 Serial
打印函数时,会导致以下问题:
- 时间延迟:
Serial
打印函数通常是比较耗时的操作,它会阻塞中断的执行时间,导致中断响应的延迟。这可能会导致在中断期间丢失其他重要的中断事件或导致系统不稳定。 - 缓冲区溢出:
Serial
对象在内部使用一个缓冲区来存储要发送的数据。如果在中断处理函数中频繁调用Serial
打印函数,可能会导致缓冲区溢出,造成数据丢失或不可预测的行为。
为了避免这些问题,建议在中断处理函数中尽量避免使用 Serial
打印函数。如果需要在中断处理函数中输出调试信息,可以使用其他方式,如设置标志位,在主循环中检查标志位并进行打印。
❓volatile 是什么?
volatile
是一个关键字,用于告诉编译器它所声明的变量可能会被程序以外的因素所改变。它的作用是确保定义为 volatile
的变量在被访问时,每次都从内存中重新读取,而不是使用缓存值,从而保证程序的正确性。
volatile
声明的变量,可以被程序中断服务例程(ISR)、多线程任务或类似操作所修改。对于这些需求,正常的变量定义方式被编译器优化为内存读写最少的方式,因此对于一些变量(例如一个外设寄存器),编译器可能会使用缓存来提高程序效率。这种情况下,如果不使用 volatile
关键字声明变量,那么当变量值被外部因素改变时,程序可能会使用已经缓存的变量值而不是最新的值,从而导致程序出错。
实例操作结果
在这个示例中,每当引脚2检测到一个下降沿(按钮按下),就会触发handleInterrupt
函数,设置按钮被按下的状态标志为true
。然后在loop()
中我们检查这个标志,并执行LED翻转操作。
6. 串口通信协议实例
串口通信协议是在计算机、微控制器或其他设备之间传输数据的一种方式。串口是指外设和处理器之间通过数据信号线、地线和控制线等,按位进行传输数据的一种通讯方式。尽管传输速度比并行传输低,但串口可以在使用一根线发送数据的同时用另一根线接收数据。 这种通信方式使用的数据线少,在远距离通信中可以节约通信成本。在Arduino项目中,串口通信非常常见也非常重要,可以用于设备间的数据传输、调试信息的输出,以及与计算机或其他串行设备的通信。
6.1 串口通信基本概念
串口通信使用TX(发送)和RX(接收)两个引脚来进行数据的发送和接收。Arduino UNO和许多其他Arduino板都有内置的串行通信功能,可以通过USB接口与计算机通信,也可以使用数字引脚(如0和1)与其他设备进行串行通信。
6.2 串口通信介绍
串口通信协议定义了在串口上进行数据交换的规则和格式。常见的串口通信协议包括ASCII协议、Modbus协议、RS-232协议等。协议规定了数据的帧结构、数据格式、校验方式等,确保发送和接收双方按照相同的规则进行数据交换,从而实现数据的正确传输和解析。
串口通信是一位一位地传输,每传输一个字符总是以起始位开始,以停止位结束,字符之间没有固定的时间间隔要求。每一个字符的前面都有一位起始位(低电平),后面由 7 位数据位组成,接着是一位校验位,最后是停止位。停止位后面是不定长的空闲位,停止位和空闲位都规定为高电平。
串口通信参数包括波特率(Baud Rate)、数据位(Data Bits)、校验位(Parity Bits)、停止位(Stop Bits)等。这些参数描述了传输数据的基本规格。例如,波特率定义了数据传输的速率,数据位确定每个数据字节中包含的位数,校验位用于数据的差错检测,停止位表示数据传输结束的标志等。
- 波特率:衡量通信速度的参数,它表示每秒钟传送的 bit 的个数。
- 数据位:衡量通信中实际数据位的参数,表示一个信息包里包含的数据位的个数。
- 停止位:用于表示单个信息包的最后位,典型值为 1、1.5 和 2 位。由于数据是在传输线上传输的,每个设备都有自己的时钟,很有可能在通信过程中出现不同步,停止位不仅仅表示传输的结束,还能提供校正时钟同步的机会。停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率也越慢。
- 奇偶检验位:表示一种简单的检查错误的方式。
6.3 串口工作模式
串口工作模式分为三种:单工、全双工模式和半双工模式。
- 单工:在通信的任意时刻,信息只能由 A 传到 B,或B传到A;
- 半双工:在通信的任意时刻,信息即可由 A 传到 B,又能由 B 传到 A,但同时只能有一个方向上的传输存在;
- 全双工:在通信的任意时刻,通信线路上存在 A 到 B 和 B 到 A 的双向信号传输;
6.4 串口通信的作用及优势
串口是计算机和外部设备之间最常见的通信接口之一,具有重要的作用和广泛的应用。在计算机领域,串口的重要性体现在以下几个方面:
- 数据传输:串口是一种常用的数据传输接口。通过串口,计算机可以与各种外部设备进行数据交换和通信。无论是传感器、执行器、显示器、打印机还是其他外部设备,串口通信都可以实现数据的传输和控制。
- 远程控制和监控:串口通信被广泛应用于远程控制和监控领域。通过串口,计算机可以远程控制设备的动作,并实时监测设备的状态和数据信息。这在工业控制、自动化系统、远程监控等场景中具有重要的作用。
- 调试和故障排查:串口通信是调试和故障排查的重要工具。通过串口,计算机可以与嵌入式系统、单片机等进行通信,实时监控和调试程序,输出调试信息,进行错误定位和排查,并对系统进行状态监测和故障诊断。
- 硬件连接:串口可以作为计算机与各种外部设备之间的连接桥梁。通过串口,可以连接和控制各类外部设备,如传感器、执行器、外围设备等。串口能够提供稳定的数据传输和双向通信功能。
- 通信协议:串口通信协议是计算机与外部设备之间数据传输的规范和约定。通过定义不同的协议,可以实现不同设备之间的数据交互和通信。常见的串口通信协议有UART、RS-232、RS-485等。
总之,串口对于计算机和外部设备之间的通信具有重要的作用。它是数据传输、远程控制和监控、调试和故障排查的关键工具,是计算机与外部设备连接和通信的桥梁。
6.5 硬件连接
本案例使用的是开发板上板载的CH340的USB转串口芯片。将开发板和电脑连接,测试串口通信功能。
CH340是一种USB转串口芯片,常用于微型控制器、单片机、Arduino的USB转串口功能,也可用于USB数据收发。使用CH340模块时,需要安装对应的驱动程序,来使得计算机能够识别CH340芯片的串口输出。对于Windows系统,驱动程序通常会自动安装;对于Mac和Linux系统,需要下载安装相应的驱动程序支持才能使用。
INFO
压缩包
CH340模块在使用上较为便捷,但是我们开发板上已经集成有了CH340模块,所以我们可以直接用一根数据线,将开发板与电脑连接。 连接电脑和开发板后后,只需要通过串口发送指令即可实现与单片机的通信。其优点是接口简单、价格低廉、 驱动程序方便使用等,因此在开发过程以及需要与计算机通信的各种项目中被广泛使用。
6.6 API介绍
在软件层面,Arduino提供了Serial
库,用于实现串行通信。这个库提供了多种方法来发送和接收数据。
初始化串口
使用Serial.begin(baudRate)
方法初始化串行通信,baudRate
指定了数据传输的速率(比特率),例如9600、115200等。这个速率必须和接收方保持一致。
void setup() {
Serial.begin(9600); // 设置波特率为9600
}
2
3
发送数据
可以使用Serial.print()
和Serial.println()
发送数据。print
方法发送数据但不添加换行符,而println会在数据末尾添加换行符。
void loop() {
Serial.println("Hello, world!"); // 发送字符串并换行
delay(1000); // 每秒发送一次
}
2
3
4
接收数据
使用Serial.available()
检查是否有数据可读,如果此函数返回0,表示没有数据可读。如果有,Serial.read()
可以用来读取一个字节的数据。
void loop() {
if (Serial.available() > 0) {
char received = Serial.read(); // 读取并存储一个字节的数据
Serial.print("Received: ");
Serial.println(received); // 显示接收到的数据
}
}
2
3
4
5
6
7
高级读取
Serial.readString()
: 读取串口接收到的字符,直到遇到超时。这个方法依赖于setTimeout()
设定的超时时间。Serial.readStringUntil(terminator)
: 读取串口数据,直到遇到指定的终止字符或超时。Serial.parseInt()
: 从串口读取数据并解析为int
类型。这对于接收数字类型的数据非常方便。Serial.parseFloat()
: 从串口读取数据并解析为float
类型。适用于需要处理浮点数的情况。
6.7 Arduino编程步骤
下面是一个简单的示例,展示了如何发送和接收数据:
void setup() {
Serial.begin(9600); // 初始化串口
}
void loop() {
// 发送数据
Serial.println("Sending data...");
delay(1000); // 等待一秒
// 检查是否有数据可读
if (Serial.available() > 0) {
String receivedData = Serial.readStringUntil('\n'); // 读取数据直到换行符
Serial.print("Received: ");
Serial.println(receivedData); // 打印接收到的数据
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
6.8 实例操作结果
在这个示例中,Arduino设备会每隔一秒发送一条消息,并检查是否有来自其他设备的数据到达。如果有,它将读取并打印这些数据。 在Arduino IDE中集成了一个简单的串口调试助手,在IDE的右上角可以选择打开。
打开后将波特率设置为9600,即可与开发板进行串口通信。
7. 传感器应用实例
7.1 0.96寸IIC单色屏
7.1.1 模块来源
7.1.2 规格参数
工作电压: 3.3V
工作电流: 9MA
模块尺寸: 27.3 x 27.8 MM
像素大小: 128(H) x 64(V)RGB
驱动芯片: SSD1306
通信协议: IIC
管脚数量: 4 Pin(2.54mm间距排针)
7.1.3 硬件连接
- VCC:连接到开发板的3.3V或5V(取决于OLED屏幕的电压要求,大多数SSD1306模块都支持3.3V和5V)。
- GND:连接到开发板的GND。
- SCL:连接到开发板的A5或者SCL引脚。
- SDA:连接到开发板的A4或者SDA引脚。
7.1.4 使用方法
安装库文件(如果已经安过则无需理会)
- 打开Arduino IDE。
- 选择“工具” > “管理库…”。
- 搜索“Adafruit SSD1306”和“Adafruit GFX”,然后分别安装这两个库。
编写代码
/******************************************************************************
* 测试硬件:ColorEasyDuino开发板
* 版 本 号: V1.0
* 修改作者: www.lckfb.com
* 修改日期: 2024年03月28日
* 功能介绍:
*****************************************************************************
* 开发板软硬件资料与相关项目软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:club.szlcsc.com
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
******************************************************************************/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// 定义屏幕宽度和高度
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
// 创建一个Adafruit_SSD1306对象。参数为复位引脚,由于许多模块没有使用,因此传递-1。
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
void setup() {
// 初始化OLED显示屏
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // 这里的0x3C是大多数OLED屏幕的I2C地址,如果无法工作,尝试0x3D
Serial.println(F("SSD1306 allocation failed"));
for(;;); // 无限循环
}
display.clearDisplay();
display.setTextSize(1); // 设置文本大小
display.setTextColor(SSD1306_WHITE); // 设置文本颜色
display.setCursor(0,0); // 设置文本起始位置
display.println(F("Hello, world!"));
display.setTextSize(2);
display.setCursor(0,10);
display.println(F("SSD1306"));
display.display(); // 显示所有的绘图操作
}
void loop() {
// 这里不需要重复执行的代码
}
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
7.1.5 使用验证
7.2 DHT11温湿度传感器
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。其成本低、长期稳定、可以测量相对湿度和温度测量,并可以只使用一根数据线进行温湿度采集。
7.2.1 模块来源
采购链接:
DHT11温度模块 湿度模块 温湿度模块 DHT11传感器
资料下载链接:
https://pan.baidu.com/s/1HQEL699-Yl5Jh3Hp87_FlQ
资料提取码:2sgq
7.2.2 规格参数
工作电压: 3-5.5V
工作电流: 1MA
测量分辨率: 8 bit
通信协议: 单总线
管脚数量: 3 Pin(2.54mm间距排针)
7.2.3 硬件连接
VCC 接 开发板 的 5V
GND 接 开发板 的 GND
DATA 接 开发板 的一个数字引脚(例如,2号引脚)
DHT11 通常有一个单独的数据线,以及一个可选的上拉电阻连接到VCC。一些模块可能已经包括这个上拉电阻。
7.2.4 使用方法
安装库
需要安装用于读取DHT11数据的库。Adafruit 提供了一个很好的库,可以用Arduino IDE的库管理器安装。
- 打开 Arduino IDE。
- 前往 工具 > 管理库。
- 搜索 DHT sensor library 并安装(作者是 Adafruit)。
编写代码
/******************************************************************************
* 测试硬件:ColorEasyDuino开发板
* 版 本 号: V1.0
* 修改作者: www.lckfb.com
* 修改日期: 2024年04月08日
* 功能介绍:
*****************************************************************************
* 开发板软硬件资料与相关项目软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:club.szlcsc.com
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
******************************************************************************/
#include "DHT.h"
#define DHTPIN 2 // 定义DHT11数据针脚连接到Arduino的2号引脚
#define DHTTYPE DHT11 // 定义DHT类型为DHT11
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(9600);
Serial.println("DHT11 温湿度测试:");
// 初始化DHT11传感器
dht.begin();
}
void loop() {
// 等待几秒钟之间的读取(DHT11 的读取速度相对较慢)
delay(2000);
// 读取温度和湿度值
float h = dht.readHumidity();
float t = dht.readTemperature();
// 检查是否读取失败,并退出早期
if (isnan(h) || isnan(t)) {
Serial.println("读取DHT11失败!");
return;
}
// 输出读取到的温度和湿度
Serial.print("湿度: ");
Serial.print(h);
Serial.print(" %\t");
Serial.print("温度: ");
Serial.print(t);
Serial.println(" °C ");
}
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
7.2.5 使用验证
7.3 HC05蓝牙模块
HC-05 蓝牙串口通信模块,是基于 Bluetooth Specification V2.0 带 EDR 蓝牙协议的数传模块。无线工作频段为 2.4GHz ISM,调制方式是 GFSK。模块最大发射功率为 4dBm,接收灵敏度-85dBm,板载 PCB 天线,可以实现 10 米距离通信。模块采用邮票孔封装方式,模块大小 27mm×13mm×2mm,方便客户嵌入应用系统之内,自带 LED 灯,可直观判断蓝牙的连接状态。模块采用 CSR 的 BC417 芯片,支持 AT 指令,用户可根据需要更改角色(主、从模式)以及串口波特率、设备名称等参数,使用灵活。
7.3.1 模块来源
7.3.2 规格参数
工作电压: 3.6-6V
供电电流: 40mA
发射功率: 4dBm(最大)
参考距离: 10米
控制方式: 串口
管脚数量: 6 Pin(2.54mm间距排针)
7.3.3 使用说明
使用HC05蓝牙模块之前,需要知道蓝牙模块的波特率,这样我们才能控制它。将蓝牙模块开发板进行连接,蓝牙模块的TX接开发板的TX,RX接RX。在插入电脑之前,按住模块上的按键再通电,插入电脑通电后此时模块上的灯是慢闪,HC-05进入AT命令模式,默认波特率是38400;此模式我们叫原始模式。原始模式下一直处于AT命令模式状态。
进入AT命令模式之后,最主要的是设置模式为从机控制,即等待手机去连接我们蓝牙模块的蓝牙,主要由手机控制。发送指令时需要注意,每一条指令都要加上\r\n或者勾选发送新行,不然是识别不到命令的。
关键指令说明
测试指令:
指令 | 响应 | 参数 |
---|---|---|
AT | OK | 无 |
设置/查询-模块角色:
设置/查询-串口参数:
配置完成完成之后,给蓝牙模块断电再通电,模块上的灯快速闪烁,说明处于正常工作状态。 打开手机的蓝牙功能进行搜索,会发现我们的蓝牙模块名称:HC-05。连接时需要输入PIN码,而我们在之前AT模式时,已经查询过为1234。
连接手机成功之后,模块上的灯进入慢闪状态,说明已经连接成功。 在手机端打开蓝牙通信软件,测试能否与电脑互传数据。
7.3.4 硬件连接
- HC-05 VCC 接 开发板 5V
- HC-05 GND 接 开发板 GND
- HC-05 TXD 接 开发板 2 号引脚
- HC-05 RXD 接 开发板 3 号引脚
7.3.5 使用方法
下面这个简单的例子展示如何设置开发板来通过串口监听HC-05模块,并且当接收到来自配对设备的数据时,开发板会将收到的数据再发送回去(回声测试)。
注意,蓝牙模块的波特率不要设置大于等于115200,不然将无法通信。
/******************************************************************************
* 测试硬件:ColorEasyDuino开发板
* 版 本 号: V1.0
* 修改作者: www.lckfb.com
* 修改日期: 2024年04月11日
* 功能介绍:
*****************************************************************************
* 开发板软硬件资料与相关项目软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:club.szlcsc.com
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
******************************************************************************/
#include <SoftwareSerial.h>
// Pin2为RX,接HC05的TXD
// Pin3为TX,接HC05的RXD
SoftwareSerial BT(2, 3);
char val;
void setup() {
pinMode(2,INPUT);
pinMode(3,OUTPUT);
Serial.begin(9600);
Serial.println("BT is ready!");
BT.begin(9600);
}
void loop() {
//将串口调试助手上的数据通过蓝牙发送到手机APP
if (Serial.available()) {
val = Serial.read();
BT.print(val);
}
//将手机上蓝牙APP发送过来的数据通过蓝牙发送到串口调试助手
if (BT.available()) {
val = BT.read();
Serial.print(val);
}
}
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
7.3.6 使用验证
手机发送hello lckfb,然后接收到hello
7.4 SG90舵机
7.4.1 模块来源
7.4.2 规格参数
驱动电压:3V~7.2V
驱动电流:
工作扭矩:1.6KG/CM
控制方式:PWM
转动角度:180度
7.4.3 使用说明
在购买时,需要分清楚你的舵机可以转180度,还是360度。360度的舵机是无法控制角度的,只可以控制旋转速度。
SG90的舵机转速不是很快,一般为0.22/60 度或0.18/60 度,所以假如你更改角度控制脉冲的宽度太快时,舵机可能反应不过来。如果需要更快速的反应,就需要更高的转速了。
7.4.4 硬件连接
- 信号线(通常是橙色或黄色线)连接到开发板的9号PWM输出引脚。
- 电源线(红色线)连接到开发板的5V。
- 地线(棕色或黑色线)连接到开发板的GND。
7.4.5 使用方法
- 包含Servo库:首先,需要在Arduino IDE中包含Servo库。
- 定义Servo对象:然后,定义一个或多个Servo对象,每个对象代表一个舵机。
- 附加舵机到引脚:使用attach()函数,将舵机对象附加到控制信号线连接的引脚上。
- 控制舵机:使用write()函数将舵机旋转到指定角度(0到180度)。
#include <Servo.h>
Servo myservo; // 创建舵机对象来控制SG90
void setup() {
myservo.attach(9); // 将舵机的信号线连接到数字引脚9
}
void loop() {
for (int pos = 0; pos <= 180; pos += 1) {
myservo.write(pos); // 从0度转到180度
delay(15); // 舵机转到新位置需要一些时间
}
for (int pos = 180; pos >= 0; pos -= 1) {
myservo.write(pos); // 从180度回转到0度
delay(15); // 舵机转到新位置需要一些时间
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
这个示例代码让舵机从0度慢慢转到180度,然后再慢慢回转到0度。delay(15)
;语句确保了舵机有足够的时间到达新的位置。
7.4.6 使用验证
其它更多请参考模块移植手册....