什么是Arduino?
Arduino 是一款开源的电子原型平台,它可以让你用简单的硬件和软件来创建各种创意的项目。无论你是初学者还是专家,Arduino 都能为你提供无限的可能性。你可以用 Arduino 来控制传感器、灯光、马达、机器人、物联网设备等等,只要你能想到的,Arduino 都能帮你实现。
如果你想了解更多关于 Arduino 的信息,你可以访问 Arduino 的官方网站,那里有丰富的资源和教程供你参考。你也可以加入 Arduino 的社区,和来自世界各地的爱好者、学生、设计师和工程师交流心得和经验。此外,你还可以使用 Arduino 的在线编程工具,在云端编写代码并上传到你的开发板上。
Arduino 是一个不断发展和创新的平台,它有着广泛的应用领域和潜力。这里希望本手册能激发你对 Arduino 的兴趣和热情,让你享受 Arduino 带来的创造力和乐趣
维基百科的定义
Arduino 是一个开源嵌入式硬件平台,用来供用户制作可交互式的嵌入式项目。此外 Arduino 作为一个开源硬件和开源软件的公司,同时兼有项目和用户社群。该公司负责设计和制造Arduino电路板及相关附件。这些产品按照GNU宽通用公共许可证(LGPL)或GNU通用公共许可证(GPL)许可的开源硬件和软件分发的,Arduino 允许任何人制造 Arduino 板和软件分发。 Arduino 板可以以预装的形式商业销售,也可以作为 DIY 套件购买。
Arduino 2005 年时面世,作为意大利伊夫雷亚地区伊夫雷亚互动设计研究所的学生设计,目的是为新手和专业人员提供一种低成本且简单的方法,以建立使用传感器与环境相互作用的装置。初学者和爱好者可用Arduino制造传感器、简单机器人、恒温器和运动检测器等装置。
Arduino 这个名字来自意大利伊夫雷亚的一家酒吧,该项目的一些创始人过去常常会去这家酒吧。 酒吧以伊夫雷亚的 Arduin(Arduin of Ivrea)命名,他是伊夫雷亚边疆伯爵,也是 1002 年至 1014 年期间的意大利国王。
十五、Arduino高级 I/O 函数 pulseIn()
pulseIn()函数是一种用于读取数字引脚上的脉冲信号的函数。pulseIn()的作用是让Arduino根据指定的电平和超时时间,测量一个脉冲信号从开始到结束的持续时间,并返回该时间的微秒数。这样可以实现一些需要测量脉冲信号的功能,例如测量距离、速度、频率等。
pulseIn()的使用范围:
1)当需要读取一个数字引脚上的高电平或低电平的脉冲信号时,例如读取一个超声波传感器、一个霍尔传感器、一个红外接收器等。
2)当需要根据一个脉冲信号的持续时间来计算其他物理量时,例如根据一个超声波传感器返回的脉冲信号来计算距离、根据一个霍尔传感器返回的脉冲信号来计算转速、根据一个红外接收器返回的脉冲信号来识别编码等。
3)当需要与其他支持脉冲调制的设备或电路进行数据交换时,例如使用PWM协议来控制LED灯、舵机、电机等。
应用场景:
1)脉冲信号测量:当需要测量外部设备发送的脉冲信号的持续时间或间隔时间时,可以使用pulseIn()函数。这在测量传感器输出的脉冲宽度、计算脉冲频率或测量两个脉冲之间的时间间隔等应用中非常有用。
2)响应外部触发:通过使用pulseIn()函数,可以实现对外部触发事件的快速响应。当接收到特定脉冲信号时,可以通过pulseIn()函数测量脉冲的持续时间,并根据测量结果执行相应的操作,如控制其他设备、触发报警或记录数据等。
3)通信协议解析:某些通信协议(如红外线通信)可以使用脉冲信号进行数据传输。通过使用pulseIn()函数,可以测量接收到的脉冲信号的持续时间,从而解析和处理通信协议中的数据。
使用pulseIn()时,需要注意以下事项:
1)pulseIn()函数的第一个参数是要读取脉冲信号的数字引脚的编号,可以是任意一个数字引脚。第二个参数是要读取脉冲信号的电平,可以是HIGH(高电平)或LOW(低电平)。第三个参数是可选的,表示要读取脉冲信号的超时时间,单位是微秒,范围是0到4294967295,默认值是1000000(1秒)。
2)pulseIn()函数会根据指定的电平和超时时间,测量一个脉冲信号从开始到结束的持续时间,并返回该时间的微秒数。如果在超时时间内没有检测到完整的脉冲信号,则返回0。如果检测到多个连续的脉冲信号,则只返回第一个脉冲信号的持续时间。
3)pulseIn()函数只能用于已经设置为输入模式的数字引脚,否则会导致不可预测的结果。要设置数字引脚的模式,可以使用pinMode()函数。
4)pulseIn()函数会阻塞程序执行,直到检测到完整的脉冲信号或超时返回。因此,在使用pulseIn()函数时,需要注意不要影响其他功能或任务的正常运行。
以下是Arduino高级 I/O 函数pulseIn()的几个实际运用程序案例:
案例一:测量超声波传感器距离:
const int triggerPin = 2;
const int echoPin = 3;
void setup() {
pinMode(triggerPin, OUTPUT);
pinMode(echoPin, INPUT);
Serial.begin(9600);
}
void loop() {
digitalWrite(triggerPin, LOW);
delayMicroseconds(2);
digitalWrite(triggerPin, HIGH);
delayMicroseconds(10);
digitalWrite(triggerPin, LOW);
long duration = pulseIn(echoPin, HIGH); // 测量回声脉冲的持续时间
// 将持续时间转换为距离
float distance = duration * 0.034 / 2;
Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" cm");
delay(1000);
}
在此案例中,我们使用超声波传感器测量距离。通过触发超声波传感器发送脉冲信号,然后使用pulseIn()函数测量接收到的回声脉冲的持续时间。根据声音的传播速度和时间,可以计算出距离。
案例二:解析红外线遥控器信号:
const int irPin = 2;
void setup() {
pinMode(irPin, INPUT);
Serial.begin(9600);
}
void loop() {
int duration = pulseIn(irPin, HIGH); // 测量红外线脉冲的持续时间
// 根据持续时间判断遥控器按下的按键
if (duration >= 1000 && duration <= 2000) {
Serial.println("Power button pressed");
} else if (duration >= 2000 && duration <= 3000) {
Serial.println("Volume up button pressed");
} else if (duration >= 3000 && duration <= 4000) {
Serial.println("Volume down button pressed");
}
delay(100);
}
在此案例中,我们使用红外线接收器接收红外线遥控器的信号。通过使用pulseIn()函数测量接收到的脉冲信号的持续时间,我们可以解析遥控器按下的按键。根据持续时间的不同范围,可以判断出不同的按键操作。
案例三:计算频率:
const int inputPin = 2;
void setup() {
pinMode(inputPin, INPUT);
Serial.begin(9600);
}
void loop() {
unsigned long pulseDuration = pulseIn(inputPin, HIGH); // 测量脉冲的持续时间
// 计算频率
float frequency = 1000000.0 / pulseDuration;
Serial.print("Frequency: ");
Serial.print(frequency);
Serial.println(" Hz");
delay(1000);
}
在此案例中,我们使用pulseIn()函数测量输入引脚上的脉冲信号的持续时间,并通过计算来计算频率。通过将脉冲持续时间的倒数除以1秒,我们可以得到频率的值。
案例四:使用pulseIn()函数读取一个霍尔传感器KY-003,从而测量转速。具体的电路图和代码如下:
// 定义两个常量DATA_PIN、CLOCK_PIN,表示分别连接到霍尔传感器的数据引脚和时钟引脚
#define DATA_PIN 2
#define CLOCK_PIN 3
// 定义一个全局变量count,表示霍尔传感器检测到的磁场变化次数,并初始化为0
volatile int count = 0;
void setup() {
// 将DATA_PIN、CLOCK_PIN两个引脚设为输入模式,并启用上拉电阻
pinMode(DATA_PIN, INPUT_PULLUP);
pinMode(CLOCK_PIN, INPUT_PULLUP);
// 初始化串口通信,波特率为9600
Serial.begin(9600);
// 设置一个中断函数,当DATA_PIN引脚从高电平变为低电平时,调用countPulse函数
attachInterrupt(digitalPinToInterrupt(DATA_PIN), countPulse, FALLING);
}
void loop() {
// 定义一个局部变量rpm,表示转速,并初始化为0
int rpm = 0;
// 禁用中断,以防止数据被修改
noInterrupts();
// 根据count的值和时间间隔,计算转速(假设每转一圈有4次磁场变化)
rpm = count * 15;
// 将count的值重置为0
count = 0;
// 启用中断,以继续检测磁场变化
interrupts();
// 通过串口输出转速
Serial.println(rpm);
// 等待1000毫秒
delay(1000);
}
// 定义一个中断函数countPulse,用于增加count的值
void countPulse() {
count++;
}
案例五:使用pulseIn()函数读取一个超声波传感器HC-SR04,从而测量距离。
// 定义两个常量TRIG_PIN、ECHO_PIN,表示分别连接到超声波传感器的触发引脚和回响引脚
#define TRIG_PIN 9
#define ECHO_PIN 10
void setup() {
// 将TRIG_PIN引脚设为输出模式,将ECHO_PIN引脚设为输入模式
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
// 初始化串口通信,波特率为9600
Serial.begin(9600);
}
void loop() {
// 定义两个局部变量duration和distance,表示脉冲信号的持续时间和距离,并初始化为0
long duration = 0;
int distance = 0;
// 将TRIG_PIN引脚设为低电平,等待2微秒
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
// 将TRIG_PIN引脚设为高电平,持续10微秒,即发送一个超声波脉冲
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
// 将TRIG_PIN引脚设为低电平,等待回响信号
digitalWrite(TRIG_PIN, LOW);
// 调用pulseIn()函数,从ECHO_PIN引脚读取一个高电平的脉冲信号,并设置超时时间为10000微秒,返回值赋给duration
duration = pulseIn(ECHO_PIN, HIGH, 10000);
// 根据duration的值和声速(340m/s),计算距离(单位厘米),并除以2(因为是来回的距离)
distance = duration * 0.034 / 2;
// 通过串口输出距离
Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" cm");
// 等待100毫秒
delay(100);
}
案例六:使用pulseIn()函数读取一个红外接收器VS1838B,从而识别红外遥控编码。
// 定义一个常量IR_PIN,表示连接到红外接收器的数据引脚
#define IR_PIN 4
// 定义一个数组codes,表示红外遥控上每个按键对应的编码(NEC协议)
unsigned long codes[] = {
0xFFA25D, // 按键POWER
0xFFE21D, // 按键MODE
0xFF629D, // 按键MUTE
0xFF22DD, // 按键PLAY/PAUSE
0xFF02FD, // 按键REWIND
0xFFC23D, // 按键FORWARD
0xFFE01F, // 按键EQ
0xFFA857, // 按键VOL-
0xFF906F, // 按键VOL+
0xFF9867, // 按键RPT
0xFFB04F, // 按键U/SD
};
// 定义一个数组keys,表示红外遥控上每个按键对应的字符
char keys[] = {
'P', // 按键POWER
'M', // 按键MODE
'U', // 按键MUTE
'S', // 按键PLAY/PAUSE
'<', // 按键REWIND
'>', // 按键FORWARD
'E', // 按键EQ
'-', // 按键VOL-
'+', // 按键VOL+
'R', // 按键RPT
'D', // 按键U/SD
};
void setup() {
// 初始化串口通信,波特率为9600
Serial.begin(9600);
}
void loop() {
// 定义一个局部变量code,表示从红外接收器读取的编码,并初始化为0
unsigned long code = 0;
// 调用readIR函数,从IR_PIN引脚读取一个红外编码,返回值赋给code
code = readIR(IR_PIN);
// 判断code的值是否为0,如果是,则表示没有检测到红外信号,继续下一次循环
if (code == 0) {
return;
}
// 定义一个局部变量key,表示按下的按键对应的字符,并初始化为空字符
char key = '\0';
// 循环遍历codes数组中的每个编码
for (int i = 0; i < sizeof(codes) / sizeof(codes[0]); i++) {
// 判断code的值是否等于codes数组中的某个编码,如果是,则将keys数组中对应的字符赋给key,并跳出循环
if (code == codes[i]) {
key = keys[i];
break;
}
}
// 判断key的值是否为空字符,如果是,则表示没有识别到有效的按键,继续下一次循环
if (key == '\0') {
return;
}
// 通过串口输出按下的按键对应的字符
Serial.println(key);
// 等待500毫秒,防止抖动和重复读取
delay(500);
}
// 定义一个函数readIR,用于从指定的引脚读取一个红外编码(NEC协议)
unsigned long readIR(int pin) {
// 定义一个局部变量value,表示要返回的编码,并初始化为0
unsigned long value = 0;
// 定义一个局部变量duration,表示脉冲信号的持续时间,并初始化为0
unsigned int duration = 0;
// 等待引脚上的信号从高电平变为低电平,即开始接收数据
while (digitalRead(pin) == HIGH);
// 等待引脚上的信号从低电平变为高电平,并测量持续时间(单位微秒)
duration = pulseIn(pin, HIGH);
// 判断持续时间是否在9000微秒左右(误差范围为200微秒),如果不是,则表示不是有效的起始信号,返回0
if (duration < 8800 || duration > 9200) {
return 0;
}
// 等待引脚上的信号从高电平变为低电平,并测量持续时间(单位微秒)
duration = pulseIn(pin, LOW);
// 判断持续时间是否在4500微秒左右(误差范围为200微秒),如果不是,则表示不是有效的起始信号,返回0
if (duration < 4300 || duration > 4700) {
return 0;
}
// 循环32次,每次读取一个位数据,并将其存入value中
for (int i = 0; i < 32; i++) {
// 等待引脚上的信号从低电平变为高电平,并测量持续时间(单位微秒)
duration = pulseIn(pin, HIGH);
// 判断持续时间是否在560微秒左右(误差范围为200微秒),如果不是,则表示该位数据为0,否则为1
if (duration < 340 || duration > 780) {
value = value << 1;
} else {
value = value << 1 | 1;
}
// 等待引脚上的信号从高电平变为低电平,准备读取下一位数据
while (digitalRead(pin) == HIGH);
}
// 返回编码值
return value;
}