Arduino硬件资源与库开发全解析
在电子项目开发中,Arduino是一款广受欢迎的开源电子原型平台。它为开发者提供了丰富的功能和便捷的开发环境,能够满足各种不同的项目需求。下面将详细介绍Arduino的一些重要硬件资源以及如何开发自定义库。
1. 光耦合器与固态继电器
- 光耦合器 :光耦合器适用于需要电气隔离的低电流切换场景,可用于低功率系统控制高功率系统,避免高电压回流到低电压的Arduino中,降低损坏IC的风险。其内部“输入”侧有一个LED,与“负载”侧的开关设备(如FET或双极晶体管)进行光耦合。由于没有移动部件,具有较高的开关速度(通常为几毫秒,某些设备甚至可达微秒级)和可靠性。典型的光耦合器可在40V下切换约150mA的电流,主要作为隔离设备使用。
- 固态继电器 :固态继电器结合了传统继电器的隔离和电流处理能力,以及光耦合器无移动部件的优点。它能可靠地高速(毫秒级)切换高电流和高电压,且驱动电流低,可直接由Arduino驱动。有多种封装样式,如可处理240VAC、5A的PCB安装单元,以及更大的可安装在机箱上以应对更大电流的单元。大多数用于交流的固态继电器提供“过零切换”功能,可减少负载磨损和电气噪声。不过,使用固态继电器也有一些注意事项,如部分设备有最小负载电流要求,关断时泄漏电流可能较高,故障时通常处于“导通”状态。
2. 数字输入/输出扩展
Arduino有20个通用I/O引脚,多数项目足够使用,但在某些情况下可能需要更多输入或输出。通过利用Arduino的SPI支持,可使用移位寄存器实现几乎无限的数字输入或输出功能。
-
移位寄存器作为输出
:使用移位寄存器提供输出时,Arduino需提供时钟(CLK)、数据(D)和锁存(Q)三个信号,还可提供输出使能(OE)信号。以单个八输出串行输入并行输出移位寄存器/锁存器连接到Arduino为例,若要将输出3置高,其他输出置低,需按特定顺序设置D和CLK信号,最后通过Q信号将新的模式移到输出引脚。多个移位寄存器可级联以增加输出引脚数量,但受Arduino驱动CLK和Q信号数量的限制。这种输出方式会增加CPU开销,但使用Arduino内部UART的SPI模式可降低开销。常见的移位寄存器设备有74HC595(每引脚约20mA,价格便宜)和TPIC6595(每引脚约200mA,功能更强大)。基于移位寄存器的输出也可实现PWM,可通过软件或硬件PWM引脚驱动OE信号,但需注意可能出现的闪烁问题。
-
移位寄存器作为输入
:并行加载移位寄存器可用于输入扩展,如常见的74HC165。其工作原理与输出电路类似,Arduino通过输出引脚提供时钟(CLK)和加载(LD)信号,通过输入引脚读取移位寄存器的数据(D)线状态。通过LD引脚的高低高转换将输入状态加载到移位寄存器,再通过CLK引脚的低高低转换依次读取每个输入的状态。
3. 输入调理
Arduino能提供的输出电流和电压有限,能承受的输入电压也有限,多数Arduino板输入引脚的最大电压通常为5V。当处理高于电源轨的输入电压时,可采用以下技术:
-
电压分压器和非隔离输入调理
:电压分压器由两个串联电阻组成,可将较高的输入电压转换为适合Arduino输入引脚的电压。例如,选择20k和10k的电阻,可将15V输入转换为5V输出。简单的分压器在良好环境中可正常工作,但在嘈杂或不稳定的环境中,可添加齐纳二极管进行保护。齐纳二极管在低于工作电压时电阻很高,达到工作电压时电阻急剧下降,可将电压钳位在5.1V,但可能无法捕捉快速瞬变或尖峰,用于保护模拟输入时可能引入非线性。此外,可变电阻(电位器)按类似方式连接也可形成电压分压器,可用于为项目添加旋钮来设置值。
-
隔离输入调理
:光耦合器可用于隔离要监测的信号与Arduino。简单的隔离数字输入电路中,只要选择合适的电阻使通过光耦合器LED侧的电流不超过10mA,输入侧可以是任意电压。隔离模拟信号更复杂,可考虑使用小型变压器和滤波电路,或专用的隔离放大器。还可利用基于光耦合器的隔离电路提供与市电同步的50Hz/60Hz参考信号。
4. 廉价DIY原型屏蔽板
标准Arduino板的物理设计存在一个问题,即用于插入屏蔽板的头部连接没有整齐地排列在标准0.1英寸网格上,导致难以使用廉价的标准条形板或穿孔板制作屏蔽板。不过,有一些商业原型屏蔽板可供选择,它们具有不同的功能,如可堆叠的头部、额外的复位按钮、状态LED等。此外,Luke Weston提出了一种简单的方法来修改Arduino,使其能够使用廉价的条形板和可分离的公头制作自己的原型屏蔽板。具体步骤如下:
1. 找到一个8引脚的母PCB头部,可从电子零件供应商处获取或从商业原型屏蔽板套件中获取。
2. 将其放在Arduino的常规数字I/O引脚8 - 13头部旁边,使引脚突出在Arduino PCB旁边。
3. 向引脚13方向稍微滑动,使新头部的第一个引脚(靠近引脚8)与旧头部的现有引脚7之间的水平间距为0.2英寸。
4. 使用一滴强力胶水将新头部牢固地粘在旧头部上。
5. 为确保间距正确,可先制作一个DIY原型屏蔽板,将其插入Arduino,同时固定新的母头部。
6. 将Arduino翻转过来,将所有头部引脚弯曲成一定角度,使其与现有头部的焊点对齐。
7. 焊接每个引脚,即可使用廉价的条形板和可分离的公头制作自己的原型屏蔽板。
5. 编写Arduino库
Arduino开发环境自带了一系列实用的库,网上也有很多可用的库,但有时创建自定义库可简化代码并方便他人使用。下面以TouchScreen库为例,介绍创建自定义库的步骤。
-
将功能实现为草图
:首先将功能直接实现为Arduino草图,在IDE中开发功能便于快速测试。以触摸屏幕驱动为例,其初始版本的草图代码如下:
int xVal = 0;
int yVal = 0;
void setup()
{
Serial.begin(38400);
}
void loop()
{
// Set up the analog pins in preparation for reading the X value
pinMode( 15, INPUT ); // Analog pin 1
pinMode( 17, INPUT ); // Analog pin 3
pinMode( 14, OUTPUT ); // Analog pin 0
digitalWrite( 14, LOW ); // Use analog pin 0 as a GND connection
pinMode( 16, OUTPUT ); // Analog pin 2
digitalWrite( 16, HIGH ); // Use analog pin 2 as a +5V connection
xVal = analogRead( 1 ); // Read the X value
// Set up the analog pins in preparation for reading the Y value
pinMode( 14, INPUT ); // Analog pin 0
pinMode( 16, INPUT ); // Analog pin 2
pinMode( 15, OUTPUT ); // Analog pin 1
digitalWrite( 15, LOW ); // Use analog pin 1 as a GND connection
pinMode( 17, OUTPUT ); // Analog pin 3
digitalWrite( 17, HIGH ); // Use analog pin 3 as a +5V connection
yVal = analogRead( 0 ); // Read the Y value
// Report the values back to the host
Serial.print(xVal);
Serial.print(",");
Serial.println(yVal);
delay(100); // Wait 100 milliseconds before repeating
}
- 创建库头文件 :创建新库的第一步是在Arduino安装目录的hardware/libraries下创建一个与库名匹配的新目录,如TouchScreen。在该目录下创建一个以.h为扩展名的头文件,如TouchScreen.h。为避免库被重复包含导致编译错误,需添加“包含保护”。同时,要包含WProgram.h文件以访问Arduino环境的常量和变量类型。由于Arduino库需作为C++对象调用,要在头文件中声明一个类来定义库,如:
#ifndef TouchScreen_h
#define TouchScreen_h
#include "WProgram.h"
class TouchScreen
{
};
#endif
此时的TouchScreen类声明只是一个空壳,后续可在其中定义功能。定义类是为对象的行为创建抽象定义,通过类的构造函数可根据类的定义创建实际对象。构造函数与类名和库名相同,并包含设置对象时需要传入的参数。
以下是一个简单的流程图,展示了创建Arduino库的主要步骤:
graph LR
A[开发功能为草图] --> B[创建库目录]
B --> C[创建头文件]
C --> D[添加包含保护]
D --> E[包含WProgram.h]
E --> F[声明类]
F --> G[定义构造函数]
另外,为了更清晰地对比不同设备的特点,下面列出一个表格:
|设备名称|特点|适用场景|
| ---- | ---- | ---- |
|光耦合器|电气隔离,开关速度快,可靠性高,电流较小|低电流切换、电气隔离场景|
|固态继电器|隔离和电流处理能力强,无移动部件,高速切换|高电流、高电压切换场景|
|74HC595|每引脚约20mA,价格便宜|对电流要求不高的输出扩展|
|TPIC6595|每引脚约200mA,功能强大|高电流输出扩展|
|74HC165|用于输入扩展|需要增加输入引脚的场景|
Arduino硬件资源与库开发全解析
6. 深入理解类与构造函数在库开发中的作用
在Arduino库开发中,类和构造函数是非常重要的概念。类为对象的行为提供了抽象定义,就像一个模板,而构造函数则负责根据这个模板创建实际的对象。在
TouchScreen
库的例子中,我们已经声明了类,接下来要详细说明构造函数的重要性和具体实现。
构造函数的名称与类名相同,它在对象被创建时自动执行,用于初始化对象的属性和状态。例如,在
TouchScreen
类中,构造函数可能需要初始化与触摸屏幕连接的引脚。以下是一个简单的示例,展示了如何在
TouchScreen.h
头文件中添加构造函数:
#ifndef TouchScreen_h
#define TouchScreen_h
#include "WProgram.h"
class TouchScreen
{
public:
TouchScreen(int xPin1, int xPin2, int yPin1, int yPin2); // 构造函数声明
private:
int xPin1;
int xPin2;
int yPin1;
int yPin2;
};
#endif
在上述代码中,构造函数
TouchScreen
接受四个参数,分别表示与触摸屏幕连接的引脚。这些参数将用于初始化类的私有成员变量,以便在后续的方法中使用。
接下来,我们需要在对应的
.cpp
文件中实现构造函数。创建一个名为
TouchScreen.cpp
的文件,内容如下:
#include "TouchScreen.h"
TouchScreen::TouchScreen(int xPin1, int xPin2, int yPin1, int yPin2)
{
this->xPin1 = xPin1;
this->xPin2 = xPin2;
this->yPin1 = yPin1;
this->yPin2 = yPin2;
}
通过这种方式,我们完成了构造函数的实现,使得在创建
TouchScreen
对象时可以传入引脚信息进行初始化。
7. 为库添加功能方法
在完成类和构造函数的定义后,我们需要为库添加具体的功能方法,以实现触摸屏幕的读取功能。在
TouchScreen.h
头文件中添加方法声明:
#ifndef TouchScreen_h
#define TouchScreen_h
#include "WProgram.h"
class TouchScreen
{
public:
TouchScreen(int xPin1, int xPin2, int yPin1, int yPin2);
int readX(); // 读取X坐标的方法声明
int readY(); // 读取Y坐标的方法声明
private:
int xPin1;
int xPin2;
int yPin1;
int yPin2;
};
#endif
然后在
TouchScreen.cpp
文件中实现这些方法:
#include "TouchScreen.h"
TouchScreen::TouchScreen(int xPin1, int xPin2, int yPin1, int yPin2)
{
this->xPin1 = xPin1;
this->xPin2 = xPin2;
this->yPin1 = yPin1;
this->yPin2 = yPin2;
}
int TouchScreen::readX()
{
// 设置模拟引脚以准备读取X值
pinMode(xPin1, INPUT);
pinMode(xPin2, INPUT);
pinMode(yPin1, OUTPUT);
digitalWrite(yPin1, LOW);
pinMode(yPin2, OUTPUT);
digitalWrite(yPin2, HIGH);
return analogRead(xPin1);
}
int TouchScreen::readY()
{
// 设置模拟引脚以准备读取Y值
pinMode(yPin1, INPUT);
pinMode(yPin2, INPUT);
pinMode(xPin1, OUTPUT);
digitalWrite(xPin1, LOW);
pinMode(xPin2, OUTPUT);
digitalWrite(xPin2, HIGH);
return analogRead(yPin1);
}
通过这些方法,我们可以方便地读取触摸屏幕的X和Y坐标。
8. 使用自定义库
完成库的开发后,就可以在Arduino项目中使用它了。以下是一个简单的示例代码,展示了如何使用
TouchScreen
库:
#include <TouchScreen.h>
// 定义触摸屏幕的引脚
TouchScreen ts(14, 16, 15, 17);
void setup()
{
Serial.begin(38400);
}
void loop()
{
int x = ts.readX();
int y = ts.readY();
Serial.print(x);
Serial.print(",");
Serial.println(y);
delay(100);
}
在这个示例中,我们首先包含了
TouchScreen.h
头文件,然后创建了一个
TouchScreen
对象,并传入了触摸屏幕的引脚信息。在
loop
函数中,我们调用
readX
和
readY
方法读取触摸屏幕的坐标,并通过串口输出。
9. 总结与注意事项
通过以上步骤,我们完成了一个简单的Arduino库的开发。在开发过程中,需要注意以下几点:
-
命名规范
:库名、类名和方法名应遵循一定的命名规范,使用驼峰命名法,保持简洁清晰,并且确保名称的唯一性。
-
错误处理
:在库的实现中,应考虑可能出现的错误情况,如引脚连接错误、读取超时等,并进行相应的错误处理。
-
兼容性
:确保库在不同的Arduino板上都能正常工作,考虑不同板的引脚定义和电气特性的差异。
下面是一个总结性的列表,概括了使用自定义库的步骤:
1. 开发功能为草图,确保功能正常工作。
2. 创建库目录和头文件,添加包含保护和必要的头文件。
3. 声明类和构造函数,实现类的初始化。
4. 添加功能方法,实现具体的功能逻辑。
5. 在Arduino项目中包含库头文件,创建对象并调用方法。
通过合理利用这些硬件资源和掌握库开发的技巧,我们可以更加高效地开发出功能丰富的Arduino项目。希望以上内容对你有所帮助,祝你在Arduino开发的道路上取得更多的成果!
另外,为了更直观地展示使用自定义库的步骤,下面给出一个流程图:
graph LR
A[开发功能草图] --> B[创建库目录和头文件]
B --> C[声明类和构造函数]
C --> D[添加功能方法]
D --> E[在项目中包含库并使用]
以下再通过一个表格,对比使用自定义库前后的代码复杂度:
|对比项|使用自定义库前|使用自定义库后|
| ---- | ---- | ---- |
|代码量|较多,需要手动处理引脚设置和读取逻辑|较少,只需调用库的方法|
|可读性|较差,逻辑复杂,难以理解|较好,代码简洁,易于维护|
|可复用性|低,代码难以在其他项目中复用|高,库可以在多个项目中重复使用|
超级会员免费看
52

被折叠的 条评论
为什么被折叠?



