一、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 在等待某些事件发生的同时可以执行其他任务。