Strange Behavior but Consistently Strange

Status
Not open for further replies.

HopWorks

Active member
Hi Everybody,
Sorry for the long-winded post. I wanted to include all the details because I need to know if there is an explanation for all of this.

I am not a C or C++ guru or I would probably be able to answer this, but I am seeing some strange behavior and it is shaking my confidence in the absolution of C++ programming. Worse, I am worried I have a bad teensy 3.1 (black board) and these things are signs of subtle issues.

I had a sketch that controlled WS2812 lights using the OctoWS2811 library and it worked very well. I did some great effects and controlled serial communications using interrupts and everything was great. Because I planned to use a few WS2812 LED modules as status indicators for my next project, I left all the code in and built around it. As a new sketch of course. Things got pretty big, but I was still WAY below my memory and flash limits (52k of 256k flash, 4.4k of 64k ram). Then I added a few global variables. Nothing fancy, just a few INT's. Now my program would run for exactly 11 flashes of the board's LED (via intervalTimer) and then went solid and crashed. I repeated the issue several times, and the LED always flashed 11 times, so I knew it was a software issue. I took those global variables back out, and the sketch worked fine. How is it that I declare a few global variables, and not even use them, and that causes a crash?

I figured it was a memory issue, especially since OctoWS2811 uses DMAMEM which I do not fully understand, so I removed everything related to the LED project, added back those few global variables, and all was good again.

Until now. Another anomaly! I created a global variable as 'int armed=false;'. I later used it in an IF, as in 'if(armed=false) Serial1.print("disabled"); else Serial.print("ENABLED"); and the result was 'ENABLED'!!! That would mean that 'armed' is set to true, but I searched my code and NOWHERE is it used except in the above line of code. So, thinking maybe I used a keyword as the variable's name, I changed it to 'system_armed' and now it works as expected, outputting 'disabled'. My question is... WHY???

I have rebooted my windows system, cycled all my project's power, and yet the behavior persists.

Do I have something to worry about?

I haven't posted code yet. I am going to do a simple sketch and see if I can duplicate it. I haven't tried any of my new green board teensy 3.1 units yet. That's next.

Thank you for your time!
 
have you run other large programs on the same Teensy?
Or your prior program?

You symptoms suggest a bad pointer or memory leak in new/delete (malloc/free)
 
if(armed=false) Serial1.print("disabled"); else Serial.print("ENABLED"); and the result was 'ENABLED'

Of course it is, what you probably want is:
Code:
if(armed[COLOR="#FF0000"][B]==[/B][/COLOR]false) Serial.print("disabled"); else Serial.print("ENABLED");
In your version you are assigning armed = false, see this.

More generally, when you start working with variables across interrupts and non-interrupt code, you need to investigate the use of the 'volatile' keyword. See this.
 
Of course it is, what you probably want is:
Code:
if(armed[COLOR="#FF0000"][B]==[/B][/COLOR]false) Serial.print("disabled"); else Serial.print("ENABLED");
In your version you are assigning armed = false, see this.

More generally, when you start working with variables across interrupts and non-interrupt code, you need to investigate the use of the 'volatile' keyword. See this.

My apologies sir. I was typing what I did and it was a typo. The code I am having the issues with does indeed have '=='.

More on this... instead of changing 'armed' to 'system_armed', I decided to leave the variable name the same length, and changed the d to a 1, as in 'arme1'. Just doing that and it works. Changing it back to 'armed' and I'm back to the issue. How can that be? Bad pointer or memory leak in new/delete can cause this behavior? I am not using any pointer manipulation or malloc/free in any way.

I think it is time for code.
Code:
// TEENSY 3.1 MODULE
#include <OneWire.h>
#include <EEPROM.h>

const String nodeid="sbec,teensy31,Seed Bed Environmental Controller,1.04,ws2812(2),ds18b20(3),ssd1306,buttons,ssr";
const String lf= "\r\n";
void EEPROM_writefloat(float value, int ea);
float EEPROM_readfloat(int ea);

IntervalTimer myTimer;
IntervalTimer comm;

volatile boolean term=LOW;
volatile unsigned int ledstate=0;
volatile unsigned char serial_rx[64];
volatile unsigned char serial_tx[64];
volatile unsigned int s_rx_in=0;
volatile unsigned int s_tx_in=0;
volatile unsigned char com[256]="";
volatile unsigned int com_in=0;
volatile unsigned int com_out=0;
volatile bool command=false;
volatile int response=0;
volatile unsigned int ledc=0;
volatile int sensor_idx=0;
bool verbose=false;
int monitor_sensor=99;
float range_low=0;
float range_high=0;
float range_alarm=0;
bool arme1=false;
bool ssr=false;

char a = 0;
const int led = LED_BUILTIN;
String cmd=""; 
byte sensors[80];
int sensor_count=0;
int get_device_ids();
void s(String msg, bool linefeed = false);
void send_init();
float avg[10][20];
//float temps[10]; // Room for 10 averaged updated temps from 10 sensors
String cmd_params[10]="";
OneWire ds(10);  // on pin 10 (a 4.7K resistor is necessary)
union v  {
  float f;
  unsigned char b[4];
}edata;
  
int get_device_ids(){
  byte addr[8];
  int x=0;
  while(ds.search(addr)){
    for(int y=0;y<8;y++){
      sensors[x*8+y]=addr[y];
    }
    x++;
    delay(100);
  }
  return x;
}

void setup()
{
  range_low=EEPROM_readfloat(0);
  range_high=EEPROM_readfloat(4);
  range_alarm=EEPROM_readfloat(8);
  monitor_sensor=EEPROM.read(12);
  Serial1.begin(115200); // Start up MCU to MCU Communications on port 1 lines 0,1
  pinMode(led, OUTPUT);
  Serial.flush();
  delay(1000);
  myTimer.begin(toggle_led2_isr,100000);
  comm.begin(communications_isr,1000);
  digitalWrite(led, HIGH);
  digitalWrite(led, LOW);
  sensor_count=get_device_ids();
  for(int x=0;x<sensor_count;x++) avg[x][0]=-999;
  send_init();
}

void loop()
{

  bool cc;
  noInterrupts();
  cc=command;
  interrupts();

  if(cc==true){
    String mycom=pop_command();
    int cmds=cmd_parse(mycom,cmd_params);

    if(cmd_params[0]=="1"||cmd_params[0]=="i"||cmd_params[0]=="init"){
      s("1,"+nodeid,true);
    }else 
    if(cmd_params[0]=="2"||cmd_params[0]=="l"||cmd_params[0]=="list"){
      s("2,1:i",!verbose); if(verbose) s(":init          - send project init headers",true);
      s("2,2:l",!verbose); if(verbose) s(":list          - list commands (this)",true);
      s("2,3:v",!verbose); if(verbose) s(":verbose (0,1) - clear,set verbose responses",true);
      s("2,4:r",!verbose); if(verbose) s(":read          - return sensor count",true);
      s("2,5:r(n)",!verbose); if(verbose) s(":read (x)   - read sensor x",true);
      s("2,6:s",!verbose); if(verbose) s(":status        - read project status",true);
    }else
    if((cmd_params[0]=="3"||cmd_params[0]=="v"||cmd_params[0]=="verbose")&&cmds<=2){
      if(cmds==2){
        if(cmd_params[1].toInt()>0){
          verbose=true;
        }else{
          verbose=false;
        }
      }else{  
        verbose=!verbose;
      }
      if(verbose){ 
          s("3,Verbose Reporting:ON",true);
      }else{
        s("3,0",true);
      }
    }else
    if((cmd_params[0]=="4"||cmd_params[0]=="5"||cmd_params[0]=="r"||cmd_params[0]=="read")&&cmds<=2){
      if(cmds==1){
        if(verbose){ 
          s("4,Number of Temperature Sensors Detected:");
          s(sensor_count,true);
        }else{
          s("4,");
          s(sensor_count,true);
        }
      }else{  
        if(cmd_params[1].toInt()<sensor_count){
          if(verbose){ 
            s("5,Reading Temperature Sensor:");
            s(cmd_params[1].toInt());
            s(" - ");
            Serial1.print(get_temp(cmd_params[1].toInt(),avg),1);
            s(lf);
          }else{
            s("5,");
            s(cmd_params[1].toInt());
            s(",");
            Serial1.print(get_temp(cmd_params[1].toInt(),avg),1);
            s(lf);
          }
        }else{
          if(verbose){ 
            s("5,ERROR: TEMPERATURE READ - SENSOR '"+cmd_params[1]+"' NOT FOUND",true);
          }else{
            s("5,99,0",true);
          }
        }
      }
    }else 
    if(cmd_params[0]=="6"||cmd_params[0]=="s"||cmd_params[0]=="status"){
      s("6,sensor_count:",false); s(sensor_count,true);
      s("6,range_low:",false); s(range_low,true);
      s("6,range_high:",false); s(range_high,true);
      s("6,range_alarm:",false); s(range_alarm,true);
      s("6,monitor_sensor:",false); s(monitor_sensor,true);
      s("6,ssr:",false); if(ssr==true) s("ON",true); else s("off",true);
      s("6,armed:",false); 
      if(arme1==false){
        s("disabled",true); 
      }else{
        s("ENABLED",true);
      }
      s("6,monitored_temp:",false); Serial1.print(get_temp(monitor_sensor,avg),1);
    }else{
      Serial1.print("ERROR: COMMAND NOT FOUND - "+mycom+"\n\r");
    }
  }
}
void s(String msg, bool linefeed){
  Serial1.print(msg);
  if(linefeed==true) Serial1.print("\r\n");
}
void send_init(){
  s("1,"+nodeid,true);
  if(verbose){
    s("11,HopWorks / TEMPERATURE SENSOR TEST #4",true);
    s("11,NODE - TEENSY 3.1",true);
    s("11,Sensors Detected: ");
    s(sensor_count,true);		
  }
}
int cmd_parse(String a,String cmd_params[]){
  int x=0;
  int index;
  a+=" ";
  while(a.indexOf(' ')!=-1){
    index=a.indexOf(' ');
    cmd_params[x]=a.substring(0,index);
    a=a.substring(index+1);
    x++;
  }
  return x;
}
void initiate_conversion(int sensor){
  byte addr[8];

  for(int y=0;y<8;y++){
    addr[y]=sensors[sensor*8+y];
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44, 0);        // start conversion, with parasite power on at the end
}
float read_sensor(int sensor){
  byte i;
  byte data[12];
  byte addr[8];
  float celsius, fahrenheit;

  for(int y=0;y<8;y++){
    addr[y]=sensors[sensor*8+y];
  }

  ds.reset();
  ds.select(addr);    
  ds.write(0xBE);         // Read Scratchpad

  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();
  }

  int16_t raw = (data[1] << 8) | data[0];
  celsius = (float)raw / 16.0;
  fahrenheit = celsius * 1.8 + 32.0;
  return fahrenheit;
}

void shift_temp_avg(int sensor,float data, float avg[][20]){
  boolean fill=false;
  if(avg[sensor][0]==-999) fill=true;
  for(int x=0;x<19;x++){
    if(fill){
      avg[sensor][x]=data;
    }else{
      avg[sensor][x]=avg[sensor][x+1];
    }
  }
  avg[sensor][19]=data;
}
float get_temp(int sensor, float avg[][20]){
  float average=0;  
  for(int x=0;x<20;x++){
    average+=avg[sensor][x];
  }
  average=average/20;
  return average;
}

String hex(int a){
  String temp=String(a,HEX);
  if(temp.length()==1){
    temp="0"+temp;
  }
  return temp;
}

void toggle_led2_isr(void)//pulse - 50% duty cycle
{
  float data=0;
  if(ledstate==LOW){
    ledstate=HIGH;
    data=read_sensor(sensor_idx);
    shift_temp_avg(sensor_idx,data,avg);
    sensor_idx++;
    if(sensor_idx==sensor_count) sensor_idx=0;
  }else{
    initiate_conversion(sensor_idx);
    ledstate=LOW;
  }
  digitalWrite(led, ledstate);
}

void communications_isr(void)
{
    if (Serial1.available()){
      char a=(char)Serial1.read();
      if(a=='~'){
        term=HIGH;
      }
      if(a==13){
        if(s_rx_in>0) push_command();
        s(lf);
      }else
      if(a==8){
        if(s_rx_in>0){
          s_rx_in--;
          s(a);
        }
      }else{
        serial_rx[s_rx_in]=a;
        s_rx_in++;
        s(a);
      }
    }
}

void push_command(void){
  //a1=s_rx_in;
  
  for(unsigned int i=0;i<s_rx_in;i++){
    com[com_in]=serial_rx[i];
    com_in++;
  }
  //a2=com_in;
  com[com_in]=0;
  com_in++;

  s_rx_in=0;
  command=true;
}

String pop_command(void){
  noInterrupts();
  char mycmd[64]="";
  int i=0;
  while(com[i]!=0){
    mycmd[i]= com[i];
    i++;
  }
  mycmd[i]=0;
  i++;
  for(int i2=0;i2<(256-i);i2++){
    com[i2]=com[i+i2];
  }
  //a3=i;
  //a4=com_in;
  com_in-=i;
  if(com_in==0) command=false;
  //a5=com_in;
  String str(mycmd);
  interrupts();
  return mycmd;
}
void EEPROM_writefloat(float value,int ea){
  edata.f=value;
  EEPROM.write(ea,edata.b[0]);
  EEPROM.write(ea+1,edata.b[1]);
  EEPROM.write(ea+2,edata.b[2]);
  EEPROM.write(ea+3,edata.b[3]);
}

float EEPROM_readfloat(int ea){
  edata.b[0]= EEPROM.read(ea);
  edata.b[1]= EEPROM.read(ea+1);
  edata.b[2]= EEPROM.read(ea+2);
  edata.b[3]= EEPROM.read(ea+3);
  return edata.f;
}
 
Last edited:
I'm going to solder the pins on one of my new teensy 3.1's and see if the issue duplicates. I need to do that anyway.
The code I posted above works as expected when I enter '6' and press ENTER in my remote terminal. That outputs the status, and in that part of the code, you will see the if() conditional. If I change arme1 to armed in the bool declaration, and then again in that conditional, I get 'ENABLED' which would mean armed is true. It is declared as false and not changed anywhere else.
 
have you run other large programs on the same Teensy?
Or your prior program?

You symptoms suggest a bad pointer or memory leak in new/delete (malloc/free)
This is my first larger program. My prior program, the LED one that controlled WS2812's was on the same teensy 3.1.

The only thing I can think of now is what you suggested. I placed Serial1.println(armed); at various places in my code. It is zero '0' up until I process my received serial command. As soon as that condition is true and I start my conditionals, the value of armed changes to '10'. Even though 'armed' isn't accessed anywhere in the program other than the places mentioned, it changes value. So it must be how I handle the intervalTimer interrupts. I still do not see anything wrong, but I'll keep looking.

Please do not give up on me or my post. I am running out of test solutions.:confused:
 
Is the code snippet below an ISR calling functions that may not be coded to be reentrant, esp. C++ class instances - however 'Serial1' is a static instance. But from an ISR, maybe not good to call code that may not be interrupt-safe.

Code:
void communications_isr(void)
{
    if (Serial1.available()){
      char a=(char)Serial1.read();
 
Is the code snippet below an ISR calling functions that may not be coded to be reentrant, esp. C++ class instances - however 'Serial1' is a static instance. But from an ISR, maybe not good to call code that may not be interrupt-safe.

Code:
void communications_isr(void)
{
    if (Serial1.available()){
      char a=(char)Serial1.read();

OK, I suppose I can rewrite that to where this happens in the main loop without interrupt support. I revisited the page on using intervalTimer and as a result, I placed noInterrupts() and interrupts() around the code in that function, but the problem still persisted. Thank you for the suggestion! I'll post after I rewrite it.

To go a little deeper... isn't it weird that the value of 'armed' is set to 10? ALWAYS 10. I set it to false again right where I discovered it changed, and the results were finally what I wanted. But I NEED to know why the declaration assigning this variable as false doesn't stick, and why changing the variable's name fixes the problem. I may have a problem that will resurface as something else later on.
 
I rewrote the code so communications_isr is called from the main loop. I also commented out the intervalTimer code for that isr. The variable changing remains the same unfortunately.

I did have another thing happen though, probably better for another post. I have a two constant string variables, as in...
Code:
const String nodeid="sbec,teensy31,Seed Bed Environmental Controller,1.04,ws2812(2),ds18b20(3),ssd1306,buttons,ssr";
const String lf= "\r\n";
and I use a function I wrote to output strings to the serial1 port, as in...
Code:
void s(String msg, bool linefeed){
  Serial1.print(msg);
  if(linefeed==true) Serial1.print("\r\n");
}
I use my function to output nodeid and it works. I do the same for lf and the teensy crashes. The only difference (shown below) is that I add quoted text to nodeid in the function call. I'm sure that has something to do with it but don't know why. I have no issue reading up on why in my old C++ manual, but it would help to know where to look.
Code:
s("1,"+nodeid,true); // works great!
s(lf); // fails - crashes
I forgot to mention that I have linefeed set to optional and equal to false in a definition.
Code:
void s(String msg, bool linefeed = false);
 
Last edited:
It is zero '0' up until I process my received serial command. As soon as that condition is true and I start my conditionals, the value of armed changes to '10'.

Just a thought here, but you might want to start looking for a buffer overflow. This all kind of seems like a buffer overflow. The variable might be changing because it is getting overwritten. The value of '10' that you mention, is that decimal 10 (not hex 0x10)?

Reason I ask is that the ASCII character '10' decimal corresponds to a newline character.

The naming dependency might be affecting where the variable is placed in memory when it is compiled. Not sure if the compiler organizes variables according to a name, but just a thought. It could explain why the problem "disappears" with a different name (eg. overwrites something else).

If you are constructing strings and passing them to functions which take C-strings as arguments (eg. you specify a string, but not a length), make sure you are using a null termination, otherwise you will almost certainly cause an overflow somewhere.
 
I found the cause. It was OneWire.h
I globally declared two bool variables. I moved my temp sensor code out of the isr and replaced it with those bool variables, setting them to true. When I see them true in the main loop, I do the temp sensor work from there. I see no noticeable difference in performance either. I guess 96MHz is fast enough to get it done without interrupts.

Now the 'armed' variable stays in the same state it was declared as, and my pointer corruption or whatever seems to be fixed.

I sincerely thank you Stevech for the nudge in the right direction. I am absolutely SURE I would not have solved the issue without your help!! I still have that nagging tagged-on issue I mentioned above about the constant strings and how the 'lf' one crashed my code where the other one 'nodeid' did not. If you have incite on that, I would appreciate it.

Thanks again Stevech! My updated working code is posted below for anyone that is curious.
Code:
// TEENSY 3.1 MODULE
#include <OneWire.h>
#include <EEPROM.h>

const String nodeid="sbec,teensy31,Seed Bed Environmental Controller,1.04,ws2812(2),ds18b20(3),ssd1306,buttons,ssr";
const String lf= "\r\n";
const int led = LED_BUILTIN;

IntervalTimer myTimer;
//IntervalTimer comm;

bool armed=false;
volatile boolean term=LOW;
volatile unsigned int ledstate=0;
volatile unsigned char serial_rx[64];
volatile unsigned char serial_tx[64];
volatile unsigned int s_rx_in=0;
volatile unsigned int s_tx_in=0;
volatile unsigned char com[256];
volatile unsigned int com_in=0;
volatile unsigned int com_out=0;
volatile bool command=false;
volatile bool rtemp=false;
volatile bool itemp=false;
volatile int response=0;
volatile int sensor_idx=0;
bool verbose=false;
int monitor_sensor=99;
float range_low=0;
float range_high=0;
float range_alarm=0;
int somevariable=0;
bool ssr=false;

char a = 0;
String cmd=""; 
byte sensors[80];
int sensor_count=0;
int get_device_ids();
void s(String msg, bool linefeed = false);
void send_init();
float avg[10][20];
//float temps[10]; // Room for 10 averaged updated temps from 10 sensors
String cmd_params[10];
OneWire ds(10);  // on pin 10 (a 4.7K resistor is necessary)
union v  {
  float f;
  unsigned char b[4];
}edata;
  
int get_device_ids(){
  byte addr[8];
  int x=0;
  while(ds.search(addr)){
    for(int y=0;y<8;y++){
      sensors[x*8+y]=addr[y];
    }
    x++;
    delay(100);
  }
  return x;
}
void EEPROM_writefloat(float value, int ea);
float EEPROM_readfloat(int ea);

void setup()
{
  //system_armed=false;
  range_low=EEPROM_readfloat(0);
  range_high=EEPROM_readfloat(4);
  range_alarm=EEPROM_readfloat(8);
  monitor_sensor=EEPROM.read(12);
  Serial1.begin(115200); // Start up MCU to MCU Communications on port 1 lines 0,1
  pinMode(led, OUTPUT);
  Serial.flush();
  delay(1000);
  Serial1.println(armed);
  myTimer.begin(toggle_led2_isr,100000);
  //comm.begin(communications_isr,1000);
  digitalWrite(led, HIGH);
  digitalWrite(led, LOW);
  sensor_count=get_device_ids();
  for(int x=0;x<sensor_count;x++) avg[x][0]=-999;
  for(int x=0;x<sensor_count;x++) avg[x][0]=-999;
  send_init();
  Serial1.println(armed);
}

void loop()
{
  float data=0;
	communications_isr();
	if(rtemp=true){
		data=read_sensor(sensor_idx);
    shift_temp_avg(sensor_idx,data,avg);
    sensor_idx++;
    if(sensor_idx==sensor_count) sensor_idx=0;
		rtemp=false;
	}
	if(itemp==true){
		initiate_conversion(sensor_idx);
		itemp=false;
	}
  if(command==true){
  Serial1.println(armed);

    String mycom=pop_command();
    int cmds=cmd_parse(mycom,cmd_params);

    if(cmd_params[0]=="1"||cmd_params[0]=="i"||cmd_params[0]=="init"){
      s("1,"+nodeid,true);
    }else 
    if(cmd_params[0]=="2"||cmd_params[0]=="l"||cmd_params[0]=="list"){
      s("2,1:i",!verbose); if(verbose) s(":init          - send project init headers",true);
      s("2,2:l",!verbose); if(verbose) s(":list          - list commands (this)",true);
      s("2,3:v",!verbose); if(verbose) s(":verbose (0,1) - clear,set verbose responses",true);
      s("2,4:r",!verbose); if(verbose) s(":read          - return sensor count",true);
      s("2,5:r(n)",!verbose); if(verbose) s(":read (x)   - read sensor x",true);
      s("2,6:s",!verbose); if(verbose) s(":status        - read project status",true);
    }else
    if((cmd_params[0]=="3"||cmd_params[0]=="v"||cmd_params[0]=="verbose")&&cmds<=2){
      if(cmds==2){
        if(cmd_params[1].toInt()>0){
          verbose=true;
        }else{
          verbose=false;
        }
      }else{  
        verbose=!verbose;
      }
      if(verbose){ 
          s("3,Verbose Reporting:ON",true);
      }else{
        s("3,0",true);
      }
    }else
    if((cmd_params[0]=="4"||cmd_params[0]=="5"||cmd_params[0]=="r"||cmd_params[0]=="read")&&cmds<=2){
      if(cmds==1){
        if(verbose){ 
          s("4,Number of Temperature Sensors Detected:");
          s(sensor_count,true);
        }else{
          s("4,");
          s(sensor_count,true);
        }
      }else{  
        if(cmd_params[1].toInt()<sensor_count){
          if(verbose){ 
            s("5,Reading Temperature Sensor:");
            s(cmd_params[1].toInt());
            s(" - ");
            Serial1.print(get_temp(cmd_params[1].toInt(),avg),1);
            s(lf);
          }else{
            s("5,");
            s(cmd_params[1].toInt());
            s(",");
            Serial1.print(get_temp(cmd_params[1].toInt(),avg),1);
            s("\r\n");
          }
        }else{
          if(verbose){ 
            s("5,ERROR: TEMPERATURE READ - SENSOR '"+cmd_params[1]+"' NOT FOUND",true);
          }else{
            s("5,99,0",true);
          }
        }
      }
    }else 
    if(cmd_params[0]=="6"||cmd_params[0]=="s"||cmd_params[0]=="status"){
      s("6,sensor_count:",false); s(sensor_count,true);
      s("6,range_low:",false); s(range_low,true);
      s("6,range_high:",false); s(range_high,true);
      s("6,range_alarm:",false); s(range_alarm,true);
      s("6,monitor_sensor:",false); s(monitor_sensor,true);
      s("6,ssr:",false); if(ssr==true) s("ON",true); else s("off",true);
      s("6,armed:",false); 
      if(armed==false){
        s("disabled",true); 
      }else{
        s("ENABLED",true);
      }
      s("6,monitored_temp:",false); Serial1.print(get_temp(monitor_sensor,avg),1);
      s("\r\n");
    }else{
      Serial1.print("ERROR: COMMAND NOT FOUND - "+mycom+"\n\r");
    }
  }
}
void s(String msg, bool linefeed){
  Serial1.print(msg);
  if(linefeed==true) Serial1.print("\r\n");
}
void send_init(){
  s("1,"+nodeid,true);
  if(verbose){
    s("11,HopWorks / TEMPERATURE SENSOR TEST #4",true);
    s("11,NODE - TEENSY 3.1",true);
    s("11,Sensors Detected: ");
    s(sensor_count,true);		
  }
}
int cmd_parse(String a,String cmd_params[]){
  int x=0;
  int index;
  a+=" ";
  while(a.indexOf(' ')!=-1){
    index=a.indexOf(' ');
    cmd_params[x]=a.substring(0,index);
    a=a.substring(index+1);
    x++;
  }
  return x;
}
void initiate_conversion(int sensor){
  byte addr[8];

  for(int y=0;y<8;y++){
    addr[y]=sensors[sensor*8+y];
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44, 0);        // start conversion, with parasite power on at the end
}
float read_sensor(int sensor){
  byte i;
  byte data[12];
  byte addr[8];
  float celsius, fahrenheit;

  for(int y=0;y<8;y++){
    addr[y]=sensors[sensor*8+y];
  }

  ds.reset();
  ds.select(addr);    
  ds.write(0xBE);         // Read Scratchpad

  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();
  }

  int16_t raw = (data[1] << 8) | data[0];
  celsius = (float)raw / 16.0;
  fahrenheit = celsius * 1.8 + 32.0;
  return fahrenheit;
}

void shift_temp_avg(int sensor,float data, float avg[][20]){
  boolean fill=false;
  if(avg[sensor][0]==-999) fill=true;
  for(int x=0;x<19;x++){
    if(fill){
      avg[sensor][x]=data;
    }else{
      avg[sensor][x]=avg[sensor][x+1];
    }
  }
  avg[sensor][19]=data;
}
float get_temp(int sensor, float avg[][20]){
  float average=0;  
  for(int x=0;x<20;x++){
    average+=avg[sensor][x];
  }
  average=average/20;
  return average;
}

String hex(int a){
  String temp=String(a,HEX);
  if(temp.length()==1){
    temp="0"+temp;
  }
  return temp;
}

void toggle_led2_isr(void)//pulse - 50% duty cycle
{
  noInterrupts();
  if(ledstate==LOW){
    ledstate=HIGH;
    rtemp=true;
  }else{
    itemp=true;
    ledstate=LOW;
  }
  digitalWrite(led, ledstate);
  interrupts();
}

void communications_isr(void)
{
  //noInterrupts();
  if (Serial1.available()){
    char a=(char)Serial1.read();
    if(a=='~'){
      term=HIGH;
    }
    if(a==13){
      if(s_rx_in>0) push_command();
      s("\r\n");
    }else
    if(a==8){
      if(s_rx_in>0){
        s_rx_in--;
        s(a);
      }
    }else{
      serial_rx[s_rx_in]=a;
      s_rx_in++;
      s(a);
    }
  }
  //interrupts();
}

void push_command(void){
  //a1=s_rx_in;
  
  for(unsigned int i=0;i<s_rx_in;i++){
    com[com_in]=serial_rx[i];
    com_in++;
  }
  //a2=com_in;
  com[com_in]=0;
  com_in++;

  s_rx_in=0;
  command=true;
}

String pop_command(void){
  //noInterrupts();
  char mycmd[64]="";
  int i=0;
  while(com[i]!=0){
    mycmd[i]= com[i];
    i++;
  }
  mycmd[i]=0;
  i++;
  for(int i2=0;i2<(256-i);i2++){
    com[i2]=com[i+i2];
  }
  //a3=i;
  //a4=com_in;
  com_in-=i;
  if(com_in==0) command=false;
  //a5=com_in;
  String str(mycmd);
  //interrupts();
  return mycmd;
}
void EEPROM_writefloat(float value,int ea){
  edata.f=value;
  EEPROM.write(ea,edata.b[0]);
  EEPROM.write(ea+1,edata.b[1]);
  EEPROM.write(ea+2,edata.b[2]);
  EEPROM.write(ea+3,edata.b[3]);
}

float EEPROM_readfloat(int ea){
  edata.b[0]= EEPROM.read(ea);
  edata.b[1]= EEPROM.read(ea+1);
  edata.b[2]= EEPROM.read(ea+2);
  edata.b[3]= EEPROM.read(ea+3);
  return edata.f;
}
 
Code:
s([COLOR="#FF0000"]"1,"+nodeid[/COLOR],true); // works great!
s(lf); // fails - crashes

I am kind of surprised the above works, using a '+' isn't the way C-string literals are concatenated (unless one of them is a std::string). See this.

edit - doh, sorry you are using String, I see now.
 
I am kind of surprised the above works, using a '+' isn't the way C-string literals are concatenated (unless one of them is a std::string). See this.

edit - doh, sorry you are using String, I see now.
I know, I feel dirty doing it this way, but my C++ is rusty and I really want to get at least a rough beta working for my Seed Bed Environmental Control project. I will revise, and do it right eventually. Then I won't have nasty issues like the one I posted here.
 
Last edited:
When you write "1,"+nodeid, unfortunately the compiler does not automatically convert "1," to an Arduino String object. Instead, it treats the "1," as a normal array of characters and adds the number nodeid to the address where those characters happen to be in memory. So printing starts somewhere after the string, with whatever happens to be in the memory after it.

You probably want to use this: String("1,")+nodeid. That turns the string (an array of char) into a proper Arduino String object. Then you can use + to concatenate other stuff to it.
 
Status
Not open for further replies.
Back
Top