Go Down

Topic: [SOLVED] Spontaneous Appearance of a Non Expected Digit in my LCD (Read 94 times) previous topic - next topic

Jarogue

Hello,

I am having a hard time trying to find out why an additional 0 suddently appears when displaying data on a LCD. I am using I2C comunication.

It's a sketch where I set the colour composition of a RGBLED using a potentiometer. The intensity of the light is set with a LDR and the LCD shows the colour composition in porcentage values.

Here is the code:
Code: [Select]
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27, 16, 2);

// PIN DECLARATION
#define red   9
#define green 6
#define blue  5
#define potentiometer A0
#define LDR A1

// LIGHT SYSTEM VALUES
int ldrValue;
int ldrMax = 0;
int ldrMin = 1023;
int potValue;
int redValue;
int greenValue;
int blueValue;

// TIMING VARIABLES
unsigned long current_time;             // Used for Serial Port
unsigned long last_time;                // Used for Serial Port
unsigned long display_interval = 2500;  // Used for Serial Port

// LCD VARIABLES
char buffer_data[16];                   // Stores the data to print in the LCD
byte display_setting = 0;               // Counter to switch the display setting

void setup() {
  lcd.begin();
  Wire.begin();
  Serial.begin(9600);
  pinMode(red,   OUTPUT);
  pinMode(green, OUTPUT);
  pinMode(blue,  OUTPUT);
// Calibration of the LDR sensor
  while (millis() < 5000) {
    ldrValue = analogRead(LDR);
    lcd.setCursor(0, 0);
    lcd.print("calibrating");
    if (ldrValue > ldrMax) {
      ldrMax = ldrValue;
    }
    else if (ldrValue < ldrMin) {
      ldrMin = ldrValue;
    }
  }
  lcd.clear();
}

void loop() {
  potValue = analogRead(potentiometer);
  ldrValue = map(analogRead(LDR), 0, 1023, 255, 0);
  ldrValue = constrain(ldrValue, 0, 255);
  if (potValue < 341) {
    redValue = map(potValue, 0, 341, ldrValue, 0);
    redValue = constrain(redValue, 0, ldrValue);
    greenValue = map(potValue, 0, 341, 0, ldrValue);
    blueValue = 0;
  }
  else if (potValue >= 341 && potValue < 682) {
    redValue = 0;
    greenValue = map(potValue, 341, 682, ldrValue, 0);
    blueValue = map(potValue, 341, 682, 0, ldrValue);
  }
  else {
    redValue = map(potValue, 682, 1023, 0, ldrValue);
    redValue = constrain(redValue, 0, ldrValue);
    greenValue = 0;
    blueValue = map(potValue, 682, 1023, ldrValue, 0);
  }
  analogWrite(red, redValue);
  analogWrite(green, greenValue);
  analogWrite(blue, blueValue);
 
  lcd.setCursor(0, 0);
  lcd.print("Composition (%)");
  sprintf(buffer_data, "R:%0.2d G:%0.2d B:%0.2d", (redValue*100)/(redValue + greenValue + blueValue), (greenValue*100)/(redValue + greenValue + blueValue), (blueValue*100)/(redValue + greenValue + blueValue));
  lcd.setCursor(0, 1);
  lcd.print(buffer_data);

  //I use this for debugging
  current_time = millis();
  if (current_time - last_time >= display_interval) {
    Serial.print("RED: ");
    Serial.print(redValue);
    Serial.print(" GREEN: ");
    Serial.print(greenValue);
    Serial.print(" BLUE: ");
    Serial.println(blueValue);
    Serial.print(" POT: ");
    Serial.println(potValue);
    last_time = current_time;
  }
}

I know using integers I don't get the exact value, but that doesn't worry me. What actually does is the fact that when manipulating the potentiometer, a 0 appears in the position (1, 14). It doesn't happen avery time, but it's always triggered when entering here:
Code: [Select]
  else {
    redValue = map(potValue, 682, 1023, 0, ldrValue);
    redValue = constrain(redValue, 0, ldrValue);
    greenValue = 0;
    blueValue = map(potValue, 682, 1023, ldrValue, 0);
  }

I know doing lcd.clear() every five seconds, for example, would work but I don't find it a clean solution.

Do anybody know what is happening?

Thanks in advance.

J-M-L

I've not read the code but very often when a characters appears in a LCD when it's not supposed to be there it's because you did not correctly erase the screen before.

imagine you print at position (x,y) a number. say 8, all good.
Now you print 10 at the same position. all good. you have '1' at (x,y) replacing the 8 and '0' at (x+1, y)
Now you print 9 at the same position and guess what, it did not erase the 0, so you see 90 (but there is no color telling you where this comes from)

---
PS: reading the code

note that the constrain is not necessary there:
Code: [Select]
  ldrValue = map(analogRead(LDR), 0, 1023, 255, 0);
  ldrValue = constrain(ldrValue, 0, 255);
as you are guaranteed that analogRead() will give you a value between 0 and 1023, which is the full range you are using in the map() call.

also you might want to do a
Code: [Select]
  Serial.println(strlen(buffer_data));, who knows you might hit a special condition where your buffer is too small as you sized it pretty tightly (although should fit)
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

lesept

Position (1, 14) is the position just after the end of your buffer_data
For example: "R:24 G:12 B:64" takes exactly 14 characters thus is displayed from position (0,1) to (13,1)

The problem is that the LCD may be too slow for the rate you want it to display your buffer. Try slowing it down: do you really need to measure every 100 microseconds or so?

Add a delay(50) at the end of your loop.
A force d'essayer on finit par réussir... Donc, plus ça rate, plus on a de chances que ça marche (proverbe Sharduinok).

J-M-L

I think you are bitten by my first guess

"R:00 G:00 B:100" will be 15 chars. If you get to display that, then rest of the time you have this trailing 0 that will stay on screen
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

Jarogue

That is what is happening. It shows R:XX G:XX B:XX until the potentiometer gets a value over 682. In that moment, it starts showing R:XX G:XX B:XX0. The last digit is added, it was not displayed before.

Quote
do you really need to measure every 100 microseconds or so?
No, but I try to avoid using delay(). I will try it ussing millis()

J-M-L

That is what is happening. It shows R:XX G:XX B:XX until the potentiometer gets a value over 682. In that moment, it starts showing R:XX G:XX B:XX0. The last digit is added, it was not displayed before.
you might have a buggy read that gets you to 0,0,255 which then gets you to the display I mentioned above "R:00 G:00 B:100"

That will add the 0 --> either you ensure this is never happening or you add a trailing space in your buffer (and make it 1 byte larger) to erase it when it happens
Code: [Select]
char buffer_data[17];                   // Stores the data to print in the LCD

...

                                            // | notice the space here
                                            // v
  sprintf(buffer_data, "R:%0.2d G:%0.2d B:%0.2d ", (redValue*100)/(redValue + greenValue + blueValue), (greenValue*100)/(redValue + greenValue + blueValue), (blueValue*100)/(redValue + greenValue + blueValue));
  lcd.setCursor(0, 1);
  lcd.print(buffer_data);
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

Jarogue

Adding that space did solve the problem. Printing data on the LDC every 250 ms also solved the issue.

Thank you very much for your help.

Go Up