Pages: [1]   Go Down
Author Topic: CreateChar LCD library with Arduino 1.0 rc1 IDE  (Read 10935 times)
0 Members and 1 Guest are viewing this topic.
Enschede
Offline Offline
Newbie
*
Karma: 0
Posts: 11
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I just installed the Arduino 1.0 rc1 IDE. Looks great!

I was working on a sketch were I want to use a custom character with my LCD display. I did this before following the guide on the LiquidCrystal library reference page which contains the following code: 

Code:
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

byte smiley[8] = {
  B00000,
  B10001,
  B00000,
  B00000,
  B10001,
  B01110,
  B00000,
};

void setup() {
  lcd.createChar(0, smiley);
  lcd.begin(16, 2); 
  lcd.write(0);
}

void loop() {}

Well that broke in Ardiuno 1.0.

It gave me the following error:

Code:
SidSynth_v01.cpp: In function 'void loop()':
SidSynth_v01:766: error: call of overloaded 'write(int)' is ambiguous
/Applications/Arduino.app/Contents/Resources/Java/libraries/LiquidCrystal/LiquidCrystal.h:82: note: candidates are: virtual size_t LiquidCrystal::write(uint8_t)
/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/cores/arduino/Print.h:49: note:                 size_t Print::write(const char*)

The solution for me was to replace

Code:
lcd.write(0);

With

Code:
lcd.print((char)0)

Maybe it would be usefull to change the LiquidCrystal reference page. This could become very frustration for a beginner to find out I believe.
« Last Edit: October 08, 2011, 03:09:22 am by DeRaaf » Logged

Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 517
Posts: 26292
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

"Maybe it would be usefull to change the LiquidCrystal reference page."

Is that in the Playground? If so, I think you can edit yourself & note your findings.
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Enschede
Offline Offline
Newbie
*
Karma: 0
Posts: 11
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Didn't see the edit page link yesterday. A little hidden.

But the page (http://arduino.cc/en/Reference/LiquidCrystalCreateChar) also clearly states:

"Corrections, suggestions, and new documentation should be posted to the Forum."

I'm very new to the Arduino forum/playground thing. So a little unsure about changing things.

p.s Just tried to login to edit the page. Doesn't let me. Does one need a separate/different login than the forum login for that?
« Last Edit: October 08, 2011, 03:05:57 am by DeRaaf » Logged

Dallas, TX USA
Offline Offline
Faraday Member
**
Karma: 63
Posts: 2636
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This is a problem with the Print class definition rather than the liquidcrystal library.
Actually, it looks like it was always an issue but it is only just now showing up.
They changed the Print class in 1.0 so now there is no longer a virtual function for passing a null terminated string to write().
The problem is that 0 (zero) could be a uint8_t or a char *
In the past it didn't show up as an issue for liquidcrystal
because liquidcrystal didn't implement the char * virtual write function,
so a 0 constant was not ambiguous since it could only map to the uint8_t write() function.

This is another example of all the last minute core code changes that have been thrown into the Arduino 1.0
release that is de-stabilizing the environment and breaking things.

This also breaks things in applications that use the ks0108/glcd library as well.
It has the potential to also break things that use the serial ports or any other library that uses
the Print class.
My view is that this should be fixed in the Print class so that all the other libraries
and sketches can continue to work.

---bill
« Last Edit: October 17, 2011, 03:15:45 am by bperrybap » Logged

Dallas, TX USA
Offline Offline
Faraday Member
**
Karma: 63
Posts: 2636
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Just a followup comment.
While it is the ambiguous Print class definition that is creating this backward compatibility issue,
it is the use of naked constants to the write() function that triggers this ambiguity in the Print
class definition.
i.e. the use of 0 or any other naked constant.
because a naked constant could either be a uint8_t  value or const char * string.

So the safest thing to do is to cast to a type that is known by the write() function
that specifies your intent.

so instead of using:
Code:
lcd.print((char)0);

Code:
lcd.write((uint8_t)0);

would be better.

This tells the compiler your true intent and allows the compiler to
pick the proper write() function.
This works for 1.0 as well as the older pre 1.0 code.

IMHO, the write(const char *str) functionality should be eliminated
and leave write() as either a single byte or a byte with a length.
If you want/need string printing, using print() instead of write().
This keeps things simple and eliminates the needed casts for writing
8 bit values that are untyped naked constants.
It also pushes all the string handling (for which there are many different string types)
all up in the print() handling and keeps write() really slim and simple.

--- bill
Logged

Enschede
Offline Offline
Newbie
*
Karma: 0
Posts: 11
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks Bill for the more elaborate answer.

I have a PHP programming background (well is the language I have the most experience with). I like to keep my code as consistent as possible. I use the print() more often than write() when fiddling with Arduino, therefore I tend to prefer print() for consistency sake.

The comments you posted made me realize that I don't fully understand the difference between print() and write() and their use cases within the Arduino IDE context. I tried searching for it but couldn't find a satisfactory answer.

Could someone explain in layman's terms the differences between write() and print() within the Arduino environment? And when and why one is preferred above the other?
Logged

Dallas, TX USA
Offline Offline
Faraday Member
**
Karma: 63
Posts: 2636
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The simplest way to think of it is that print() calls write().
print() can do formatting but eventually calls write() to push the characters out.
write() is for simple 8 bit data output.

In some simple cases the functionality overlaps, but in all cases print() eventually calls
write().

So when you call print() with something like a number, it converts the number to characters
and calls write() to output the characters.


====
more details.

The write() functions in the Print class can be mapped to write() functions in the library.
So when lcd.write() is called, for example, the  write() from the print class calls the lcd libraries
write() function (if it is defined).

The issue is that the Print class defined more than 1 write() function.
It defined 3.
write(uint8_t);
write(uint8_t *ptr);
write(uint8_t *ptr, size_t size);

The one that creates the issue is the 2nd/middle one.
because a constant could be a 8 bit value or a pointer so if both
are defined and a naked constant is used, the compiler does not know
which one to pick.

In 0022 the Print class allowed mapping all 3 functions.
Arduino 1.0 currently does not allow mapping the middle one. It internally
handles it and calls the bottom one so in 1.0 the middle one always exists
even if the class that uses the Print class does not define it.

This creates a problem because now the middle functions is always defined,
where as in 0022 it was only defined if it was remapped or the class that uses
it pulls it in.

So now since that middle function always exists, the compiler becomes confused
about a naked constant when the top function is defined.
Libraries like the liquidcrystal library didn't use anything but the write(uint8_t) function
(the top one) in the past. With the new Print class in 1.0 the write(uint8_t *) function now exists
automatically, so that is why you now get the ambiguity error on 1.0

My view is that the middle one could go away to keep things simple and clean
and avoid the ambiguity and having to cast naked constants to write().
That way if you want to output simple 8 bit data, you call write() and can pass either a simple
byte (from a variable or a naked constant) or a pointer to byte and a number of bytes.
Anything else could go through print(), because print() is smart enough to
know about many other types like numbers, C strings, C++ strings, Arduino 1.0 knows about
strings stored in FLASH, etc...
So given that print() knows how to print all these things as well as simple C strings,
there was no real need for the additional simple C string support in write().

Its not a deal killer, but "as is" in 1.0 it does cause previously working code to break until
any calls to write() that used naked constants are re-casted to uint8_t

--- bill




Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
The simplest way to think of it is that print() calls write().
print() can do formatting but eventually calls write() to push the characters out.
Print usually DOES formatting. It printing an integer, the value will be converted to a string, and the string sent out using write().
Logged

Enschede
Offline Offline
Newbie
*
Karma: 0
Posts: 11
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks Bill and PaulS!

Clear answer. Could prevent a lot of headaches for the project I'm working on which uses a lot of print()/write() thingies, not only for the LiquidCrystal library but also serial and a few other things.

I hope the final version of Arduino 1.0 has a way to fix this potentially tear jerking problem for the absolut beginner trying to use a library!

 
Logged

Hobart, Tasmania
Offline Offline
Newbie
*
Karma: 0
Posts: 1
Senior Newbie
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I got over the problem by ignoring the 0 and re-numbered the characters 1,2,3, etc. The next problem was that only half of the code is there. There is no use of the heart character or the frownie, let alone the lcd.setCursor() to place them.
The pinout also changes with the LCD/buttons Shield from Freetronics
Here is my rewrite:

 
 */

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

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// make some custom characters:
byte heart[8] = {
  0b00000,
  0b01010,
  0b11111,
  0b11111,
  0b11111,
  0b01110,
  0b00100,
  0b00000
};

byte smiley[8] = {
  0b00000,
  0b00000,
  0b01010,
  0b00000,
  0b00000,
  0b10001,
  0b01110,
  0b00000
};

byte frownie[8] = {
  0b00000,
  0b00000,
  0b01010,
  0b00000,
  0b00000,
  0b00000,
  0b01110,
  0b10001
};

byte armsDown[8] = {
  0b00100,
  0b01010,
  0b00100,
  0b00100,
  0b01110,
  0b10101,
  0b00100,
  0b01010
};

byte armsUp[8] = {
  0b00100,
  0b01010,
  0b00100,
  0b10101,
  0b01110,
  0b00100,
  0b00100,
  0b01010
};
void setup() {
  // create a new character
  lcd.createChar(1, heart);
  // create a new character
  lcd.createChar(2, smiley);
  // create a new character
  lcd.createChar(3, frownie);
  // create a new character
  lcd.createChar(4, armsDown); 
  // create a new character
  lcd.createChar(5, armsUp); 

  // set up the lcd's number of columns and rows:
  lcd.begin(16, 2);
  // Print a message to the lcd.
  lcd.print("I ");
  lcd.write(1);
  lcd.print(" Arduino! ");
  lcd.write(2);

}

void loop() {
  // read the potentiometer on A0:
  int sensorReading = analogRead(A0);
  // map the result to 200 - 1000:
  int delayTime = map(sensorReading, 0, 1023, 200, 1000);
  // set the cursor to the bottom row, 5th position:
  lcd.setCursor(4, 1);
  // draw the little man, arms down:
  lcd.write(4);
  // set the cursor to the top row, 14th position
  lcd.setCursor(13, 0);
  // draw a frownie
  lcd.write(3);
  delay(delayTime);
  lcd.setCursor(4, 1);
  // draw him arms up:
  lcd.write(5);
  lcd.setCursor(13, 0);
  // draw a smiley
  lcd.write(2);
  delay(delayTime);
}



Logged

Keeping it weird in Portland
Offline Offline
Newbie
*
Karma: 1
Posts: 44
Arduino Noob, Veteran Programmer
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Just a followup comment.
While it is the ambiguous Print class definition that is creating this backward compatibility issue,
it is the use of naked constants to the write() function that triggers this ambiguity in the Print
class definition.
i.e. the use of 0 or any other naked constant.
because a naked constant could either be a uint8_t  value or const char * string.

So the safest thing to do is to cast to a type that is known by the write() function
that specifies your intent.

so instead of using:
Code:
lcd.print((char)0);

Code:
lcd.write((uint8_t)0);

would be better.

This tells the compiler your true intent and allows the compiler to
pick the proper write() function.
This works for 1.0 as well as the older pre 1.0 code.

--- bill


I haven't finished reading this thread but casting the lcd.write parameter seems to have solved a problem for me where only one of my custom character (#6) was occasional displayed incorrectly as a gibberish character.

I'm still unclear why this was not consistent but if it was interpreting the constant as a pointer who knows what value would be at that location? Makes me wonder how it would ever have displayed correctly, which it did and why it seemed to be limited to just one of the seven custom characters I use in my sketch. Maybe I need to test it more thoroughly to be sure the problem is gone.
« Last Edit: August 11, 2013, 12:14:22 pm by LinhartR » Logged

Pages: [1]   Go Up
Jump to: