Go Down

Topic: Arduino stops running when reading certain chars from Serial (Read 155 times) previous topic - next topic

45gfg9

Board: Arduino Pro Mini (Compatible), 5V/16MHz
IDE: 1.8.9
OS: macOS 10.14.5

When I send serial data which begins with char T/N/D, the arduino stops running.
Connected to a light sensor on PinA5, a push switch on Pin11, a 4x7seg display on Pin2,3,4, a DS1302 RTC module on Pin6,7,8.

The whole program:
Code: [Select]
#include <EEPROM.h>
#include <RTClib.h>
#include <Seg7List.h>

#define R_PIN 10
#define B_PIN 11
#define L_PIN A5

#define T_ADDR 0x00
#define L_ADDR 0x10

DS1302 RTC(8, 6, 7);
Seg7 S7(2, 3, 4);

const DateTime UPLOAD(__DATE__, __TIME__);
DateTime target;
DateTime currdt;

int L_base, i;
double days;
bool state, ts, powerOk = true;
byte ms = 0;
String str;

void setup() {
  delay(2000);

  Serial.begin(9600);
  pinMode(B_PIN, INPUT_PULLUP);

  RTC.begin();

  if (RTC.now() < UPLOAD) {
    RTC.adjust(UPLOAD);
  }

  EEPROM.get(T_ADDR, target);
  currdt = RTC.now();

  Serial.println(dt2string(target) + " T");
  Serial.println(dt2string(UPLOAD) + " C");
  Serial.println(dt2string(currdt) + " N");
  Serial.setTimeout(0);

  EEPROM.get(L_ADDR, L_base);

  str.reserve(32);

  update();
}

void loop() {
  Serial.println(millis());
  if (state != ts) {
    state = ts;

    state ? S7.show(days) : S7.show();
  }

  ts = getState();
  currdt = RTC.now();

  if (!((10 * (target - currdt).totalseconds() + ms) % 8640)) {
    update();

    Serial.println(dt2string(currdt) + " N");
  }

  while (Serial.available()) {
    switch (Serial.read()) {
      case 'R':
        RTC.begin();
        pinMode(R_PIN, OUTPUT);
        digitalWrite(R_PIN, LOW);
        break;

      case 'T':
        Serial.println(1);
        str = Serial.readStringUntil('\n');
        Serial.println(2);
        if (str.length() == 17) {
          Serial.println(3);
          target = DateTime(str.toInt(), str.substring(3).toInt(), str.substring(6).toInt(),
                            str.substring(9).toInt(), str.substring(12).toInt(), str.substring(15).toInt());
          Serial.println(4);
          EEPROM.put(T_ADDR, target);
          Serial.println(5);
          update();
          Serial.println(6);
        }
        Serial.println(dt2string(target) + " T");
        break;

      case 'S':
        str = "S:";   str += state;
        str += " B:"; str += !digitalRead(B_PIN);
        str += " L:"; str += analogRead(L_PIN);
        Serial.println(str);
        break;

      case 'N':
        Serial.println(1);
        str = Serial.readStringUntil('\n');
        Serial.println(2);
        if (str.length() == 17) {
          Serial.println(3);
          RTC.adjust(DateTime(str.toInt(), str.substring(3).toInt(), str.substring(6).toInt(),
                              str.substring(9).toInt(), str.substring(12).toInt(), str.substring(15).toInt()));
          Serial.println(4);
          currdt = RTC.now();
          Serial.println(5);
          update();
          Serial.println(6);
        }
        Serial.println(dt2string(currdt) + " N");
        break;

      case 'D':
        i = Serial.parseInt();
        S7.show(Serial.readStringUntil('\n'));
        delay(i);
        update();
        break;

      case 'L':
        i = Serial.parseInt();
        if (0 <= i - 50 && i + 50 <= 1023) {
          L_base = i;
          EEPROM.put(L_ADDR, L_base);
        }
        Serial.println(L_base);
        break;

    }
    //Serial.flush();
  }

  ++ms %= 10;
  delay(100);
}

void update() {
  days = (((target - currdt).totalseconds() + .1 * ms) / 86400);

  state = false;
}

bool getState() {
  return (analogRead(L_PIN) < L_base + (state ? 50 : -50) || !digitalRead(B_PIN));
}

String dt2string(DateTime dt) {
  char str[20];

  snprintf_P(str, 20, PSTR("%04u/%02u/%02u %02u:%02u:%02u"),
             dt.year(), dt.month(), dt.day(), dt.hour(), dt.minute(), dt.second());
  return str;
}


The problem begins from Line70, switch->case 'T' / case 'N' / case 'D' .
Code: [Select]
switch (Serial.read()) {
      case 'T':
        Serial.println(1);
        str = Serial.readStringUntil('\n');
        Serial.println(2);
        if (str.length() == 17) {
          Serial.println(3);
          target = DateTime(str.toInt(), str.substring(3).toInt(), str.substring(6).toInt(),
                            str.substring(9).toInt(), str.substring(12).toInt(), str.substring(15).toInt());
          Serial.println(4);
          EEPROM.put(T_ADDR, target);
          Serial.println(5);
          update();
          Serial.println(6);
        }
        Serial.println(dt2string(target) + " T");
        break;

      case 'N':
        Serial.println(1);
        str = Serial.readStringUntil('\n');
        Serial.println(2);
        if (str.length() == 17) {
          Serial.println(3);
          RTC.adjust(DateTime(str.toInt(), str.substring(3).toInt(), str.substring(6).toInt(),
                              str.substring(9).toInt(), str.substring(12).toInt(), str.substring(15).toInt()));
          Serial.println(4);
          currdt = RTC.now();
          Serial.println(5);
          update();
          Serial.println(6);
        }
        Serial.println(dt2string(currdt) + " N");
        break;

      case 'D':
        i = Serial.parseInt();
        S7.show(Serial.readStringUntil('\n'));
        delay(i);
        update();
        break;

    }
  }


In normal situation, it will first respond to case 'R'. Pin10 is soldered to PinRST, for a "soft" reset.
It will print something like this when booted.
Code: [Select]
2019/06/28 09:00:00 T
2019/05/26 00:47:19 C
2019/06/20 11:08:07 N
2008
2115
2217
2319
2420

...

and it DOES reset itself when receiving 'R' signal.
If 'T'/'N'/'D' is received instead:
1) (When debugging) none of 1/2/3/4/5/6 indicators are printed, millis() stops indicating (Line53) and marks that the Arduino stops running.
2) After this, 'R' won't make it reset. ("Hard" reset i.e. RST button still works)

Also, if PinA5 (Light sensor) is read as too dark(>750, can be changed via 'L' signal), the display will go off. BUT when light restores, Arduino ALSO stops running, leaving some dirty chars on the display.

What could go wrong? Please discuss and help, thanks a lot.
If you need more information please don't hesitate to reply.
"Any device is hackable. Take advantage of it. " - Hacknet::World.exe

jremington

Perhaps not the cause of the immediate problem, but use of Strings pretty much guarantees memory problems and program crashes.  See https://arduinoplusplus.wordpress.com/2019/03/01/are-strings-really-that-evil/

Get rid of the Strings and you will be a happier person!

Robin2

This is a very haphazard way to deal with Serial data
Code: [Select]
 while (Serial.available()) {
    switch (Serial.read()) {
      case 'R':
        RTC.begin();
        pinMode(R_PIN, OUTPUT);
        digitalWrite(R_PIN, LOW);
        break;

      case 'T':
        Serial.println(1);
        str = Serial.readStringUntil('\n');
        Serial.println(2);


The whole system could easily get out of sync.

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.

The technique in the 3rd example will be the most reliable.


Also, it is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. This can happen after the program has been running perfectly for some time. Just use cstrings - char arrays terminated with '\0' (NULL).

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

45gfg9

Oh wow that's some quick responses
A lot of thanks! :D I'll try it.
(Going to sleep)
"Any device is hackable. Take advantage of it. " - Hacknet::World.exe

Go Up