2 Issues with my LCD

I'm having two maybe simple issues with my LCD.

  1. I'm receiving carriage return and line feed symbols from my responding device (which I can not change) but I'm getting some weird symbols instead of the actual "" on the lcd screen. I've tried making some custom characters with an online generator but I'm unsure how to implement these into my code... The code is attached below.

  2. Another issue after printing the "H FCM" command to the LCD, I should just be receiving back "*MICBAC" but I'm getting the command in my response too. this may be confusing for someone who comes to use the device in the future. I'm also not sure how to stop this from happening. (I'm guessing the Arduino is pulling the command from the serial port again and printing it out, is there away to stop/filter this out?). Video Attached - https://photos.app.goo.gl/9SvTbsxtTkiyDmLb8

//RS232 TA TOILET PROGRAM
#include <LiquidCrystal.h>  //lcd library

const int rs = 2, en = 3, d4 = 4, d5 = 5, d6 = 6, d7 = 7;  //lcd pinout

uint8_t p[] = { 0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02, 0x00 };
uint8_t h[] = { 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x00 };
uint8_t u[] = { 0x0e, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0e, 0x00 };
uint8_t r[] = { 0x1e, 0x11, 0x11, 0x1e, 0x14, 0x12, 0x11, 0x00 };
uint8_t l[] = { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1f, 0x00 };
uint8_t f[] = { 0x1f, 0x10, 0x10, 0x1e, 0x10, 0x10, 0x10, 0x00 };

int button_h_fcm = 10;  //sets H FCM button as digital pin #2
int button_d1 = 11;     // sets D1 button as digital pin #3
int button_right = 12;
int button_left = 13;

LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

void setup() {                      //starts Comms, lcd and button pinouts.
  pinMode(button_h_fcm, INPUT);     //sets pintype to input with an internal pull-up resistor
  pinMode(button_d1, INPUT);        //sets pintype to input with an internal pull-up resistor
  lcd.begin(16, 2);                 //starts lcd and screen sizing
  lcd.createChar(0, p);
  lcd.createChar(1, h);
  lcd.createChar(2, u);
  lcd.createChar(3, r);
  lcd.createChar(4, l);
  lcd.createChar(5, f);
  Serial.begin(9600);               //starts comms and sets baudrate on serial monitor/usb
  Serial1.begin(9600, SERIAL_7O2);  //starts comms and sets baudrate on rs485 bus
}

void loop() {
  if (Serial.available() > 0) {  //prints incoming serial data and name tag to LCD and Serial monitor (for testing)
    String rx = Serial.readString();
    Serial.print("TOILET: ");
    Serial.println(rx);
    delay(3000);
    lcd.clear();
    lcd.setCursor(4, 0);
    lcd.print("TOILET: ");
    lcd.setCursor(0, 1);
    lcd.print(rx);
  }
  if (Serial1.available() > 0) {  //prints incoming serial1 data and name tag to LCD and Serial monitor (for toilet bus)
    String rx1 = Serial1.readString();
    Serial.print("TOILET: ");
    Serial.println(rx1);
    lcd.clear();
    lcd.setCursor(4, 0);
    lcd.print("TOILET: ");
    lcd.setCursor(0, 1);
    lcd.print(rx1);
  }
  if (digitalRead(button_h_fcm) == HIGH) {  //prints specific command plus name tag to serial1, serial monitor and lcd.
    Serial.println("H FCM");
    Serial1.println("H FCM");
    lcd.clear();
    lcd.setCursor(4, 0);
    lcd.write("COMMAND: ");
    lcd.setCursor(5, 1);
    lcd.write("H FCM");
    delay(500);
  }
  if (digitalRead(button_d1) == HIGH) {  //prinD1 startaddress stopaddress");
    Serial1.println("D1 startaddress stopaddress");
    lcd.clear();
    lcd.setCursor(4, 0);
    lcd.write("COMMAND: ");
    lcd.setCursor(0, 1);
    lcd.write("D1 startaddress stopaddress");
    delay(500);
  }
  if (digitalRead(button_right) == HIGH) {  //scrolls the lcd to the right
    for (int pos = 0; pos < 15; pos++)
      ;
    lcd.scrollDisplayRight();
    lcd.setCursor(0, 1);
    delay(200);
  }
  if (digitalRead(button_left) == HIGH) {  //scrolls the lcd to the left
    for (int pos = 0; pos < 15; pos++)
      ;
    lcd.scrollDisplayLeft();
    lcd.setCursor(0, 1);
    delay(200);
  }
}

I count three...

  • CRLF
  • custom characters.
  • The third issue of lcd-printing H FCM is in your code:

If you do not want to print CRLF, do not print the last two bytes received.

H FCM...

  if (digitalRead(button_h_fcm) == HIGH) {  //prints specific command plus name tag to serial1, serial monitor and lcd.
    Serial.println("H FCM");
    Serial1.println("H FCM");
    lcd.clear();
    lcd.setCursor(4, 0);
    lcd.write("COMMAND: ");
    lcd.setCursor(5, 1);
    lcd.write("H FCM"); // <- this says to print H FCM to LCD when the button is pressed
    delay(500);
  }

"MICBAC" must be incoming data, because it is not mentioned in the code you posted... maybe the line identified previously should read

  lcd.print(rx1);

or something else received from the serial channel.

I usually use lcd.write() for single characters and ASCII values, and lcd.print() for strings/character arrays. I do not know if what I do is good/standard practice or a bad habit.

1 Like

The CRLF is the custom character issue, they appear as " ☰" symbols when received rather than "CRLF". I'd like to get rid of these if that's possible so the system is more "English" for the end user.
I'm not sure how to stop the last two bytes sending like you said.

Yes, this is when i send my command so that the user can acknowledge they've pressed the button. i should then receive the response "TOILET: MICBAC", but I'm receiving "TOILET: H FCMMICBAC"... basically receiving H FCM don't he lcd again when I just want to send.

I've corrected this

Correct

1 Like

It looks like you are also sending this command on both serial channels... Maybe something on the other end is seeing both channels busy, so does not send your desired response.

I'm getting my desired response but just extra. If you watch the video you can see what i mean pretty clearly.

No, I can not. Sounds like you found what you need.

1 Like

I've edited my code so i'm hoping that a solves the "H FCM" issue.

However, I'm still unsure how to go about deleting the CRLF characters at the end of the response as the response can be different each time.

Show a picture of the CRLF (or the problem around it).

Look at the String reference; methods indexOf and charAt.

If you wouldn't use String (capital S) objects but char arrays, this could be the solution

char message[] = "Hello world\r\n";

void setup()
{
  Serial.begin(115200);
  Serial.println("Before trim");
  print(message);
  trimRight(message);
  Serial.println("After trim");
  print(message);
}

void loop()
{
  // put your main code here, to run repeatedly:
}

void trimRight(char *txt)
{
  while (txt[strlen(txt) - 1] == '\r' || txt[strlen(txt) - 1] == '\n')
  {
    txt[strlen(txt) - 1] = '\0';
  }
}

void print(char *txt)
{
  Serial.print("[");
  Serial.print(txt);
  Serial.println("]");
}

Output:

Before trim
[Hello world
]
After trim
[Hello world]

Square brackets used to indicate start and end of text.

1 Like

you could ignore any CR LF to be sent to the LCD. Just make your "own" LCD class and modify the write function:

/*
  LiquidCrystal Library - Serial Input

   avoid CR & LF from Serial Input to be printed to the LCD

   by noiasca

*/

// include the library code:
#include <LiquidCrystal.h>

// create your own class with a modified write function
class MyLCD : public LiquidCrystal {

  public :
    MyLCD(uint8_t rs, uint8_t en, uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7) : LiquidCrystal(rs, en, d4, d5, d6, d7) {}
   // add more constructors if you need other pin variants also

    size_t write(uint8_t value) {
      if (value == '\r' || value == '\n') return 0;  // ignore characters
      return LiquidCrystal::write(value);            // call original write
    }
};

// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const uint8_t rs = 8, en = 9, d4 = 4, d5 = 5, d6 = 6, d7 = 7;
MyLCD lcd(rs, en, d4, d5, d6, d7);

void setup() {
  lcd.begin(16, 2);
  Serial.begin(115200);
  lcd.println(F("Test"));   // will print without CR LF 
}

void loop() {
  // when characters arrive over the serial port...
  if (Serial.available()) {
    // wait a bit for the entire message to arrive
    delay(100);
    // clear the screen
    lcd.clear();
    lcd.setCursor(0, 1);
    // read all the available characters
    while (Serial.available() > 0) {
      // display each character to the LCD
      lcd.write(Serial.read());
    }
  }
}
//

but I recommend you should do a better parsing of the incomming data.

1 Like

I'm unfamiliar with this, assuming I can just paste this into my own code?

this and adopt the line where the object lcd is created, because you want an instance of the the new MyLCD class and not LiquidCrystal

I'm not sure how this would work as i'd be receiving different sized messages etc... Novice so i can't even understand half of this lol.

You need a buffer (message) that is big enough to hold what you receive plus one character.

You read the data (see e.g. example 2 in Robin's updated serial input basics tutorial; if your biggest message is e.g. 99 characters, you need to change const byte numChars = 32; to const byte numChars = 100;.

The variable receivedChars is what you need to trim.

The recieved messages will vary in lengths so I'm not sure how that'll work. It could be 30 characters long one time and 200 the next etc...

Thats also way above my level, again I'm a COMPLETE novice. is there any decent guide that revolves around my problem? I'm not even sure where to start looking.

You should have a char array that is large enough to hold the longest message that you can possibly expect. Your uploaded sketch needs that space anyway. It can be wasteful if you know what you're doing but it's always the safest bet.

If you continue to use the String class (I know, it's convenient) you should read the reference (https://docs.arduino.cc/language-reference/en/variables/data-types/stringObject/) and find out the available methods. There is a trim() method that might suite your needs

String rx = "\r\nabc...xyz \r\n";

void setup()
{
  Serial.begin(115200);
  Serial.print("Before trim length = ");
  Serial.println(rx.length());
  Serial.print("\t[");
  Serial.print(rx);
  Serial.println("]");
  rx.trim();
  Serial.print("After trim length = ");
  Serial.println(rx.length());
  Serial.print("\t[");
  Serial.print(rx);
  Serial.println("]");
}

void loop()
{

}

The square brackets are added for clarity. Output

08:55:40.867 -> Before trim length = 14
08:55:40.867 -> 	[
08:55:40.867 -> abc...xyz 
08:55:40.867 -> ]
08:55:40.905 -> After trim length = 9
08:55:40.905 -> 	[abc...xyz]

Do a search on the web for c-string.