PropWare  3.0.0.229
C++ objects and CMake build system for Parallax Propeller
hd44780.h
Go to the documentation of this file.
1 
27 #pragma once
28 
29 #include <PropWare/PropWare.h>
30 #include <PropWare/gpio/pin.h>
34 
35 namespace PropWare {
36 
43 class HD44780 : public PrintCapable {
44  public:
48  enum class BusWidth {WIDTH4 = 4,WIDTH8 = 8,
51  };
52 
77  };
78 
80 #define HD44780_ERRORS_LIMIT 16
81 
82 #define HD44780_ERRORS_BASE 48
83 
93  } ErrorCode;
94 
95  protected:
100  typedef struct {
102  uint8_t charRows;
104  uint8_t charColumns;
108  uint8_t ddramCharRowBreak;
110  uint8_t ddramLineEnd;
111  } MemMap;
112 
113  public:
115  static const uint8_t TAB_WIDTH = 4;
116 
122  static const uint8_t CLEAR = BIT_0;
123  static const uint8_t RET_HOME = BIT_1;
124  static const uint8_t ENTRY_MODE_SET = BIT_2;
125  static const uint8_t DISPLAY_CTRL = BIT_3;
126  static const uint8_t SHIFT = BIT_4;
127  static const uint8_t FUNCTION_SET = BIT_5;
128  static const uint8_t SET_CGRAM_ADDR = BIT_6;
129  static const uint8_t SET_DDRAM_ADDR = BIT_7;
136  static const uint8_t SHIFT_INC = BIT_1;
137  static const uint8_t SHIFT_EN = BIT_0;
144  static const uint8_t DISPLAY_PWR = BIT_2;
145  static const uint8_t CURSOR = BIT_1;
146  static const uint8_t BLINK = BIT_0;
153  static const uint8_t SHIFT_DISPLAY = BIT_3; // 0 = shift cursor
154  static const uint8_t SHIFT_RIGHT = BIT_2; // 0 = shift left
164  static const uint8_t FUNC_8BIT_MODE = BIT_4;
168  static const uint8_t FUNC_2LINE_MODE = BIT_3;
172  static const uint8_t FUNC_5x10_CHAR = BIT_2;
175  public:
176  /************************
177  *** Public Functions ***
178  ************************/
189  HD44780 (const Pin::Mask lsbDataPin, const Pin::Mask rs, const Pin::Mask rw, const Pin::Mask en,
190  const HD44780::BusWidth bitMode, const HD44780::Dimensions dimensions)
191  : m_dataPort(lsbDataPin, static_cast<uint8_t>(bitMode), Port::Dir::OUT),
192  m_rs(rs, Pin::Dir::OUT),
193  m_rw(rw, Pin::Dir::OUT),
194  m_en(en, Pin::Dir::OUT),
195  m_bitMode(bitMode),
196  m_dimensions(dimensions) {
197  this->m_curPos.row = 0;
198  this->m_curPos.col = 0;
199 
200  // Save all control signal pin masks
201  this->m_rs.clear();
202  this->m_rw.clear();
203  this->m_en.clear();
204 
205  // Save the modes
206  this->generate_mem_map();
207  }
208 
217  void start () {
218  uint8_t arg;
219 
220  // Wait for a couple years until the LCD has finished internal initialization
221  waitcnt(250 * MILLISECOND + CNT);
222 
223  // Begin init routine:
224  if (BusWidth::WIDTH8 == this->m_bitMode)
225  arg = 0x30;
226  else
227  /* Implied: "if (HD44780::WIDTH4 == this->m_bitMode)" */
228  arg = 0x3;
229 
230  this->m_dataPort.write(arg);
231  this->clock_pulse();
232  waitcnt(100 * MILLISECOND + CNT);
233 
234  this->clock_pulse();
235  waitcnt(100 * MILLISECOND + CNT);
236 
237  this->clock_pulse();
238  waitcnt(10 * MILLISECOND + CNT);
239 
240  if (BusWidth::WIDTH4 == this->m_bitMode) {
241  this->m_dataPort.write(0x2);
242  this->clock_pulse();
243  }
244 
245  // Default functions during initialization
246  arg = PropWare::HD44780::FUNCTION_SET;
247  if (BusWidth::WIDTH8 == this->m_bitMode)
250  this->cmd(arg);
251 
252  // Turn off display shift (set cursor shift) and leave default of
253  // shift-left
254  arg = PropWare::HD44780::SHIFT;
255  this->cmd(arg);
256 
257  // Turn the display on; Leave cursor off and not blinking
258  arg = PropWare::HD44780::DISPLAY_CTRL
259  | PropWare::HD44780::DISPLAY_PWR;
260  this->cmd(arg);
261 
262  // Set cursor to auto-increment upon writing a character
263  arg = PropWare::HD44780::ENTRY_MODE_SET
264  | PropWare::HD44780::SHIFT_INC;
265  this->cmd(arg);
266 
267  this->clear();
268  }
269 
273  void clear (void) {
274  this->cmd(PropWare::HD44780::CLEAR);
275  this->m_curPos.row = 0;
276  this->m_curPos.col = 0;
277  waitcnt(1530 * MICROSECOND + CNT);
278  }
279 
286  void move (const uint8_t row, const uint8_t col) {
287  uint8_t ddramLine, addr = 0;
288 
289  // Handle weird special case where a single row LCD is split across
290  // multiple DDRAM lines (i.e., 16x1 type 1)
291  if (this->m_memMap.ddramCharRowBreak > this->m_memMap.ddramLineEnd) {
292  ddramLine = col / this->m_memMap.ddramLineEnd;
293  if (ddramLine)
294  addr = 0x40;
295  addr |= col % this->m_memMap.ddramLineEnd;
296  } else if (4 == this->m_memMap.charRows) {
297  // Determine DDRAM line
298  if (row % 2)
299  addr = 0x40;
300  if (row / 2)
301  addr += this->m_memMap.ddramCharRowBreak;
302  addr += col % this->m_memMap.ddramCharRowBreak;
303 
304  } else /* implied: "if (2 == memMap.charRows)" */{
305  if (row)
306  addr = 0x40;
307  addr |= col;
308  }
309 
310  this->cmd(addr | PropWare::HD44780::SET_DDRAM_ADDR);
311  this->m_curPos.row = row;
312  this->m_curPos.col = col;
313  }
314 
315  void puts (const char string[]) {
316  const char *s = (char *) string;
317 
318  while (*s) {
319  this->put_char(*s);
320  ++s;
321  }
322  }
323 
324  void put_char (const char c) {
325  // For manual new-line characters...
326  if ('\n' == c) {
327  this->m_curPos.row++;
328  if (this->m_curPos.row == this->m_memMap.charRows)
329  this->m_curPos.row = 0;
330  this->m_curPos.col = 0;
331  this->move(this->m_curPos.row, this->m_curPos.col);
332  } else if ('\t' == c) {
333  do {
334  this->put_char(' ');
335  } while (this->m_curPos.col % PropWare::HD44780::TAB_WIDTH);
336  } else if ('\r' == c)
337  this->move(this->m_curPos.row, 0);
338  // And for everything else...
339  else {
340  //set RS to data and RW to write
341  this->m_rs.set();
342  this->write((const uint8_t) c);
343 
344  // Insert a line wrap if necessary
345  ++this->m_curPos.col;
346  if (this->m_memMap.charColumns == this->m_curPos.col)
347  this->put_char('\n');
348 
349  // Handle weird special case where a single row LCD is split
350  // across multiple DDRAM lines (i.e., 16x1 type 1)
351  if (this->m_memMap.ddramCharRowBreak
352  > this->m_memMap.ddramLineEnd)
353  this->move(this->m_curPos.row, this->m_curPos.col);
354  }
355  }
356 
362  void cmd (const uint8_t command) const {
363  //set RS to command mode and RW to write
364  this->m_rs.clear();
365  this->write(command);
366  }
367 
368  static void print_error_str (const Printer &printer, const HD44780::ErrorCode err) {
369  static const char str[] = "HD44780 Error ";
370 
371  printer << str << err - PropWare::HD44780::BEG_ERROR << ": ";
372  switch (err) {
374  printer << "invalid control signal\n";
375  break;
377  printer << "invalid LCD dimension; please choose from the HD44780::Dimensions type\n";
378  break;
379  default:
380  printer << "unknown error code\n";
381  break;
382  }
383  }
384 
385  protected:
386  /***************************
387  *** Protected Functions ***
388  ***************************/
394  void write (const uint8_t val) const {
395  // Clear RW to signal write value
396  this->m_rw.clear();
397 
398  if (BusWidth::WIDTH4 == this->m_bitMode) {
399  // shift out the high nibble
400  this->m_dataPort.write(val >> 4);
401  this->clock_pulse();
402 
403  // Shift out low nibble
404  this->m_dataPort.write(val);
405  }
406  // Shift remaining four bits out
407  else /* Implied: if (HD44780::8BIT == this->m_bitMode) */{
408  this->m_dataPort.write(val);
409  }
410  this->clock_pulse();
411  }
412 
416  void clock_pulse (void) const {
417  this->m_en.set();
418  waitcnt(MILLISECOND + CNT);
419  this->m_en.clear();
420  }
421 
425  void generate_mem_map () {
426  // TODO: Make this a look-up table instead of a switch-case
427  switch (this->m_dimensions) {
428  case Dimensions::DIM_8x1:
429  this->m_memMap.charRows = 1;
430  this->m_memMap.charColumns = 8;
431  this->m_memMap.ddramCharRowBreak = 8;
432  this->m_memMap.ddramLineEnd = 8;
433  break;
434  case Dimensions::DIM_8x2:
435  this->m_memMap.charRows = 2;
436  this->m_memMap.charColumns = 8;
437  this->m_memMap.ddramCharRowBreak = 8;
438  this->m_memMap.ddramLineEnd = 8;
439  break;
440  case Dimensions::DIM_8x4:
441  this->m_memMap.charRows = 4;
442  this->m_memMap.charColumns = 8;
443  this->m_memMap.ddramCharRowBreak = 8;
444  this->m_memMap.ddramLineEnd = 16;
445  break;
447  this->m_memMap.charRows = 1;
448  this->m_memMap.charColumns = 16;
449  this->m_memMap.ddramCharRowBreak = 8;
450  this->m_memMap.ddramLineEnd = 8;
451  break;
453  this->m_memMap.charRows = 1;
454  this->m_memMap.charColumns = 16;
455  this->m_memMap.ddramCharRowBreak = 16;
456  this->m_memMap.ddramLineEnd = 16;
457  break;
459  this->m_memMap.charRows = 2;
460  this->m_memMap.charColumns = 16;
461  this->m_memMap.ddramCharRowBreak = 16;
462  this->m_memMap.ddramLineEnd = 16;
463  break;
465  this->m_memMap.charRows = 4;
466  this->m_memMap.charColumns = 16;
467  this->m_memMap.ddramCharRowBreak = 16;
468  this->m_memMap.ddramLineEnd = 32;
469  break;
471  this->m_memMap.charRows = 1;
472  this->m_memMap.charColumns = 20;
473  this->m_memMap.ddramCharRowBreak = 20;
474  this->m_memMap.ddramLineEnd = 20;
475  break;
477  this->m_memMap.charRows = 2;
478  this->m_memMap.charColumns = 20;
479  this->m_memMap.ddramCharRowBreak = 20;
480  this->m_memMap.ddramLineEnd = 20;
481  break;
483  this->m_memMap.charRows = 4;
484  this->m_memMap.charColumns = 20;
485  this->m_memMap.ddramCharRowBreak = 20;
486  this->m_memMap.ddramLineEnd = 40;
487  break;
489  this->m_memMap.charRows = 1;
490  this->m_memMap.charColumns = 24;
491  this->m_memMap.ddramCharRowBreak = 24;
492  this->m_memMap.ddramLineEnd = 24;
493  break;
495  this->m_memMap.charRows = 2;
496  this->m_memMap.charColumns = 24;
497  this->m_memMap.ddramCharRowBreak = 24;
498  this->m_memMap.ddramLineEnd = 24;
499  break;
501  this->m_memMap.charRows = 1;
502  this->m_memMap.charColumns = 40;
503  this->m_memMap.ddramCharRowBreak = 40;
504  this->m_memMap.ddramLineEnd = 40;
505  break;
507  this->m_memMap.charRows = 2;
508  this->m_memMap.charColumns = 40;
509  this->m_memMap.ddramCharRowBreak = 40;
510  this->m_memMap.ddramLineEnd = 40;
511  break;
512  }
513  }
514 
515  private:
516  typedef struct {
517  uint8_t row;
518  uint8_t col;
519  } Position;
520 
521  protected:
522  HD44780::MemMap m_memMap;
523 
524  private:
525  const SimplePort m_dataPort;
526  const Pin m_rs;
527  const Pin m_rw;
528  const Pin m_en;
529  const BusWidth m_bitMode;
530  const Dimensions m_dimensions;
531  Position m_curPos;
532 };
533 
534 }
PropWare::HD44780::HD44780
HD44780(const Pin::Mask lsbDataPin, const Pin::Mask rs, const Pin::Mask rw, const Pin::Mask en, const HD44780::BusWidth bitMode, const HD44780::Dimensions dimensions)
Construct an LCD object.
Definition: hd44780.h:189
printer.h
PropWare::HD44780::NO_ERROR
@ NO_ERROR
Definition: hd44780.h:88
PropWare::HD44780::clear
void clear(void)
Clear the LCD display and return cursor to home.
Definition: hd44780.h:273
PropWare::HD44780::Dimensions::DIM_20x4
@ DIM_20x4
PropWare::HD44780::FUNC_8BIT_MODE
static const uint8_t FUNC_8BIT_MODE
Definition: hd44780.h:164
PropWare::HD44780::put_char
void put_char(const char c)
Print a single character.
Definition: hd44780.h:324
PropWare::HD44780::Dimensions::DIM_40x2
@ DIM_40x2
PropWare::SimplePort::write
void write(uint32_t value) const
Allow easy writing to a port w/o destroying data elsewhere in the port; A shift is performed before w...
Definition: simpleport.h:105
PropWare::HD44780::Dimensions::DIM_16x1_1
@ DIM_16x1_1
PropWare::HD44780::FUNC_5x10_CHAR
static const uint8_t FUNC_5x10_CHAR
Definition: hd44780.h:172
PropWare::HD44780::Dimensions::DIM_16x2
@ DIM_16x2
PropWare::Port::Mask
Mask
Definition: port.h:43
PropWare::HD44780::Dimensions
Dimensions
Supported LCD dimensions; Used for determining cursor placement.
Definition: hd44780.h:62
PropWare::HD44780::Dimensions::DIM_40x1
@ DIM_40x1
PropWare::Pin
Utility class to handle general purpose I/O pins.
Definition: pin.h:36
PropWare::HD44780::Dimensions::DIM_8x1
@ DIM_8x1
PropWare::HD44780::ErrorCode
ErrorCode
Definition: hd44780.h:87
PropWare::HD44780::Dimensions::DIM_16x1_2
@ DIM_16x1_2
PropWare::Port
Flexible port that can have any pin enabled or disabled. Pins are independent of each other.
Definition: port.h:38
PropWare::PrintCapable
Interface for all classes capable of printing.
Definition: printcapable.h:38
simpleport.h
PropWare::HD44780::start
void start()
Initialize an HD44780 LCD display.
Definition: hd44780.h:217
PropWare.h
PropWare::HD44780::Dimensions::DIM_24x1
@ DIM_24x1
PropWare::HD44780::BEG_ERROR
@ BEG_ERROR
Definition: hd44780.h:89
PropWare::Port::set
void set() const
Set selected output port high (set all pins to 1)
Definition: port.h:226
PropWare::HD44780::BusWidth::WIDTH4
@ WIDTH4
PropWare::HD44780::Dimensions::DIM_16x4
@ DIM_16x4
HD44780_ERRORS_BASE
#define HD44780_ERRORS_BASE
Definition: hd44780.h:82
PropWare::HD44780::TAB_WIDTH
static const uint8_t TAB_WIDTH
Definition: hd44780.h:115
PropWare::HD44780::Dimensions::DIM_20x1
@ DIM_20x1
PropWare::HD44780::BusWidth::WIDTH8
@ WIDTH8
PropWare::HD44780::Dimensions::DIM_24x2
@ DIM_24x2
PropWare::HD44780::BusWidth
BusWidth
LCD databus width.
Definition: hd44780.h:48
waitcnt
#define waitcnt(a)
Wait until system counter reaches a value.
Definition: propeller.h:176
printcapable.h
CNT
#define CNT
The system clock count.
Definition: propeller1.h:151
PropWare::HD44780
Support for the common "character LCD" modules using the HD44780 controller for the Parallax Propelle...
Definition: hd44780.h:43
PropWare::HD44780::Dimensions::DIM_8x4
@ DIM_8x4
PropWare::HD44780::move
void move(const uint8_t row, const uint8_t col)
Move the cursor to a specified column and row.
Definition: hd44780.h:286
PropWare::HD44780::Dimensions::DIM_8x2
@ DIM_8x2
pin.h
PropWare::Printer
Container class that has formatting methods for human-readable output. This class can be constructed ...
Definition: printer.h:76
PropWare::HD44780::END_ERROR
@ END_ERROR
Definition: hd44780.h:92
PropWare
Generic definitions and functions for the Parallax Propeller.
Definition: runnable.h:33
PropWare::HD44780::INVALID_DIMENSIONS
@ INVALID_DIMENSIONS
Definition: hd44780.h:91
PropWare::Port::clear
void clear() const
Clear selected output port (set it to 0)
Definition: port.h:249
PropWare::HD44780::cmd
void cmd(const uint8_t command) const
Send a control command to the LCD module.
Definition: hd44780.h:362
PropWare::HD44780::Dimensions::DIM_20x2
@ DIM_20x2
PropWare::HD44780::FUNC_2LINE_MODE
static const uint8_t FUNC_2LINE_MODE
Definition: hd44780.h:168
PropWare::HD44780::INVALID_CTRL_SGNL
@ INVALID_CTRL_SGNL
Definition: hd44780.h:90
PropWare::HD44780::puts
void puts(const char string[])
Send a null-terminated character array. Though this method could be created using put_char,...
Definition: hd44780.h:315