AVRly - AVR Development Resources
hd44780_lcd.c File Reference

Driver for the HD44780 based 16x2 liquid crystal display. More...

#include <avr/io.h>
#include <util/delay.h>
#include "hd44780_lcd.h"
#include "pin_defines.h"

Go to the source code of this file.

Macros

#define CLEAR_DISPLAY   0b00000001U
 
#define CURSOR_HOME   0b00000010U
 
#define ENTRY_MODE_SET   0b00000100U
 
#define ON_OFF_CTRL   0b00001000U
 
#define CURSOR_DISPLAY_SHIFT   0b00010000U
 
#define FUNCTION_SET   0b00100000U
 
#define DATA_LENGTH_BIT   4U
 
#define DISPLAY_LINES_BIT   3U
 
#define FONT_SIZE_BIT   2U
 
#define MOVE_DIRECTION_BIT   1U
 
#define DISPLAY_SHIFT_BIT   0U
 
#define CURSOR_ENABLE_BIT   1U
 
#define BLINK_ENABLE_BIT   0U
 
#define ON_OFF_CTRL_BIT   2U
 
#define RIGHT_LEFT_BIT   2U
 
#define SHIFT_OR_CURSOR_BIT   3U
 
#define BUSY_FLAG_BIT   7U
 
#define DISPLAY_ON   true
 
#define DISPLAY_OFF   false
 
#define POWER_RAMP_DELAY_MS   100
 
#define SHORT_INSTR_DELAY_MS   2
 
#define LONG_INSTR_DELAY_MS   10
 
#define SCROLL_DELAY_MS   400
 
#define ENABLE_DELAY_US   2
 

Functions

void lcd_command (uint8_t data)
 
void lcd_char (char character)
 
void pulse_enable (void)
 
void init_lcd (lcd_config_t *p_config)
 Initialisation routine (run once at startup). More...
 
void lcd_display_off (void)
 Turn display off (config settings are retained). More...
 
void lcd_display_on (void)
 Turn display on. More...
 
void lcd_print_string (const char *str)
 Prints a string of characters to the display. More...
 
void lcd_print_integer (int16_t number)
 Prints an integer variable. More...
 
void lcd_set_cursor (uint8_t column, uint8_t row)
 Sets cursor location using x and y coordinates. More...
 
void lcd_fast_clear (void)
 Writes space characters to all 32 sections of display (or 16 if in 1 line mode). More...
 
void lcd_reconfigure (void)
 Edits config settings on the display (lcd_config_t members must be changed first). More...
 
void lcd_return_home (void)
 Sets DDRAM address 0 in address counter. More...
 
void lcd_shift_cursor_left (uint8_t distance)
 Moves cursor left without changing DDRAM contents. More...
 
void lcd_shift_cursor_right (uint8_t distance)
 Moves cursor right without changing DDRAM contents. More...
 
void lcd_shift_display_left (uint8_t distance, bool delay)
 Shifts display left without changing DDRAM contents. More...
 
void lcd_shift_display_right (uint8_t distance, bool delay)
 Shifts display right without changing DDRAM contents. More...
 

Detailed Description

Driver for the HD44780 based 16x2 liquid crystal display.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Author
Jason Duffy
Date
1st March 2022

This file provides the basic low-level functionality for the ubiquitous 16x2 display. Please note that it uses long blocking waits in the initialisation routine (100ms), and short blockign waits in other utility functions (2uS - 2mS). This was done to simplify the code as the busy flag read introduced pitfalls. This driver currently only allows for a single display to be used, but this might be improved on at a later date.

NOTE: Values used in bitwise operations MUST be of unsigned type.

This driver was written using the datasheet for the HITACHI HD44780U LCD driver chip, which can be found here:

See also
http://www.datasheet-pdf.com/PDF/HD44780U-Datasheet-Hitachi-1109874

Definition in file hd44780_lcd.c.

Macro Definition Documentation

◆ CLEAR_DISPLAY

#define CLEAR_DISPLAY   0b00000001U

Definition at line 64 of file hd44780_lcd.c.

◆ CURSOR_HOME

#define CURSOR_HOME   0b00000010U

Definition at line 65 of file hd44780_lcd.c.

◆ ENTRY_MODE_SET

#define ENTRY_MODE_SET   0b00000100U

Definition at line 66 of file hd44780_lcd.c.

◆ ON_OFF_CTRL

#define ON_OFF_CTRL   0b00001000U

Definition at line 67 of file hd44780_lcd.c.

◆ CURSOR_DISPLAY_SHIFT

#define CURSOR_DISPLAY_SHIFT   0b00010000U

Definition at line 68 of file hd44780_lcd.c.

◆ FUNCTION_SET

#define FUNCTION_SET   0b00100000U

Definition at line 69 of file hd44780_lcd.c.

◆ DATA_LENGTH_BIT

#define DATA_LENGTH_BIT   4U

Definition at line 72 of file hd44780_lcd.c.

◆ DISPLAY_LINES_BIT

#define DISPLAY_LINES_BIT   3U

Definition at line 73 of file hd44780_lcd.c.

◆ FONT_SIZE_BIT

#define FONT_SIZE_BIT   2U

Definition at line 74 of file hd44780_lcd.c.

◆ MOVE_DIRECTION_BIT

#define MOVE_DIRECTION_BIT   1U

Definition at line 75 of file hd44780_lcd.c.

◆ DISPLAY_SHIFT_BIT

#define DISPLAY_SHIFT_BIT   0U

Definition at line 76 of file hd44780_lcd.c.

◆ CURSOR_ENABLE_BIT

#define CURSOR_ENABLE_BIT   1U

Definition at line 77 of file hd44780_lcd.c.

◆ BLINK_ENABLE_BIT

#define BLINK_ENABLE_BIT   0U

Definition at line 78 of file hd44780_lcd.c.

◆ ON_OFF_CTRL_BIT

#define ON_OFF_CTRL_BIT   2U

Definition at line 79 of file hd44780_lcd.c.

◆ RIGHT_LEFT_BIT

#define RIGHT_LEFT_BIT   2U

Definition at line 80 of file hd44780_lcd.c.

◆ SHIFT_OR_CURSOR_BIT

#define SHIFT_OR_CURSOR_BIT   3U

Definition at line 81 of file hd44780_lcd.c.

◆ BUSY_FLAG_BIT

#define BUSY_FLAG_BIT   7U

Definition at line 82 of file hd44780_lcd.c.

◆ DISPLAY_ON

#define DISPLAY_ON   true

Definition at line 85 of file hd44780_lcd.c.

◆ DISPLAY_OFF

#define DISPLAY_OFF   false

Definition at line 86 of file hd44780_lcd.c.

◆ POWER_RAMP_DELAY_MS

#define POWER_RAMP_DELAY_MS   100

Definition at line 89 of file hd44780_lcd.c.

◆ SHORT_INSTR_DELAY_MS

#define SHORT_INSTR_DELAY_MS   2

Definition at line 90 of file hd44780_lcd.c.

◆ LONG_INSTR_DELAY_MS

#define LONG_INSTR_DELAY_MS   10

Definition at line 91 of file hd44780_lcd.c.

◆ SCROLL_DELAY_MS

#define SCROLL_DELAY_MS   400

Definition at line 92 of file hd44780_lcd.c.

◆ ENABLE_DELAY_US

#define ENABLE_DELAY_US   2

Definition at line 93 of file hd44780_lcd.c.

Function Documentation

◆ lcd_command()

void lcd_command ( uint8_t  data)

Definition at line 395 of file hd44780_lcd.c.

396{
397 LCD_CTRL_PORT &= ~(1U << LCD_RS);
398
399 if (p_config_local->eight_bit_mode)
400 {
401 LCD_DATA_PORT = data;
402 pulse_enable();
403 }
404 else
405 {
406 uint8_t byte = 0;
407
408 LCD_DATA_PORT &= ~(data_length_bitmask); // Clear relevant bits in port
409 byte = (data & 0b11110000); // Keep high 4 bits only
410 byte = (byte >> (7U - LCD_D7)); // Shift nibble into place
411 LCD_DATA_PORT |= byte; // Send first nibble to LCD
412 pulse_enable();
413
414 LCD_DATA_PORT &= ~(data_length_bitmask); // Clear relevant bits in port
415 byte = (data & 0b00001111); // Keep low 4 bits only
416 byte = (byte << (LCD_D7 - 3U)); // Shift nibble into place
417 LCD_DATA_PORT |= byte; // Send second nibble to LCD
418 pulse_enable();
419 }
420 _delay_ms(SHORT_INSTR_DELAY_MS);
421}
bool eight_bit_mode
true = 8 bit mode, false = 4 bit mode.
Definition: hd44780_lcd.h:58

◆ lcd_char()

void lcd_char ( char  character)

Definition at line 427 of file hd44780_lcd.c.

428{
429 LCD_CTRL_PORT |= (1U << LCD_RS);
430
431 if (p_config_local->eight_bit_mode)
432 {
433 LCD_DATA_PORT = character;
434 pulse_enable();
435 }
436 else
437 {
438 uint8_t byte = 0;
439
440 LCD_DATA_PORT &= ~(data_length_bitmask); // Clear relevant bits in port
441 byte = (character & 0b11110000); // Keep high 4 bits only
442 byte = (byte >> (7U - LCD_D7)); // Shift nibble into place
443 LCD_DATA_PORT |= byte; // Send first nibble to LCD
444 pulse_enable();
445
446 LCD_DATA_PORT &= ~(data_length_bitmask); // Clear relevant bits in port
447 byte = (character & 0b00001111); // Keep low 4 bits only
448 byte = (byte << (LCD_D7 - 3U)); // Shift nibble into place
449 LCD_DATA_PORT |= byte; // Send second nibble to LCD
450 pulse_enable();
451 }
452 _delay_ms(SHORT_INSTR_DELAY_MS);
453}

◆ pulse_enable()

void pulse_enable ( void  )

Definition at line 459 of file hd44780_lcd.c.

460{
461 LCD_CTRL_PORT |= (1U << LCD_EN);
462 _delay_us(ENABLE_DELAY_US);
463 LCD_CTRL_PORT &= ~(1U << LCD_EN);
464 _delay_us(ENABLE_DELAY_US);
465}

◆ init_lcd()

void init_lcd ( lcd_config_t p_config)

Initialisation routine (run once at startup).

This function is to be called immediately after powerup of the display module. Instantiate the lcd_config_t object first then pass it's address into init_lcd() before using any other lcd functions.

Parameters
p_configis a pointer to the lcd_config_t object.
Returns
Returns void.

Definition at line 104 of file hd44780_lcd.c.

105{
106 // copy address of config object pointer to a local pointer
107 p_config_local = p_config;
108
109 // Set data direction registers to output where applicable
110 LCD_CTRL_DDR |= (1U << LCD_RS) | (1U << LCD_EN);
111
112 // Test for bit mode and set appropriate bitmask
113 if (p_config_local->eight_bit_mode)
114 {
115 data_length_bitmask = 0xff; // 0b11111111
116 }
117 else
118 {
119 data_length_bitmask |= (1U << LCD_D7) | (1U << LCD_D6);
120 data_length_bitmask |= (1U << LCD_D5) | (1U << LCD_D4);
121 }
122
123 // Set relevant lcd data port direction to output
124 LCD_DATA_DDR |= data_length_bitmask;
125
126 // Delay to allow power ramp up in LCD controller
127 _delay_ms(POWER_RAMP_DELAY_MS);
128
129 // Begin initialising HD44780
130 uint8_t byte = 0;
131 byte |= FUNCTION_SET;
132 byte |= (p_config_local->eight_bit_mode << DATA_LENGTH_BIT);
133
134 for (uint8_t count = 0; count < 3; ++count)
135 {
136 lcd_command(byte);
137 _delay_ms(LONG_INSTR_DELAY_MS);
138 }
139
140 byte = 0;
141 byte |= FUNCTION_SET;
142 byte |= (p_config_local->eight_bit_mode << DATA_LENGTH_BIT);
143 byte |= (p_config_local->two_line_display << DISPLAY_LINES_BIT);
144 byte |= (p_config_local->five_by_ten_font << FONT_SIZE_BIT);
145 lcd_command(byte);
146
147 byte = 0;
148 byte |= ON_OFF_CTRL;
149 byte |= (DISPLAY_OFF << ON_OFF_CTRL_BIT);
150 byte |= (p_config_local->cursor_enable << CURSOR_ENABLE_BIT);
151 byte |= (p_config_local->blink_enable << BLINK_ENABLE_BIT);
152 lcd_command(byte);
153
154 byte = 0;
155 byte |= CLEAR_DISPLAY;
156 lcd_command(byte);
157
158 byte = 0;
159 byte |= ENTRY_MODE_SET;
160 byte |= (p_config_local->increment_counter << MOVE_DIRECTION_BIT);
161 byte |= (p_config_local->display_shift << DISPLAY_SHIFT_BIT);
162 lcd_command(byte);
163
164 byte = 0;
165 byte |= ON_OFF_CTRL;
166 byte |= (DISPLAY_ON << ON_OFF_CTRL_BIT);
167 byte |= (p_config_local->cursor_enable << CURSOR_ENABLE_BIT);
168 byte |= (p_config_local->blink_enable << BLINK_ENABLE_BIT);
169 lcd_command(byte);
171}
void lcd_return_home(void)
Sets DDRAM address 0 in address counter.
Definition: hd44780_lcd.c:309
bool display_shift
true = display shift, false = cursor shift.
Definition: hd44780_lcd.h:62
bool cursor_enable
true = enabled, false = disabled.
Definition: hd44780_lcd.h:63
bool increment_counter
true = increment, false = decrement.
Definition: hd44780_lcd.h:61
bool blink_enable
true = enabled, false = disabled.
Definition: hd44780_lcd.h:64
bool five_by_ten_font
true = 5x10 dots, false = 5x8 dots.
Definition: hd44780_lcd.h:60
bool two_line_display
true = 2 lines, false = 1 line.
Definition: hd44780_lcd.h:59

◆ lcd_display_off()

void lcd_display_off ( void  )

Turn display off (config settings are retained).

Side effect: cursor_enable and blink_enable variable states are written to the display during this command, so if they have been changed but lcd_reconfigure() was not called afterwards, this function will update those config bits on the display.

Returns
Returns void.

Definition at line 177 of file hd44780_lcd.c.

178{
179 uint8_t byte = 0;
180 byte |= ON_OFF_CTRL; // Default is off
181 byte |= (p_config_local->cursor_enable << CURSOR_ENABLE_BIT);
182 byte |= (p_config_local->blink_enable << BLINK_ENABLE_BIT);
183 lcd_command(byte);
184}

◆ lcd_display_on()

void lcd_display_on ( void  )

Turn display on.

Side effect: cursor_enable and blink_enable variable states are written to the display during this command, so if they have been changed but lcd_reconfigure() was not called afterwards, this function will update those config bits on the display.

Returns
Returns void.

Definition at line 190 of file hd44780_lcd.c.

191{
192 uint8_t byte = 0;
193 byte |= ON_OFF_CTRL;
194 byte |= (DISPLAY_ON << ON_OFF_CTRL_BIT);
195 byte |= (p_config_local->cursor_enable << CURSOR_ENABLE_BIT);
196 byte |= (p_config_local->blink_enable << BLINK_ENABLE_BIT);
197 lcd_command(byte);
198}

◆ lcd_print_string()

void lcd_print_string ( const char *  str)

Prints a string of characters to the display.

This function takes a string literal (constant) as it's parameter. Be sure to enclose text passed in with "" quotation marks. eg: "Hello, World!".

Parameters
stris a string literal.
Returns
Returns void.

Definition at line 204 of file hd44780_lcd.c.

205{
206 for (uint8_t index = 0; str[index] != 0; ++index)
207 {
208 lcd_char(str[index]);
209 }
210}

◆ lcd_print_integer()

void lcd_print_integer ( int16_t  number)

Prints an integer variable.

This function prints a signed integer value to the display, values from -32768 to 32767 are acceptable.

Parameters
numberis a signed, fixed width integer.
Returns
Returns void.

Definition at line 216 of file hd44780_lcd.c.

217{
218 if (number < 0)
219 {
220 lcd_char('-');
221 }
222
223 uint8_t count = 0;
224 uint8_t digit = 0;
225 char str[20];
226
227 while (number > 0)
228 {
229 digit = number % 10;
230 str[count] = (digit + '0');
231 ++count;
232 number /= 10;
233 }
234
235 while (count > 0)
236 {
237 lcd_char(str[count - 1]);
238 --count;
239 }
240}

◆ lcd_set_cursor()

void lcd_set_cursor ( uint8_t  column,
uint8_t  row 
)

Sets cursor location using x and y coordinates.

Column is 0 for top row, 1 for bottom row (in 2 row mode). Row can be from 0 - 15, values outside of this range will be written to non visible spaces on the display.

Parameters
columnis the x coordinate.
rowis the y coordinate.
Returns
Returns void.

Definition at line 246 of file hd44780_lcd.c.

247{
248 uint8_t address = 0;
249
250 if (row == 0)
251 {
252 address = column;
253 }
254
255 else if (row == 1)
256 {
257 address = (column + 64);
258 }
259
260 address |= 0x80U; // Write 1 to MSB
261 lcd_command(address);
262}

◆ lcd_fast_clear()

void lcd_fast_clear ( void  )

Writes space characters to all 32 sections of display (or 16 if in 1 line mode).

This is much faster than the clear_display command, as that works by writing a space character to every single section of the display, even all the non-visible ones.

Returns
Returns void.

Definition at line 269 of file hd44780_lcd.c.

270{
271 lcd_set_cursor(0,0);
272 for (uint8_t count = 0; count < 16; ++count)
273 {
274 lcd_char(' ');
275 }
276
277 if (p_config_local->two_line_display)
278 {
279 lcd_set_cursor(0,1);
280 for (uint8_t count = 0; count < 16; ++count)
281 {
282 lcd_char(' ');
283 }
284 }
285}
void lcd_set_cursor(uint8_t column, uint8_t row)
Sets cursor location using x and y coordinates.
Definition: hd44780_lcd.c:247

◆ lcd_reconfigure()

void lcd_reconfigure ( void  )

Edits config settings on the display (lcd_config_t members must be changed first).

data_length, display_lines, and font_size cannot be changed after init_lcd() is called.

Returns
Returns void.

Definition at line 291 of file hd44780_lcd.c.

292{
293 uint8_t byte = 0;
294 byte |= ENTRY_MODE_SET;
295 byte |= (p_config_local->increment_counter << MOVE_DIRECTION_BIT);
296 byte |= (p_config_local->display_shift << DISPLAY_SHIFT_BIT);
297 lcd_command(byte);
298
299 // Also resends cursor and blink settings
301}
void lcd_display_on(void)
Turn display on.
Definition: hd44780_lcd.c:191

◆ lcd_return_home()

void lcd_return_home ( void  )

Sets DDRAM address 0 in address counter.

Also returns display from being shifted to original position. DDRAM contents remain unchanged.

Returns
Returns void.

Definition at line 308 of file hd44780_lcd.c.

309{
310 lcd_command(CURSOR_HOME);
311 _delay_ms(SHORT_INSTR_DELAY_MS);
312}

◆ lcd_shift_cursor_left()

void lcd_shift_cursor_left ( uint8_t  distance)

Moves cursor left without changing DDRAM contents.

Parameters
distanceis used to specify how many spaces to move.
Returns
Returns void.

Definition at line 318 of file hd44780_lcd.c.

319{
320 uint8_t byte = 0;
321 byte |= CURSOR_DISPLAY_SHIFT;
322
323 for (uint8_t count = 0; count < distance; ++count)
324 {
325 lcd_command(byte);
326 }
327}

◆ lcd_shift_cursor_right()

void lcd_shift_cursor_right ( uint8_t  distance)

Moves cursor right without changing DDRAM contents.

Parameters
distanceis used to specify how many spaces to move.
Returns
Returns void.

Definition at line 333 of file hd44780_lcd.c.

334{
335 uint8_t byte = 0;
336 byte |= CURSOR_DISPLAY_SHIFT;
337 byte |= (1U << RIGHT_LEFT_BIT);
338
339 for (uint8_t count = 0; count < distance; ++count)
340 {
341 lcd_command(byte);
342 }
343}

◆ lcd_shift_display_left()

void lcd_shift_display_left ( uint8_t  distance,
bool  delay 
)

Shifts display left without changing DDRAM contents.

Optional delay between shifts for scrolling effect.

Parameters
distanceis used to specify how many spaces to move.
delay- pass in true for scrolling effect, false for no delay.
Returns
Returns void.

Definition at line 349 of file hd44780_lcd.c.

350{
351 uint8_t byte = 0U;
352 byte |= CURSOR_DISPLAY_SHIFT;
353 byte |= (1U << SHIFT_OR_CURSOR_BIT);
354
355 for (uint8_t count = 0; count < distance; ++count)
356 {
357 lcd_command(byte);
358 if (delay == true)
359 {
360 _delay_ms(SCROLL_DELAY_MS);
361 }
362 }
363}

◆ lcd_shift_display_right()

void lcd_shift_display_right ( uint8_t  distance,
bool  delay 
)

Shifts display right without changing DDRAM contents.

Optional delay between shifts for scrolling effect.

Parameters
distanceis used to specify how many spaces to move.
delay- pass in true for scrolling effect, false for no delay.
Returns
Returns void.

Definition at line 369 of file hd44780_lcd.c.

370{
371 uint8_t byte = 0;
372 byte |= CURSOR_DISPLAY_SHIFT;
373 byte |= (1U << SHIFT_OR_CURSOR_BIT);
374 byte |= (1U << RIGHT_LEFT_BIT);
375
376 for (uint8_t count = 0; count < distance; ++count)
377 {
378 lcd_command(byte);
379 if (delay == true)
380 {
381 _delay_ms(SCROLL_DELAY_MS);
382 }
383 }
384}