Leonardo board stops responding after reading value from LM35DZ

Shortly:
After reading value from LM35DZ temperature sensor whole board stops responding i have to power it off and on again.

Full story:
I want to make a little control panel for my home server with LCD display, bunch of buttons and leds, 3 temperature sensors, RFID card reader and fan controler.

I’ve got working LCD, buttons with leds (by PCF8574 chip) and RFID reader. Next stop was temperature sensor, one at start and rest of them later. But i got hit a wall.

Because i want to be able to control some functions of server and display on panel LCD some server statistics i needed two way communication. I decided to send in both directions simple text like: 0001;Hello; where first 4 digits are for actual command and rest are optional text associated with that command, like a text to display on LCD (srv => panel) or a temperature reading (panel => srv).

After connecting a LM35DZ sensor i made command to receive its reading and second one (something like echo) for connection tests.

So, the problem is, that after reading the value from sensor board stops responding. Nothing happens after:

  1. reading RFID card (RFID reader is external module connected by arduino with one wire by SoftwareSerial - it is still alive, blinks when i place card near antenna) - data from reader is sent and arduino should beep and show content on LCD but it dont.
  2. No response after echo command,
  3. Buttons and leds connected to PCD8574 are dead.

Here is how it all looks:

On image theres only one led nad button connected to PCF8674 - there are actually 4 but all connected in same way.

An there is my code:

#include <LiquidCrystal.h>
#include <SoftwareSerial.h>
#include <Wire.h>
#define xpAddr 0x38
#define lcdBGpin 10
#define TMP1 0

String readed;
String command;
String label;
boolean reading;
boolean pcpresent = true;
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);
SoftwareSerial mysrl(8,13);
int buzzPort = 9;
byte xpBuff = 0xFF;
unsigned long tstart = 0;
unsigned long tnow = 0;
float tempC = 0;

void setup() {
  Serial.begin(9600);
  mysrl.begin(9600);
  pinMode(buzzPort, OUTPUT);
  pinMode(lcdBGpin, OUTPUT);
  digitalWrite(lcdBGpin, HIGH);
  lcd.begin(16,2);
  Wire.begin();
  Wire.beginTransmission(xpAddr);
  Wire.write(xpBuff);
  Wire.endTransmission();
  lcd.clear();
  tstart = millis();
}

void loop() {
  //detecting if pc console is open
  if(!Serial) {
    if(pcpresent) {
      lcdPrint(0,0,fullfill("No PC connected !"));
      pcpresent = false;
    }
  } else {
    if(!pcpresent) {
      pcpresent = true;
      Serial.println(F("0000:SCP01;"));
      lcdPrint(0,0,fullfill("PC connected!"));
    }
  }
  //Turning off LCD backlight after 15s. inactivity
  if(digitalRead(lcdBGpin) == HIGH) {
    //check delay only if backlight is on
    if(((millis()-tstart)) > 15000) {
      digitalWrite(lcdBGpin, LOW);
      tstart = 0;
    }
  }
  //check for data from RFID reader
  while(mysrl.available() > 0) {
    int kod = mysrl.read();
    switch(kod) {
      case 2: //start
        reading = true;
        break;
      case 3: //end 
        reading = false;
        break;
      default://id
        readed += (char)kod;  
    }
  }
  //Print ID if available
  if(readed != "" && reading == false) {
    Serial.print("ID: ");
    Serial.println(readed);
    readed = fullfill("ID: " + readed);
    lcdPrint(0,1,readed);
    readed = "";
    beep(64);
  }
  //check if there is command form pc
  while(Serial.available()) {
    command += String((char)Serial.read());
  }
  //parse and execute
  if(command.length() > 0) {
    parseCommand(command);
    command = "";
  }
  //PCF buttons
  Wire.requestFrom(xpAddr, 1);
  if(Wire.available()) {
    byte _read = Wire.read();
    bitWrite(xpBuff,0,bitRead(_read,7));
    bitWrite(xpBuff,1,bitRead(_read,6));
    bitWrite(xpBuff,2,bitRead(_read,5));
    bitWrite(xpBuff,3,bitRead(_read,4));
    Wire.beginTransmission(xpAddr);
    Wire.write(xpBuff);
    Wire.endTransmission();
  }
}

void parseCommand(String cmd) {
  //command format: XXXX;YYYYY;
  //XXXX = 4 digit command code,
  //YYYY = optional text data for command
  int co = cmd.substring(0,4).toInt(); //code
  String msg = cmd.substring(5,cmd.length()-1); //text
  switch(co) {
    case 1:
      //Computer name
      label = fullfill(msg);
      //Show it on LCD
      lcdPrint(0,0,label);
      break;
    case 2:
      //Test command, print back received text
      if(pcpresent) {
        Serial.println(msg);
      }
      lcdPrint(0,1,msg);
      break;
    case 101:
      //return current temp.
      tempC = (analogRead(TMP1) * 500.0) / 1023;
      char tmp[5];
      dtostrf(tempC, 2, 2, tmp);
      if(pcpresent) {
        Serial.println("TEMP.: " + String(tmp));
      }
      lcdPrint(0,1,fullfill("TEMP.: " + String(tmp)));
      break;
    default:
      //Show bad command code msg
      lcdPrint(0,1,fullfill("NK: " + cmd.substring(0,4)));
  }
}

//beep beep!
void beep(int bval) {
  analogWrite(buzzPort, bval);
  delay(100);
  analogWrite(buzzPort, 0);
  delay(25);
  analogWrite(buzzPort, bval);
  delay(100);
  analogWrite(buzzPort, 0);
}

//Increase string with spaces to full LCD line length
String fullfill(String ins) {
  while(ins.length() < 16) {
    ins += " ";
  }
  return ins;
}

//Print text at LCD at specified location
void lcdPrint(int col, int row, String txt) {
  if(digitalRead(lcdBGpin) == LOW) {
    //turn on backlight if necessary
    digitalWrite(lcdBGpin, HIGH);
  }
  lcd.setCursor(col,row);
  lcd.print(txt);
  //reset backlight timer
  tstart = millis();
}

Maybe its just stupid little thing, but im stuck and cannot see it :frowning:

Maybe its just stupid little thing

Actually, its a stupid big thing. A big S, as in String. Rewrite your sketch to use strings, instead. Quit pissing resources away on Strings, unless you bought an Arduino with a gigabyte of SRAM.

And, if you did, please let us know where you got it.

Really? And thats all? Oh my....

So, all i have to do is to swich from String objects into arrays of chars? More, if thats a memory issue, how i can "delete" unneeded string from memory? Is this enough:

char sth[] = "blahblah";
... some code....
sth  = "";

?

Is this enough:

No.

how i can "delete" unneeded string from memory?

You can't unless you want to malloc() some space and subsequently free() it. Not hard to do but that will probably fragment RAM the same as String can do.

Why do you need to delete string data?


Rob

Graynomad: Why do you need to delete string data?

I dont [u]need[/u]. At least now. Just thinking of it because i suddenly ran into low memory problem. My program will operate on many different strings so i though it would be good idea to clean a bit after completing operation with particular string.

This is possibly the main offender

while(Serial.available()) {
    command += String((char)Serial.read());
  }

This will fragment RAM something terrible unless they have done a lot of work on the String class lately.

char command[100]; // or max size you ever expect to see + 1
int index = 0;
while(Serial.available() > 0) {
   command[index] = Serial.read();
   index++;
   command[index] = '\0';
   index++;
  }

  //parse and execute
  if(strlen(command) > 0) {   // this doesn't seem right
    parseCommand(command);
    command[0] = '\0';
    index = 0;
}

This is a way to do it without Strings, however is this a problem?

if(command.length() > 0)

That will usually parse the command as soon as you see a single character. How long are these commands?


Rob

Graynomad: How long are these commands?

I think no more than 38 characters. Most data sent TO pc will contain sensor readings, buttons state etc, so it will be something like XXXX;12.34; where XXXX id 4 digit command code. In other way, data sent FROM pc may contain longer strings to display on LCD.

But! Because of LCD size i wont be able to display more than 32 characters (16x2) once, so longest command will contain 4 + 1 + 32 + 1 = 38 characters.

I'll write more when i go back to home and try to convert code to array of chars and ill see what happens.

no more than 38 characters.

Then I think that test for length>0 is flawed, that will pass after the first character is received. Then again after the second, then again after the third etc etc because you process the chars a 1000x faster than they arrive at the serial port.

You need some method of determining that the command has finished before parsing it. Maybe detecting a CR/LF at the end or something.


Rob

Well, it was a memory issue. I made everything again with char arrays instead of Strings and there is no problem with reading temperature.

Thank you all for help! :slight_smile: