Stange I2C problem

Hi there

I have this LCD - LCD03 hooked up to my arduino. I did have it all working in serial mode but there seemed to be some noise which occasionally displayed rubbish on the screen. I changed over to I2C mode and it works perfectly now (in terms of stability but I am left with the problem below).

I have a bunch of values that I display to the screen. They all work fine apart from 2 of them. The values that don't work correctly are ints.

humidity = atoi(strtok(NULL, ","));

Wire.print("Humidity   ");
Wire.print(humidity);
Serial.println(humidity);
Wire.print("%");

The code above is where the data is printed to the LCD. The LCD shows "8" but the correct value is 89 and this is outputted on the serial interface (I have done this just to test). There is also one line that takes the data value out of an incoming data string. This seems to be working correctly though as the value coming out of the serial is OK. The other strange thing is that it does not print the "%" symbol. However if I comment out the Wire.print(humidity) line then the "%" symbol is displayed fine.

David

What happens if, instead of converting the humidity string to an int, and printing the int, you just print the humidity string?

What is Wire an instance of? If Wire is the standard Wire library, I don't believe it really handles ints. I didn't think it had a print() method at all.

Hi

I created a String called tempstring as follows -

String tempstring ="89";
Wire.print(tempstring);

(It gives an error if I try to use Wire.write above.)

This only displays "9" on the screen. All of the other values I have are floats which work fine.

The code below is what I use to extract the data values from the string. The floats as I said print out to the LCD without a problem with this code - Wire.print(windspeed,1);

I have tried switch humidity to a float as well to see if it would work with the same results - only "8" is displayed on the screen.

  temptempC = atof(strtok(pageValue, ","));
  tempwindspeed = atof(strtok(NULL, ",")); 
  tempwinddir = atof(strtok(NULL, ","));
  temppressure = atof(strtok(NULL, ","));
  temprainfall = atof(strtok(NULL, ","));
  temprainfall = temprainfall / 1000;
  temphumidity = atoi(strtok(NULL, ","));
  tempdewpoint = atof(strtok(NULL, ","));
  tempminutes = atoi(strtok(NULL, ","));
  temphours = atoi(strtok(NULL, ","));
  tempday = atoi(strtok(NULL, ","));
  tempmonth = atoi(strtok(NULL, ","));
  tempyear = atoi(strtok(NULL, ","));

The correct ratio of answers to questions is generally 1. A higher ratio is better than a ratio less than 1.

Post all of your code if you don't understand the questions.

#include <SPI.h>
#include <Ethernet.h>
#include <stdio.h>
#include <EthernetUdp.h>
#include <Wire.h>

EthernetClient client;
char inString[60]; // string for incoming serial data
char pageValue[60]; // string for incoming serial data
int stringPos = 0; // string index counter
boolean startRead = false; // is reading?

#define LCD_TIMEOUT 3000
#define address 0x63  //OBS! 0xC6 but 7 bit does 63 Hex dvs.1100011 1100011 last bit disappear

int lcd03_clearScreen = 12;
int lcd03_ledon = 19;
int lcd03_setcursor = 2;
int lcd03_hidecursor = 4;
int whichscreen = 10;

int humidity = 0;
float dewpoint = 0;
float pressure = 0;
float winddir = 0;
float windspeed = 0;
float tempC = 0;
float rainfall = 0;
unsigned int year = 0, month = 0, day = 0, hours = 0, minutes = 0, seconds = 0;

int temphumidity = 0;
float tempdewpoint = 0;
float temppressure = 0;
float tempwinddir = 0;
float tempwindspeed = 0;
float temptempC = 0;
float temprainfall = 0;
unsigned int tempyear = 0, tempmonth = 0, tempday = 0, temphours = 0, tempminutes = 0, tempseconds = 0;
String tempstring = "99";
unsigned long lcdPrevTime = 0;



byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,1, 200);

void setup() {

  Wire.begin();
  
  Wire.beginTransmission(address);
  Wire.write(0);
  Wire.write(27);                                  //Create a custom character for the degrees symbol
  Wire.write(128);
  Wire.write(135);
  Wire.write(133);
  Wire.write(135);
  Wire.write(128);
  Wire.write(128);
  Wire.write(128);
  Wire.write(128);
  Wire.write(128);
  delay(50);
  Wire.write(21);                                   // Disable the startup screen
    
  Wire.write(lcd03_clearScreen);                    // Clear data to the screen
  delay(50);
  Wire.write(lcd03_ledon);
  delay(50);
  Wire.write(21);                                   // Disable the startup screen
  delay(50);
  Wire.write(lcd03_hidecursor);
  delay(50);
  Wire.endTransmission();
  delay(50);
  Wire.beginTransmission(address);
  Wire.write(0);
  Wire.write(lcd03_setcursor);
  Wire.write(3);
  delay(50);
  Wire.write("Weather");
  delay(50);
  Wire.write(lcd03_setcursor);
  Wire.write(28);
  Wire.write("Centre");
  
  Wire.write(lcd03_setcursor);
  Wire.write(0);
  Wire.write(45);

  Wire.endTransmission();
  delay(50);
  
    if (Ethernet.begin(mac) == 0) {
    // initialize the ethernet device not using DHCP:
    Ethernet.begin(mac, ip);
  }
 
   Serial.begin(9600);
   
  ip = Ethernet.localIP();
    
  Wire.beginTransmission(address);
  delay(1000);
  Wire.print("1");      //192 shows up as 92 so fudge it

  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    // print the value of each byte of the IP address:
    Serial.print(ip[thisByte],DEC);
    Wire.print(ip[thisByte],DEC);
    //Wire.print(ip[thisByte], DEC);
    if (thisByte < 3){
      Serial.print(".");
      Wire.write(".");
    }
  }
  Wire.endTransmission();
  delay(500);
  

}


void loop() {
  
  memset( &pageValue, 0, 60 ); //clear inString memory
  
connectAndRead().toCharArray(pageValue, 59);

if (pageValue == "connection failed")
{
  Wire.beginTransmission(address);
  Wire.write(lcd03_clearScreen);                    // Clear data to the screen
  Wire.write(lcd03_setcursor);
  Wire.write(65);
  Wire.print("Coms Error");
  Wire.endTransmission();
  delay(2000);
  setup();
}
else
{
  temptempC = atof(strtok(pageValue, ","));
  tempwindspeed = atof(strtok(NULL, ",")); 
  tempwinddir = atof(strtok(NULL, ","));
  temppressure = atof(strtok(NULL, ","));
  temprainfall = atof(strtok(NULL, ","));
  temprainfall = temprainfall / 1000;
  temphumidity = atoi(strtok(NULL, ","));
  tempdewpoint = atof(strtok(NULL, ","));
  tempminutes = atoi(strtok(NULL, ","));
  temphours = atoi(strtok(NULL, ","));
  tempday = atoi(strtok(NULL, ","));
  tempmonth = atoi(strtok(NULL, ","));
  tempyear = atoi(strtok(NULL, ","));
  
  if (temptempC < 80)                  //Simple limit checks
  {
    if (tempdewpoint < 80)
    {
      //Then the data is OK
      tempC = temptempC;
      windspeed = tempwindspeed;
      winddir = tempwinddir;
      pressure = temppressure;
      rainfall = temprainfall;
      humidity = temphumidity;
      dewpoint = tempdewpoint;
      minutes = tempminutes;
      hours = temphours;
      day = tempday;
      month = tempmonth;
      year = tempyear;
    }
  }
}

delay(5000); //wait 5 seconds before connecting again
  
Serial.write(lcd03_clearScreen);                    // Clear data to the screen
    delay(50);
    
 if (millis() - lcdPrevTime > LCD_TIMEOUT)
  {
    Wire.beginTransmission(address);                    //Full config each time incase the display has just been turned on
    Wire.write(0);
    Wire.write(lcd03_clearScreen);                    // Clear data to the screen
    delay(50);
    Wire.write(lcd03_ledon);
    delay(50);
    Wire.write(lcd03_hidecursor);
    delay(50);
    Wire.endTransmission();
    
    
    Wire.beginTransmission(address);                    //Full config each time incase the display has just been turned on
    Wire.write(0);
    Wire.write(lcd03_clearScreen);                    // Clear data to the screen
    delay(50);
    Wire.write(lcd03_ledon);
    delay(50);
    Wire.write(lcd03_hidecursor);
    delay(50);
    Wire.endTransmission();
    whichscreen++;
    
    if (whichscreen < 5){
      Wire.beginTransmission(address); 
      Wire.write(0);
      Wire.print("Wind Speed   ");
      Wire.print(windspeed,1);
      Wire.write(lcd03_setcursor);
      Wire.write(18);
      Wire.print("mph");
      delay(100);
      Wire.write(lcd03_setcursor);
      Wire.write(21);
      Wire.print("Wind Dir     ");
      delay(50);
      Wire.print(winddir,0);
      delay(50);
      Wire.endTransmission();
      
      Wire.beginTransmission(address); 
      Wire.write(0);
      delay(100);
      Wire.write(lcd03_setcursor);
      Wire.write(38);
      Wire.print("deg");
      delay(100);
      Wire.write(lcd03_setcursor);
      Wire.write(41);
      Wire.print("Temperature  ");
      delay(100);
      Wire.print(tempC,2);
      delay(50);
      Wire.endTransmission();
      
      Wire.beginTransmission(address); 
      Wire.write(0);
      delay(50);
      Wire.write(128);
      Wire.print("C");
      delay(100);
      Wire.write(lcd03_setcursor);
      Wire.write(61);
      Wire.print("Pressure     ");
      Wire.print(pressure,0);
      Wire.print("mB");
      delay(50);
      Wire.endTransmission();
    }
    else
    {
      Wire.beginTransmission(address); 
      Wire.write(0);
      delay(100);
      Wire.print("Rainfall   ");
      Wire.print(rainfall,2);
      Wire.print("mm");
      Wire.write(lcd03_setcursor);
      Wire.write(21);
      delay(50);
      Wire.print("Humidity   ");
      Wire.print(humidity); 
      Wire.print("%");
      delay(50);
      Wire.endTransmission();
      
      Wire.beginTransmission(address); 
      Wire.write(0);
      Wire.write(lcd03_setcursor);
      Wire.write(41);
      delay(50);
      Wire.print("Dew Point  ");
      Wire.print(dewpoint);
      Wire.write(128);
      Wire.print("C");
      delay(0);
      Wire.endTransmission();
      
      Wire.beginTransmission(address); 
      Wire.write(0);
      Wire.write(lcd03_setcursor);
      Wire.write(61);
      Wire.print(hours);
      Wire.print(":");
      if (minutes<10)  {
        // In the first 10 minutes of each hour, we'll want a leading '0'
        Wire.print('0');
      }
      Wire.print(minutes);
      Wire.print("     ");
      Wire.print(day);
      Wire.print(":");
      Wire.print(month);
      Wire.print(":");
      Wire.print(year);
      delay(100);
      Wire.endTransmission();
      
      if (whichscreen > 10)
      {
        whichscreen = 0;
      }
    }
    
    lcdPrevTime = millis();
  }
}


String connectAndRead(){

  //connect to the server

  //port 80 is typical of a www page
  if (client.connect("someaddress", 80)) {

    client.print("GET ");
    client.println("/?100");
    client.println();

    //Connected - Read the page
    return readPage(); //go and read the output
  }else{
    return "connection failed";
  }

}

String readPage(){
  //read the page, and capture & return everything between '*' and '!'

  stringPos = 0;
  memset( &inString, 0, 60 ); //clear inString memory
  

  while(true){

    if (client.available()) {

      char c = client.read();

      if (c == '*' ) { //'<' is our begining character
        startRead = true; //Ready to start reading the part 
      }else if(startRead){

        if(c != '!'){ //'>' is our ending character
          inString[stringPos] = c;
          stringPos ++;
        }else{
          //got what we need here! We can disconnect now
          startRead = false;
          client.stop();
          client.flush();
                 
          return(inString);
        }

      }
    }

  }

}

Why do all of your variable names have temp in them? Is nothing permanent in your world?

  Wire.print("1");      //192 shows up as 92 so fudge it

No. This is wrong. It seems clear that the LCD expects some kind of "start of text" indication, and so it consumes the first character sent as that indicator.

I would like to see a link to this LCD. I don't think banging out an extra character is the answer.

connectAndRead().toCharArray(pageValue, 59);

if (pageValue == "connection failed")

The address of the pageValue array will never equal the address where "connection failed" is stored, so this test will never result in the following code being executed. You might as well delete it.

Or, use strcmp() to do the test right.

    Wire.endTransmission();
    
    
    Wire.beginTransmission(address);                    //Full config each time incase the display has just been turned on

Why? If the previous data got to the LCD, why would the next stuff not? If the previous data didn't, why assume that the next stuff will?

Why are you clearing the screen twice each time there is data to write to it?

I don't understand the stopping and starting of sending data to the LCD.

      Wire.print(pressure,0);

If you don't want decimal points, why is pressure a float?

      Wire.beginTransmission(address); 
      Wire.write(0);
      delay(50);
      Wire.write(128);
      Wire.print("C");
      delay(100);

I'm not a big fan of magic numbers. What does Wire.write(128); do? Could you make a function with a meaningful name, and call that, instead?

Same for this:

      Wire.write(lcd03_setcursor);
      Wire.write(61);

A function called setCursor() that took an argument (the new cursor position) would be better, in my opinion.

      Wire.print(minutes);
      Wire.print("     ");
      Wire.print(day);
      Wire.print(":");
      Wire.print(month);
      Wire.print(":");
      Wire.print(year);

These are all ints, are they not? They all print correctly, do they not? I think you need to look into some other area of the code, rather than thinking that printing ints to the LCD is not working.

That whole mess with wrapping a global char array in a String and then extracting the char array as a local variable has got to go.

Wire.print is all very well but the Wire library has a limit of 32 bytes to be sent between Wire.beginTransmission and Wire.endTransmission.

A quick count would tend to suggest you have overflowed that which explains why you are getting truncation and you "fix" it by reducing the stuff that comes before.

Also please note that, at present, the String library has bugs as discussed here and here.

In particular, the dynamic memory allocation used by the String class may fail and cause random crashes.

I recommend reworking your code to manage without String. Use C-style strings instead (strcpy, strcat, strcmp, etc.).

You are bang on the money!

Just tried breaking up the data transmission further and then it worked!

I didn't realise about the limit of 32 bytes per transmission cycle. I was starting to work towards something like that but it would have taken me much longer to figure it out.

Thanks very much!