Print degree symbol ° on LCD

Was wondering how I can correctly print the Celsius degree symbol ° with LiquidCrystalLCD

I tried with

lcd.print( "°C");

but I read a non-sense char.

Thanks in advance

I think 223 (0xDF) is the code for the degree symbol, try:

lcd.print(223); or lcd.print((char)223);

1 Like

The second instruction works fine. Thanks again!

Interesting that the ASCII table in the reference section of arduino.cc only shows the first 128 characters. Would seem that HD44780-compatible LCD do more than this...

/david

ASCII is a 7 bit standard.

ASCII (the American Standard for Computer Information Interchange) only covers values between 32 and 127, and the meanings of control characters below 32.

Above that, if you're using a it's a no-mans-land where any device can come up with whatever they want: smileys, graphics blocks, arrows, space invaders, copyright, degrees, fractions, whatever. Your PC's idea of what to do with these characters is different from the old Commodore computers, and different from Tandy computers, etc.

To go beyond ASCII, you need to know what the encoding for a given device (and the device's mode) is. These can be 8-bit encoding systems, or multiple bytes per character, depending on the language(s) required. JIS is a coding standard that supports Japanese characters, for example. In other cases, there are even variations on how multiple bytes are ordered must be part of the definition. Unicode can be packed into equal widths (UTF-16) or variable widths (UTF-7, UTF-8).

The "default standard" for WWW pages is Unicode in UTF-8, but many pages get it wrong. Web browsers usually have a menu to let you choose the encoding in case it wasn't specified on the page itself. Tiny little embedded devices like this LCD panel don't have that luxury, so you have to send it the correct bytes to get the characters you expect.

Those LCDs have a bunch of "special" characters in positions above 128, such as 'mu' (as in microFarads) at 0xE4, Omega (Ohms) at 0xF4, and PI at 0xF7. It's worth checking the data sheet for the chip, or writing a little test program that displays them, a few at a time.

Here’s the HD44780’s character set…

Hoops

Heh, a full set of katakana. Perfect for an Arduino Japanese RPG.

[ch12290][ch12300][ch12301][ch12289]?[ch12530][ch12449][ch12451][ch12455][ch12457][ch12515][ch12517][ch12519][ch12483] [ch12540][ch12450][ch12452][ch12454][ch12456][ch12458][ch12459][ch12461][ch12463][ch12465][ch12467][ch12469][ch12471][ch12473][ch12475][ch12477] [ch12479][ch12481][ch12484][ch12486][ch12488][ch12490][ch12491][ch12492][ch12493][ch12494][ch12495][ch12498][ch12501][ch12504][ch12507][ch12510] [ch12511][ch12512][ch12513][ch12514][ch12516][ch12518][ch12520][ch12521][ch12522][ch12523][ch12524][ch12525][ch12527][ch12531]

[ch12450][ch12523][ch12485][ch12452]ch12494

The "degrees symbol" and the `` double-quote there are serving a dual purpose, they're diacritical symbols used in Japanese also.

Three characters near the end are ch21315 ch19975 and ch20870.

Note that the first column in that table contains user-programmable characters. I have a sketch here that programs one of them, and displays it. If anyone's interested, I can tidy it up a bit and post it to the forum.

I haven’t used LCDs much and I didn’t know how to do the custom characters. I’d be interested in seeing how to do that. Please post.

OK, will do! I used the custom-character code at Dorkbot London the other day, so I have an example sketch. It reads the analog input and displays a bar-graph across the LCD; to increase resolution, it defines a set of characters with columns of pixels lit.

That sounds great! Thanks.

OK, this is the sketch that I used to try out user-defined characters on a four-row, 20 character LCD. If you have a two-row LCD, you’ll have to change the calls to “drawbar” in the main loop. You’ll need a potentiometer with the track connected to 0V and 5V, and the wiper connected to analog in 0. Turn (or slide) the pot to see the bar extend across the LCD. The crucial command to the LCD is 0x40, which is used to position the “cursor” in the CGRAM, which is where the user-defined characters are stored. A call to “home” is required after defining the characters, to put the cursor back into the main display memory. All this is documented in the HD44780 data sheet.

// lcd_test --- testing the 20x4 LCD for DorkSnow
// John Honniball

#include <LiquidCrystal.h>

LiquidCrystal lcd (8, 9, 10, 4, 5, 6, 7);

/* defChar --- set up a user-defined character in CGRAM */

void defChar (LiquidCrystal &thelcd, int asc, const unsigned char row[8])
{
  int i;
  
  if ((asc < 0) || (asc > 7))
    return;
    
  thelcd.command (0x40 | (asc << 3));
  
  for (i = 0; i < 8; i++)
    thelcd.write (row[i]);
    
  thelcd.home ();
}


/* setup --- Arduino initialisation */

void setup ()
{
  static unsigned char cheq[8] = {
    0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA
  };
  static unsigned char bar0[8] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  };
  static unsigned char bar1[8] = {
    0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
  };  
  static unsigned char bar2[8] = {
    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18
  };
  static unsigned char bar3[8] = {
    0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c
  };
  static unsigned char bar4[8] = {
    0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e
  };
  static unsigned char bar5[8] = {
    0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f
  };
  
  lcd.clear ();
  defChar (lcd, 0x00, bar0);
  defChar (lcd, 0x01, bar1);
  defChar (lcd, 0x02, bar2);
  defChar (lcd, 0x03, bar3);
  defChar (lcd, 0x04, bar4);
  defChar (lcd, 0x05, bar5);
  defChar (lcd, 0x06, cheq);

  lcd.print ("Hello, DorkSnow");
}


/* loop -- Arduino main loop */

void loop ()
{
  int ana;
  
  // Read from potentiometer connected to analog pin 0
  ana = analogRead (0);
  
  lcd.setCursor (0, 1);

  // Display analog value in decimal
  lcd.print ("analogRead = ");
  lcd.print (ana, DEC);
  lcd.print ("   ");

  // Display two rows of "analog" bar-graph
  // For a two-row LCD, change these next two lines to: drawbar (0, ana);
  drawbar (2, ana);
  drawbar (3, ana);

  // Update rate is 50Hz (approx)
  delay (20);
}


/* drawbar -- draw a bar on one row of the LCD */

void drawbar (int row, int ana)
{
  int bar;
  int i;
  
  lcd.setCursor (0, row);
  
  // Bar is 120 pixels long; analog range is 0..1023
  bar = ((long int)ana * 120L) / 1023L;
  
  // Each character cell represents six pixels
  for (i = 0; i < bar / 6; i++)
    lcd.write (0x05);

  // Display last few pixels using user-defined characters (if not at extreme right)
  if ( i < 20) {
    lcd.write (bar % 6);
    i++;
  }
  
  // Clear remainder of row
  for ( ; i < 20; i++)
    lcd.write (0x00);
}

Help me understand your code a little here. It appears that at the beginning of Void Setup, you're defining the pixels that will be "on".

void setup ()
{
  static unsigned char cheq[8] = {
    0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA
  };
  static unsigned char bar0[8] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  };
  static unsigned char bar1[8] = {
    0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
  };  
  static unsigned char bar2[8] = {
    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18
  };
  static unsigned char bar3[8] = {
    0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c
  };
  static unsigned char bar4[8] = {
    0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e
  };
  static unsigned char bar5[8] = {
    0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f
  };

The second part in Void Setup is giving a variable name to each of the characters as well as telling it which memory location it will be stored in. Am I understanding this correctly?

lcd.clear ();
  defChar (lcd, 0x00, bar0);
  defChar (lcd, 0x01, bar1);
  defChar (lcd, 0x02, bar2);
  defChar (lcd, 0x03, bar3);
  defChar (lcd, 0x04, bar4);
  defChar (lcd, 0x05, bar5);
  defChar (lcd, 0x06, cheq);
defChar (lcd, 0x01, bar1);

"Define a custom character, on the lcd, to appear whenever printing character code 0x01, from bytes found in the array called bar1."

The calls to 'defChar' take three arguments, the 'lcd' object, an ASCII code and an array of pixels. The ASCII code specifies which of the user-defined characters we want to redefine (there are eight of them). Then the array of pixels specifies which pixels are lit (ones) and un-lit (zeroes).

A strange thing to note that I followed the same format and could only get the first array to print when I called it by name. In my case, it was called up_arrow and down_arrow. The second array, named down_arrow, would not print, only up_arrow. When I called the memory location (0x01), it printed just fine.

Here is my code from void setup:

void setup
static unsigned char up_arrow[8] = {0x04, 0x0E, 0x15, 0x04, 0x04, 0x04, 0x04, 0x00};
static unsigned char down_arrow[8] = {0x00, 0x04, 0x04, 0x04, 0x04, 0x15, 0x0E, 0x04};

lcd.clear();

defChar (lcd, 0x00, up_arrow);
defChar (lcd, 0x01, down_arrow);

void DRAW_UP_ARROW()
    {
      int up_arrow;
      lcd.write(up_arrow);
    }
    

void DRAW_DOWN_ARROW()
    {
      int down_arrow;
      lcd.write(down_arrow);
    }

When I call DRAW_UP_ARROW, it will print the up arrow. When I call DRAW_DOWN_ARROW, it prints an up arrow. If I tell it lcd.write(0x01) instead, it will then print a down arrow. Any ideas?

I was able to make it work correctly by changing the code a little. I'm still not sure why it wouldn't work without equating the variable to a value, but it did the trick nonetheless.

void DRAW_UP_ARROW()
    {
      int up_arrow = 0x00;
      lcd.write(up_arrow);
    }
    

void DRAW_DOWN_ARROW()
    {
      int down_arrow = 0x01;
      lcd.write(down_arrow);
    }

In your original code, up_arrow and down_arrow are local variables that have the same name as the static arrays (presumably within the 'setup' function, but you have omitted some of the code there it seems). That is, they only exist within the function(s). They are unitialised, which means they have no defined value. In your second version, you've fixed that by initialising them to 0x00 and 0x01. If you want to keep consistent names throughout your code, you could try:

const int UP_ARROW = 0x00;
const int DOWN_ARROW = 0x01;

void setup ()
{
static unsigned char up_arrow[8] = {0x04, 0x0E, 0x15, 0x04, 0x04, 0x04, 0x04, 0x00};
static unsigned char down_arrow[8] = {0x00, 0x04, 0x04, 0x04, 0x04, 0x15, 0x0E, 0x04};

...

defChar (lcd, UP_ARROW, up_arrow);
defChar (lcd, DOWN_ARROW, down_arrow);

...
}

void DrawUpArrow()
{
     lcd.write (UP_ARROW);
}

void DrawDownArrow()
{
     lcd.write (DOWN_ARROW);
}

[ch12450][ch12523][ch12485][ch12452]ch12494

what you have there is actually (a ru dzu i no). Is that actually what what actual japanese people say for "arduino"? I would google it but I can't do japanese typing at work. There really is no 'du' in japanese.