NHD-0216KZW-AG5 Font Tables in 4-bit Mode

Comments

5 comments

  • Michael_L

    Can you send the part of your code that is changing the font table?

    0
  • cody

    Sorry for the late reply, here is the C++ class that I'm using.

    I gave up trying to get the font table to change, and instead used custom characters. However, I ran into a small issue there as well. I was unable program use the first custom character (character 0x00). I just shifted to using characters 0x01 to 0x03 and it worked fine.

    Code: (c++)

    /*
    The MIT License (MIT)

    Copyright (c) 2014 Cody Browne

    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.
    */
    #ifndef _LCD_HPP_
    #define _LCD_HPP_

    #include <stdint.h>

    template< class HW >
    class LCD {
    public:
    static const uint16_t WIDTH = 16;
    static const uint16_t CHARHEIGHT = 8;
    private:
    enum {
    CMD_CLEAR_DISPLAY = 0x01
    , CMD_RETURN_HOME = 0x02
    , CMD_SET_ENTRY_MODE = 0x04
    , CMD_SET_DISPLAY = 0x08
    , CMD_SET_SHIFT = 0x10
    , CMD_SET_FUNCTION = 0x28
    , CMD_SET_CGRAM_ADDRESS = 0x40
    , CMD_SET_DDRAM_ADDRESS = 0x80
    , ENTRY_MODE_INCREMENT = 0x02
    , ENTRY_MODE_DECREMENT = 0x00
    , ENTRY_MODE_SHIFT = 0x01
    , ENTRY_MODE_DONTSHIFT = 0x00
    , DISPLAY_ON = 0x04
    , DISPLAY_OFF = 0x00
    , DISPLAY_CURSOR_ON = 0x02
    , DISPLAY_CURSOR_OFF = 0x00
    , DISPLAY_CURSOR_BLINK = 0x01
    , DISPLAY_CURSOR_SOLID = 0x00
    , SHIFT_DISPLAY = 0x08
    , SHIFT_CURSOR = 0x00
    , SHIFT_LEFT = 0x00
    , SHIFT_RIGHT = 0x04
    , FUNCTION_FT_ENGLISH_JAPANESE = 0x00
    , FUNCTION_FT_WESTERN_EUROPE_1 = 0x01
    , FUNCTION_FT_ENGLISH_RUSSIAN = 0x02
    , FUNCTION_FT_WESTERN_EUROPE_2 = 0x03
    , FUNCTION_DL_8BIT = 0x10
    , FUNCTION_DL_4BIT = 0x00
    , DDRAM_LINE2 = 0x40
    };

    static uint8_t _displayMode;

    static void _probe( void );
    static void _write( uint8_t data );
    public:
    static void Init( void );
    static void Clear( void );
    static void On( void );
    static void Off( void );
    static void GoL1( void );
    static void GoL2( void );
    static void Puts( const uint8_t* str );
    static void PutAll( const uint8_t* line1 , const uint8_t* line2 );
    static void Putc( uint8_t c );
    static void SetCursor( bool ison , bool isblinking = true );
    static void MakeCharacter( uint8_t value , const uint8_t* data , uint16_t data_lenght );
    };
    template< class HW>
    uint8_t LCD< HW >::_displayMode;

    template< class HW >
    void LCD< HW >::PutAll( const uint8_t* line1 , const uint8_t* line2 ){
    GoL1();
    Puts( line1 );
    GoL2();
    Puts( line2 );
    }
    template< class HW >
    void LCD< HW >::_probe( void ){
    HW::template E<true>();
    HW::template E<false>();
    }
    template< class HW >
    void LCD< HW >::_write( uint8_t data ){
    HW::SetNibble( data >> 4 );
    _probe();
    HW::SetNibble( data );
    _probe();
    }
    template< class HW >
    void LCD< HW >::Init( void ){
    HW::Init();

    // Start in command mode.
    HW::template RS<false>();
    HW::template RW<false>();

    // Wake the LCD up in 8-bit mode.
    HW::SetNibble( 0x3 );
    _probe();
    HW::Delay_ms( 100 );

    // Wake the LCD up again in 8-bit mode.
    HW::SetNibble( 0x3 );
    _probe();
    HW::Delay_ms( 10 );

    // Set 4-bit mode.
    HW::SetNibble( 0x2 );
    _probe();
    HW::Delay_ms( 10 );

    // Set 4-bit mode with font table.
    //FUNCTION_FT_ENGLISH_JAPANESE
    //FUNCTION_FT_WESTERN_EUROPE_2
    _write(
    CMD_SET_FUNCTION
    | FUNCTION_DL_4BIT
    | FUNCTION_FT_ENGLISH_JAPANESE
    );
    HW::Delay_ms( 10 );

    // Turn of display and cursor
    _displayMode =
    CMD_SET_DISPLAY
    | DISPLAY_OFF
    ;
    _write( _displayMode );
    HW::Delay_ms( 1 );

    // Set incrementing address without shifting the display.
    _write(
    CMD_SET_ENTRY_MODE
    | ENTRY_MODE_INCREMENT
    | ENTRY_MODE_DONTSHIFT
    );
    HW::Delay_ms( 1 );
    }
    template< class HW >
    void LCD< HW >::MakeCharacter( uint8_t value , const uint8_t* data , uint16_t data_length ){
    _write( 0x40 | ( value << 3 ) );
    HW::Delay_ms( 1 );
    HW::template RS<true>();
    uint16_t i;
    for( i = 0; i < data_length; ++i ){
    _write( data[ i ] );
    HW::Delay_ms( 1 );
    }
    while( i < CHARHEIGHT ){
    _write( 0x00 );
    HW::Delay_ms( 1 );
    ++i;
    }
    HW::template RS<false>();
    _write( 0x80 );
    HW::Delay_ms( 1 );
    }
    template< class HW >
    void LCD< HW >::Puts( const uint8_t* str ){
    // Set LCD control lines to write character data.
    HW::template RS<true>();
    HW::template RW<false>();

    // Write the string out, limiting the maximum size of the string.
    for( uint16_t i = 0; i < WIDTH; ++i ){
    if( *str == '\0' ){
    // Null termination reached.
    break;
    }
    Putc( *str );
    ++str;
    }
    }
    template< class HW >
    void LCD< HW >::On( void ){
    _displayMode |= DISPLAY_ON;
    HW::template RS<false>();
    HW::template RW<false>();
    _write( _displayMode );
    HW::Delay_ms( 1 );
    }
    template< class HW >
    void LCD< HW >::Off( void ){
    _displayMode &= ~DISPLAY_ON;
    HW::template RS<false>();
    HW::template RW<false>();
    _write( _displayMode );
    HW::Delay_ms( 1 );
    }
    template< class HW >
    void LCD< HW >::SetCursor( bool ison , bool isblinking ){
    if( ison ){
    _displayMode |= DISPLAY_CURSOR_ON;
    if( isblinking ){
    _displayMode |= DISPLAY_CURSOR_BLINK;
    }
    else {
    _displayMode &= ~DISPLAY_CURSOR_BLINK;
    }
    }
    else {
    _displayMode &= ~ DISPLAY_CURSOR_ON;
    }
    HW::template RS<false>();
    HW::template RW<false>();
    _write( _displayMode );
    HW::Delay_ms( 1 );
    }
    template< class HW >
    void LCD< HW >::Clear( void ){
    HW::template RS<false>();
    HW::template RW<false>();
    _write( CMD_CLEAR_DISPLAY );
    HW::Delay_ms( 3 );
    }
    template< class HW >
    void LCD< HW >::GoL1( void ){
    HW::template RS<false>();
    HW::template RW<false>();
    _write( CMD_SET_DDRAM_ADDRESS );
    HW::Delay_ms( 1 );
    }
    template< class HW >
    void LCD< HW >::GoL2( void ){
    HW::template RS<false>();
    HW::template RW<false>();
    _write( CMD_SET_DDRAM_ADDRESS | DDRAM_LINE2 );
    HW::Delay_ms( 1 );
    }
    template< class HW >
    void LCD< HW >::Putc( uint8_t c ){
    HW::template RS<true>();
    HW::template RW<false>();
    _write( c );
    HW::Delay_ms( 1 );
    }
    #endif /* _LCD_HPP_ */

     

     

    0
  • Michael_L

    I have successfully modified my code to select that font table you are trying to use in 4-bit mode and have shared it below:

    //---------------------------------------------------------
    /*
    NHD_0216KZW_uno4bit.ino
    Program for writing to Newhaven Display 2 x 16 Character OLED (4-bit, 6800 mode)

    (c)2014 Mike LaVine - Newhaven Display International, LLC.

            This program is free software; you can redistribute it and/or modify
            it under the terms of the GNU General Public License as published by
            the Free Software Foundation; either version 2 of the License, or
            (at your option) any later version.

            This program is distributed in the hope that it will be useful,
            but WITHOUT ANY WARRANTY; without even the implied warranty of
            MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
            GNU General Public License for more details.
    */
    //---------------------------------------------------------

    // The 4 bit data bus is connected to PORTD[3..0] of the Arduino Uno

    int RS =  9;    // RS signal connected to digital pin 9 of Arduino Uno
    int RW =  10;    // R/W signal connected to digital pin 10 of Arduino Uno
    int  E =  11;    // E signal connected to digital pin 11 of Arduino Uno

    const char text1[] = {"Newhaven Display"};
    const char text2[] = {" 2x16 Char OLED "};

    void toggle()
    {
       digitalWrite(E, HIGH);
       delay(1);
       digitalWrite(E, LOW);
    }

    void command(char c)

       PORTD = (c>>4);
       digitalWrite(RS, LOW);
       toggle();
       PORTD = c;
       toggle();
    }

    void data(char d)
    {
       PORTD = (d>>4);
       digitalWrite(RS, HIGH);
       toggle();
       PORTD = d;
       toggle();
    }

    void disp()
    {
       int i;
       delay(50);
       command(0x02);  //Home Command  [Set DDRAM address to Line 1 position 1]
       delay(5);
       for (i=0;i<20;i++)
       {
          data(text1[i]);
       }
       command(0xC0);  //Second Line  [Set DDRAM address to Line 2 position 1]
       for (i=0;i<20;i++)
       {
          //data(text2[i]);
          data(0xF0+i);  //to prove western european table 2 is selected
       }
    }

    void writeCGRAM()
    {
       command(0x40);    //first CGRAM position
       data(0x00);
       data(0x00);
       data(0x0F);
       data(0x14);
       data(0x14);
       data(0x14);
       data(0x14);
       data(0x0F);
    }

    void setup()         //runs first at power on
    {
       DDRD = 0xFF;    //set PORTD (data bus) as output
       PORTD = 0x00;   //initialize PORTD to 0x00
       DDRB = 0xFF;    //set PORTB (control lines) as output
       PORTB = 0x00;   //initialize PORTB to 0x00
       
       /////////////////////Initialization Start///////////////////////
       PORTD = 0x2;        //extra leading nibble for 4-bit mode
       toggle();
       command(0x2B);      //4-bit mode, western european table 2
       command(0x08);      //display OFF
       command(0x01);      //clear display
       delay(5);
       command(0x06);      //entry mode set
       command(0x02);      //return home
       command(0x0C);      //display ON
       delay(10);
       //////////////////////Initialization End////////////////////////
    }

    void loop()         //main loop

      disp();
      delay(2000);    //2 seconds delay
      command(0x01);  //clear display
      delay(5);       //5 milliseconds delay
      writeCGRAM();   //write custom character to CGRAM (sideways 'A')
      command(0x02);  //Home Command  [Set DDRAM address to Line 1 position 1]
      data(0x00);     //display custom char at CGRAM location 0x00 (sideways 'A')
      delay(3000);    //3 seconds delay
    }
    0
  • Michael_L
    I've also successfully wrote a custom sideways 'A' to the CGRAM's first location 0x00.

    Please also take special note of the extra leading nibble in the initialization, as you will see undesirable results on the display if this is not present.
    0
  • cody

    Thank you, I'll work though your code as soon as I get a chance.

    0

Please sign in to leave a comment.