Go Down

Topic: Wierd characters on display (Read 2678 times) previous topic - next topic

dwattel

Oct 19, 2012, 08:36 pm Last Edit: Oct 20, 2012, 12:06 am by dwattel Reason: 1
I have combined several example sketches for a real time clock and the result is that the LCD displays two wierd characters at the end of the lines.
I used the example sketches from several libraries, DS1302, LiquidCrystal_I2C.
What am I doing wrong here?

Here is the code:
Code: [Select]
// include the library code:
#include <stdio.h>
#include <string.h>
#include <DS1302.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

/* Set the appropriate digital I/O pin connections */
uint8_t CE_PIN   = 2;
uint8_t IO_PIN   = 3;
uint8_t SCLK_PIN = 11;

/* Create buffers */
char buf1[20];
char buf2[20];
char buf3[20];
//char buf4[25];
char day[10];

/* Create a DS1302 object */
DS1302 rtc(CE_PIN, IO_PIN, SCLK_PIN);

// initialize the LCD library
LiquidCrystal_I2C lcd2(0x20,20,4);  // set the LCD address of the first lcd to 0x20 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd1(0x21,16,2);  // set the LCD address of the second lcd to 0x21 for a 16 chars and 2 line display

void print_time()
{
 /* Get the current time and date from the chip */
 Time t = rtc.time();

 /* Name the day of the week */
 memset(day, 0, sizeof(day));  /* clear day buffer */
 switch (t.day) {
   case 1:
     strcpy(day, "Zo");
     break;
   case 2:
     strcpy(day, "Ma");
     break;
   case 3:
     strcpy(day, "Di");
     break;
   case 4:
     strcpy(day, "Wo");
     break;
   case 5:
     strcpy(day, "Do");
     break;
   case 6:
     strcpy(day, "Vr");
     break;
   case 7:
     strcpy(day, "Za");
     break;
 }

 /* Format the time and date and insert into the temporary buffer */
 snprintf(buf1, sizeof(buf1), "%s %02d-%02d-%04d   ",
           day,
           t.date, t.mon, t.yr);
 snprintf(buf2, sizeof(buf2), "%02d:%02d:%02d        ",
          t.hr, t.min, t.sec);

 /* Print the formatted string to LCD so we can see the time */
 lcd1.clear();
//  lcd1.setCursor(5, 0);
 lcd1.println(buf1);
 lcd1.setCursor(0, 1);
 lcd1.println(buf2);
//  lcd1.setCursor(4, 2);
//  lcd1.println(buf3);
}

void setup() {
 lcd1.init();                      // initialize the first lcd
 lcd2.init();                      // initialize the second lcd

 // Print a message on the first LCD.
 lcd1.backlight();
 lcd1.print("Hello, #1 world!");

 // Print a message on the second LCD.
 lcd2.backlight();
 lcd2.setCursor(0, 0);
 lcd2.print("Hello, #2 world!");
 delay(1000);
}

void loop() {
 // set the cursor to column 0, line 1
 // (note: line 1 is the second row, since counting begins with 0):
 lcd1.setCursor(0, 0);
//  // print the number of seconds since reset:
//  lcd.print(millis()/1000);
 print_time();
 delay(1000);

}


liudr

Please post code with the code block:



Search and replacing all your println with print in your code.

dwattel

Thanks, that did the trick.

But can someone explain me the difference between print and println?

Krupski


Thanks, that did the trick.

But can someone explain me the difference between print and println?



"print" just sends what it's told to send. "println" sends the content, plus a newline (i.e. CR/LF).

To clarify, if you are sending the string "123" to an LCD, "print" (or "write") will send, in hex:

[font=monospace]31, 32, 33[/font]

If you use "println", it sends this:

[font=monospace]31, 32, 33, 0D, 0A[/font]

The last two characters make a serial terminal move to the next new line, but to an LCD, they are just gibberish.

Make sense?
Gentlemen may prefer Blondes, but Real Men prefer Redheads!

liudr

If you do println on serial port, then the next output will start on a new line in the serial monitor. Serial monitor understands those two characters. It makes reading the output so much easier. On the other hand, the LCD controller doesn't understand the new line characters so it just prints out some random stuff. If you need to start a new line on an LCD, you will have to do it with setCursor to a new line.

Another major difference between LCD and the serial monitor is serial monitor scrolls the information when there is too much to be displayed on the monitor. LCD will not. There is no scroll mechanism in either the LCD controller or the liquidcrystal library.

To implement both scroll and new line is quite time consuming. On the other hand, my phi-panels can process all that and a whole lot more like rendering menus etc. I do sell them so take my recommendation with your own discretion. I am, anyway, pretty proud of what I designed :)

floresta

All of the above is absolutely correct when explaining the action of the LiquidCrystal library that is included with the Arduino when it is driving a 14 (or 16) pin LCD module directly through a parallel interface.  That is why you will find no mention of println in the LiquidCrystal documentation.

In this case we are dealing with a serial interface and an unspecified library.  The OP was unlucky in that his particular library did not intercept the 0x0D and 0x0A characters and make those codes do what he expected.  The responders were lucky in that their explanation was correct for this particular library. 

By the way the reason that the resulting characters are weird and possibly random is because they are accessing two of the eight available custom characters (the ones that you can create using createChar) via their 'foldback' addresses.  These characters are associated with ASCII codes 0x00 - 0x07, but the same eight characters are also accessible by using 0x08 - 0x0F.


Don

dwattel

#6
Oct 20, 2012, 01:28 pm Last Edit: Oct 20, 2012, 01:33 pm by dwattel Reason: 1
Thank you all, I have learned a lot from you.

It is the first time I do any programming (besides some BASIC in the past).

Don, the liquidCrystal_I2C library came from the playground and is for the PCF8474 IO expander.

liudr

Quote
The responders were lucky in that their explanation was correct for this particular library. 

If the println compiles at all, and two random characters show up with println, I am not lucky. It's inheritance.

floresta


Quote
The responders were lucky in that their explanation was correct for this particular library. 

If the println compiles at all, and two random characters show up with println, I am not lucky. It's inheritance.

I understand that 'inheritance' is what causes the standard LiquidCrystal library to display the weird characters instead of barfing when it encounters the undocumented (for that library) println.  I thought that it was luck that the other libraries reacted the same way.  So I have some questions: Does inheritance always work?  Are there some cases where it will and others where it won't?

Don

liudr

Don,

There used to be no such thing as LCD.println before Arduino 1.0 (or around that version). In Arduino 1.0 (or around that version), the LiquidCrystal library was modified with this line:

Code: [Select]
class LiquidCrystal : public Print

This essentially makes LiquidCrystal object inherit Print class, which has all the print and println with different types of arguments (byte, int, char, char * etc.).

LiquidCrystal class thus no longer implements print or println and just implements write, the writing single byte to LCD. The print and println are implemented in the parent class, the Print. They are very simple implementations where write is called repeatedly until all that needs to be printed is sent out byte per byte with write.

The newer libraries with I2C LCDs probably just takes the Arduino 1.0 LiquidCrystal library and rewrites the begin and write4bytes etc. methods and keep the rest unchanged, slap on a new library name. I don't think the I2C library writers are all eager beavers to write out their println method to OVERRIDE the parent ones. The mere fact that println works and with 2 strange characters covers maybe 90% of the logic leading to my conclusion, not 100%.

floresta

#10
Oct 20, 2012, 09:21 pm Last Edit: Oct 20, 2012, 09:23 pm by floresta Reason: 1
Quote
There used to be no such thing as LCD.println before Arduino 1.0 (or around that version).

Well there still is 'no such thing' if you look at the documentation for the LiquidCrystal library.

So if I understand correctly, in older Arduini IDE versions the use of LCD.println would have resulted in an error of some kind but now there is none since there really is no error, just some unusual behavior due to the characteristics of the LCD controller that I explained in reply #5.

By not mentioning println in the LiquidCrystal documentation the powers that be are essentially absolving themselves of responsibility for this strange (to the uninitiated) behavior.  It seems to me that it would be more responsible to mention why println was omitted from the documentation.


Don


liudr


Quote
There used to be no such thing as LCD.println before Arduino 1.0 (or around that version).

Well there still is 'no such thing' if you look at the documentation for the LiquidCrystal library.

So if I understand correctly, in older Arduini IDE versions the use of LCD.println would have resulted in an error of some kind but now there is none since there really is no error, just some unusual behavior due to the characteristics of the LCD controller that I explained in reply #5.

By not mentioning println in the LiquidCrystal documentation the powers that be are essentially absolving themselves of responsibility for this strange (to the uninitiated) behavior.  It seems to me that it would be more responsible to mention why println was omitted from the documentation.


Don




Right, undocumented but exists through inheritance. The potential problem of inheritance is showing its color here with LCD lib. You make a bunch of these functions in your base class and your child class inherits these functions but not all are working with the child class. The base class does nothing special other than printing 0D and 0A, assuming the receiving device understands it. But the child class hardware (LCD) is not exactly a super set of the base class hardware (computer serial monitor). A child should have all base plus extra but this case it is not. The base class should probably declare println as virtual so a child class has to define it to use it. We have a bunch of newbies that don't know these subtleties and think they can use println anywhere it won't complain. In an extreme case, say a base class defines .kill_self() and the child class commits suicide with .kill_self() but finds the method doesn't really apply to the child due to different hardware, maybe the child is a cylon and inherits from human parents, the child may become zombie or something LOL

bperrybap

#12
Oct 24, 2012, 01:49 am Last Edit: Oct 24, 2012, 01:53 am by bperrybap Reason: 1

Don,

There used to be no such thing as LCD.println before Arduino 1.0 (or around that version). In Arduino 1.0 (or around that version), the LiquidCrystal library was modified with this line:

Code: [Select]
class LiquidCrystal : public Print


This is incorrect. I just went back and looked. The LiquidCrystal library was added in IDE 0012 (Sept of 2008)
and from its very beginning until today's 1.0.1,
the Print class was always inherited. (I just looked at every single IDE release since 0012)

The issue is that the LiquidCrystal library inherited the Print class but failed to implement everything that the
Print class supports and can attempt to use. As a result, things like lcd.println() don't provide the expected/desired behavior.

Don, with C++ inheritance, if you choose to inherit a class  *ALL* the public
functions and members in that class get dragged in.
Think of it like pulling in a gigantic set of Assembler macros.

The way the Print class works, the layer below it really does not know anything about println() or that
println() is being called by the sketch. The lower layer, LiquidCrystal in this case, only sees calls to write()
as that is the interface between Print and LiquidCrystal.
Print implements println() and then converts it to a series of write() calls.
So from LiquidCrystal's point of view, it cannot tell the difference between a sketch doing:
Code: [Select]
lcd.println("hello");
and
Code: [Select]

lcd.write('h');
lcd.write('e');
lcd.write('l');
lcd.write('l');
lcd.write('o');
lcd.write('\r');
lcd.write('\n');


Because in both cases LiquidCrystal only sees the calls to write().

Rather than write the needed code in LiquidCrystal to fully support all the inherited functions in the Print class,
(which meant writing code to handle newline processing and line wrapping)
the developers took the easy way out and chose to simply say that println() isn't supported.
They also took a short cut by simply not documenting println().
What they should have done instead is to explicitly document that LiquidCrystal supports all the functions in the Print class (with a reference to the Print class documentation) but, state that println() is not implemented in LiquidCrystal and therefore
is not supported and if used will create undesired results.

When they chose to not write the additional code to support  println() (new line processing), they could have added
a tiny amount of code to swallow the <CR> and <LF> characters to at least avoid the junk characters
but then there would never be a way to send 0x0d and 0x0a to the display, which might be desirable in
some cases.

There are some Arduino hd44780 libraries out there like this one:
http://www.pjrc.com/teensy/td_libs_LiquidCrystal.html
that have the code to support newline processing and line wrapping.
When using those libraries that support newline processing, println() will work as expected.

--- bill




floresta

Quote
... but then there would never be a way to send 0x0d and 0x0a to the display, which might be desirable in
some cases.

They don't even get this as an excuse.  As I said in reply #5 these two codes are included in the eight foldback addresses for the eight documented addresses used to access the 'custom characters'.  The ability to use 0x0D and 0x0A will not get you any added capability.

Don

liudr

Quote
Don, with C++ inheritance, if you choose to inherit a class  *ALL* the public


Nah. Inheritance gets you all public and protected functions from parent. But one needs to know the difference between public keyword of members and public inheritance. This case is public inheritance, a standard way to inherit. You can also inherit privately, in which case the public members become private members so they can't be accessed from outside. I hate this fact that they just can't invent words but instead use public in different places for different meanings, like public members, public static variables, public inheritance. It's madness.

IMHO, this should be done: println should instead of calling print then print(0d, 0a), call print then cursor(home), cursor(next line). This way lcd library needs to define cursor(home) to be setcursor(0,current row), and cursor(next line) as setcursor(column,current row+1). Since lcd library is not making use of cursor position, it can't be implemented. Then serial can define cursor(home) as write(od) etc.

Go Up