Help With Arduino Memory

Hello,

It is a shame that my first post has to be of me begging for help understanding why I am having issues with some simple code.

I am trying to do the following.

Hardware:
Arduino UNO
Raspberry Pi 3

I have a KY-0015 Temp and Humidity Sensor. I have it hooked up on a breadboard, with the signal pin going to pin 8 on the Arduino header.

I have a USB cable going from the Arduino to the Raspberry Pi, the plan is to use serial communications to send sensor data from the Arduino to the Raspberry Pi. The sensor data will be wrapped up in json packets that the Raspberry Pi will capture and do something with.

The Raspberry Pi would send a start or stop command to the Arduino to let it know if it should read the sensor.

This is a small part of a much larger project I am working on.

Everything was working fine, I left it running for several days and it was providing Temp and humidity, the Temp value was a bit off, however I understand I need to calibrate the device.

So, I am happy with the code, its working well, so I decide to remove the debug code and let it run. Once I removed a few Serial.prints, recompiled, uploaded the code, I noticed that after 2 correct readings the data was now coming back incorrect. The packets were right, but the values were off.

The code for reading the sensor was open source example, while I have some questions about the code itself (If statements that don’t do anything.) I will save those questions for some other day.

Yes, I am aware that the code presented does nothing with the received command from the Pi yet. It is functional, it does work, it was removed to make debugging this easier.

I have include the complete source below. Please note the run loop, the 5 lines, if I remove them, after about 3 readings from the sensor, the numbers that are returned are incorrect.

If I leave these 5 lines in the code, the sensor readings are consistent with the temp changes in the room or near the sensor.

My question, why?

       Serial.print(currentMillis);
       Serial.print("-");
       Serial.print(previousMillis);
       Serial.print("=");
       Serial.println(currentMillis - previousMillis);
#include <aJSON.h>
aJsonClass json;
#define ACTIVELED 10

int DHpin = 8;
byte sensorData[5];

unsigned long previousMillis = 0;
const int interval = 5000;

String cmdString = "";         
boolean haveString = false;

boolean startCmdReceived = false;
#define INFO      1
#define START    2
#define STOP     3
#define ERR      4
#define UPD       5

#define DEVTYPE  12       //Arduino
#define DEVPROC  3        //ArduinoWeatherStation

int deviceId = 5;    //This needs to be assigned somehow
int processId  = 1;    //This will have a process id, as such we should mantian it.
int functionId = 1;  //  TEMPOne device can have many functions.

const char name[] = "Weather Station";
const char command[] = "command";
const char devType[] = "deviceType";
const char devProc[] = "deviceProc";
const char devId[] = "deviceId";
const char procId[] = "processId";
const char funcId[] = "functionId";
const char desc[] = "desc";



byte readSensor() 
{
  byte data;
  for (int i = 0; i < 8; i ++) 
  {
    if (digitalRead (DHpin) == LOW) 
    {
      while (digitalRead (DHpin) == LOW)
        ; // wait for 50us
      
      delayMicroseconds (30); // determine the duration of the high level to determine the data is '0 'or '1'
      if (digitalRead (DHpin) == HIGH)
        data |= (1 << (7-i)); // high front and low in the post
      
      while (digitalRead (DHpin) == HIGH)
        ; // data '1 ', wait for the next one receiver
     }
  }
  return data;
}
 
void probeSensor () 
{
  digitalWrite (DHpin, LOW); // bus down, send start signal
  delay (30); // delay greater than 18ms, so DHT11 start signal can be detected
 
  digitalWrite (DHpin, HIGH);
  delayMicroseconds (40); // Wait for DHT11 response
 
  pinMode (DHpin, INPUT);
  while (digitalRead (DHpin) == HIGH);
  delayMicroseconds (80); // DHT11 response, pulled the bus 80us
  
  if (digitalRead (DHpin) == LOW);  //WHY IS THIS HERE? If i saw this doing a code review I would have a fit.
  
  
  delayMicroseconds (80); // DHT11 80us after the bus pulled to start sending data
 
  for (int i = 0; i < 4; i ++) // receive temperature and humidity data, the parity bit is not considered
    sensorData[i] = readSensor();
 
  pinMode (DHpin, OUTPUT);
  digitalWrite (DHpin, HIGH); // send data once after releasing the bus, wait for the host to open the next Start signal
}
 
void setup () 
{
  cmdString.reserve(100);

  Serial.begin (9600);
  startCmdReceived = false;
   
  pinMode(ACTIVELED, OUTPUT);
  digitalWrite(ACTIVELED, 0);
 // serialFlush();
  
  pinMode (DHpin, OUTPUT);
  
  probeSensor();
     
}
 
 void sendCmd(int cmd, String txt)
{
  
  aJsonObject* root = json.createObject();

  json.addItemToObject(root, command, json.createItem(UPD));
  json.addItemToObject(root, devType, json.createItem(DEVTYPE));
  json.addItemToObject(root, devProc, json.createItem(DEVPROC));
  json.addItemToObject(root, devId, json.createItem(deviceId));
  json.addItemToObject(root, procId, json.createItem(processId));
  json.addItemToObject(root, funcId, json.createItem(functionId));
  json.addItemToObject(root, desc, json.createItem(name));
  json.addItemToObject(root, "info", json.createItem(txt.c_str()));
  

  char* jString = json.print(root);
  Serial.write(jString);
  Serial.write('\x23');

  json.deleteItem(root);
  free(jString);

}

void sendStatusTemp()
{
  
  int   c;
  int   h;
  int   f;
  
  aJsonObject* root = json.createObject();

  json.addItemToObject(root, command, json.createItem(UPD));
  json.addItemToObject(root, devType, json.createItem(DEVTYPE));
  json.addItemToObject(root, devProc, json.createItem(DEVPROC));
  json.addItemToObject(root, devId, json.createItem(deviceId));
  json.addItemToObject(root, procId, json.createItem(processId));
  json.addItemToObject(root, funcId, json.createItem(functionId));
  json.addItemToObject(root, desc, json.createItem(name));

  h = (int)sensorData[0];
  c = (int)sensorData[2];
  f = (int) (c * 1.8) + 32;
  
  json.addItemToObject(root, "h", json.createItem(h));
  json.addItemToObject(root, "c", json.createItem(c));
  json.addItemToObject(root, "f", json.createItem(f));
  
  char* jString = json.print(root);
  Serial.write(jString);
  Serial.write('\x23');

  json.deleteItem(root);
  free(jString);

}

void processCommand(String inString)
{
  aJsonObject   *root = json.parse((char*)inString.c_str());
  aJsonObject   *cmd = json.getObjectItem(root, "command");
  if(cmd != NULL)
  {
    switch(cmd->valueint)
    {
       case START:
         sendCmd(START, "Started");
         startCmdReceived = true;
       break;
     
       case STOP:
        sendCmd(STOP, "Stopping");
        startCmdReceived = false;
        Serial.write('\x04');
        

       break;
       
       default:
         sendCmd(ERR, "Unknown Command");
         break;
    }
  }
  json.deleteItem(root);
}


void loop () 
{
  
  if (haveString == true) 
  {
    processCommand(cmdString);    
    cmdString = "";
    haveString = false;
    
  }
  
  
   unsigned long currentMillis = millis();

    if ( (currentMillis - previousMillis) >= interval) 
    {
       Serial.print(currentMillis);
       Serial.print("-");
       Serial.print(previousMillis);
       Serial.print("=");
       Serial.println(currentMillis - previousMillis);

       probeSensor();
       sendStatusTemp();
       
       previousMillis = millis();

    }
}



void serialFlush()
{
  while(Serial.available() > 0)
  {
    char t = Serial.read();
  }
} 

void serialEvent() 
{
  char inChar = 0;
  
  while (Serial.available()) 
  {
    
    inChar = (char)Serial.read();
    
    if ( (inChar == '\0' || inChar == '\x23') && haveString == false) 
    {
       if(cmdString.length() != 0)
          haveString = true;
    }
    else
    {
      cmdString += inChar;
    }
    
    
  }
  
  
}

Still thinking this is some odd memory issue I attempted to reduce the code. I combined to functions into one for the sending of status and updates.

Works with the debug serial prints inside the loop. Take them out, stops working correctly.

#include <aJSON.h>
aJsonClass json;
#define ACTIVELED 10

int DHpin = 8;
byte sensorData[5];

unsigned long previousMillis = 0;
const int interval = 5000;

String cmdString = "";         
boolean haveString = false;

boolean startCmdReceived = false;
#define INFO      1
#define START    2
#define STOP     3
#define ERR      4
#define UPD       5

#define DEVTYPE  12       //Arduino
#define DEVPROC  3        //ArduinoWeatherStation

int deviceId = 5;    //This needs to be assigned somehow
int processId  = 1;    //This will have a process id, as such we should mantian it.
int functionId = 1;  //  TEMPOne device can have many functions.

const char name[] = "Weather Station";
const char command[] = "command";
const char devType[] = "deviceType";
const char devProc[] = "deviceProc";
const char devId[] = "deviceId";
const char procId[] = "processId";
const char funcId[] = "functionId";
const char desc[] = "desc";



byte readSensor() 
{
  byte data;
  for (int i = 0; i < 8; i ++) 
  {
    if (digitalRead (DHpin) == LOW) 
    {
      while (digitalRead (DHpin) == LOW)
        ; // wait for 50us
      
      delayMicroseconds (30); // determine the duration of the high level to determine the data is '0 'or '1'
      if (digitalRead (DHpin) == HIGH)
        data |= (1 << (7-i)); // high front and low in the post
      
      while (digitalRead (DHpin) == HIGH)
        ; // data '1 ', wait for the next one receiver
     }
  }
  return data;
}
 
void probeSensor () 
{
  digitalWrite (DHpin, LOW); // bus down, send start signal
  delay (30); // delay greater than 18ms, so DHT11 start signal can be detected
 
  digitalWrite (DHpin, HIGH);
  delayMicroseconds (40); // Wait for DHT11 response
 
  pinMode (DHpin, INPUT);
  while (digitalRead (DHpin) == HIGH);
  delayMicroseconds (80); // DHT11 response, pulled the bus 80us
  
  if (digitalRead (DHpin) == LOW);  //WHY IS THIS HERE? If i saw this doing a code review I would have a fit.
  
  
  delayMicroseconds (80); // DHT11 80us after the bus pulled to start sending data
 
  for (int i = 0; i < 4; i ++) // receive temperature and humidity data, the parity bit is not considered
    sensorData[i] = readSensor();
 
  pinMode (DHpin, OUTPUT);
  digitalWrite (DHpin, HIGH); // send data once after releasing the bus, wait for the host to open the next Start signal
}
 
void setup () 
{
  cmdString.reserve(100);

  Serial.begin (9600);
  startCmdReceived = false;
   
  pinMode(ACTIVELED, OUTPUT);
  digitalWrite(ACTIVELED, 0);
 // serialFlush();
  
  pinMode (DHpin, OUTPUT);
  
  probeSensor();
     
}
 
 void sendCmd(int cmd, String txt, boolean sendTemp )
{
  int   c;
  int   h;
  int   f;
  
  aJsonObject* root = json.createObject();

  json.addItemToObject(root, command, json.createItem(cmd));
  json.addItemToObject(root, devType, json.createItem(DEVTYPE));
  json.addItemToObject(root, devProc, json.createItem(DEVPROC));
  json.addItemToObject(root, devId, json.createItem(deviceId));
  json.addItemToObject(root, procId, json.createItem(processId));
  json.addItemToObject(root, funcId, json.createItem(functionId));
  json.addItemToObject(root, desc, json.createItem(name));
  
  if(sendTemp == true)
  {
    h = (int)sensorData[0];
    c = (int)sensorData[2];
    f = (int) (c * 1.8) + 32;
    
    json.addItemToObject(root, "h", json.createItem(h));
    json.addItemToObject(root, "c", json.createItem(c));
    json.addItemToObject(root, "f", json.createItem(f));
    
  }
  else
  {
     json.addItemToObject(root, "info", json.createItem(txt.c_str()));
  }

  char* jString = json.print(root);
  Serial.write(jString);
  Serial.write('\x23');

  json.deleteItem(root);
  free(jString);

}


void processCommand(String inString)
{
  aJsonObject   *root = json.parse((char*)inString.c_str());
  aJsonObject   *cmd = json.getObjectItem(root, "command");
  if(cmd != NULL)
  {
    switch(cmd->valueint)
    {
       case START:
         sendCmd(START, "Started", false);
         startCmdReceived = true;
       break;
     
       case STOP:
        sendCmd(STOP, "Stopping", false);
        startCmdReceived = false;
        Serial.write('\x04');
        

       break;
       
       default:
         sendCmd(ERR, "Unknown Command", false);
         break;
    }
  }
  json.deleteItem(root);
}


void loop () 
{
  
  if (haveString == true) 
  {
    processCommand(cmdString);    
    cmdString = "";
    haveString = false;
    
  }
  
  
   unsigned long currentMillis = millis();

    if ( (currentMillis - previousMillis) >= interval) 
    {
      Serial.print(currentMillis);
       Serial.print("-");
       Serial.print(previousMillis);
       Serial.print("=");
       Serial.println(currentMillis - previousMillis);

       probeSensor();
       sendCmd(UPD, "", true);
       
       previousMillis = millis();

    }
}



void serialFlush()
{
  while(Serial.available() > 0)
  {
    char t = Serial.read();
  }
} 

void serialEvent() 
{
  char inChar = 0;
  
  while (Serial.available()) 
  {
    
    inChar = (char)Serial.read();
    
    if ( (inChar == '\0' || inChar == '\x23') && haveString == false) 
    {
       if(cmdString.length() != 0)
          haveString = true;
    }
    else
    {
      cmdString += inChar;
    }
    
    
  }
  
  
}

In then end, after refactoring the code a bit, adding a new variable. Rewiring the check for the start command received, I was able to get the code running correctly without the debug statements.

Being new to development on the Arduino makes me suspect I did something wrong that I was unable to spot. As a programmer, I would like to understand why adding more variables, adding more code, caused the program to work correctly.

It is counter intuitive to me, the behavior I was seeing was manifesting itself as memory. Clearly, I did make attempts to insure that was the case. In the end, the issue does not appear to be memory, thus I am left thinking it is code.

I had posted the original code, I now present the complete code without debugging prints. If someone is able to see what I was doing wrong in the first bit of code and explain it to me I would be most appreciative.

#include <aJSON.h>
aJsonClass json;
#define ACTIVELED 10

int DHpin = 7;
byte sensorData[5];

unsigned long previousMillis = 0;
const int interval = 5000;

String cmdString = "";         
boolean haveString = false;

boolean startCmdReceived = false;
#define INFO      1
#define START    2
#define STOP     3
#define ERR      4
#define UPD       5

#define DEVTYPE  12       //Arduino
#define DEVPROC  3        //ArduinoWeatherStation

int deviceId = 5;    //This needs to be assigned somehow
int processId  = 1;    //This will have a process id, as such we should mantian it.
int functionId = 1;  //  TEMPOne device can have many functions.

int runTime = 0;
  
const char name[] = "Weather Station";
const char command[] = "command";
const char devType[] = "deviceType";
const char devProc[] = "deviceProc";
const char devId[] = "deviceId";
const char procId[] = "processId";
const char funcId[] = "functionId";
const char desc[] = "desc";



byte readSensor() 
{
  byte data;
  for (int i = 0; i < 8; i ++) 
  {
    if (digitalRead (DHpin) == LOW) 
    {
      while (digitalRead (DHpin) == LOW)
        ; // wait for 50us
      
      delayMicroseconds (30); // determine the duration of the high level to determine the data is '0 'or '1'
      if (digitalRead (DHpin) == HIGH)
        data |= (1 << (7-i)); // high front and low in the post
      
      while (digitalRead (DHpin) == HIGH)
        ; // data '1 ', wait for the next one receiver
     }
  }
  return data;
}
 
void probeSensor () 
{
  digitalWrite (DHpin, LOW); // bus down, send start signal
  delay (30); // delay greater than 18ms, so DHT11 start signal can be detected
 
  digitalWrite (DHpin, HIGH);
  delayMicroseconds (40); // Wait for DHT11 response
 
  pinMode (DHpin, INPUT);
  while (digitalRead (DHpin) == HIGH);
  delayMicroseconds (80); // DHT11 response, pulled the bus 80us
  
  if (digitalRead (DHpin) == LOW);  //WHY IS THIS HERE? If i saw this doing a code review I would have a fit.
  
  
  delayMicroseconds (80); // DHT11 80us after the bus pulled to start sending data
 
  for (int i = 0; i < 4; i ++) // receive temperature and humidity data, the parity bit is not considered
    sensorData[i] = readSensor();
 
  pinMode (DHpin, OUTPUT);
  digitalWrite (DHpin, HIGH); // send data once after releasing the bus, wait for the host to open the next Start signal
}
 
void setup () 
{
  cmdString.reserve(100);

  Serial.begin(9600);
  startCmdReceived = false;
   
  pinMode(ACTIVELED, OUTPUT);
  digitalWrite(ACTIVELED, 0);
  
  pinMode (DHpin, OUTPUT);
  
  probeSensor();
     
}
 
 void sendCmd(int cmd, String txt, boolean sendTemp )
{
  int   c;
  int   h;
  int   f;
  
  aJsonObject* root = json.createObject();

  json.addItemToObject(root, command, json.createItem(cmd));
  json.addItemToObject(root, devType, json.createItem(DEVTYPE));
  json.addItemToObject(root, devProc, json.createItem(DEVPROC));
  json.addItemToObject(root, devId, json.createItem(deviceId));
  json.addItemToObject(root, procId, json.createItem(processId));
  json.addItemToObject(root, funcId, json.createItem(functionId));
  json.addItemToObject(root, desc, json.createItem(name));
  
  if(sendTemp == true)
  {
    h = (int)sensorData[0];
    c = (int)sensorData[2];
    f = (int) (c * 1.8) + 32;
    
    json.addItemToObject(root, "h", json.createItem(h));
    json.addItemToObject(root, "c", json.createItem(c));
    json.addItemToObject(root, "f", json.createItem(f));
    
  }
  else
  {
     json.addItemToObject(root, "info", json.createItem(txt.c_str()));
  }

  char* jString = json.print(root);
  Serial.write(jString);
  Serial.write('\x23');

  json.deleteItem(root);
  free(jString);

}


void processCommand(String inString)
{
  aJsonObject   *root = json.parse((char*)inString.c_str());
  aJsonObject   *cmd = json.getObjectItem(root, "command");
  if(cmd != NULL)
  {
    switch(cmd->valueint)
    {
       case START:
         sendCmd(START, "Started", false);
         startCmdReceived = true;
       break;
     
       case STOP:
        sendCmd(STOP, "Stopping", false);
        startCmdReceived = false;
        runTime = 0;
        Serial.write('\x04');
        

       break;
       
       default:
         sendCmd(ERR, "Unknown Command", false);
         break;
    }
  }
  json.deleteItem(root);
}


void loop () 
{

  if (haveString == true) 
  {
    processCommand(cmdString);    
    cmdString = "";
    haveString = false;
    
  }
  startCmdReceived = true;
  if(startCmdReceived == true)
  {
    
    unsigned long currentMillis = millis();
    if ( (currentMillis - previousMillis) >= (interval - runTime) )
    {
      digitalWrite(ACTIVELED, 1);

      probeSensor();
      sendCmd(UPD, "", true);
      
      previousMillis = millis(); //Lets make sure we run every 5 sec
      runTime = previousMillis - currentMillis;
      
      digitalWrite(ACTIVELED, 0);
    
    }
  }
}



void serialFlush()
{
  while(Serial.available() > 0)
  {
    char t = Serial.read();
  }
} 

void serialEvent() 
{
  char inChar = 0;
  
  while (Serial.available()) 
  {
    
    inChar = (char)Serial.read();
    
    if ( (inChar == '\0' || inChar == '\x23') && haveString == false) 
    {
       if(cmdString.length() != 0)
          haveString = true;
    }
    else
    {
      cmdString += inChar;
    }
    
    
  }
  
  
}

As a programmer, I would like to understand why adding more variables, adding more code, caused the program to work correctly.

It may be that you had a pointer doing nasty stuff, and adding variables moved or masked that behavior.

If you add debug print statements, always make sure that you use the F() macro, where appropriate - there's few things worse than having your debug code eat into your RAM, to the point that it starts introducing bugs.

AWOL:
It may be that you had a pointer doing nasty stuff, and adding variables moved or masked that behavior.

If you add debug print statements, always make sure that you use the F() macro, where appropriate - there's few things worse than having your debug code eat into your RAM, to the point that it starts introducing bugs.

Yep, I also thought of memory corruption.

Well, it is up and running, it is working fine. I suspect one day, I will sit down and find what was causing it.

Thanks for responding.

The serial prints could also delay the processes slightly so that the comm with the sensor can be read correctly. I doubt it has anything to do with memory. The arduino would crash if so.

mistergreen:
The serial prints could also delay the processes slightly so that the comm with the sensor can be read correctly. I doubt it has anything to do with memory. The arduino would crash if so.

I also thought of that, went so far as to time the calls, I then removed the prints and added a delay for that amount of time. I know, not exact.

Odd thing is, now it works perfect.

Your comment about it would just crash had it been memory. I was under the impression that it could crash, or it could behave unexpectedly, similar to what I was seeing.

Thanks for responding.

processCommand
sensStatusTemp

Please check your pointers for NULL before using them. Often a cause of problems.

sterretje:
processCommand
sensStatusTemp

Please check your pointers for NULL before using them. Often a cause of problems.

Yep, I agree and the only place where pointers could come into play is using the json parser, seeing that I was getting output I dismissed that as a culprit. However, I will go and reexamine this.

Normally attempting to access a NULL pointer would lead to a crash of an application. Is that not true on the Arduino?

With no MMU, a rogue or null pointer can cause all sorts of problems on an AVR

I know a very good way of reducing the memory size of a program. Instead of using digitalRead / digitalWrite, u could look up the atmega 328p datasheet and code it somewhat like this -

PORTD |= B11110000; = Setting digital port 4, 5, 6 and 7 high.