什么是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 开关中断 interrupts()
Arduino的interrupts()是一个函数,用于开启之前被关闭的中断功能。这个函数可以用于在需要恢复中断功能时重新激活中断服务程序(ISR)。
interrupts()的适用范围:
1)用于在主程序中临时地关闭某个引脚的中断功能,比如为了避免干扰或冲突而暂停中断。例如,如果要在主程序中使用串口或其他与时间有关的函数,可以用noInterrupts()函数先关闭可能影响时间计算的中断功能,然后在完成后用interrupts()函数重新开启。
2)用于在中断服务程序中动态地关闭和开启自身或其他引脚的中断功能,比如根据条件或计数器来控制中断。例如,如果要实现一个定时器功能,可以用noInterrupts()函数在定时器到达设定时间后关闭自身的中断功能,然后在下一次触发前用interrupts()函数重新开启。
3)用于在不同的模式或状态下切换不同的中断服务程序,比如根据按键的次数或时间来执行不同的任务。例如,如果要实现一个双击开关功能,可以用noInterrupts()函数和attachInterrupt()函数在单击和双击之间切换不同的中断服务程序。
应用场景:
1)实时响应:在某些情况下,需要实时响应特定事件或触发机制。通过调用interrupts()函数,可以开启中断,使得中断服务程序能够即时地对中断事件进行处理,提高系统的实时性。
2)多任务处理:在多任务处理的系统中,中断可以用于处理一些关键任务,而不会阻塞其他任务的执行。通过使用interrupts()函数,可以确保中断服务程序能够及时地处理中断事件,从而实现多任务的协调运行。
3)优先级管理:在系统中,可能存在多个中断触发源,每个中断触发源的重要性和优先级不同。通过使用interrupts()函数,可以根据需要合理设置中断的优先级,确保高优先级的中断能够及时响应并处理。
interrupts()的使用注意事项有以下几点:
1)interrupts()只能开启之前使用noInterrupts()函数关闭的中断功能,不能开启其他方式关闭的中断功能。例如,不能使用interrupts()函数开启pinMode(pin, INPUT_PULLUP)设置的内部上拉电阻产生的低电平触发的中断。
2)interrupts()不需要任何参数,也没有返回值。它只是简单地恢复之前被关闭的所有中断功能。如果要针对某个引脚单独开启或关闭中断功能,需要使用attachInterrupt()函数和detachInterrupt()函数。
3)interrupts()应尽量与noInterrupts()函数成对使用,以保证程序的逻辑正确性。如果没有使用noInterrupts()函数就调用interrupts()函数,可能会导致意外的结果。
以下是Arduino的interrupts()几个实际运用程序案例:
例1:临时关闭某个引脚的中断功能
//定义编码器连接的引脚
const int encoderPinA = 2;
const int encoderPinB = 3;
//定义编码器的计数器和转速
volatile long counter = 0;
volatile float speed = 0;
//定义编码器的每转步数和测量时间间隔
const int stepsPerRevolution = 20;
const int interval = 1000;
void setup() {
//为编码器引脚设置中断服务程序
attachInterrupt(digitalPinToInterrupt(encoderPinA), countStep, RISING);
attachInterrupt(digitalPinToInterrupt(encoderPinB), countStep, RISING);
//初始化串口
Serial.begin(9600);
}
void loop() {
//每隔一定时间间隔
if (millis() % interval == 0) {
//临时关闭编码器引脚的中断功能,避免干扰计算转速
noInterrupts();
//计算转速,单位为转/分
speed = counter * 60.0 / stepsPerRevolution / interval * 1000.0;
//打印转速
Serial.print("Speed: ");
Serial.print(speed);
Serial.println(" RPM");
//重置计数器
counter = 0;
//重新开启编码器引脚的中断功能,继续测量转速
interrupts();
}
}
//定义中断服务程序
void countStep() {
//增加计数器的值
counter++;
}
例2:动态关闭和开启自身或其他引脚的中断功能
//定义定时器和LED连接的引脚
const int timerPin = 2;
const int ledPin = 13;
//定义定时器的时间间隔和上次触发的时间
const int interval = 5000;
volatile unsigned long lastTime = 0;
//定义定时器的次数和上限
volatile int count = 0;
const int limit = 10;
void setup() {
//为定时器引脚设置中断服务程序
attachInterrupt(digitalPinToInterrupt(timerPin), doTask, RISING);
//设置LED的模式
pinMode(ledPin, OUTPUT);
}
void loop() {
//无需在主循环中做任何事情
}
//定义中断服务程序
void doTask() {
//获取当前时间
unsigned long currentTime = millis();
//如果当前时间与上次触发的时间差大于等于时间间隔
if (currentTime - lastTime >= interval) {
//切换LED状态
digitalWrite(ledPin, !digitalRead(ledPin));
//更新上次触发的时间
lastTime = currentTime;
//增加计数器的值
count++;
//如果计数器达到上限
if (count == limit) {
//关闭自身的中断功能
noInterrupts();
}
}
}
例3:切换不同的中断服务程序
//定义中断引脚
const byte interruptPin = 2;
//变量用于控制当前服务程序
volatile byte isr = 0;
//中断服务程序1
void isr1() {
//输出High
digitalWrite(LED_BUILTIN, HIGH);
//重置isr标志
isr = 0;
}
//中断服务程序2
void isr2() {
//输出Low
digitalWrite(LED_BUILTIN, LOW);
//重置isr标志
isr = 1;
}
void setup() {
//设置中断引脚为输入
pinMode(interruptPin, INPUT_PULLUP);
//附加isr1作为中断服务程序
attachInterrupt(digitalPinToInterrupt(interruptPin), isr1, RISING);
}
void loop() {
//按下中断引脚时,切换中断服务程序
if(digitalRead(interruptPin) == LOW) {
if(isr == 0) {
attachInterrupt(digitalPinToInterrupt(interruptPin), isr2, RISING);
} else {
attachInterrupt(digitalPinToInterrupt(interruptPin), isr1, RISING);
}
}
//小延时
delay(10);
}
这个程序定义了两个中断服务程序isr1和isr2,在主循环中通过按键来切换服务程序。isr标志位用于控制当前使用的是哪个服务程序。
:例4:实时响应
void setup() {
// 初始化设置
// ...
interrupts(); // 开启中断
// 继续执行其他操作
// ...
}
void loop() {
// 执行其他操作
// ...
}
案例5:多任务处理
void setup() {
// 初始化设置
// ...
interrupts(); // 开启中断
// 继续执行其他操作
// ...
}
void loop() {
// 执行任务1
// ...
// 执行任务2
// ...
// 执行任务3
// ...
}
例6:优先级管理
void setup() {
// 初始化设置
// ...
attachInterrupt(digitalPinToInterrupt(2), isr1, RISING); // 注册中断服务程序1,优先级较高
attachInterrupt(digitalPinToInterrupt(3), isr2, RISING); // 注册中断服务程序2,优先级较低
interrupts(); // 开启中断
// 继续执行其他操作
// ...
}
void loop() {
// 执行其他操作
// ...
}
void isr1() {
// 中断服务程序1,处理高优先级中断事件
// 执行相应的操作
// ...
}
void isr2() {
// 中断服务程序2,处理低优先级中断事件
// 执行相应的操作
// ...
}
:例7:使用noInterrupts()和interrupts()禁用和开启中断处理
const int interruptPin = 2; // 中断引脚
void setup() {
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), handleInterrupt, FALLING);
}
void loop() {
// 主循环中的其他代码
// ...
// 在某个条件满足时禁用中断处理
if (condition) {
noInterrupts();
// 执行其他代码,此时中断处理被禁用
// ...
interrupts();
}
}
void handleInterrupt() {
// 中断处理程序
// ...
}
案例8:使用noInterrupts()和interrupts()在关键代码段禁用和开启中断处理
const int criticalPin = 3; // 关键代码触发引脚
void setup() {
pinMode(criticalPin, INPUT_PULLUP);
}
void loop() {
// 主循环中的其他代码
// ...
// 在关键代码段禁用中断处理
noInterrupts();
// 关键代码段
// ...
interrupts();
// 继续执行其他代码
// ...
}
案例9:使用noInterrupts()和interrupts()优化临界区代码执行时间
const int sensorPin = A0; // 传感器引脚
void setup() {
pinMode(sensorPin, INPUT);
analogRead(sensorPin); // 预热传感器
}
void loop() {
// 主循环中的其他代码
// ...
// 在临界区域禁用中断处理以优化传感器读取时间
noInterrupts();
int sensorValue = analogRead(sensorPin); // 在临界区域读取传感器值
interrupts();
// 使用读取到的传感器值执行其他代码
// ...
}
这些案例展示了interrupts()函数的一些常见应用。通过使用noInterrupts()和interrupts()函数,我们可以在需要禁用和重新启用中断处理的情况下控制中断的执行。请确保在正确的时机使用这两个函数,并注意中断处理程序的编写和中断触发的配置。通过使用interrupts()函数,可以实现实时响应、多任务处理和优先级管理。请根据具体的应用需求,选择适当的时机和条件来使用interrupts()函数。