为什么这个简单的 Arduino 草图会在一段时间后变慢?

Why does this simple Arduino sketch slow down after a short while?

我有一个相当简单的 Uno3 的 Arduino 草图(见下文),它在主循环中读取许多传感器并 serial.prints(发送)结果(作为字符)到串行端口9600 波特。

前 24 次循环大约 运行s 以预期速度(可变等待),但随后速度显着减慢——时间戳(毫秒)见下文。

我认为这一定与传感器读数有关,因为仅发送 millis() 的更简单的草图将全速继续。还是串口通讯卡住了?

我的简图:

#include <OneWire.h>
#include <DallasTemperature.h>

const int oneWireBus = 7; 
// read the input on analog pin 0:
int vas = analogRead(A0);
int time = millis();
int wait = 10;


OneWire oneWire(oneWireBus);
DallasTemperature sensors(&oneWire);

void setup() {
  Serial.begin(9600);
  sensors.begin();
  pinMode(2, OUTPUT);
}

void loop() {
  sensors.requestTemperatures();

  if (millis() > time + wait) {
     time = time + wait; 

    //Serial.println(Serial.availableForWrite());
    Serial.print(millis());
    Serial.print(",");
    Serial.print(analogRead(A0));
    Serial.print(",");
    Serial.print(analogRead(A5));
    Serial.print(",");
    Serial.print(sensors.getTempCByIndex(0));
    Serial.print(",");
    Serial.println(digitalRead(4));
    //delay(10);        // delay in between reads for stability
    if (vas > 300) {
      digitalWrite(2, HIGH);  
    }
    else {
      digitalWrite(2, LOW);  
    }
  }
}

...产生这样的串行流:

48,171,0,22.50,1
77,172,0,22.50,1
107,172,0,22.50,1
138,171,0,22.50,1
167,172,0,22.50,1
197,171,0,22.50,1
227,171,0,22.50,1
258,170,0,22.50,1
287,170,0,22.50,1
317,171,0,22.50,1
347,171,0,22.50,1
377,172,0,22.50,1
407,171,0,22.50,1
437,172,0,22.50,1
466,170,0,22.50,1
497,171,0,22.50,1
527,170,0,22.50,1
557,171,0,22.50,1
586,171,0,22.50,1
617,171,0,22.50,1
647,170,0,22.50,1
676,171,0,22.50,1
706,171,0,22.50,1
737,171,0,22.50,1
1350,172,0,22.50,1
2023,170,0,22.50,1
2697,172,0,22.50,1
3369,170,0,22.50,1
4043,171,0,22.50,1
4716,171,0,22.50,1

..注意每次循环的时间大约是 30 毫秒,直到时间 737,然后增加到大约 700 毫秒

如果我运行这个小草图:

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println(millis());
}

..每个循环大约需要 4 毫秒到 10 毫秒,并且会继续这样做...

我在每个循环中都尝试了 Serial.flush() 并且也只在 Serial.availableForWrite() > 30 时读取传感器 .. 没有什么不同

任何导致速度变慢的建议?

您的计时代码有误,容易出现翻转错误。你必须反过来写,计算间隔而不是未来的时间。

if (millis() > 时间 + 等待) { 时间=时间+等待;

应该是

if (millis() - 时间 > 等待) { 时间=时间+等待;

这个问题通常不会这么快就困扰你,但你也有时间变量的变量类型问题,我在评论你的问题时指出了这一点。又来了:

int time = millis(); 

我猜它可以正常运行 30 秒多一点。查看 int 变量可以保存哪些类型的值,看看你是否能弄清楚我是怎么知道的。然后看经典的"Blink Without Delay"例子。他们都使用 unsigned long 表示时间,这就是 millis() returns。

阅读 "Blink Without Delay" 示例,您将了解为什么未签名很重要。

Or is it perhaps the serial comm which gets clogged up?

...

..notice how the time for each loop is about 30ms up until time 737 and then it increases to about 700ms

...

Any suggestions what is causing this slow down?

您使用的达拉斯温度传感器需要 最多 750 毫秒,ADC 才能以默认的 12 位分辨率锁存温度值。当传感器准备就绪时,它们会使用 1-Wire 协议将响应信号发回总线主机(Arduino)。

您可以看到您的时间延迟。在最初的 737 毫秒内,图书馆准备好阅读。在此之后,它正在阻塞并等待传感器发送读数。

您可以使用 setWaitForConversion(FALSE) 来获得更恒定的延迟。来自 https://github.com/milesburton/Arduino-Temperature-Control-Library/blob/master/DallasTemperature.cpp#L359:

// sets the value of the waitForConversion flag
// TRUE : function requestTemperature() etc returns when conversion is ready
// FALSE: function requestTemperature() etc returns immediately (USE WITH CARE!!)
//        (1) programmer has to check if the needed delay has passed
//        (2) but the application can do meaningful things in that time

根据 Ben T、Delta_G 和 gre-gor 的上述非常有用的评论,我提供了一个可行的解决方案作为我自己问题的答案。

出于教学原因,我扩展了示例以允许读取各种传感器之间的差异化时间间隔。比我需要的更灵活,但它可以派上用场。

例如我想尽可能多地阅读按钮状态(pressed/not 按下),否则我可能会错过短按按钮。因此,我在循环中完全不包含任何延迟。

相反,我对每 5 秒读取一次温度非常满意。然而,电位器和浸入式传感器读数应该更频繁,尽管不像按下按钮那样频繁。我也不需要通过串口输出结果——10 times/sec 就可以了。 50 readings/sec 似乎是我的 Arduino Uno rev3 可以管理的最大值——这对我来说绰绰有余:-)

#include <OneWire.h>
#include <DallasTemperature.h>

const int oneWireBus = 7;         // read the temperature from digital 7
const byte potentiometerPin = A0; // read the potentiometer input on analog pin 0
const byte submersionPin = A5;    // read the submersion input on analog pin 5
const byte buttonPin = 4;         // read the button input on digital pin 4
const byte relayPin = 2;          // write the relay output to digital pin 2

unsigned long timeOfLastSerialOutput = millis();        // holds time of last serial output
const long serialOutputWait = 100;                    // how long to wait between serial outputs (ms)

unsigned long timeOfLastTemperatureInput = millis();    // holds time of last temprature input
const long temperatureInputWait = 5000;               // how long to wait between temperature reads (ms)
float temperatureInputValue = 0;                      // holds the lastest temperature reading

unsigned long timeOfLastPotentiometerInput = millis();  // holds time of last potentiometer input
const long potentiometerInputWait = 500;              // how long to wait between potentiometer reads (ms)
int potentiometerInputValue = 0;                      // hold the latest potentiometer reading (0-255)

unsigned long timeOfLastSubmersionInput = millis();     // holds time of last submersion input
const long submersionInputWait = 500;                 // how long to wait between submersion reads (ms)
int submersionInputValue = 0;                         // holds the latest submersion reading (0-255)

bool buttonInputValue = false;                        // holds the latest button reading
bool buttonPressed = false;                           // holds 1 if button has been pressed since last check

unsigned long presentTime = millis();                 // holds present time 

OneWire oneWire(oneWireBus);
DallasTemperature sensors(&oneWire);

void setup() {
  Serial.begin(9600);
  sensors.setWaitForConversion(false);
  sensors.begin();
  pinMode(2, OUTPUT);
}

void loop() {
  // we read the time and button input as often as possible -- we dont want to miss a short button press!
  presentTime = millis();
  buttonInputValue = !digitalRead(buttonPin); // We reverse (!) because open switch=1, closed switch=0
  if (buttonInputValue) { // we must remember a (short) button press in future loops -- only reset to 0 after serial send
    buttonPressed = true;
  }

  // Time to read temperature input?
  if (presentTime - timeOfLastTemperatureInput > temperatureInputWait) {
    timeOfLastTemperatureInput = presentTime;
    sensors.requestTemperatures();
    temperatureInputValue = sensors.getTempCByIndex(0);
  }

  // Time to read potentiometer input?
  if (presentTime - timeOfLastPotentiometerInput > potentiometerInputWait) {
    timeOfLastPotentiometerInput = presentTime;
    potentiometerInputValue = analogRead(potentiometerPin);
    if (potentiometerInputValue > 300) {
      digitalWrite(2, HIGH);  
    }
    else {
      digitalWrite(2, LOW); 
    }
  }

  // Time to read submersion sensor input?
  if (presentTime - timeOfLastSubmersionInput > submersionInputWait) {
    timeOfLastSubmersionInput = presentTime;
    submersionInputValue = analogRead(submersionPin);
  }

  // Time to write to serial output?
  if (presentTime - timeOfLastSerialOutput > serialOutputWait) {
    timeOfLastSerialOutput = presentTime;
    Serial.print(presentTime);
    Serial.print(",");
    Serial.print(potentiometerInputValue);
    Serial.print(",");
    Serial.print(submersionInputValue);
    Serial.print(",");
    Serial.print(temperatureInputValue);
    Serial.print(",");
    Serial.println(buttonPressed);
    buttonPressed = false;
  }
}

感谢您的帮助——希望这也有帮助...