TouchShield text() display error

Hi everyone. This is my first attempt at C code programming. I have used idea oriented languages like Python and MATLAB, but C is giving me some trouble.

I am trying to use the Arduino and the TouchShield to monitor a couple of pressures and temperatures in my car. Right now I just have one 50 PSIA pressure sensor. The problem is when boost_max is printed to the TouchShield using the text() command. It looks like the four digit character array is bein printed several times across the screen. The text that is specified by the code is deleted and overwritten correctly when the boost_max array is updated, but the excess text is just overwritten. I am not sure if this lends any clues.

Arduino Code:

//This code should be downloaded onto the Arduino

#include "NewSoftSerial.h"
#define RXPIN 3 //3
#define TXPIN 2 //2
NewSoftSerial mySerial(RXPIN,TXPIN);

int val=0;
float boost=0;
float boost_max=0;
void setup()
{
pinMode(RXPIN, INPUT);
pinMode(TXPIN, OUTPUT);
mySerial.begin(9600);
}

void loop()
{
  //mySerial.print(123456);
  val = analogRead(0);
  boost = val*.0049;              //  A/D conversion
  boost = boost*(50/4)-(50/4*0.5);  //  Applying scaling  
  
  mySerial.print(1);
  mySerial.print(boost);
  delay(500);

  if (boost > boost_max)
  {
    boost_max = boost;
    mySerial.print(2);
    mySerial.print(boost);
    delay(200);
  }
}

TouchShield Slide Code:

//This code should be downloaded onto the TouchShield Classic or Steath

char input[5];
char boost_max[4];
char output[4];

void setup()
{
Serial.begin(9600);
background(0,0,0);

  stroke(0,255,0);
  text("Manifold Pressure",40,40,14);
  stroke(255,0,0);
  text("PSI",220,80,24);
  
  stroke(0,255,0);
  text("Maximum Pressure",40,120,14);
  stroke(255,0,0);
  text("PSI",220,160,24);
}

void loop()
{  
  if (Serial.available()>5)
  {
    for (int i=0; i <= 5; i++)
    {
      input[i] = Serial.read();
    }  
//    Serial.flush();
  }
  
  if (input[0] == '1')
  {
    stroke(0,0,0);
    text(output,60,80,24);
    
    for (int k=0; k <= 4; k++)
    {
      output[k]=input[k+1];
    }
    stroke(255,0,0);
    text(output,60,80,24);
    delay(10);
  }

  if (input[0] == '2')
  {
    
   stroke(0,0,0);
    text(boost_max,60,160,24);
    
    for (int j=0; j <= 4; j++)
    {
      boost_max[j]=input[j+1];
    }
    stroke(255,0,0);
    text(boost_max,60,160,24);
    delay(10);
  }
}

Thanks in advance for any assistance...

C_Inept,

For a first attempt at C, you did pretty darn well. Here are some suggestions:

  1. Use the code button for posting programs. If you click on the '#' button at the top of the posting window, it will insert 'code' and '/code' markup. Putting your code between those markup tags will make it easier to read.

  2. Here's your Arduino code, with my comments:

//This code should be downloaded onto the Arduino

#include "NewSoftSerial.h"
#define RXPIN 3 //3
#define TXPIN 2 //2
NewSoftSerial mySerial(RXPIN,TXPIN);

//**** I'd move val, boost, and boost_max into loop().  When you put them
//**** here, they are global to the whole program.  When your programs
//**** get bigger, it will become more important to only make variables
//**** global when they need to be global.

int val=0;
float boost=0;
float boost_max=0;
void setup()
{
pinMode(RXPIN, INPUT);       // I think NewSoftSerial sets the pinMode 
pinMode(TXPIN, OUTPUT);    // for you, so you don't need these 2 lines.
mySerial.begin(9600);
}

void loop()
{
 //mySerial.print(123456);
 val = analogRead(0);
 boost = val*.0049;              //  A/D conversion

// When you do the division (50 / 4), it does integer division and truncates.  The answer will be 12, not 12.5
// Use floating point constants to get the right answer
//  boost = boost*(50/4)-(50/4*0.5);  //  Applying scaling  
 boost = boost*(50.0/4.0)-(50.0/4.0*0.5);  //**** corrected Applying scaling  
 
 mySerial.print(1);
 mySerial.print(boost);
 delay(500);

 if (boost > boost_max)
 {
   boost_max = boost;
   mySerial.print(2);
   mySerial.print(boost);
   delay(200);
 }
}

Now, the TouchShield code:

//This code should be downloaded onto the TouchShield Classic or Steath

// Increase size of input[] to allow for NUL terminator
char input[5+1];           // also, should be in loop(), not global
// I made changes so you don't need boost_max[] or output[]
// See below.  If you do use them, add 1 to size for NUL terminator.
//char boost_max[4+1];
//char output[4+1];

void setup()
{
Serial.begin(9600);
background(0,0,0);

 stroke(0,255,0);
 text("Manifold Pressure",40,40,14);
 stroke(255,0,0);
 text("PSI",220,80,24);
 
 stroke(0,255,0);
 text("Maximum Pressure",40,120,14);
 stroke(255,0,0);
 text("PSI",220,160,24);
}

void loop()
{  
 if (Serial.available()>5)
 {
   for (int i=0; i <= 5; i++)
   {
     input[i] = Serial.read();
   }
   input[i] = '\0';       // Add NUL terminator
//    Serial.flush();
 }
 
 if (input[0] == '1')
 {
   stroke(0,0,0);
   //text(output,60,80,24);
   text((input+1),60,80,24);       // **** corrected
   
   //for (int k=0; k <= 4; k++)
   //{
   //  output[k]=input[k+1];
   //}
  
   stroke(255,0,0);
   //text(output,60,80,24);
   text(input+1,60,80,24);      //**** corrected
   delay(10);
//****  I don't understand why you output it once as (0,0,0), then again
//**** as (255,0,0).
 }

 if (input[0] == '2')
 {
   
  stroke(0,0,0);
   //text(boost_max,60,160,24);     //**** boost_max has not been set
   
   //for (int j=0; j <= 4; j++)
   //{
   //  boost_max[j]=input[j+1];
   //}
   stroke(255,0,0);
   //text(boost_max,60,160,24);
   text((input+1),60,160,24);        //**** corrected
   delay(10);
 }
}

I hope this helps you to get it working!

Regards,

-Mike

Mike, thanks for the quick answer and detailed info. I will implement your suggestions tonight and see how it goes.

The reason I write the previous text in black (0,0,0) and then the new text in red (255,0,0) is just to clear that part of the screen. For example, if the previous value was '8' and the new value '1' and I did not overwrite the '8', the text() function would print the '1' over the '8' and leave all the pixels lit. By writing the '8' in black first I essentially clear that portion of the screen so all that shows up is the '1'.

This does result in a slight flicker of the screen. I have thought of turning off and on specific pixels using some type of matrix, but that seems much more complicated than it should be. If there is a better way to do this I am all ears.

C_Inept,

Thanks for the clarification. Your original code makes more sense to me now. Your problem was caused by not NUL-terminating the strings you were passing to text().

The changes I posted would mess up the erasing of the previous text. Here's a better version:

//This code should be downloaded onto the TouchShield Classic or Steath

void setup()
{
Serial.begin(9600);
background(0,0,0);

 stroke(0,255,0);
 text("Manifold Pressure",40,40,14);
 stroke(255,0,0);
 text("PSI",220,80,24);

 stroke(0,255,0);
 text("Maximum Pressure",40,120,14);
 stroke(255,0,0);
 text("PSI",220,160,24);
}

void loop()
{
  char input[5+1];
  static char boost_max[4+1];   // static vars persist from call to call
  static char output[4+1];

 if (Serial.available()>5)
 {
   for (int i=0; i <= 5; i++)
   {
     input[i] = Serial.read();
   }
   input[i] = '\0';       // Add NUL terminator
//    Serial.flush();
 }

 if (input[0] == '1')
 {
   if (strlen(output) > 0)       // not first time through
     {
     stroke(0,0,0);
     text(output,60,80,24);
     }
   strcpy(output,(input+1));  
   stroke(255,0,0);
   text(output,60,80,24);
   delay(10);
 }

 if (input[0] == '2')
 {
  if (strlen(boost_max) > 0)           // not first time through
    {
    stroke(0,0,0);
    text(boost_max,60,160,24);
    }
  strcpy(boost_max,(input+1));  
  stroke(255,0,0);
  text(boost_max,60,160,24);
  delay(10);
 }
}

Regards,

-Mike

Mike,

Thank you for the code corrections. I had to change the length of the boost and boost_max to make them display correctly, but other than that, it works great.

I hope this makes sense:

The next problem that I encountered was that if the pressure went below 10 PSI (scaled) the code on the Touchshield did not work properly and it shifted the 'case' byte (1 or 2 in this case) into the ten's spot and than read the rest of the string from there. To fix this I added mySerial.print(0) if the scaled PSI was below 10 PSI. This fixes the problem, but the OLED displays a zero in the ten's spot if the boost is below 10 PSI (e.x. 09.53 PSI).

I think this problem is also going to happen if the pressure goes to a slight vacuum state (during engine decel or idling). Any ideas of a better way to format my float variables to solve this problem.

Ardiuno:

//This code should be downloaded onto the Arduino

#include "NewSoftSerial.h"
#define RXPIN 3 //3
#define TXPIN 2 //2
NewSoftSerial mySerial(RXPIN,TXPIN);

int val=0;
float boost=00.00;
float boost_max=0;

void setup()
{
pinMode(RXPIN, INPUT);       // I think NewSoftSerial sets the pinMode
pinMode(TXPIN, OUTPUT);    // for you, so you don't need these 2 lines.
mySerial.begin(9600);
Serial.begin(9600);
}

void loop()
{
 val = analogRead(0);
 boost = val*.0049;              //  A/D conversion


 boost = boost*(50.0/4.0)-(50.0/4.0*0.5);  //**** corrected Applying scaling  

if(boost > 10.00)
{
   mySerial.print(1);
   mySerial.print(boost);
   
   Serial.println(1);
   Serial.println(boost);
   delay(200);
}
else
{
   mySerial.print(1);
   mySerial.print(0);
   mySerial.print(boost);
   
   Serial.println(1);
   Serial.println(0);
   Serial.println(boost);
   delay(200);
}  

 if (boost > boost_max)
 {
   boost_max = boost;
   mySerial.print(2);
   mySerial.print(boost);
   delay(200);
 }
}

TouchShield

//This code should be downloaded onto the TouchShield Classic or Steath

void setup()
{
Serial.begin(9600);
background(0,0,0);

 stroke(0,255,0);
 text("Manifold Pressure",40,40,14);
 stroke(255,0,0);
 text("PSI",220,80,24);

 stroke(0,255,0);
 text("Maximum Pressure",40,120,14);
 stroke(255,0,0);
 text("PSI",220,160,24);
}

void loop()
{
  char input[5+1];
  static char boost_max[5+1];   // static vars persist from call to call
  static char output[5+1];

 if (Serial.available()>5)
 {
   for (int i=0; i <= 5; i++)
   {
     input[i] = Serial.read();
   }
   input[6] = '\0';       // Add NUL terminator
   Serial.flush();
 }

 if (input[0] == '1')
 {
   if (strlen(output) > 0)       // not first time through
     {
     stroke(0,0,0);
     text(output,60,80,24);
     }
   strcpy(output,(input+1));  
   stroke(255,0,0);
   text(output,60,80,24);
   delay(10);
 }

 if (input[0] == '2')
 {
  if (strlen(boost_max) > 0)           // not first time through
    {
    stroke(0,0,0);
    text(boost_max,60,160,24);
    }
  strcpy(boost_max,(input+1));  
  stroke(255,0,0);
  text(boost_max,60,160,24);
  delay(10);
 }
 
 input[0]='0';  //set the 'case' value to '0'
 }

C_Inept,

Here's how I would do it

mySerial.print(1);
if(boost < 10.00)
   mySerial.print(" ");     /* pad on left with a space */
mySerial.print(boost);

Serial.println(1);
if (boost < 10.00)
  Serial.println(" ");       /* pad on left with a space */
Serial.println(boost);
delay(200);

You could also format it with sprintf(), but that can be rather slow. For simple formatting like this, what you're doing should be fine.

Regards,

-Mike