0
\$\begingroup\$

Story (skip if you want)

Last week I received two malfunctioning DAB radio's from the 'brand' Tesco (type DR1551W) for free and because I cannot fix the problem with these units (missing service manual and datasheets DAB "Frontier Silicon KINO4 FS1445L" chip), I decided to try to reverse engineer some parts such as COG display and main control board to be able to reuse it, instead of throwing away. Also want to reuse the cabinet.

tesco-lcd


Libraries and datasheet

After a long decent search (no device type numbers) I found out that a similar looking display (Batron BTHQ 21605V-FSTF-I2C-COG and such) is driven by a NXP PFC2119x driver and it seems also this display does (however pincount differs, both I2C).

batron-lcd


I search the net for a library, found a couple of libraries in different 'languages' however the libraries seem incomplete, dedicated to specific device/configuration or simply wrong. Also found the datasheet for the PFC2119x driver however the provided example on page 68/69 doesn't do the trick either.

Now I create my own driver code (that I will post on github when finished) with things that really works, with useful/clear names (seen awful formattings, really) and that will work with any Arduino.


Question

Does anybody know what is the correct way to set a custom character? I have tried many 'solutions' found in the libraries however none of them seems to work. The datasheet (page 68/69) is also not very helpful because the provided example does not even work. Also tried examples of some other controllers that drives a Hitachi HD44780 LCD, 'of course' it doesn't work.


My code - function

Because I tried many 'solutions' to figure out if it will work, I don't know what is right. This is just an example of the many I have tried (however doesn't work):

// Allows us to fill the first 8 CGRAM locations
// with custom characters
bool LiquidCrystal_pcf2119::setCustomChar( uint8_t iAddress, uint8_t* aCharmap, uint8_t iLength ) 
{
  bool bResult = (( iAddress < 32 ) && ( iLength > 0 )); 

  if( bResult )
  {
    /*
     // Opens I2C connection and send 0x00, ( 0x80 | (iAddress >= 8 ? 0x40 : 0)) as command
    bResult = ( beginUpdate() && command( LCD_SETCGRAMADDR | (iAddress >= 8 ? 0x40 : 0) ));

    if( bResult )
    {   
       // Next: Send 0x00, 0x40 | (8 * (iAddress % 8)), 0x40
       bResult = ( command( LCD_SETDDRAMADDR | (8 * (iAddress % 8)) )  
                  && write( LCD_SETDDRAMADDR ) ); 
    } */

    //bResult = command( 0x40 + (iAddress * 8 ) );
    bResult = beginUpdate( 0x40 + (iAddress * 8 ) );

    if( bResult )
    {
      // Finally: Send character bits markup
      while( iLength-- ) 
      {
        Serial.println( *aCharmap, HEX );
        write( *aCharmap );
        ++aCharmap;
      }
    }

     // Close I2C connection
    endUpdate();

    // switch back to character output mode
    //command(LCD_SETDDRAMADDR);
  }

  return bResult;
}

-----------------

Full source

Here is the library I made so far. At the end you can find the sketch I use to test it.


LiquidCrystal_pcf2119.h

#ifndef _H_LCD_PCF2119
#define _H_LCD_PCF2119

#include "arduino.h"

 // commands
#define LCD_COMMAND             0x00
#define LCD_CLEARDISPLAY        0x01
#define LCD_RETURNHOME          0x02
#define LCD_ENTRYMODESET        0x04
#define LCD_DISPLAYCONTROL      0x08
#define LCD_CURSORSHIFT         0x10
#define LCD_FUNCTIONSET         0x20
#define LCD_SETCGRAMADDR        0x80
#define LCD_SETDDRAMADDR        0x40


 // flags for display entry mode
#define LCD_ENTRYRIGHT          0x00
#define LCD_ENTRYLEFT           0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00

 // flags for display on/off control
#define LCD_DISPLAYON           0x04
#define LCD_DISPLAYOFF          0x00
#define LCD_CURSORON            0x02
#define LCD_CURSOROFF           0x00
#define LCD_BLINKON             0x01
#define LCD_BLINKOFF            0x00

 // flags for backlight control
#define LCD_BACKLIGHT           0x08
#define LCD_NOBACKLIGHT         0x00

 // flags for display/cursor shift
#define LCD_DISPLAYMOVE         0x08
#define LCD_CURSORMOVE          0x00
#define LCD_MOVERIGHT           0x04
#define LCD_MOVELEFT            0x00

 // flags for function set
#define LCD_4BITMODE            0x00
#define LCD_8BITMODE            0x10
#define LCD_1LINE               0x00
#define LCD_2LINE               0x08
#define LCD_4LINE               0x16
#define LCD_5x10DOTS            0x04
#define LCD_5x8DOTS             0x00

#define LCD_FLIP_REVERSE        (1 | 2) 

 // Display types
#define LCD_TYPE_16x2
#define LCD_TYPE_16x2B
#define LCD_TYPE_20x2
#define LCD_TYPE_20x4

 // Charsets
#define LCD_CHARSET_ASCII           0x00
#define LCD_CHARSET_FLIP            0x01
#define LCD_CHARSET_FLIP_SPACE      0x02

 // Custom chars
#define LCD_CUSTOM_CHAR1            0x00
#define LCD_CUSTOM_CHAR2            0x01
#define LCD_CUSTOM_CHAR3            0x02
#define LCD_CUSTOM_CHAR4            0x03
#define LCD_CUSTOM_CHAR5            0x04
#define LCD_CUSTOM_CHAR6            0x05
#define LCD_CUSTOM_CHAR7            0x06
#define LCD_CUSTOM_CHAR8            0x06


/**
 * This is the driver for the Liquid Crystal LCD displays that use the I2C bus.
 *
 * After creating an instance of this class, first call begin() before anything else.
 */

class LiquidCrystal_pcf2119
{
  private:  
    // private variables
    uint8_t _update    = 0;
    uint8_t _lastError = 0;
    uint8_t _displaycontrol;
    uint8_t _displaymode;

    uint8_t _addr;  // I2C address
    uint8_t _cols      = 0;
    uint8_t _rows      = 0;
    uint8_t _rstPin;
    uint8_t _charsize;
    uint8_t _charset;   // type of charset: ASCII, FLIP, FLIP_SPACE

  public:   
    /**
     * Constructor
     *
     * @param lcd_addr  I2C slave address of the LCD display. Most likely printed on the
     *          LCD circuit board, or look in the supplied LCD documentation.
     * @param lcd_rst   reset pin (255 or -1 for none)
     * @param charset   character set in CGROM of the used controller (A, D, F, I, R or S)
     */
    LiquidCrystal_pcf2119( uint8_t lcd_addr, uint8_t lcd_rst = 0xFF, char chrset = 'A' );


  // Getters
  uint8_t getPositionAddress( uint8_t x, uint8_t y ); 
  uint8_t getWidth();
  uint8_t getHeight();

   // Setters
  bool setWidth(  uint8_t iValue, bool bForceUpdate = false );
  bool setHeight( uint8_t iValue, bool bForceUpdate = false );

  bool setOrientation( bool bUpsideDown );

   // Scroll: These commands scroll the content of the display without changing the RAM
  bool scrollDisplay( bool bRight, uint8_t iStepCount = 1, uint16_t iDelay = 0 );
  bool scrollDisplayLeft(  uint8_t iStepCount = 1, uint16_t iDelay = 0 );
  bool scrollDisplayRight( uint8_t iStepCount = 1, uint16_t iDelay = 0 );

   // Sets text x-orientation
  bool setLeftToRight(); // Normal
  bool setRightToLeft(); // Characters in reverse and x-coordinates swapped!

  bool setCursorPos( uint8_t x, uint8_t y ); 
  void setCharset( char charset ); 
  bool setCustomChar( uint8_t iAddress, uint8_t* aCharmap, uint8_t iLength );

    bool clear();
    void home();

  bool enableDisplay( bool bEnable = true );
  bool disableDisplay();

  bool enableBacklight( bool bEnable = true ); 
  bool disableBacklight();

  bool enableCursor( bool bEnable = true );
  bool disableCursor();

  bool enableCursorBlink( bool bEnable = true );
  bool disableCursorBlink();

  bool enableAutoScroll( bool bEnable = true );
  bool disableAutoScroll();

  bool beginUpdate();
  bool beginUpdate( uint8_t iCmd );
  bool write( uint8_t iValue );
  bool write( uint8_t iCmd, uint8_t iValue );
  bool endUpdate();

    bool command( uint8_t );

  bool setChar( uint8_t);
  void setChars( const char* value, uint8_t offset = 0, bool bClrScr = false );
  void print( const char* value ); 
  void print( uint8_t value );

    // default functions
  bool begin( uint8_t iWidth, uint8_t iHeight, uint8_t charsize = LCD_5x8DOTS );
  bool reset();

};

#endif // _H_      

LiquidCrystal_pcf2119.cpp

#include "LiquidCrystal_pcf2119.h"

#include <Wire.h>
#include <arduino.h>

/*
 * This library is for I2C connected text mode LCDs based on the PCF2119 controller
 *
 * Default I2C address 0x3c, alternative address 0x3d
 *
 */
// 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).

// private constants

// public functions/methods
LiquidCrystal_pcf2119::LiquidCrystal_pcf2119(uint8_t lcd_addr, uint8_t lcd_rst, char chrset )
{
    _addr = lcd_addr;
    _rstPin = lcd_rst;
    setCharset( chrset );
}

uint8_t LiquidCrystal_pcf2119::getPositionAddress( uint8_t x, uint8_t y ) 
{
  if( x >= _cols )
   { x = _cols-1; }
  if( y >= _rows )
   { y = _rows-1; }

  if( _rows == 4 )
   {
      switch( y ) 
      {
        case 1 : return 0xc0 + x;
        case 2 : return 0x94 + x;
        case 3 : return 0xd4 + x;
        default: return 0x80 + x;
      }
   }    

  if( _rows == 2 )
  {
    if( _charset != LCD_CHARSET_ASCII )
    {  
     // LCD16x2B:
     return 0x80 + (y * 40) + x;
    }     

    return 0x80 + (y * 0x40) + x;
  }

  // else:
  return LCD_SETDDRAMADDR + x;
}


uint8_t LiquidCrystal_pcf2119::getWidth()
{
  return _cols;
}

uint8_t LiquidCrystal_pcf2119::getHeight()
{
  return _rows;
}

bool LiquidCrystal_pcf2119::setWidth( uint8_t iValue, bool bForceUpdate )
{
  if( iValue == 0 )
   { return false; }

  if( (iValue == _cols) && !bForceUpdate )
   { return true; }

  _cols = iValue;

  return true;
}

bool LiquidCrystal_pcf2119::setHeight( uint8_t iValue, bool bForceUpdate )
{
  if( iValue == 0 || iValue > 4 || iValue == 3 ) 
   { return false; }

  if( iValue == _rows && !bForceUpdate )
   { return true; }

  uint8_t iDispMode = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;

  if( iValue == 2 ) 
   { iDispMode |= LCD_2LINE; }
  else if( iValue == 4 ) 
        { iDispMode |= LCD_4LINE; }

  // for some 1 line displays you can select a 10 pixel high font
  if ((_charsize != 0) && ( iValue  == 1)) 
   { iDispMode |= LCD_5x10DOTS; }

  // Send function set command sequence
  if( command( LCD_FUNCTIONSET | iDispMode ) )
  {
    _rows = iValue;
    return true;
  }
  //delayMicroseconds(4500);  // wait more than 4.1ms
  return false;
}

bool LiquidCrystal_pcf2119::setOrientation( bool bUpsideDown )
{ 
   // NOT WORKING!
  uint8_t iSet = _displaycontrol; //_displaymode;

  //       H   V
  // cmd | 0 | 0  ; Normal 
  //     | 1 | 2  ; Upside down  

  if( bUpsideDown )
   { iSet|= LCD_FLIP_REVERSE; }
  else { iSet&= ~LCD_FLIP_REVERSE; } 

  if( command(LCD_DISPLAYCONTROL | iSet ))
  {
    _displaycontrol = iSet;
    return true;
  }

  return false;
}  


bool LiquidCrystal_pcf2119::clear()
{
  if( _charset != LCD_CHARSET_FLIP_SPACE )
  { 
     // ASCII charset (A,D,F,I,S) -> use built-in clear
    return command( LCD_CLEARDISPLAY );  // clear display, set cursor position to zero
     //delayMicroseconds(2000);  // this command takes a long time!
  }

  // non-ASCII charset R -> manually fill with space
    // see page 32 in datasheet

  home();
  if( beginUpdate( 0x40 ))
  {
          uint8_t i=_cols*_rows;
          while (i--) 
           { write(' '|0x80); }

    endUpdate();
      home();
    return true;
    }

  home();
  return false;
}

void LiquidCrystal_pcf2119::home()
{
  command(LCD_RETURNHOME);  // set cursor position to zero
  //delayMicroseconds(2000);  // this command takes a long time!
}

bool LiquidCrystal_pcf2119::setCursorPos( uint8_t x, uint8_t y )
{
  return command( getPositionAddress( x,y ) );
}


bool LiquidCrystal_pcf2119::enableDisplay( bool bEnable /* = true */) 
{
  uint8_t iSet = _displaycontrol;

  if( bEnable )
   { iSet|= LCD_DISPLAYON; }
  else { iSet&= ~LCD_DISPLAYON; } 

  if( command(LCD_DISPLAYCONTROL | iSet ))
  {
    _displaycontrol = iSet;
    return true;
  }

  return false;
}

bool LiquidCrystal_pcf2119::disableDisplay() 
{ return enableDisplay( false ); }

bool LiquidCrystal_pcf2119::enableBacklight( bool bEnable /* = true */) 
{
  if( beginUpdate( LCD_COMMAND | (bEnable?LCD_BACKLIGHT:LCD_NOBACKLIGHT) ) )
  {
    return endUpdate();
  }

  endUpdate();   
  return false;
}

bool LiquidCrystal_pcf2119::disableBacklight() 
{ return enableBacklight( false ); }


bool LiquidCrystal_pcf2119::enableCursor( bool bEnable /* = true */) 
{
  uint8_t iSet = _displaycontrol;

  if( bEnable )
   { iSet|= LCD_CURSORON; }
  else { iSet&= ~LCD_CURSORON; } 

  if( command(LCD_DISPLAYCONTROL | iSet ))
  {
    _displaycontrol = iSet;
    return true;
  }

  return false;
}

bool LiquidCrystal_pcf2119::disableCursor()
{ return enableCursor( false ); } 

bool LiquidCrystal_pcf2119::enableCursorBlink( bool bEnable /* = true */) 
{
  uint8_t iSet = _displaycontrol;

  if( bEnable )
   { iSet|= LCD_BLINKON; }
  else { iSet&= ~LCD_BLINKON; } 

  if( command(LCD_DISPLAYCONTROL | iSet ))
  {
    _displaycontrol = iSet;
    return true;
  }

  return false;
}

bool LiquidCrystal_pcf2119::disableCursorBlink()
{ return enableCursorBlink( false ); } 

bool LiquidCrystal_pcf2119::enableAutoScroll( bool bEnable /* = true */) 
{
  uint8_t iSet = _displaymode;

  if( bEnable )
   { iSet|= LCD_ENTRYSHIFTINCREMENT; }
  else { iSet&= ~LCD_ENTRYSHIFTINCREMENT; } 

  if( command(LCD_ENTRYMODESET | iSet ))
  {
    _displaymode = iSet;
    return true;
  }

  return false;
}

bool LiquidCrystal_pcf2119::disableAutoScroll()
{ return enableAutoScroll( false ); } 

// Scroll: These commands scroll the content of the display without changing the RAM

bool  LiquidCrystal_pcf2119::scrollDisplay( bool bRight, uint8_t iStepCount = 1, uint16_t iDelay = 0 )
{
  uint8_t iCmd    = LCD_CURSORSHIFT | LCD_DISPLAYMOVE | (bRight?LCD_MOVERIGHT:LCD_MOVELEFT);
  bool    bResult = (iStepCount > 0)?((iDelay == 0)?beginUpdate( iCmd ):true):false;
  uint8_t iBytes  = (iDelay == 0)?2:0; 

  if( bResult )
  {
    //if( iStepCount > _cols )
    // { iStepCount = _cols; }

    if( iDelay == 0 )
     { iStepCount--; }

    while( iStepCount-- && (bResult = command( iCmd )) )
    {
        if( iDelay > 0 )
         { delay( iDelay ); }
        else {
                 // Count up 2 bytes send
                iBytes+=2;

                 // Split/divided sended bytes sessions to avoid overrun
                if( iStepCount > 0 && iBytes >= 16  )
                {
                    // Restart I2C connection
                   if( !endUpdate() || !beginUpdate() )
                    { 
                      endUpdate();
                      return false; // Ugly, I know, I don't care
                    } 
                }
             }
    }

    if( iDelay == 0 )
     { endUpdate(); }
  }  

  return bResult;
}



bool LiquidCrystal_pcf2119::scrollDisplayLeft( uint8_t iStepCount, uint16_t iDelay ) 
{
  return scrollDisplay( false, iStepCount, iDelay );
}

bool LiquidCrystal_pcf2119::scrollDisplayRight( uint8_t iStepCount, uint16_t iDelay ) 
{
  return scrollDisplay( true, iStepCount, iDelay );
}

// This is for text that flows Left to Right
bool LiquidCrystal_pcf2119::setLeftToRight() 
{
  if( command(LCD_ENTRYMODESET | (_displaymode | LCD_ENTRYLEFT ) ))
  {
    _displaymode |= LCD_ENTRYLEFT;
    return true;
  }
  return false;
}

// This is for text that flows Right to Left
bool LiquidCrystal_pcf2119::setRightToLeft() 
{
   // Reverses characters && x-coordinates are swapped!
   // To be honest, don't get the sense of this.
  if( command(LCD_ENTRYMODESET | (_displaymode & (~LCD_ENTRYRIGHT) ) ))
  {
    _displaymode&=~LCD_ENTRYRIGHT;
    return true;
  }
  return false;
}

// Allows us to fill the first 8 CGRAM locations
// with custom characters
bool LiquidCrystal_pcf2119::setCustomChar( uint8_t iAddress, uint8_t* aCharmap, uint8_t iLength ) 
{
  bool bResult = (( iAddress < 32 ) && ( iLength > 0 )); 

  if( bResult )
  {
    /*
     // Opens I2C connection and send 0x00, ( 0x80 | (iAddress >= 8 ? 0x40 : 0)) as command
    bResult = ( beginUpdate() && command( LCD_SETCGRAMADDR | (iAddress >= 8 ? 0x40 : 0) ));

    if( bResult )
    {   
       // Next: Send 0x00, 0x40 | (8 * (iAddress % 8)), 0x40
       bResult = ( command( LCD_SETDDRAMADDR | (8 * (iAddress % 8)) )  
                  && write( LCD_SETDDRAMADDR ) ); 
    } */

    //bResult = command( 0x40 + (iAddress * 8 ) );
    bResult = beginUpdate( 0x40 + (iAddress * 8 ) );

    if( bResult )
    {
      // Finally: Send character bits markup
      while( iLength-- ) 
      {
        Serial.println( *aCharmap, HEX );
        write( *aCharmap );
        ++aCharmap;
      }
    }

     // Close I2C connection
    endUpdate();

    // switch back to character output mode
    //command(LCD_SETDDRAMADDR);
  }

  return bResult;
}

/*
 bool LiquidCrystal_pcf2119::setCustomChar( uint8_t iAddress, uint8_t* aCharmap, uint8_t iLength ) 
{
  bool bResult = (( iAddress < 8 ) && ( iLength > 0 )); 

  if( bResult )
  {
    //&& ( beginUpdate(0x40) ));
    //iAddress&= 0x7; // we only have 8 locations 0-7
    //bResult = beginUpdate() && command( LCD_SETCGRAMADDR | (iAddress << 3) );
    bResult = ( beginUpdate() && command( LCD_SETCGRAMADDR + iAddress ));

    if( bResult )
    {
      while( iLength-- ) 
      {
        Serial.println( *aCharmap, HEX );
        write( *aCharmap );
        ++aCharmap;
      }
    }

    endUpdate();
    // switch back to character output mode
    //command(LCD_SETDDRAMADDR);
  }



  return bResult;
}

 */
/*********** internal helper functions */

// Set character set (default=ASCII). Some charsets require remapping,
// see page 19ff in https://www.nxp.com/docs/en/data-sheet/PCF2119X.pdf

/* The PCF2119 comes in six versions with different character sets.
 * Unfortunatly, not all of them use a ASCII compatible encoding for
 * at least the latin alphabet. Some of them encode the latin characters
 * in the higher half of the codepage (bit 7 set).
 * One of them (charset R) even encodes the space character differently,
 * rendering the build in clear command pointless and requiring a manual
 * memory sweep to clear the display content.
 *
 * A: standard ASCII charset, similar to HD4480 controller
 * D: ASCII, but upper case only
 * F: non-ASCII. Bit 7 needs to be flipped.
 * I: ASCII
 * R: non-ASCII. Bit 7 needs to be flipped, even space is at 0xa0 instead of 0x20
 * S: non-ASCII. Bit 7 needs to be flipped.
 */
void LiquidCrystal_pcf2119::setCharset(char charset) 
{
    charset &= ~0x20;   // convert lower to uppper case
    if ((charset=='F') || (charset=='S'))
    {
        _charset = LCD_CHARSET_FLIP;
    }
    else if (charset=='R')
    {
        _charset = LCD_CHARSET_FLIP_SPACE;
    }
    else
    {
        _charset=LCD_CHARSET_ASCII;
    }
} 

bool LiquidCrystal_pcf2119::beginUpdate()
{
  if( _update == 0 )
   { 
     //Serial.println( "beginUpdate" );
     Wire.beginTransmission( _addr ); 
   }

  ++_update;

  return true;
}

bool LiquidCrystal_pcf2119::beginUpdate( uint8_t iCmd )
{
  beginUpdate();
  return write( iCmd );
}

bool LiquidCrystal_pcf2119::write( uint8_t iValue )
{
 return ( Wire.write( iValue ) > 0 );
}

bool LiquidCrystal_pcf2119::write( uint8_t iCmd, uint8_t iValue )
{
 beginUpdate();

 bool bResult = ( write( iCmd ) && write( iValue ) );
 if( !endUpdate())
  { bResult = false; }

 return bResult; 
}

bool LiquidCrystal_pcf2119::endUpdate()
{
  //Serial.println( _update );
  if( _update > 0 )
   { --_update; }  

  if( _update == 0 )
  { 
     //Serial.println( "endUpdate" );
     return ( Wire.endTransmission() == 0 ); 
  }

  return true;
}

bool LiquidCrystal_pcf2119::command(uint8_t value) 
{
    // write to command register
    return write( LCD_COMMAND, value );
}

// write a character. Do ASCII conversion if needed
bool LiquidCrystal_pcf2119::setChar(uint8_t value) 
{
    if( _charset != LCD_CHARSET_ASCII ) 
    {
        // do not convert values 0x00..0x1f/0x80..0x9f
        // this would mess up the user defined characters
        if ((value&0x7f) >= 32) {
            value ^= 0x80;
        }
    }

  if( _update > 0 )
   { return write(value); }

    return write( 0x40, value );
}

void LiquidCrystal_pcf2119::setChars(const char* value, uint8_t offset, bool bClrScr )
{
   beginUpdate( 0x40 );
   {
      while( *value && (offset < _cols) )
      {
        setChar( *value++ );
        offset++;
      }

      if( bClrScr )
      { 
       while( offset < _cols )
        { setChar( ' ' ); 
          offset++;
        }
      }
   }
   endUpdate();   
}

 // Default functions
bool LiquidCrystal_pcf2119::begin(uint8_t iWidth, uint8_t iHeight, uint8_t charsize )
{
  beginUpdate();
  {
    if( !setWidth( iWidth, true ) || !setHeight( iHeight, true ) )
    { 
       endUpdate();
       return false; 
    }
  }
  endUpdate();

  _charsize = charsize;
  return reset();
}

bool LiquidCrystal_pcf2119::reset()
{  
  // turn the display on with no cursor or blinking default
  _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;

  if (_rstPin != 0xFF)
  {
     // do a hardware reset if reset pin is defined
     pinMode(_rstPin, OUTPUT);
     digitalWrite(_rstPin, LOW);
     delay(10);
     digitalWrite(_rstPin, HIGH);
     delay(100);
     digitalWrite(_rstPin, LOW);

     delay(2000);

     beginUpdate();
     {
        if( !setWidth( _cols, true ) || !setHeight( _rows, true ) )
        { 
          endUpdate();
          return false; 
        }
     }
     endUpdate();
  }

  if( !enableDisplay() )
   { return false; }

  // clear the display
  if( !clear() )
   { return false; }

  // set the entry mode
  if( !command(LCD_ENTRYMODESET | _displaymode ))
   { return false; }

  home();
  return true;
}

void LiquidCrystal_pcf2119::print(const char* value)
{ 
  setChars(value);
}

void LiquidCrystal_pcf2119::print( uint8_t value )
{ 
  Serial.println( "Print uint8_t" );
  uint8_t ch[2] = {0,0};
  ch[0] = value; 
  setChars( &ch[0] );
}

Test sketch

#include <Wire.h>
#include "LiquidCrystal_pcf2119.h"

// LCD controller settings
#define LCD_ADDR    0x3C    // I2C address: 0x3A or 0x3B, dep. on pin SA0 state
#define LCD_RST     11     // reset pin (active high)
#define LCD_CHARSET 'A'     // character set (A, D, F, I, R or S)

// Set LCD address and reset pin
LiquidCrystal_pcf2119 lcd(LCD_ADDR, LCD_RST, LCD_CHARSET);

uint8_t eurosign[] = {
  0x06,
  0x09,
  0x08,
  0x1E,
  0x1E,
  0x08,
  0x09,
  0x06
};


void setup()
{
 Serial.begin(9600);
 while( !Serial );

 Wire.setClock( 200000UL ); // 200Mhz is max, higher don't work
 Wire.begin();

  // initialize the LCD (16x2 display)
 lcd.begin(16,2);

 if( !lcd.setCustomChar( LCD_CUSTOM_CHAR2, &eurosign[0], sizeof( eurosign ) ))
  { Serial.println( "Creating custom char failed!" ); }


  // Print a message.
 lcd.enableCursor();
 lcd.enableCursorBlink();
 lcd.disableBacklight();
 lcd.clear();
 delay( 1000 );
 lcd.print( (uint8_t)LCD_CUSTOM_CHAR2 );
 delay( 5000 );
 lcd.enableBacklight();
}

void loop()
{
 lcd.clear();

 //lcd.print("Hello world!");
 lcd.print("Hello... dudes!");

 for( uint8_t y=0; y< lcd.getHeight(); y++ ) 
  for( uint8_t x=0; x< lcd.getWidth(); x++ )
  {
    Serial.print( "Set Cursor at: "); 
    Serial.print( x );
    Serial.print( " " );
    Serial.println( y );


    if( !lcd.setCursorPos(x,y) )
     { Serial.println( "Cannot set cursor!" ); }
    delay( 300 ); 
  }

 //lcd.home();

 delay( 2000 );
 Serial.println( "Print new value" );
 lcd.setCursorPos(0,1);
 lcd.print("Hello world!");
 lcd.setCursorPos(0,0);
 Serial.println( "new value printed" );
 uint8_t i = lcd.getWidth();
 delay( 2000 );
 lcd.scrollDisplayRight( lcd.getWidth(), 200 );
 lcd.scrollDisplayLeft( lcd.getWidth()+1 );
 delay( 2000 );
 lcd.disableDisplay();
 delay( 2000 );
 lcd.enableDisplay();
 delay( 1000 );

}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.