NHD-0216AW-IB3 - User Defined Characters - HOW?

Comments

6 comments

  • Sergio_M

    Hi Martin,

    Please have a look at page 28 of the datasheet.
    User defined characters can be loaded via 512 bits (8 characters) Character Generator RAM (CGRAM).

    Spec: https://newhavendisplay.com/content/app_notes/US2066.pdf 

    You will need to call the Set CGRAM adress command, also please see  the command description listed on page 39.

    Below please find some reference example code.

    //------------------------------------------------------------------------------------------------
    // HS_US2066 OLED Library
    // Copyright (c) 2014, 2015, 2016, 2017 by Haute Solutions / Ed Van Every (www.haute-solutions.com)
    //
    // FUNCTION: This Library is intended to control the Newhaven Display Slim OLEDs based on US2066 controller
    //
    // - Supports I2C Interface Mode Only
    // - Autodetects/configures for both Arduino and Mega I2C Pinouts
    // - Supports flexible address, row and column geometry via class construction intitialization
    // - Modified from original example code created by Newhaven Display International Inc
    //
    // LICENSE:  This library 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 3 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.
    //           <http://www.gnu.org/licenses/>.
    //
    //------------------------------------------------------------------------------------------------

    #define HS_US2066_LIBVER "1.0"

    #include <Arduino.h>
    #include <Wire.h>

    #include "HS_US2066.h"

    OLED::OLED(char address=0x3C, int rows=2, int cols=16) {
    _Address = address;
    _Rows = rows;
    _Cols = cols;
    }

    void OLED::Display( int Center, char *Line1, char *Line2, char *Line3, char *Line4) {

    //  Center:       0 = No (Left Justify and pad as necessary)
    //                1 = Yes (and pad left/right as necessary)
    //
    //  Line1-4:      "String" = Will display string (truncated/padded/centered as necessary)
    //                ""       = Will effectively clear the line
    //                {NULL}   = Will ignore the line and leave existing info intact
    //

      if(Line1) DisplayLine(1, Line1, Center);
      if(Line2) DisplayLine(2, Line2, Center);
      if(Line3) DisplayLine(3, Line3, Center);
      if(Line4) DisplayLine(4, Line4, Center);
    }

    void OLED::DisplayLine(int Line, char *Text, int Center) {
    //  Line:         = Line Number to Display (1-4 as supported)
    //
    //  Text:         "String" = Will display string (truncated/padded/centered as necessary)
    //                ""       = Will effectively clear the line
    //                {NULL}   = Will ignore the line and leave existing info intact
    //
    //  Center:       0 = No (Left Justify and pad as necessary)
    //                1 = Yes (and pad left/right as necessary)
    int i;
    int len;
    int char_offset;
    char temp[21];
    char line_offset[4]={0x80, 0xA0, 0xC0, 0xE0};

      if(Line<1 || Line>_Rows) return;
      if(Text == NULL) return;
     
      Command(line_offset[Line-1]);

      len=strlen(Text);
      if(len == 0) {
        for(i=0; i<_Cols; i++) temp[i]=' ';
      } else if(len > _Cols) {
        strncpy(temp,Text,_Cols);
      } else {
        if(Center) {
          char_offset=(_Cols-len)/2;
    //    if(len%2) char_offset++;
          for(i=0; i<char_offset; i++) temp[i]=' ';
          strcpy(temp+char_offset,Text);
          for(i=len+char_offset; i<_Cols; i++) temp[i]=' ';   
        } else {
          strcpy(temp,Text);
          for(i=len; i<_Cols; i++) temp[i]=' ';
        }
      }
      temp[_Cols]='\0';
     
      for(i=0; i<_Cols; i++) Data(temp[i]);
    }

    void OLED::DisplayChar(int Row, int Col, char C) {
    char offset;

      if(Row<1 || Row>_Rows) return;
      if(Col<1 || Col>_Cols) return;
      
      offset=(0x80 + ((Row-1)*0x20) + (Col-1));
      Command(offset);
     
      Data(C);
    }

    void OLED::Clear() {
      Command(0x01);
      delay(2); 
    }

    void OLED::Init() {
      pinMode(ASCL, OUTPUT);      //set Arduino I2C lines as outputs
      pinMode(ASDA, OUTPUT);      //
      digitalWrite(ASCL, LOW);    //
      digitalWrite(ASDA, LOW);    //
      pinMode(SCLK, OUTPUT);
      pinMode(SDIN, OUTPUT);
      pinMode(SDOUT, INPUT);
      digitalWrite(SCLK, HIGH);
      digitalWrite(SDIN, HIGH);
      delay(10);
      Wire.begin();
      delay(10);
      Command(0x2A);  //function set (extended command set)
      Command(0x71);  //function selection A, disable internal Vdd regualtor
      Data(0x00);
      Command(0x28);  //function set (fundamental command set)
      Command(0x08);  //display off, cursor off, blink off
      Command(0x2A);  //function set (extended command set)
      Command(0x79);  //OLED command set enabled
      Command(0xD5);  //set display clock divide ratio/oscillator frequency
      Command(0x70);  //set display clock divide ratio/oscillator frequency
      Command(0x78);  //OLED command set disabled
      Command(0x09);  //extended function set (4-lines)
      Command(0x06);  //COM SEG direction
      Command(0x72);  //function selection B, disable internal Vdd regualtor
      Data(0x00);     //ROM CGRAM selection
      Command(0x2A);  //function set (extended command set)
      Command(0x79);  //OLED command set enabled
      Command(0xDA);  //set SEG pins hardware configuration
      Command(0x10);  //set SEG pins ... NOTE: When using NHD-0216AW-XB3 or NHD_0216MW_XB3 change to (0x00)
      Command(0xDC);  //function selection C
      Command(0x00);  //function selection C
      Command(0x81);  //set contrast control
      Command(0x7F);  //set contrast control
      Command(0xD9);  //set phase length
      Command(0xF1);  //set phase length
      Command(0xDB);  //set VCOMH deselect level
      Command(0x40);  //set VCOMH deselect level
      Command(0x78);  //OLED command set disabled
      Command(0x28);  //function set (fundamental command set)
      Command(0x01);  //clear display
      Command(0x80);  //set DDRAM address to 0x00
      Command(0x0C);  //display ON
      delay(100);
    }

    void OLED::Command(unsigned char c) {
      _Packet[0] = 0x00;
      _Packet[1] = c;
      SendPacket(2);
    }

    void OLED::Data(unsigned char d) {
       _Packet[0] = 0x40;
       _Packet[1] = d;
       SendPacket(2);
    }

    void OLED::SendPacket(unsigned char x) {
    unsigned char i;
     
      Wire.beginTransmission(_Address);
      for(i=0; i<x; i++) Wire.write(_Packet[i]);
      Wire.endTransmission();
    }


    Hope this helps!

    0
  • mprowe

    No! Not in any way!

    The code you offer is from the Arduinio library and that only offers VERY limited functions.
    The reference URL given is equally void of any high-level strategy on programming user defined characters. 

    Sorry but the display is going back in the "interesting but useless" bin.

    Regards, Martin

    0
  • Sergio_M

    Hello,

    I'm sorry the previous example was not helpful.
    We have made some example code that has been verified to work.
    It was tested with our Slim CW series OLED and it should work with the AW-IB3 modular OLED since both series use the same controller US2066.
    It should give the user a good idea on how to program custom characters.

    /*****************************************************************************
     *
    / Program for writing to Newhaven Display's 2x16 Character OLED with the US2066 Controller.
    / This code is written for the Arduino Uno R3 using 4-bit Parallel Interface
    /
    / Newhaven Display invests time and resources providing this open source code.
    / Please support Newhaven Display by purchasing products from Newhaven Display!

    * Copyright (c) 2019, Newhaven Display International
    *
    * This code is provided as an example only and is not guaranteed by Newhaven Display.
    * Newhaven Display accepts no responsibility for any issues resulting from its use.
    * The developer of the final application incorporating any parts of this
    * sample code is responsible for ensuring its safe and correct operation
    * and for any consequences resulting from its use.
    *
    *****************************************************************************/


    /******** INITIAL DEFINITIONS***************/

    #define E_Pin 10
    #define R_W    9
    #define R_S    8
    #define C_S    11
    #define RES    12

    /************************ CHAR STRING**********/

    char const text1[] = ("NEWHAVEN DISPLAY");

    /************ Functions************/
    void latch(){                           // command to latch E
      digitalWrite(E_Pin, HIGH);            // Latch
      delay(1);
      digitalWrite(E_Pin, LOW);
      delay(1);
    }

    void command(char i){
      PORTD = i;
      digitalWrite(R_S, LOW);               // Command
      digitalWrite(R_W, LOW);               // Write
      latch();                              // take 1st 4 bits
      i = i<<4;
      PORTD = i;
      latch();                              // take 2nd 4 bits
    }

    void data(char i){
      PORTD = i;
      digitalWrite(R_S, HIGH);              // Data
      digitalWrite(R_W, LOW);               // Write
      latch();                              // take 1st 4 bits
      i = i<<4;
      PORTD = i;
      latch();                              // take 2nd 4 bits
    }


    /***********INITIALIZE DISPLAY************************/

    void init1(){
    digitalWrite(E_Pin, LOW);                                                   //Needed so latch function can work properly.
     delay(100);                            //Wait >15 msec after power is applied
    command(0x2A);  //function set (extended command set)     
      command(0x71);  //function selection A
      data(0x00);  //disable internal Vdd regualtor
      command(0x2C);  //function set (fundamental command set)
      command(0x08);  //display off, cursor off, blink off
      command(0x2A);  //function set (extended command set)
      command(0x79);  //OLED command set enabled
      command(0xD5);  //set display clock divide ratio/oscillator frequency
      command(0x70);  //set display clock divide ratio/oscillator frequency
      command(0x78);  //OLED command set disabled 
      command(0x08);  //extended function set (2-lines)
      command(0x06);  //COM SEG direction
      command(0x72);  //function selection B, disable internal Vdd regualtor
      data(0x00);     //ROM CGRAM selection
      command(0x2A);  //function set (extended command set)
      command(0x79);  //OLED command set enabled
      command(0xDA);  //set SEG pins hardware configuration
      command(0x10);  //set SEG pins hardware configuration //////////////0x10 on other slim char OLEDs
      command(0xDC);  //function selection C
      command(0x00);  //function selection C
      command(0x81);  //set contrast control
      command(0x4F);  //set contrast control         //CHANGED FROM 0x7F
      command(0xD9);  //set phase length
      command(0xF1);  //set phase length
      command(0xDB);  //set VCOMH deselect level
      command(0x40);  //set VCOMH deselect level
      command(0x78);  //OLED command set disabled
      command(0x28);  //function set (fundamental command set)
      command(0x01);  //clear display
      command(0x80);  //set DDRAM address to 0x00           
      command(0x0C);  //display ON
      delay(100);
     
    }


    void clear_screen(){                    // clear display
     command(0x01);
    }
    void ret_home(){                        // Return to home position
     command(0x02);
    }

    void disp(){                            // DISPLAY TEXT
      clear_screen();
      ret_home();
      for( int i = 0; i<16; i++){ //40 for whole section
        data(text1[i]);
      }
      command(0xC0);
      for (int i = 0; i<16; i++){ //40 for whole section
        data(text1[i]);
      }
    }

    void Store_Custom_Characters(){
      command(0x40);            //CGRAM ADDRESS 1: Slot 1
      data(0x00);
      command(0x41);            //CGRAM ADDRESS 1: Slot 2
      data(0x00);
      command(0x42);            //CGRAM ADDRESS 1: Slot 3
      data(0x00);
      command(0x43);            //CGRAM ADDRESS 1: Slot 4
      data(0x00);
      command(0x44);            //CGRAM ADDRESS 1: Slot 5
      data(0x00);
      command(0x45);            //CGRAM ADDRESS 1: Slot 6
      data(0x00);
      command(0x46);            //CGRAM ADDRESS 1: Slot 7
      data(0x00);
      command(0x47);            //CGRAM ADDRESS 1: Slot 8
      data(0x0F);

      command(0x48);            //CGRAM ADDRESS 2: Slot 1
      data(0x00);
      command(0x49);            //CGRAM ADDRESS 2: Slot 2
      data(0x00);
      command(0x4A);            //CGRAM ADDRESS 2: Slot 3
      data(0x00);
      command(0x4B);            //CGRAM ADDRESS 2: Slot 4
      data(0x00);
      command(0x4C);            //CGRAM ADDRESS 2: Slot 5
      data(0x00);
      command(0x4D);            //CGRAM ADDRESS 2: Slot 6
      data(0x00);
      command(0x4E);            //CGRAM ADDRESS 2: Slot 7
      data(0x0F);
      command(0x4F);            //CGRAM ADDRESS 2: Slot 8
      data(0x0F);

      command(0x50);            //CGRAM ADDRESS 3: Slot 1
      data(0x00);
      command(0x51);            //CGRAM ADDRESS 3: Slot 2
      data(0x00);
      command(0x52);            //CGRAM ADDRESS 3: Slot 3
      data(0x00);
      command(0x53);            //CGRAM ADDRESS 3: Slot 4
      data(0x00);
      command(0x54);            //CGRAM ADDRESS 3: Slot 5
      data(0x00);
      command(0x55);            //CGRAM ADDRESS 3: Slot 6
      data(0x0F);
      command(0x56);            //CGRAM ADDRESS 3: Slot 7
      data(0x0F);
      command(0x57);            //CGRAM ADDRESS 3: Slot 8
      data(0x0F);

      command(0x58);            //CGRAM ADDRESS 4: Slot 1
      data(0x00);
      command(0x59);            //CGRAM ADDRESS 4: Slot 2
      data(0x00);
      command(0x5A);            //CGRAM ADDRESS 4: Slot 3
      data(0x00);
      command(0x5B);            //CGRAM ADDRESS 4: Slot 4
      data(0x00);
      command(0x5C);            //CGRAM ADDRESS 4: Slot 5
      data(0x0F);
      command(0x5D);            //CGRAM ADDRESS 4: Slot 6
      data(0x0F);
      command(0x5E);            //CGRAM ADDRESS 4: Slot 7
      data(0x0F);
      command(0x5F);            //CGRAM ADDRESS 4: Slot 8
      data(0x0F);

      command(0x60);            //CGRAM ADDRESS 5: Slot 1
      data(0x00);
      command(0x61);            //CGRAM ADDRESS 5: Slot 2
      data(0x00);
      command(0x62);            //CGRAM ADDRESS 5: Slot 3
      data(0x00);
      command(0x63);            //CGRAM ADDRESS 5: Slot 4
      data(0x0F);
      command(0x64);            //CGRAM ADDRESS 5: Slot 5
      data(0x0F);
      command(0x65);            //CGRAM ADDRESS 5: Slot 6
      data(0x0F);
      command(0x66);            //CGRAM ADDRESS 5: Slot 7
      data(0x0F);
      command(0x67);            //CGRAM ADDRESS 5: Slot 8
      data(0x0F);

      command(0x68);            //CGRAM ADDRESS 6: Slot 1
      data(0x00);
      command(0x69);            //CGRAM ADDRESS 6: Slot 2
      data(0x00);
      command(0x6A);            //CGRAM ADDRESS 6: Slot 3
      data(0x0F);
      command(0x6B);            //CGRAM ADDRESS 6: Slot 4
      data(0x0F);
      command(0x6C);            //CGRAM ADDRESS 6: Slot 5
      data(0x0F);
      command(0x6D);            //CGRAM ADDRESS 6: Slot 6
      data(0x0F);
      command(0x6E);            //CGRAM ADDRESS 6: Slot 7
      data(0x0F);
      command(0x6F);            //CGRAM ADDRESS 6: Slot 8
      data(0x0F);

      command(0x70);            //CGRAM ADDRESS 7: Slot 1
      data(0x00);
      command(0x71);            //CGRAM ADDRESS 7: Slot 2
      data(0x0F);
      command(0x72);            //CGRAM ADDRESS 7: Slot 3
      data(0x0F);
      command(0x73);            //CGRAM ADDRESS 7: Slot 4
      data(0x0F);
      command(0x74);            //CGRAM ADDRESS 7: Slot 5
      data(0x0F);
      command(0x75);            //CGRAM ADDRESS 7: Slot 6
      data(0x0F);
      command(0x76);            //CGRAM ADDRESS 7: Slot 7
      data(0x0F);
      command(0x77);            //CGRAM ADDRESS 7: Slot 8
      data(0x0F);

      command(0x78);            //CGRAM ADDRESS 8: Slot 1
      data(0x0F);
      command(0x79);            //CGRAM ADDRESS 8: Slot 2
      data(0x0F);
      command(0x7A);            //CGRAM ADDRESS 8: Slot 3
      data(0x0F);
      command(0x7B);            //CGRAM ADDRESS 8: Slot 4
      data(0x0F);
      command(0x7C);            //CGRAM ADDRESS 8: Slot 5
      data(0x0F);
      command(0x7D);            //CGRAM ADDRESS 8: Slot 6
      data(0x0F);
      command(0x7E);            //CGRAM ADDRESS 8: Slot 7
      data(0x0F);
      command(0x7F);            //CGRAM ADDRESS 8: Slot 8
      data(0x0F);
    }

    void Show_Custom_Characters(){
      ret_home();
      delay(2);
      data(0x00); //CGRAM ADDRESS 1
      data(0x01); //CGRAM ADDRESS 2
      data(0x02); //CGRAM ADDRESS 3
      data(0x03); //CGRAM ADDRESS 4
      data(0x04); //CGRAM ADDRESS 5
      data(0x05); //CGRAM ADDRESS 6
      data(0x06); //CGRAM ADDRESS 7
      data(0x07); //CGRAM ADDRESS 8
    }

    void disp2(){                            // DISPLAY TEXT
      clear_screen();
      ret_home();
      for( int i = 0; i<16; i++){
        data(text1[i]);
      }
      command(0xC0);
      for (int i = 0; i<16; i++){
        data(text1[i]);
      }
    }

    void setup(){
     
      DDRD = 0xFF; // First 8 pins of PORT D as output
      DDRB = 0x1F; // Port B first 5 pins as output
      digitalWrite(C_S, LOW);               
      digitalWrite(RES, HIGH);             
      init1();
      delay(500);
      Store_Custom_Characters();
      Show_Custom_Characters();
    }

     void loop() {
     
    }
    Thank you.

    « Last Edit: April 08, 2020, 05:06:52 PM by Alee_S »
    0
  • mprowe

    Thank you Sergio,

    Firstly, my NHD_0216AW_x3B is an I2C device, so to try and get your code to work, I had to cut-out the bit-bashing and use the provided Arduino Library.


    Starting with just setup() function, this what I have paired it down to:

    void setup()
    {
      Serial.begin(115200);
    /***************************************    This section is not relevent - The _3XB is an I2C device
      DDRD = 0xFF; // First 8 pins of PORT D as output
      DDRB = 0x1F; // Port B first 5 pins as output
      digitalWrite(C_S, LOW);               
      digitalWrite(RES, HIGH); 
    */
      init1();                //This does NOT clear screen?
      //init_oled();          //This DOES! From #include "NHD_US2066.h"
      //delay(500);
      //Store_Custom_Characters();
      //Show_Custom_Characters();
      Serial << "I've done SETUP now" << endl;
      while (1);
    }

    Fallen at the first step! The init1() function you have provided does not match the published oled_init().
    Before wasting any more time, what else does it not do? Which should I use?

    I really am trying, but soon I'll solder in it into a project an move on.

    Regards, Martin

    0
  • mprowe

    Thank you Sergio,

    Got it at last!

    One more moan! Can you do something about your CAPTCHA - I can't read or hear it.
    I know it has a function, but it must be the worst example I have seen?

    0
  • Ted M.
    NHD Staff
    Hi mprowe,

    Thanks for the feedback.
    Our Web design team is looking into the CAPTCHA function to see if we can improve it's use.

    Best Regards,
    0

Please sign in to leave a comment.