Demo of LCD modified to use interrupts not delays.

Dependencies:   mbed

Fork of LCD_nonblocking_demo by Oliver Broad

This is an experiment in controlling an LCD from callbacks independently of the main program loop. As it runs from callbacks it is necessary to check if the library is "busy", which is currently indicated by an integer called "busy".

Busy checking should be converted into a method so that the criteria for being "busy" can be changed without changing the API.

As this is rough I have not issued it as a library ... yet.

Also due to my inexperience using the repository manager this is currently listed as a fork of itself. Sorry.

Revision:
2:d87266912897
Parent:
1:1106d7adbe79
Child:
3:f18aa98bc9a8
--- a/main.cpp	Mon Nov 18 13:58:53 2013 +0000
+++ b/main.cpp	Wed Nov 20 11:07:09 2013 +0000
@@ -1,7 +1,21 @@
 // Hello World! for the TextLCD
+/*
+ * Heavily modified LCD "Hello world"
+ *
+ * LCD Library has been merged into program for convenience of development, and
+ * can be de-merged once its looking reliable
+ * currently this gives good results with a small LCD and with a LCD emulation VFD
+ * but is not reliable with a GU140x32-7806A graphic VFD
+ *
+ * Note E is set to 1 at end of cycle in an attempt to force a bug as display works fine
+ * on first power-up but tends to corrupt after MBED manual reset. I am speculating that
+ * something appears on MBED pins that the display "objects" to during a manual reset
+ *
+ */
 
 #include "mbed.h"
 /* mbed TextLCD Library, for a 4-bit LCD based on HD44780
+ * Copyright (c) 2013, oliverb, http://mbed.org
  * Copyright (c) 2007-2010, sford, http://mbed.org
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -32,18 +46,23 @@
  *
  * Currently supports 16x2, 20x2 and 20x4 panels
  *
+ * Implements a "Busy" flag to indicate when display is unavailable
+ * Busy is currently set by a timer and not by polling actual module
+ * 
+ * 
  * @code
  * #include "mbed.h"
  * #include "TextLCD.h"
- * 
+ *
  * TextLCD lcd(p10, p12, p15, p16, p29, p30); // rs, e, d4-d7
- * 
+ *
  * int main() {
  *     lcd.printf("Hello World!\n");
  * }
  * @endcode
  */
-class TextLCD : public Stream {
+class TextLCD : public Stream
+{
 public:
 
     /** LCD panel format */
@@ -62,17 +81,9 @@
      * @param type  Sets the panel size/addressing mode (default = LCD16x2)
      */
     TextLCD(PinName rs, PinName e, PinName d4, PinName d5, PinName d6, PinName d7, LCDType type = LCD16x2);
-    
+
     void init();
-    void init2();
-    void init3();
-    void init4();
-    void init5();
-    void init6();
-    void init7();
-    void init8();
-    void init9();
-   
+
 
 #if DOXYGEN_ONLY
     /** Write a character to the LCD
@@ -86,7 +97,7 @@
      * @param format A printf-style format string, followed by the
      *               variables to use in formating the string.
      */
- volatile   int printf(const char* format, ...);
+    volatile   int printf(const char* format, ...);
 #endif
 
     /** Locate to a screen column and row
@@ -101,21 +112,34 @@
 
     int rows();
     int columns();
-    
+
     volatile int busy;
 
 protected:
     Timeout timer;
+
+// callbacks used by "init" to carry out steps of initialisation
+    void init2();
+    void init2b();
+
+    void init3();
+    void init4();
+    void init5();
+    void init6();
+    void init7();
+    void init8();
+//    void init9();
     // Stream implementation functions
     virtual int _putc(int value);
     virtual int _getc();
 
     int address(int column, int row);
-    void character(int column, int row, int c);
+//    void character(int column, int row, int c);
     void writeByte(int value);
     void writeCommand(int command);
     void writeData(int data);
     void callback();
+    void locate_cb();
 
     DigitalOut _rs, _e;
     BusOut _d;
@@ -126,7 +150,7 @@
     char _queue[40];
     volatile int _head;
     volatile int _tail;
- //   int _loop;
+//   int _loop;
 };
 
 #endif
@@ -167,24 +191,37 @@
 
 TextLCD::TextLCD(PinName rs, PinName e, PinName d4, PinName d5,
                  PinName d6, PinName d7, LCDType type) : busy(0),_rs(rs),
-        _e(e), _d(d4, d5, d6, d7),
-        _type(type) , _head(0), _tail(0) {}
+    _e(e), _d(d4, d5, d6, d7),
+    _type(type) , _column(0),_row(0),
+    _head(0), _tail(0) {}
 void TextLCD::init()
-{         
-        
+{
+
     busy=1;
+    _rs = 1;
+    _d  = 0;
+    wait_us(1);
     _e  = 0;
     _rs = 0;            // command mode
-    timer.attach(this,&TextLCD::init2,0.015);
+    timer.attach_us(this,&TextLCD::init2,15000);
 }
 void TextLCD::init2()
-{    
+{
+    _rs = 0;
+    _d = 0x3;
+    _e = 1;
+    wait_us(1);
+    _e = 0;
+    timer.attach_us(this,&TextLCD::init2b,4100);
+}
+void TextLCD::init2b()
+{
 
     _d = 0x3;
     _e = 1;
     wait_us(1);
     _e = 0;
-    timer.attach(this,&TextLCD::init3,0.0041);
+    timer.attach_us(this,&TextLCD::init3,4100);
 }
 void TextLCD::init3()
 {
@@ -192,7 +229,7 @@
     _e = 1;
     wait_us(1);
     _e = 0;
-    timer.attach(this,&TextLCD::init4,0.0001);
+    timer.attach_us(this,&TextLCD::init4,1000);
 }
 void TextLCD::init4()
 {
@@ -200,77 +237,117 @@
     _e = 1;
     wait_us(1);
     _e = 0;
-    timer.attach(this,&TextLCD::init5,0.000050);
+    timer.attach_us(this,&TextLCD::init5,60);
 }
 void TextLCD::init5()
 {
 
-    writeCommand(0x28); // Function set 001 BW N F - -
-    timer.attach(this,&TextLCD::init6,0.000050);
+    writeByte(0x28); // Function set 001 BW N F - -
+    timer.attach_us(this,&TextLCD::init6,60);
 }
 void TextLCD::init6()
 {
-    writeCommand(0x0C);
-    timer.attach(this,&TextLCD::init7,0.000050);
+    writeByte(0x0C);
+    timer.attach_us(this,&TextLCD::init7,60);
 }
 void TextLCD::init7()
 {
-    writeCommand(0x6);  // Cursor Direction and Display Shift : 0000 01 CD S (CD 0-left, 1-right S(hift) 0-no, 1-yes
-    timer.attach(this,&TextLCD::init8,0.000050);
+    writeByte(0x6);  // Cursor Direction and Display Shift : 0000 01 CD S (CD 0-left, 1-right S(hift) 0-no, 1-yes
+    timer.attach_us(this,&TextLCD::init8,60);
 }
 void TextLCD::init8()
 {
-    writeCommand(0x01); // cls, and set cursor to 0
-                       // This command takes 1.64 ms
-    timer.attach(this,&TextLCD::callback,0.00164);
+    writeByte(0x01); // cls, and set cursor to 0
+    // This command takes 1.64 ms
+    locate(0, 0);
+    timer.attach_us(this,&TextLCD::locate_cb,1640);
 }
-
-void TextLCD::character(int column, int row, int c) {
+/*
+void TextLCD::character(int column, int row, int c)
+{
     int a = address(column, row);
     writeCommand(a);
     writeData(c);
 }
-
-void TextLCD::cls() {
+*/
+void TextLCD::cls()
+{
     writeCommand(0x01); // cls, and set cursor to 0
     wait(0.00164f);     // This command takes 1.64 ms
     locate(0, 0);
 }
 
-void TextLCD::locate(int column, int row) {
+void TextLCD::locate(int column, int row)
+{
     _column = column;
     _row = row;
 }
+/* this is the general buffered-write callback for writing text to the display
+ * it normally chains to itself unless a newline occurs in which case it chains to
+ * locate_cb
+ * or the buffer runs out in which case it clears busy and does not chain
+ */
+
 void TextLCD::callback()
 {
-  if (_tail<_head)
-  {
-    _rs = 1; // data mode
-    writeByte(_queue[_tail++]);
-    timer.attach(this,&TextLCD::callback,0.000050f);
-  }
-  else
-  {
-    _head=_tail=0;
-    busy=0;
-  }
+    if (_tail<_head) {
+        int value=_queue[_tail++];
+        if (value == '\n') {
+            _column = 0;
+            _row++;
+            if (_row >= rows()) {
+                _row = 0;
+            }
+            locate_cb(); // newline isn't printed so go straight to "locate" code
+        } else {
+            _rs = 1; // data mode
+            writeByte(value);
+            _column++;
+            if (_column >= columns()) { //if we've reached the end of line then chain to "locate"
+                                        //otherwise go back to callback
+                _column = 0;
+                _row++;
+                if (_row >= rows()) {
+                    _row = 0;
+                }
+                timer.attach_us(this,&TextLCD::locate_cb,60);
+            } else {
+                timer.attach_us(this,&TextLCD::callback,60);
+            }
+
+        }
+
+    } else {  //if we've run out of text then clear flag
+        _head=_tail=0;
+        busy=0;
+    }
 }
 
-    
-    
+void TextLCD::locate_cb()
+{
+    int a = address(_column, _row);
+    _rs=0;
+    writeByte(a);
+    timer.attach_us(this,&TextLCD::callback,60);
+}
 
-int TextLCD::_putc(int value) 
+
+int TextLCD::_putc(int value)
 {
-  if (_head<40)
-  {
-    _queue[_head++]=value;
-  };
-  if (!busy)
-  {
-    busy=1;
-    callback();
-  };
-  return value;
+    if (_head<40) {
+        _queue[_head++]=value;
+    };
+    if (busy==0) {
+        busy=1;
+        locate_cb(); // set cursor position before text
+        /*
+        int a = address(_column, _row);
+        _rs=0;
+        writeByte(a);
+        timer.attach_us(this,&TextLCD::callback,60);
+        */
+    };
+    return value;
 }
 
 /*{
@@ -294,35 +371,40 @@
     return value;
 }
 */
-int TextLCD::_getc() {
+int TextLCD::_getc()
+{
     return -1;
 }
 
-void TextLCD::writeByte(int value) {
+void TextLCD::writeByte(int value)
+{
     _d = value >> 4;
     _e = 1;
     wait_us(1);
     _e = 0;
     _d = value >> 0;
-    wait_us(1);
+    wait_us(2);
     _e = 1;
     wait_us(1);  // most instructions take 40us
     _e = 0;
 }
 
-void TextLCD::writeCommand(int command) {
+void TextLCD::writeCommand(int command)
+{
     _rs = 0;  //command mode
     wait_us(50); // most instructions take 40us
     writeByte(command);
 }
 
-void TextLCD::writeData(int data) {
+void TextLCD::writeData(int data)
+{
     _rs = 1; // data mode
     wait_us(50); // most instructions take 40us
     writeByte(data);
 }
 
-int TextLCD::address(int column, int row) {
+int TextLCD::address(int column, int row)
+{
     switch (_type) {
         case LCD20x4:
             switch (row) {
@@ -344,7 +426,8 @@
     }
 }
 
-int TextLCD::columns() {
+int TextLCD::columns()
+{
     switch (_type) {
         case LCD20x4:
         case LCD20x2:
@@ -356,7 +439,8 @@
     }
 }
 
-int TextLCD::rows() {
+int TextLCD::rows()
+{
     switch (_type) {
         case LCD20x4:
             return 4;
@@ -368,20 +452,26 @@
     }
 }
 
-TextLCD lcd(p15, p16, p17, p18, p19, p20); // rs, e, d4-d7
+TextLCD lcd(p15, p16, p17, p18, p19, p20, TextLCD::LCD20x4); // rs, e, d4-d7
 
 
-int main() {
-    Led1=1;
-    lcd.init();
-    Led2=1;
-    Led1=0;
-  //  while (lcd.busy) {}
-    Led3=1;
-    Led2=0;
-    lcd.printf("Hello World!\n");
-    Led4=1;
-    Led3=0;
-    while (lcd.busy) {}
-    Led1=1;
+int main()
+{
+    while(1) {
+        Led1=1;
+        lcd.init();
+        Led2=1;
+        Led1=0;
+        while (lcd.busy) {}
+        Led3=1;
+        Led2=0;
+        lcd.printf("Test String that goes over end of line!\n");
+        Led4=1;
+        Led3=0;
+        while (lcd.busy) {}
+        Led1=1;
+        wait(1);
+        // DigitalOut E(p17);
+        // E=1; // try to break it
+    }
 }