一、SIR的补充
在上几篇博客中,有朋友私信问我,在ticker函数程序和中断服务程序(ISR)中写 物联网请求报错。怎么回事,在此解释。控制台如下
1.1解释
在使用 Ticker 函数和中断服务程序(ISR)时,如果在 ISR 中进行物联网请求可能会导致一些问题,因为 ISR 中需要尽量保持简洁和快速执行,而物联网请求可能涉及到网络通信,执行时间较长,容易引起不可预期的问题,比如中断嵌套、堆栈溢出等。
通常来说,在 ISR 中不应该执行耗时的操作,包括网络通信、文件操作等。如果需要在 ISR 中进行某些操作,可以考虑通过设置标志位的方式,在主循环中检查该标志位并执行相应的操作。
1.2说明
因此在实现网络请求时,请将请求程序写入loop()主循环内,简单的硬件信号输入输出程序则可以放入 多任务处理 ticker和中断执行ISR中。如下
#include <Ticker.h>
Ticker ticker;
Ticker ticker1;
void setup() {
attachInterrupt(digitalPinToInterrupt(keyPin), handleInterrupt, FALLING); // 设置外部中断
ticker.attach_ms(10, controlLED); // 10微秒执行一次
// ------
// 设置定时器,在1秒后发送设备信息
ticker1.once(1, startedInstruction);
}
// 1.外部中断处理函数
ICACHE_RAM_ATTR void handleInterrupt() {
flag = !flag; // 切换 LED 状态
//不能在 ticker 和中断中写网络请求
}
// 2.控制 LED 状态
void controlLED() {
digitalWrite(ledPin, flag ? HIGH : LOW); // 根据标志控制 LED 亮灭
}
//3.ticker检测启动说明
void startedInstruction() {
Serial.println("启动说明");
String tag = String("/LoveMomServer/jb82IWj8q")
+ "?dIdmail=" + String(DEVICE_ID) + "&netWork="
+ netWork + "&deviceName=" + deviceName + "&localIp="
+ localIp + "&deviceMac=" + deviceMac;
Serial.println(tag);
}
二、loop也有阻塞的时候
2.1案例
网络请求写在loop中,有的请求是10秒请求一次,有的请求是20秒、甚至是5秒、1秒。这么多网络请求都写在loop函数内,请求和休眠时间各不一样。
尤其是对硬件监听digitalRead(keyPin) == LOW是毫秒级的不间歇的。强行加delay(1000),会导致程序阻塞的。
2.2阻塞情况
void loop() {
if (sendDeviceInfoRequestCount < 3) {
sendDeviceInfo();
sendDeviceInfoRequestCount++;
} else {
Serial.println("------");
}
if (digitalRead(keyPin) == LOW) {
sendChangeLEDRequest();
while (!digitalRead(keyPin))
; //按键释放时候退出while循环,防止按键按下多次触发
}
delay(10000);
httpRequest();
delay(10000);
}
在 loop()
函数中,当执行 delay(10000);
的时候,代码会暂停执行10秒钟。如果在这10秒钟内按下了按钮,digitalRead(keyPin) == LOW
将会成立,从而触发 sendChangeLEDRequest()
。然而,由于 delay(10000);
正在执行,代码会一直停留在这个延迟函数中,直到时间到了才会继续执行后面的代码。因此,在延迟期间按下按钮是不会触发 sendChangeLEDRequest()
的。
2.3非阻塞逐个定时
void loop() {
unsigned long currentMillis = millis();
if (sendDeviceInfoRequestCount < 1) {
sendDeviceInfo();
sendDeviceInfoRequestCount++;
} else {
//Serial.println("eeeeee");
}
if (digitalRead(keyPin) == LOW) {
sendChangeLEDRequest();
while (!digitalRead(keyPin))
; //等待按键释放
}
if (currentMillis - previousMillis >= interval) {
httpRequest();
previousMillis = currentMillis; // 重置计时器
}
}
millis()
函数是 Arduino 编程中常用的一个函数,用于获取从 Arduino 开始运行以来经过的毫秒数。它返回一个 unsigned long
类型的值,表示自 Arduino 开始运行以来经过的毫秒数。
在 Arduino 程序中,通常需要进行时间相关的操作,比如控制执行某些任务的时间间隔、实现定时功能等。millis()
函数可以帮助你实现这些功能,而不必使用阻塞延迟函数 delay()
,从而使得 Arduino 在等待某些事件发生的同时可以执行其他任务。