Arduino stops sending serial data after different time intervals

Hello everyone!

I’m new to the forums and hope to place my question in the right subforum. I’ve worked with Arduino before but this is my first project with serial communication. It’s also just a test run, the device shall be standalone with a SD card one day…

My code and board are really simple as of now (only few comments, i deleted all my german comments to avoid confusion):

int sensorPin0 = A0; 
int sensorPin1 = A1; // 
int sensorPin2 = A2; // 
int sensorPin3 = A3; //

int west = 0; 
int nord = 0;
int sued = 0;
int ost = 0;

void setup() {

Serial.begin(9600); //initiate serial communication with baud rate 9600
Serial.println("West \t Nord \t Sued \t Ost");
}

void loop() {
  // put your main code here, to run repeatedly:
  
 delay(2000);
 west = analogRead(sensorPin0);
 nord = analogRead(sensorPin1);
 sued = analogRead(sensorPin2);
 ost = analogRead(sensorPin3);

Serial.print(west);
Serial.print(" \t ");
Serial.print(nord);
Serial.print(" \t ");
Serial.print(sued);
Serial.print(" \t ");
Serial.println(ost);

}

It’s just four light resistors in different directions. I want to read their sensor data and send them to the PC via USB. I use an Arduino Uno / Pretzel Board and the current Arduino version from this site.

Thing is: It worked yesterday for 6 hours with a 10 second delay(i stopped it manually) and then it worked from 11pm yesterday till 10:30am this morning with a 15 second delay, i didn’t stop it here though.
I used CoolTerm for logging the data with a timestamp. After that i could only get it to work for about 20 minutes tops with varying delays during today. I’m down to only using the serial monitor because i only need one 24 hour cycle of data for now but even that doesn’t work. My last try was a 60 second delay (which would be sufficient) but it only showed 18 lines of data before stopping. The only thing that changed might be my PC use while running the arduino, but its data is so insignificant (75kb in 6 hours), i just cant believe it could be an issue.

Thanks for reading this!
Any ideas?

Edit:
I now use a millis-Timer like this:

int sensorPin0 = A0; // LDR richtung West, Input zwischen 0 und 1023, gelbes Kabel
int sensorPin1 = A1; // LDR richtung Nord, orange
int sensorPin2 = A2; // LDR richtung Sued, rot
int sensorPin3 = A3; // LDR richtung Ost, braun

int west = 0; //Messwertstart auf Null setzen
int nord = 0;
int sued = 0;
int ost = 0;
long Timer = 0;
long interval=60000;


void setup() {

Serial.begin(9600); //initiate serial communication with baud rate 9600
Serial.println("Time \t West \t Nord \t Sued \t Ost");  //Variablen mit Sensorwerten an den Rechner übertragen
}

void loop() {  // put your main code here, to run repeatedly:
unsigned long current = millis();
if (current - Timer >interval){
  Timer = current - 1;
   west = analogRead(sensorPin0);  // sensorwerte in Variablen hinterlegen
   nord = analogRead(sensorPin1);
   sued = analogRead(sensorPin2);
   ost = analogRead(sensorPin3);
   Serial.print(Timer);
   Serial.print(" \t ");
   Serial.print(west);
   Serial.print(" \t ");
   Serial.print(nord);
   Serial.print(" \t ");
   Serial.print(sued);
   Serial.print(" \t ");
   Serial.println(ost);
  }
}

I tried a watchdog but the 8 second response interval is too small for my 60 seconds of nothing - or would the watchdog be ok with millis?
I’ll let it run for a while now, i don’t know for how long it will last though, so i’d appreciate ideas on my mistake before either way!
Thanks~

Not your direct pb but

Timer and interval should be unsigned long
I would write (just for the sake of it) unsigned long interval=60000UL; to force unsigned long notation
I would use Serial.begin(115200); instead of 9600

The question on your PC is did it go to sleep? Did you open another terminal trying to connect to the same serial port?

 delay(2000);
 west = analogRead(sensorPin0);
 nord = analogRead(sensorPin1);
 sued = analogRead(sensorPin2);
 ost = analogRead(sensorPin3);

Reading from different pins is a good way to get corrupt analog data. You need to read from the same pin twice to get good data. Get rid of the stupid delay(), and spend the time reading the data properly.

I tried a watchdog but the 8 second response interval is too small for my 60 seconds of nothing - or would the watchdog be ok with millis?

Count how many times you are woken up. Every 8th time, do something.

Are you having power issues, perhaps?

J-M-L:
Not your direct pb but

Timer and interval should be unsigned long
I would write (just for the sake of it) long interval=60000UL; to force unsigned long notation
I would use Serial.begin(115200); instead of 9600

The question on your PC is did it go to sleep? Did you open another terminal trying to connect to the same serial port?

Ok thank you! I will change that. I changed my PC settings to never go asleep and it didn’t when i let it run over night, so that should not be an issue. Also i’ve been using it all day long. Don’t think there was a separate connection to the serial port, or could that happen accitentally? I’ve only been writing an essay and using the browser while logging data.
Out of curiosity: Why the 115200? I’ve read 9600 everywhere up till now.

PaulS:

 delay(2000);

west = analogRead(sensorPin0);
nord = analogRead(sensorPin1);
sued = analogRead(sensorPin2);
ost = analogRead(sensorPin3);



Reading from different pins is a good way to get corrupt analog data. You need to read from the same pin twice to get good data. Get rid of the stupid delay(), and spend the time reading the data properly.
Count how many times you are woken up. Every 8th time, do something.

Are you having power issues, perhaps?

Hello and thanks! Do you mean i should read every pin twice before reading the next or should i change my hardware wiring and read them all over the same pin (and then twice)? Sorry, English is not my native language, i might have misunderstood that.

How would i notice it being power issues?

Thanks again!
For the last hour, the millis-solution has been running, but since this is only my prototype i’m very happy to get some good suggestions.

Everyone uses 9600 because they copy existing code without thinking twice, as a legacy of an old world when serial lines where slow… your USB has no pb with 115200 not does your arduino hardware so it’s a shame not to go quicker, especially since you have a small 64 byte buffer in the serial line so if it fills up then the next serial.print will block your program until the computer reads it.

J-M-L:
Everyone uses 9600 because they copy existing code without thinking twice, as a legacy of an old world when serial lines where slow… your USB has no pb with 115200 not does your arduino hardware so it’s a shame not to go quicker, especially since you have a small 64 byte buffer in the serial line so if it fills up then the next serial.print will block your program until the computer reads it.

Great thank you so much!!

This is my code as of now, if anyone still has annotations, i’m open! (Just going to bed soon)

int sensorPin0 = A0; 
int sensorPin1 = A1; 
int sensorPin2 = A2;
int sensorPin3 = A3; 

int west = 0; 
int nord = 0;
int sued = 0;
int ost = 0;
unsigned long Timer = 0;
long interval=60000UL;


void setup() {

Serial.begin(115200); //initiate serial communication with baud rate
Serial.println("Time \t West \t Nord \t Sued \t Ost"); 
}

void loop() {  // put your main code here, to run repeatedly:
unsigned long current = millis();  //millis overflows after 52 days
if (current - Timer >interval){
  Timer = current - 1;
  unsigned long Timer2 = Timer/60000;
   west = analogRead(sensorPin0);
   west = analogRead(sensorPin0); 
   nord = analogRead(sensorPin1);
   nord = analogRead(sensorPin1);
   sued = analogRead(sensorPin2);
   sued = analogRead(sensorPin2);
   ost = analogRead(sensorPin3);
   ost = analogRead(sensorPin3);
   Serial.print(Timer2);
   Serial.print(" \t ");
   Serial.print(west);
   Serial.print(" \t ");
   Serial.print(nord);
   Serial.print(" \t ");
   Serial.print(sued);
   Serial.print(" \t ");
   Serial.println(ost);
  }
}

PaulS:
Reading from different pins is a good way to get corrupt analog data. You need to read from the same pin twice to get good data.

Where is that documented? I'm not doubting you but I can only find where it was mentioned to throw one away in free running mode when changing pins.

Use [b]unsigned[/b] long interval=60000UL;

@Delta_G
The Atmega datasheet does caution against switching quickly analog pins while making A/D readings (analogRead) on other analog pins. This can cause electrical noise and introduce jitter in the analog system.

24.5.1 ADC Input Channels
When changing channel selections, the user should observe the following guidelines to ensure that the correct channel is selected:
In Single Conversion mode, always select the channel before starting the conversion. The channel selection may be changed one ADC clock cycle after writing one to ADSC. However, the simplest method is to wait for the conversion to complete before changing the channel selection.
In Free Running mode, always select the channel before starting the first conversion. The channel selection may be changed one ADC clock cycle after writing one to ADSC. However, the simplest method is to wait for the first conversion to complete, and then change the channel selection. Since the next conversion has already started automatically, the next result will reflect the previous channel selection. Subsequent conversions will reflect the new channel selection.

My understanding is that because there's only 1 ADC shared between the pins through the Analog Multiplexer (which allows six to eight single-ended voltage inputs constructed from the pins of Port A to be selected) , When the MUX changes with a high impedance source, the voltage will take time to stabilize. So indeed the advice I've often seen is to use two analogReads; the first to switch the mux, and to give time for voltage to stabilize, the second as the actual reading.

Yes but analogRead switches the mux BEFORE it starts the conversion. So it should be fine in that case. Every analogRead call should get a fresh good conversion. The only warning about it I've ever been able to find was like you posted above and was about free running mode. In that case I totally get it but I've used back to back analigRead calls to different pins with no issues for a long time.

I think this particular warning got misread and propagated through people repeating what they'd heard said somewhere else. I can't find it anywhere anyway. And the datasheet just has the warning about free running mode where the conversion might already be started when the mux is switched.

J-M-L:
Use [b]unsigned[/b] long interval=60000UL;

I did that but now its back to not working longer than a few minutes. Do i have a variable problem of some sorts? I don't know what else to change.

Here the code again:

int sensorPin0 = A0;

int sensorPin1 = A1;
int sensorPin2 = A2;
int sensorPin3 = A3;

int west = 0;
int nord = 0;
int sued = 0;
int ost = 0;
unsigned long Timer = 0;
unsigned long interval = 30000ul;

void setup() {

Serial.begin(115200); //initiate serial communication with baud rate
Serial.println("West \t Nord \t Sued \t Ost");

void loop() {  // put your main code here, to run repeatedly:
unsigned long current = millis();  //millis overflows after ~52 days
if (current - Timer >interval){
  Timer = current - 1;
  west = analogRead(sensorPin0);
  west = analogRead(sensorPin0);
  nord = analogRead(sensorPin1);
  nord = analogRead(sensorPin1);
  sued = analogRead(sensorPin2);
  sued = analogRead(sensorPin2);
  ost = analogRead(sensorPin3);
  ost = analogRead(sensorPin3);
  Serial.print(west);
  Serial.print(" \t ");
  Serial.print(nord);
  Serial.print(" \t ");
  Serial.print(sued);
  Serial.print(" \t ");
  Serial.println(ost);
  }
}




Also i have to restart the Arduino and the PC very often because the software often doesn't get the sketch uploaded or i get a warning from the PC that it doesn't know the USB device... maybe that's a hint?
I'll come back tomorrow, thanks for your help so far!

@Delta_G

Yes - but see my extra comment above . I think it's about the impedance change at the mux entry and the "sample and hold" circuitry: In order for the ADC to do its job (which takes time) on a stable value, the output of the MUX is fed into a capacitor that is charged to match the voltage of the selected input analog pin. This takes some time that depends on the time constant of a RC circuit and thus on the impedance of what is attached to the pin. I think the doc states that the circuit feeding that pin needs to have 10 kΩ or less impedance so that the capacitor's charge is within 1 digit approximation of a 10 bit sampling for the default arduino analogRead max sampling rate.

Ok. So it's an issue with high input impedance then. But not a general rule. I think most things people hook to an analog pin would fall well under 10 K-ohm impedance.

@Symaen

You are missing a closing } for the setup()

Just to play safe I would actually put Timer=current; rather than to Timer = current - 1; to ensure you don't set your Timer to -1 in case millis() returns 0 . That would make your code fail

J-M-L:
you don't set your Timer to -1 in case millis() returns 0 .

Timer is unsigned right? Or should be if it isn't.

@delta-g

According to the doc the S/H cap is 14 pF, so with a 10k ohms total on the line, TC is 140 ns and you need 5TC to have the capacitor charged at 99% so 0,7micro sec so about 11 CPU clock cycles at 16MHz

If you look at the code of analogRead they set the MUX register with a mask and then trigger the conversion - that's probably very close to the 11 clock cycles (assuming the MUX req is executed directly)

So even at 10k ohms the precision might not be superb


Re Timer yes it is unsigned so if millis() was 0 then it's set to 0xFFFFFFFF with the -1 which then Timer is used for the next time to do something, 50 days later giving the impression the program is stuck?

J-M-L:
@Symaen

You are missing a closing } for the setup()

Just to play safe I would actually put Timer=current; rather than to Timer = current - 1; to ensure you don’t set your Timer to -1 in case millis() returns 0 . That would make your code fail

Thanks i did that! I accidentally deleted the } when deleting the german commentary. Starting another test run. Do you think my interval could be a problem? Or does the Arduino do better with millis because it still has to do something every millisecond? I’m capturing the data with CoolTerm again, lets see what happens.
Thanks for the input!

One milli second is a long time for you Arduino - time to execute 16,000 instructions!
So besides the -1 thingy that could create an issue, no you should be fine and unstability might come forme elsewhere. Do you have a good USB cable? How long it is? Do you have a USB switch in between the computer and the arduino?

J-M-L:
One milli second is a long time for you Arduino - time to execute 16,000 instructions!
So besides the -1 thingy that could create an issue, no you should be fine and unstability might come forme elsewhere. Do you have a good USB cable? How long it is? Do you have a USB switch in between the computer and the arduino?

Hello again. It stopped working after 18 minutes this time.
CoolTerm says Error 31(Serial Port Error) and the serial monitor by arduino says the port is busy.

My USB is quite long, i'd say 6m plus the small adapter cable. Is that too much?
The cables were given to me by the institute where i'm working so they should be good but i don't know how old they are.
No switch inbetween. I could change the Arduinos place to another room or move my PC...

Here's my code again.

int sensorPin0 = A0; // LDR richtung West, Input zwischen 0 und 1023, gelbes Kabel
int sensorPin1 = A1; // LDR richtung Nord, orange
int sensorPin2 = A2; // LDR richtung Sued, rot
int sensorPin3 = A3; // LDR richtung Ost, braun

int west = 0; //Messwertstart auf Null setzen
int nord = 0;
int sued = 0;
int ost = 0;
unsigned long Timer = 0;
unsigned long interval = 10000ul;

void setup() {

Serial.begin(115200); //initiate serial communication with baud rate 9600
Serial.println("West \t Nord \t Sued \t Ost");  //Variablen mit Sensorwerten an den Rechner übertragen
}

void loop() {  // put your main code here, to run repeatedly:
unsigned long current = millis();  //millis overflows after ~52 days
if (current - Timer >interval){
  Timer = current;
   west = analogRead(sensorPin0);  // sensorwerte in Variablen hinterlegen
   nord = analogRead(sensorPin1);
   sued = analogRead(sensorPin2);
   ost = analogRead(sensorPin3);
   Serial.print(west);
   Serial.print(" \t ");
   Serial.print(nord);
   Serial.print(" \t ");
   Serial.print(sued);
   Serial.print(" \t ");
   Serial.println(ost);
  }
}

Delta_G:
Where is that documented? I'm not doubting you but I can only find where it was mentioned to throw one away in free running mode when changing pins.

It's not, that I know of. It IS, however, a fact related to the fact that the Arduino has only one ADC, and how that ADC is implemented in the hardware.

CoolTerm says Error 31(Serial Port Error) and the serial monitor by arduino says the port is busy.

You are not opening the Arduino Serial monitor from time to time, are you? Only one Terminal can be connected to the Serial input.

My USB is quite long, i'd say 6m plus the small adapter cable. Is that too much?

The USB 2.0 specification limits the length of a cable between USB 2.0 devices (Full Speed or Hi-Speed) to 5 meters, so yes this might be too long. You should try with much shorter (the USB 3 specification recommends length of 3 meters max If I remember correctly)