Unterschied lcd.print und lcd.write?

Hi!

hab folgendes Problem:
ich möchte Sonderzeichen am LCD Display anzeigen. Gehen tut es im Detail um das °Gradzeichen. Hab schon alles mögliche probiert. Doch leider wird es mir nicht angezeigt. Jetzt hab ich es mal mit einem Beispielprogramm vom Arduino probiert. Auch hier bekomm ich immer eine Fehlermeldung.

Das ist der Code:

/*
  LiquidCrystal Library - Custom Characters
 
 Demonstrates how to add custom characters on an LCD  display.  
 The LiquidCrystal library works with all LCD displays that are 
 compatible with the  Hitachi HD44780 driver. There are many of 
 them out there, and you can usually tell them by the 16-pin interface.
 
 This sketch prints "I <heart> Arduino!" and a little dancing man
 to the LCD.
 
  The circuit:
 * LCD RS pin to digital pin 12
 * LCD Enable pin to digital pin 11
 * LCD D4 pin to digital pin 5
 * LCD D5 pin to digital pin 4
 * LCD D6 pin to digital pin 3
 * LCD D7 pin to digital pin 2
 * LCD R/W pin to ground
 * 10K potentiometer:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)
 * 10K poterntiometer on pin A0
 
 created21 Mar 2011
 by Tom Igoe
 Based on Adafruit's example at
 https://github.com/adafruit/SPI_VFD/blob/master/examples/createChar/createChar.pde
 
 This example code is in the public domain.
 http://www.arduino.cc/en/Tutorial/LiquidCrystal
 
 Also useful:
 http://icontexto.com/charactercreator/
 
 */

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

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// 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(0, heart);
  // create a new character
  lcd.createChar(1, smiley);
  // create a new character
  lcd.createChar(2, frownie);
  // create a new character
  lcd.createChar(3, armsDown);  
  // create a new character
  lcd.createChar(4, 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(0);
  lcd.print(" Arduino! ");
  lcd.write(1);

}

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(3);
  delay(delayTime);
  lcd.setCursor(4, 1);
  // draw him arms up:
  lcd.write(4);
  delay(delayTime); 
}

Beim Überprüfen bekomme ich folgende Meldung:

Nun meine eigentliche Frage(n):
Was ist eigentlich der Unterschied zwischen lcd.print und lcd.write?

Wie ist die Vorgehensweise für Sonderzeichen?


achja: Arduino UNO, LCD = LCM1602C V2.1, MAC

Generell ist der Unterschied, dass print ASCII ist und write rohe Binärdaten. Genauso wie bei Serial

Das Grad Zeichen musst du dir aus dem LCD Datenblatt raussuchen und mit write schicken:
http://www.dfrobot.com/image/data/DFR0154/LCD2004%20hd44780%20Datasheet.pdf

Das ist meistens Code Page A00, Seite 17. Das Grad Zeichen ist unten rechts: 11011111 -> 0xDF

Die Tabelle stimmt was die Standard ASCII Zeichen betrifft überein, aber für den rechten Teil musst die Codes selbst zusammenbasteln

Bei meiner I2C Lib war auch ein Beispiel dabei um alle Zeichen mit ihren Codes in einer Loop anzuzeigen. Musst du eventuell für deine Lib anpassen (z.B. init/begin und solche Sachen) aber im Prinzip sollte es passen:

void setup()
{
  lcd.init();
  lcd.backlight();
  
  lcd.home();
  
  lcd.print("Hello world...");
  lcd.setCursor(0, 1);
  lcd.print(" i ");
  lcd.write(3);                    //Adresse 3 war mit custom characters ein Herz. Den Teil habe ich weggelassen
  lcd.print(" arduinos!");
  delay(5000);
  displayKeyCodes();
}


void displayKeyCodes(void) 
{
  uint8_t i = 0;
  while (1) 
  {
    lcd.clear();
    lcd.print("Codes 0x"); lcd.print(i, HEX);
    lcd.print("-0x"); lcd.print(i+16, HEX);
    lcd.setCursor(0, 1);
    for (int j=0; j<16; j++) {
      lcd.write(i+j);
    }
    i+=16;
    
    delay(4000);
  }
}

Besten Dank für die Rasche Info!

Was hat es mit der Fehlermeldung auf sich?

write(0) könnte schief gehen, da 0 auch NULL bedeuten kann. Dann weiß er nicht ob er den Wert oder einen NULL-Pointer nehmen soll (da die eine Variante einen const char* als Parameter hat). Versuche vielleicht mal write((int)0));

oder besser write((byte)0);

Eigentlich sollen da ja nur 8 Bit geschickt werden und der Compiler meint auch, dass der eine Kandidat einen uint8_t erwartet

Besten Dank Serenifly!

write((byte)0) war die Lösung, jetzt versteh ich auch was mit "ambigous" - "zweideutig" gemeint ist.

Jetzt dürfte das °Gradzeichen auch kein Problem mehr sein.

Danke nochmal!

Ich stand vor dem gleichen Problem und habe es so gelöst:

  lcd0.setCursor(15,0);
    lcd0.print((char)223);
    lcd0.print("C");

Frank

Hallo emsig :slight_smile:
das Problem hatte ich auch. Wenn du Arduino 1.0 oder höher nutzt versuch es mal mit
lcd.write((uint8_t)0);
das geht bei mir.
gruß
Bernward

@Frank: habs genaus so gelöst. konnte mit dem Binärcode im Datenblatt des Displays nicht viel anfangen, habs auf Dezimal umgerechnet und siehe da, mit

lcd.write(223);

bekommt man ein schönes ° am Display zu sehen.

@Bernward: Danke für den Tip, werd ich mir notieren, füer den Fall daß ich mal Zeichen brauche, die nicht im Zeichensatz des Displays drinnen sind.

schöne Grüße
Bernhard

füer den Fall daß ich mal Zeichen brauche, die nicht im Zeichensatz des Displays drinnen sind.

Die Zeichen sind im Display, aber sie sind nicht im Standard ASCII Table! ASCII geht bis 127. Und bis 125 stimmt der Zeichensatz des Displays mit den ASCII Codes überein. Aber der Extended ASCII Table ist nicht so drin. Da musst du dir die Zeichen im Datenblatt suchen.

223 = 0xDF
Wie ich oben sagte die beide Halb-Bytes aus der Tabelle raus picken. Das funktioniert genauso mit allen anderen Zeichen die größer als 125 sind (solange sie im Display sind). Dafür kannst du übrigens praktisch den Windows-Taschenrechner nehmen. Ob dann Hex oder Dezimal ist Geschmackssache :slight_smile:

Wenn du Zeichen willst, die gar nicht enthalten sind, musst du custom characters basteln. Dafür gibt es web-basierende Apps, bei der man die Pixel setzen kann und die Bytes angezeigt bekommt. z.B.:
http://omerk.github.io/lcdchargen/

Was auch geht ist sowas ähnliches:

char grad[] = { (char)223, 'C' };
lcd.print(grad);

Du kannst dir so gleich einen C-String "°C" basteln. Wegen der genauen Syntax bin ich da nicht 100%ig sicher, aber eventuell muss noch ein '\0' hinten dran gehängt werden. Das ist praktisch wenn du das mehrmals brauchst.

"print((char)223)" ist dabei das gleiche wie "write(223)". Eben weil print ASCII macht (deshalb der Cast) und write Binärdaten schickt (deshalb nur die blanke Adresse).

@maverick1509:
"uint8_t" ist nur eine andere Compiler-unabhängige Schreibweise für "byte". Byte sind immer 8 Bit, aber bei "int" ist das von dem Prozessor abhängig. Wenn man dann sagt "uint16_t" hat das immer 16 Bit und ist nicht auf einem anderen Prozessor plötzlich 32 Bit.

Ich habs so gemacht:"Celsius: \337C"