Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 314 lines (279 sloc) 11.49 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
// ---------------------------------------------------------------------------
// Originally Created by Francisco Malpartida on 2011/08/20.
// Copyright 2011 - Under creative commons license 3.0:
// Attribution-ShareAlike CC BY-SA
//
// This software is furnished "as is", without technical support, and with no
// warranty, express or implied, as to its usefulness for any purpose.
//
// 2012/01/21 - Marc MERLIN
// This library, LiquidCrystal_SR_LCD3, was forked off LiquidCrystal_SR which
// used a different wiring than the Pebble and Pebblev2 (just released by
// freetronics in the arduino miniconf as part of linux.conf.au 2012) and
// therefore this code organizes the output data differently.
//
// Original source for this module is
// https://github.com/marcmerlin/NewLiquidCrystal
// Web page is:
// http://marc.merlins.org/perso/arduino/post_2012-01-23_LiquidCrystal-driver-support-LCD3Wire-hardware-_pebble-and-others_.html
// This code was since then included in
// https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home
// this last location should be considered the up to date location and contains
// the 'FastIO' branch which makes this code 4 times faster.
//
// Thread Safe: No
// Extendable: Yes
//
// @file LiquidCrystal_SR_LCD3.h
// Connects an LCD using 3 pins from the Arduino, via an 8-bit
// ShiftRegister (SR from now on).
//
// @brief
// This is a port of the ShiftRegLCD library from raron and ported to the
// LCD library.
//
// The functionality provided by this class and its base class is identical
// to the original functionality of the Arduino LiquidCrystal library and can
// be used as such.
//
// Pinout for this code is used by derivatives of the original LCD3Wire page:
// http://www.arduino.cc/playground/Code/LCD3wires
//
// This includes the LCA (linux.conf.au) Arduino Miniconf Pebble:
// http://shieldlist.org/luke-weston/pebble
// https://github.com/lukeweston/Pebble
//
// It also includes the Pebble v2:
// http://www.arduinominiconf.org/index.php/Pebble_V2.0_Instructions
// http://www.freetronics.com/pages/pebble-v2
// https://github.com/lukeweston/pebble20/blob/master/README.md
// https://github.com/lukeweston/pebble20/blob/master/pebble-sch.pdf
//
// Shiftregister connection description:
// MC14094 input: Arduino digital pin 2=Clock, pin 3=Data, pin 4=Strobe
// MC14094 output: Q8=DB4, Q7=DB5, Q6=DB6, Q5=DB7, Q4=E, Q3=RW, Q2=RS, Q1=None
// http://www.ee.mut.ac.th/datasheet/MC14094.pdf
//
// +--------------------------------------------+
// | Arduino (ATMega 168 or 328) |
// | D02 D03 D04 |
// +----+-------------+-------------+-----------+
// |4 |5 |6
// |1 |2 |3
// +----+-------------+-------------+-----------+
// | Strobe Data Clock |
// | MC14094 8-bit shift/latch register |
// | Q8 Q7 Q6 Q5 Q4 Q3 Q2 Q1 |
// +----+----+----+----+----+----+----+----+----+
// |11 |12 |13 |14 |7 |6 |5 |4
// |11 |12 |13 |14 |6 |5 |4
// +----+----+----+----+----+----+----+---------+
// | DB4 DB5 DB6 DB7 E RW RS |
// | LCD KS0066 |
// +--------------------------------------------+
//
// 3 Pins required from the Arduino for Data, Clock, and Enable/Strobe.
//
// This code was inspired from LiquidCrystal_SR from
// http://code.google.com/p/arduinoshiftreglcd/
// but was written for implementing LiquidCrystal support for the Pebble
// and Pebblev2 (see below).
// The Pebbles's LCD and shift register wiring were inspired from this
// original page:
// http://www.arduino.cc/playground/Code/LCD3wires
//
// Pebbles and the LCD3Wires design are compatible hardware-wise, but
// the LCD3Wire code does not work with arduino 1.0 anymore and is generally
// quite limited in functionality compared to this framework that provides the
// entire LiquidDisplay functionality.
// Why not just use the LiquidCrystal_SR pinout?
// - LCD3Wire was first and therefore have hardware that was designed with
// incompatible (IMO better if you don't mind 3 wires) pinout.
// - The pinout used here is same saner (the 4 bits for the LCD are all in one
// nibble of the shift register, not spread across 2 like in the
// LiquidCrystal_SR pinout)
// Note however that LiquidCrystal_SR while a bit more complex wiring and code
// wise, supports non latching shift registers and it a few percent faster than
// this code since it can address the LCD enable pin without having to send
// a pulse through the shift register like the LCD3Wires setup requires.
//
// This code makes sure to properly follow the specifications when talking
// to the LCD while using minimal delays (it's faster than the LCD3wire and aiko
// pebble code).
//
// @author Marc MERLIN - marc_soft<at>merlins.org.
// ---------------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include <inttypes.h>

#if (ARDUINO < 100)
#include <WProgram.h>
#else
#include <Arduino.h>
#endif
#include <LiquidCrystal_SR_LCD3.h>

// When the display powers up, it is configured as follows:
//
// 1. Display clear
// 2. Function set:
// DL = 1; 8-bit interface data
// N = 0; 1-line display
// F = 0; 5x8 dot character font
// 3. Display on/off control:
// D = 0; Display off
// C = 0; Cursor off
// B = 0; Blinking off
// 4. Entry mode set:
// I/D = 1; Increment by 1
// S = 0; No shift
//
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
// can't assume that its in that state when a sketch starts (and the
// LiquidCrystal constructor is called).
// A call to begin() will reinitialize the LCD.

// STATIC helper routines
// ---------------------------------------------------------------------------
/*!
@function
@abstract waits for a given time in microseconds (compilation dependent).
@discussion Waits for a given time defined in microseconds depending on
the FAST_MODE define. If the FAST_MODE is defined the call will return
inmediatelly.
@param uSec[in] time in microseconds.
@result None
*/
inline static void waitUsec ( uint16_t uSec )
{
#ifndef FAST_MODE
   delayMicroseconds ( uSec );
#endif // FAST_MODE
}


// CONSTRUCTORS
// ---------------------------------------------------------------------------
// Assuming 1 line 8 pixel high font
LiquidCrystal_SR_LCD3::LiquidCrystal_SR_LCD3 ( uint8_t srdata, uint8_t srclock,
                                     uint8_t strobe )
{
init ( srdata, srclock, strobe, 1, 0 );
}
// Set nr. of lines, assume 8 pixel high font
LiquidCrystal_SR_LCD3::LiquidCrystal_SR_LCD3 ( uint8_t srdata, uint8_t srclock,
                                     uint8_t strobe, uint8_t lines )
{
init ( srdata, srclock, strobe, lines, 0 );
}

// Set nr. of lines and font
LiquidCrystal_SR_LCD3::LiquidCrystal_SR_LCD3 ( uint8_t srdata, uint8_t srclock,
                                     uint8_t strobe, uint8_t lines,
                                     uint8_t font )
{
init ( srdata, srclock, strobe, lines, font );
}


// PRIVATE METHODS
// ---------------------------------------------------------------------------

//
// init
void LiquidCrystal_SR_LCD3::init(uint8_t srdata, uint8_t srclock, uint8_t strobe,
                                 uint8_t lines, uint8_t font )
{
   // Initialise private variables
   _srdata_pin = srdata;
   _srclock_pin = srclock;
   _strobe_pin = strobe;
   
   // Configure control pins as outputs
   // ------------------------------------------------------------------------
   pinMode(_srclock_pin, OUTPUT);
   pinMode(_srdata_pin, OUTPUT);
   pinMode(_strobe_pin, OUTPUT);

   // Initialize _strobe_pin at low.
   digitalWrite( _strobe_pin, LOW );
   // Little trick to force a pulse of the LCD enable bit and make sure it is
   // low before we start further writes since this is assumed.
   write4bits(0);
   
   _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x10DOTS;
}

// PUBLIC METHODS
// ---------------------------------------------------------------------------

//
// begin
void LiquidCrystal_SR_LCD3::begin(uint8_t cols, uint8_t lines, uint8_t dotsize)
{
   if (lines > 1)
   {
      _displayfunction |= LCD_2LINE;
   }

   _numlines = lines;
   _cols = cols;
   
   // for some 1 line displays you can select a 10 pixel high font
   // ------------------------------------------------------------
   if ((dotsize != 0) && (lines == 1))
   {
      _displayfunction |= LCD_5x10DOTS;
   }
   
   // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
   // according to datasheet, we need at least 40ms after power rises above 2.7V
   // before sending commands. Arduino can turn on way before 4.5V so we'll wait
   // 50
   // ---------------------------------------------------------------------------
   delayMicroseconds(50000);

   // This init is copied verbatim from the spec sheet.
   // 8 bit codes are shifted to 4 bit
   write4bits((LCD_FUNCTIONSET | LCD_8BITMODE) >> 4);
   delayMicroseconds(4500); // wait more than 4.1ms
   
   // Second try
   write4bits((LCD_FUNCTIONSET | LCD_8BITMODE) >> 4);
   delayMicroseconds(150);
   // Third go
   write4bits((LCD_FUNCTIONSET | LCD_8BITMODE) >> 4);
   
   // And finally, set to 4-bit interface
   write4bits((LCD_FUNCTIONSET | LCD_4BITMODE) >> 4);
   
   // Set # lines, font size, etc.
   command(LCD_FUNCTIONSET | _displayfunction);
   // Turn the display on with no cursor or blinking default
   _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
   display();
   // Clear it off
   clear();
   // Initialize to default text direction (for romance languages)
   _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
   // set the entry mode
   command(LCD_ENTRYMODESET | _displaymode);
   home();
   
}

/************ low level data pushing commands **********/

// Code below was borrowed from LCD3Wire from
// http://www.arduino.cc/playground/Code/LCD3wires

// bitmasks for control bits on shift register
#define SR_EN_BIT B00010000 // LCD Data enable bit.
#define SR_RW_BIT B00100000 // RW can be pinned low since we only send
#define SR_RS_BIT B01000000 // LOW: command. HIGH: character.

void LiquidCrystal_SR_LCD3::send(uint8_t value, uint8_t mode)
{
   uint8_t nibble;
   
   mode = mode ? SR_RS_BIT : 0; // RS bit; LOW: command. HIGH: character.

   nibble = value >> 4; // Get high nibble.
   write4bits(nibble | mode);

   //delay(1); // This was in the LCD3 code but does not seem needed -- merlin

   nibble = value & 15; // Get low nibble
   write4bits(nibble | mode);
}

void LiquidCrystal_SR_LCD3::write4bits(uint8_t nibble)
{
    nibble &= ~SR_RW_BIT; // set RW LOW (we do this always since we only write).

    // Send a High transition to display the data that was pushed
    nibble |= SR_EN_BIT; // LCD Data Enable HIGH
    _pushOut(nibble);
    nibble &= ~SR_EN_BIT; // LCD Data Enable LOW
    _pushOut(nibble);
}

// push byte to shift register and on to LCD
void LiquidCrystal_SR_LCD3::_pushOut(uint8_t nibble)
{
    // Make data available for pushing to the LCD.
    shiftOut(_srdata_pin, _srclock_pin, LSBFIRST, nibble);

    // Make new data active.
    digitalWrite(_strobe_pin, HIGH);
    waitUsec( 1 ); // strobe pulse must be >450ns (old code had 10ms)
    digitalWrite(_strobe_pin, LOW);
    waitUsec( 40 ); // commands need > 37us to settle
}
Something went wrong with that request. Please try again.