Author Topic: Interfacing NHD-0420CW-AY3 to PIC controller via I2C  (Read 561 times)

cbrun17

  • Newbie
  • *
  • Posts: 2
  • Karma: 0
    • View Profile
Interfacing NHD-0420CW-AY3 to PIC controller via I2C
« on: May 04, 2017, 10:43:51 AM »
I am trying to write a library for use in MikroC environment and I have to say the datasheet for the NHD-0420CW-AY3 is the most confusing. I'm sure this is due to my limited experience with these type of displays but unfortunately the example provided in the datasheet is not very helpful to me.

One example of difficulty is creating a function for contrast.

Here is my code:
Code: [Select]
void LCD_Contrast(short level)
{
        if (level < 1 || level > 255) level = 127;  //default to 127 if out of range
        I2C1_Start();
        I2C1_Wr(_I2C_ADDRESS);
        // ***Do I need to enter the function level here first? i.e. extended command set.***
        I2C1_Wr(0x81);
        I2C1_Wr(0x28);
        I2C1_Wr(level);
        Delay_us(500);
        I2C1_Stop();
        Delay_ms(5);
}
The question here is, do I also need to define the function level command prior to defining the contrast control?

Also, I am unable to figure out how to specify row/column for writing data. This is the big issue for me!!
The code I typically use to output string information to a I2C LCD is:

//************************Define display position*************************************
Code: [Select]
void LCD_Set_Pos(short line, short col)
{
        short ln;
 
      //default to line 1 if value passed is out of range

      if (line < 1 || line > 4) line = 1;

      //default to column 0  if value passed is out of range

      if (col < 1 || col > _LCD_WIDTH ) col = 0;

        I2C1_Start();
        I2C1_Wr(_I2C_ADDRESS);
        I2C1_Wr(0x45); //Set cursor
        switch (line)
        {
                case 1:
                    ln = 0x80;
                    break;
                case 2:
                    ln = 0xA0;
                     break;
                case 3:
                    ln = 0xC0;
                    break;
                case 4:
                    ln = 0xE0;
                                       
        }
        I2C1_Wr(ln + (col-1));
        Delay_us(100);
        I2C1_Stop();
}


//************************StringSize definition*************************************
Code: [Select]
unsigned int StringSize(char* InString)
{
    unsigned int StrSize;
    char StrByte;
   
    StrSize = 0;
    StrByte = InString[StrSize];
    while( StrByte != '\0' )
    {
        StrSize++;
        StrByte = InString[StrSize];

    }
    return StrSize;

}

Then
// *************Passing standard text to display**************************************
Code: [Select]
void LCD_Line_Out(short line, short col, char* info)
{
    short size;
    short ccount;
    //default to line 1 if value passed is out of range
    if (line < 1 || line > 4) line = 1;
    //default to column 1  if value passed is out of range
    if (col < 1 || col > _LCD_WIDTH ) col = 0;
    size =  StringSize(info);
    LCD_Set_Pos(line, col);
    for (ccount = 0; ccount < size; ccount++)
        LCD_Chr_Out_CP(info[ccount]);       
}

Most of the struggle I have is understanding the relationship of some of the commands such as "set SEG pins hardware configuration" and "Entry Mode".

I know these are a lot of questions but I hope someone can provide some direction for me.

Thank you in advance.

Chris

Saurabh_B

  • Administrator
  • Hero Member
  • *****
  • Posts: 341
  • Karma: 10
    • View Profile
Re: Interfacing NHD-0420CW-AY3 to PIC controller via I2C
« Reply #1 on: May 05, 2017, 09:31:01 AM »
Hello,

This OLED display does have a rather lengthy command input process. Unfortunately it is one of the few available controllers for OLED displays of this type. I can help guide you to get the display working.

I will be referring to the controller datasheet as well, this can be found here: http://www.newhavendisplay.com/app_notes/US2066.pdf

In your examples below, I don't see you sending the control byte after sending the I2C address. (Page 11, controller datasheet)
After sending the I2C address, you would need to send the Control Byte, this will let the display know that the following incoming information is either Data or a Command. The Control Byte will also be needed between each byte of data.

For the contrast setting, you would first need to activate the RE Flag, then the SD flag.
For this you would send the function SET command (0x2A), then the OLED Characterization command (0x79), this will allow you to modify the contrast.

For the set cursor command I am not sure what the 0x45 is, however you would need to send the Set DDRAM Address command.

The Set SEG pins & hardware configuration command will allow you to rotate the display, or have text coming in from a different location rather than the top left. The entry mode command determines whether you want to enable the shift on the display, or if you would like the Address counter to auto increment or decrement after receiving a character.

I would also recommend looking at the example code here: https://github.com/NewhavenDisplay/NHD_US2066

Could you also provide your I2C1_Wr function?

cbrun17

  • Newbie
  • *
  • Posts: 2
  • Karma: 0
    • View Profile
Re: Interfacing NHD-0420CW-AY3 to PIC controller via I2C
« Reply #2 on: May 05, 2017, 12:46:46 PM »
Hello Saurabh_B,

Thank you so much for the quick response. Unfortunately the I2C_WRITE function is part of the built I2C library within MikroC for PIC based controllers.

The code attached is what I have so far. It is comprised of bits and pieces of several sources. I'm attempting to build a library for use within MikroC to use for several projects. Also, my hope is to be able to share the final result to other users of this compiler. These are wonderful displays, however, very little support by the MikroC community.
Code: [Select]
//***************************************************************
//
// I2C functions for NHD-0420CW-AY3
// and other serial LCDs with US2066 controller
// made by Newhaven Display
//
// Compiler: MikroC Pro For PIC 7.1
//
// MikroC Libraries used: I2C  C_String
//
// Controller for this project: PIC18F4520
//***************************************************************
#include "I2C_LCD_functions.h"    // Header file
#include <stdint.h>
#define DC LATC.F0      // define D/C control pin connected to PORTC.0
#define DataS 1         // Make pin high for data mode
#define CommandS 0    // make pin low for command mode


// !!!These constants must be declared in the project source code.!!!
// I2C Address for LCD
extern const unsigned short _I2C_ADDRESS; //With SA0 tied to VSS address will be 0x3C. When SA0 is tied to VDD, address will be 0x3D
// Column width of LCD
extern const unsigned short _LCD_WIDTH;

//****************************************************************
//
//  Function: StringSize
//
//  Action: Returns the length (in characters) of a string
//
//  Parameters: 1
//          InString = String whose length will be returned
//
//
//  Returns: The size of the string
//
//****************************************************************

unsigned int StringSize(char* InString)
{
    unsigned int StrSize;
    char StrByte;

    StrSize = 0;
    StrByte = InString[StrSize];
    while( StrByte != '\0' )
    {
        StrSize++;
        StrByte = InString[StrSize];

    }
    return StrSize;

}


//****************************************************************
//
//  Function: LCD_Init
//
//  Action: LCD Initialization sequence:
//
//  Parameters: 0
//
//
//  Returns: Nothing
//
//****************************************************************
void LCD_Init()
{
unsigned short rows = 0x08;

//______________________________________________________________________________________________________________________________________
        uint8_t ack;
        I2C_Write(_I2C_ADDRESS); // Configured for 0x3C in main program       
        I2C1_Init(100000);   // initialize I2C (module 1  - change this if using a different module
       
        I2C_Start();
       

        I2C_Write(0x2A); //function set (extended command set)
        I2C_Write(0x71); //function selection A
        DC = DataS // Bring D/C high
        delay_us(50);  //delay
        I2C_Write(0x00);  // **** disable internal VDD regulator
        delay_us(50);  //delay
        DC = CommandS // Bring D/C low
        I2C_Write(0x28); //function set (fundamental command set)
        I2C_Write(0x08); //display off, cursor off, blink off
        I2C_Write(0x2A); //function set (extended command set)
        I2C_Write(0x79); //OLED command set enabled
        I2C_Write(0xD5); //set display clock divide ratio/osc freq
        I2C_Write(0x70); //set display clock divide ratio/osc freq
        I2C_Write(0x78); //OLED command set disabled
        I2C_Write(0x09); //extended function set (4-lines)
        I2C_Write(0x06); //COM SEG direction
        I2C_Write(0x72); //function selection B. Choose ROM set & CGRAM
        DC = DataS // Bring D/C high
        delay_us(50);  //delay
        I2C_Write(0x00); //Select CGRAM & character ROM 0
        delay_us(50);  //delay
        DC = CommandS // Bring D/C low
        I2C_Write(0x2A); //function set (extended command set)
        I2C_Write(0x79); //OLED command set enabled
        I2C_Write(0xDA); //set SEG pins hardware configuration
        I2C_Write(0x10); //set SEG pins hardware configuration
        I2C_Write(0xDC); //function selection C
        I2C_Write(0x00); //function selection C
        I2C_Write(0x81); //set contrast control
        I2C_Write(0x02); //set contrast control 0x7F default
        I2C_Write(0xD9); //set phase length
        I2C_Write(0xF1); //set phase length
        I2C_Write(0xDB); //set VCOMH deselect level
        I2C_Write(0x40); //set VCOMH deselect level
        I2C_Write(0x78); //OLED command set disabled
        I2C_Write(0x28); //function set (fundamental command set)
        I2C_Write(0x01); //clear display
        I2C_Write(0x80); //set DDRAM address to 0x00
        I2C_Write(0x0C); //display ON
        I2C_Stop();
        delay_ms(100);  //delay

}
//______________________________________________________________________________________________________________________________________

//***************************************************************
//
//  Function: LCD_Line_Out
//
//  Action: Send a string of characters to the LCD
//          String will be displayed at given position
//
//  Parameters: 3
//          line = line on which text will display (1-4)
//          col = column at which text will display (1-20)
//          info = string which will be sent to LCD
//
//  Returns: Nothing
//
//***************************************************************

void LCD_Line_Out(short line, short col, char* info)
{
    short size;
    short ccount;
    //default to line 1 if value passed is out of range
    if (line < 1 || line > 4) line = 1;
    //default to column 1  if value passed is out of range
    if (col < 1 || col > _LCD_WIDTH ) col = 0;
    size =  StringSize(info);
    LCD_Set_Pos(line, col);
    for (ccount = 0; ccount < size; ccount++)
        LCD_Chr_Out_CP(info[ccount]);
}

//****************************************************************
//
//  Function: LCD_Line_Out_CP
//
//  Action: Send a string of characters to the LCD
//          String will be displayed at cursor position
//
//  Parameters: 1
//          info = string which will be sent to LCD
//
//  Returns: Nothing
//
//****************************************************************

void LCD_Line_Out_CP(char* info)
{
    short size;
    short ccount;
    size =  StringSize(info);
    for (ccount = 0; ccount < size; ccount++)
        LCD_Chr_Out_CP(info[ccount]);

}

//***************************************************************
//
//  Function: LCD_Line_Out_Centered
//
//  Action: Send a string of characters to the LCD
//          String will displayed horizontally centered
//          on the given line
//
//  Parameters: 2
//          line = line where string will be displayed
//          info = string which will be sent to LCD
//
//  Returns: Nothing
//
//***************************************************************

void LCD_Line_Out_Centered(short line, char* info)
{
        //char len,col;
        //default to line 1 if value passed is out of range
       if (line < 1 || line > 4) line = 1;

        //len = StrLen(info);
        //col = ((_LCD_WIDTH - len)/2) + 1;
        LCD_Set_Pos(line,( (_LCD_WIDTH - StringSize(info)) / 2) + 1);
        LCD_Line_Out_CP(info);
}

//***************************************************************
//
//  Function: LCD_Chr_Out
//
//  Action: Send a single character to the LCD
//          Character will be displayed at a given position
//
//  Parameters: 3
//          row = line on which text will display (1-4)
//          col = column at which character will be displayed (1-20)
//          chr = character to send
//
//  Returns: Nothing
//
//***************************************************************

void LCD_Chr_Out(short line, short col, char chr)
{
    //default to line 1 if value passed is out of range
    if (line < 1 || line > 4) line = 1;

    //default to column 0  if value passed is out of range
    if (col < 1 || col > _LCD_WIDTH ) col = 0;

    LCD_Set_Pos(line,col);
    I2C1_Start();
    I2C1_Wr(_I2C_ADDRESS);
    I2C1_Wr(chr);
    Delay_us(100);
    I2C1_Stop();
}

//***************************************************************
//
//  Function: LCD_Chr_Out_CP
//
//  Action: Send a single character to the LCD
//          Character will be displayed at cursor position
//
//  Parameters: 1
//          chr = character to send
//
//  Returns: Nothing
//
//***************************************************************

void LCD_Chr_Out_CP(char chr)
{
    I2C1_Start();
    I2C1_Wr(_I2C_ADDRESS);
    I2C1_Wr(chr);
    Delay_us(100);
    I2C1_Stop();
}

//***************************************************************
//
//  Function: LCD_Set_Pos
//
//  Action: Set cursor position
//
//  Parameters: 2
//           line = Cursor line (1-4)
//           col = Cursor column (1-20)
//
//  Returns: Nothing
//
//***************************************************************

void LCD_Set_Pos(short line, short col)
{
        short ln;

      //default to line 1 if value passed is out of range

      if (line < 1 || line > 4) line = 1;

      //default to column 0  if value passed is out of range

      if (col < 1 || col > _LCD_WIDTH ) col = 0;

        I2C1_Start();
        I2C1_Wr(_I2C_ADDRESS);
        //I2C1_Wr(0xFE);
        I2C1_Wr(0x45); //Set cursor
        switch (line)
        {
                case 1:
                    ln = 0x80;
                    break;
                case 2:
                    ln = 0xA0;
                     break;
                case 3:
                    ln = 0xC0;
                    break;
                case 4:
                    ln = 0xE0;

        }
        I2C1_Wr(ln + (col-1));
        Delay_us(100);
        I2C1_Stop();
}

//***************************************************************
//
//  Function: LCD_Clear
//
//  Action: Clear LCD display
//
//  Parameters: 0
//
//  Returns: Nothing
//
//***************************************************************

void LCD_Clear() //Done
{
        I2C1_Start();
        I2C1_Wr(_I2C_ADDRESS);
        //I2C1_Wr(0xFE);
        I2C1_Wr(0x20);
        Delay_us(1500);
        I2C1_Stop();
}

//***************************************************************
//
//  Function: LCD_ClearToHome
//
//  Action: Clear LCD display and place cursor to home position
//
//  Parameters: 0
//
//  Returns: Nothing
//
//***************************************************************
void LCD_ClearToHome() //Done
{
        I2C1_Start();
        I2C1_Wr(_I2C_ADDRESS);
        //I2C1_Wr(0xFE);
        I2C1_Wr(0x01);
        Delay_us(1500);
        I2C1_Stop();
}


//***************************************************************
//
//  Function: LCD_Contrast
//
//  Action: Set display contrast level
//
//  Parameters: 1
//          level = Contrast level ( 1 low - 50 high )
//
//  Returns: Nothing
//
//***************************************************************

void LCD_Contrast(short level)
{
        if (level < 1 || level > 255) level = 127;  //default to 127 if out of range
        I2C1_Start();
        I2C1_Wr(_I2C_ADDRESS);
        I2C1_Wr(0x81);
        I2C1_Wr(0x28);
        I2C1_Wr(level);
        Delay_us(500);
        I2C1_Stop();
        Delay_ms(5);
}

//***************************************************************
//
//  Function: LCD_Blink_On
//
//  Action: Turn on blinking cursor
//
//  Parameters: 0
//
//  Returns: Nothing
//
//***************************************************************

void LCD_Blink_On()
{
        I2C1_Start();
        I2C1_Wr(_I2C_ADDRESS);
        I2C1_Wr(0x28);
        I2C1_Wr(0x09);
        Delay_us(100);
        I2C1_Stop();
}

//***************************************************************
//
//  Function: LCD_Blink_Off
//
//  Action: Turn off blinking cursor
//
//  Parameters: 0
//
//  Returns: Nothing
//
//***************************************************************

void LCD_Blink_Off() //Done
{
        I2C1_Start();
        I2C1_Wr(_I2C_ADDRESS);
        //I2C1_Wr(0xFE);
        I2C1_Wr(0x0C);
        Delay_us(100);
        I2C1_Stop();
}



//***************************************************************
//
//  Function: LCD_Underline_On
//
//  Action: Turn on the underline cursor
//
//  Parameters: 0
//
//  Returns: Nothing
//
//***************************************************************

void LCD_Underline_On()
{
        I2C1_Start();
        I2C1_Wr(_I2C_ADDRESS);
        I2C1_Wr(0xFE);
        I2C1_Wr(0x47);
        Delay_us(1500);
        I2C1_Stop();
}

//***************************************************************
//
//  Function: LCD_Underline_Off
//
//  Action: Turn off the underline cursor
//
//  Parameters: 0
//
//  Returns: Nothing
//
//***************************************************************

void LCD_Underline_Off()
{
        I2C1_Start();
        I2C1_Wr(_I2C_ADDRESS);
        I2C1_Wr(0xFE);
        I2C1_Wr(0x48);
        Delay_us(1500);
        I2C1_Stop();
}


//***************************************************************
//
//  Function: LCD_Cursors_Off
//
//  Action: Turns off blinking & underline cursors
//
//  Parameters: 0
//
//  Returns: Nothing
//
//***************************************************************

void LCD_Cursors_Off()
{
        LCD_Blink_Off();
        LCD_Underline_Off();
}


//***************************************************************
//
//  Function: LCD_Cursor_Right
//
//  Action: Move cursor one position right (display unchanged)
//
//  Parameters: 0
//
//  Returns: Nothing
//
//***************************************************************

void LCD_Cursor_Right()
{
        I2C1_Start();
        I2C1_Wr(_I2C_ADDRESS);
        I2C1_Wr(0xFE);
        I2C1_Wr(0x4A);
        Delay_us(100);
        I2C1_Stop();
}

//***************************************************************
//
//  Function: LCD_Cursor_Left
//
//  Action: Move cursor one position left (display unchanged)
//
//  Parameters: 0
//
//  Returns: Nothing
//
//***************************************************************

void LCD_Cursor_Left()
{
        I2C1_Start();
        I2C1_Wr(_I2C_ADDRESS);
        I2C1_Wr(0xFE);
        I2C1_Wr(0x49);
        Delay_us(100);
        I2C1_Stop();
}

//***************************************************************
//
//  Function: LCD_Cursor_Home
//
//  Action: Move cursor to Line 1, Column 1 (display unchanged)
//
//  Parameters: 0
//
//  Returns: Nothing
//
//***************************************************************

void LCD_Cursor_Home()
{
        I2C1_Start();
        I2C1_Wr(_I2C_ADDRESS);
        //I2C1_Wr(0xFE);
        I2C1_Wr(0x00);
        Delay_us(1500);
        I2C1_Stop();
}


//***************************************************************
//
//  Function: LCD_Backspace
//
//  Action: Move cursor one position left (character deleted)
//
//  Parameters: 0
//
//  Returns: Nothing
//
//***************************************************************

void LCD_Backspace()
{
        I2C1_Start();
        I2C1_Wr(_I2C_ADDRESS);
        I2C1_Wr(0xFE);
        I2C1_Wr(0x4E);
        Delay_us(100);
        I2C1_Stop();
}

//***************************************************************
//
//  Function: LCD_Display_Right
//
//  Action: Shift display one position right (display unchanged)
//
//  Parameters: 0
//
//  Returns: Nothing
//
//***************************************************************

void LCD_Display_Right()
{
        I2C1_Start();
        I2C1_Wr(_I2C_ADDRESS);
        I2C1_Wr(0xFE);
        I2C1_Wr(0x56);
        Delay_us(100);
        I2C1_Stop();
}

//***************************************************************
//
//  Function: LCD_Display_Left
//
//  Action: Shift display one position left (display unchanged)
//
//  Parameters: 0
//
//  Returns: Nothing
//
//***************************************************************

void LCD_Display_Left()
{
        I2C1_Start();
        I2C1_Wr(_I2C_ADDRESS);
        //I2C1_Wr(0xFE);
        I2C1_Wr(0x55);
        Delay_us(100);
        I2C1_Stop();
}


//***************************************************************
//
//  Function: LCD_Display_on
//
//  Action: Turns on LCD screeen (display unchanged)
//
//  Parameters: 0
//
//  Returns: Nothing
//
//***************************************************************

void LCD_Display_On()
{
        I2C1_Start();
        I2C1_Wr(_I2C_ADDRESS);
        //I2C1_Wr(0xFE);
        I2C1_Wr(0x0C);
        Delay_us(100);
        I2C1_Stop();
}

//***************************************************************
//
//  Function: LCD_Display_Off
//
//  Action: Turns off LCD screen (display unchanged)
//
//  Parameters: 0
//
//  Returns: Nothing
//
//***************************************************************

void LCD_Display_Off()
{
        I2C1_Start();
        I2C1_Wr(_I2C_ADDRESS);
        //I2C1_Wr(0xFE);
        I2C1_Wr(0x08);
        Delay_us(100);
        I2C1_Stop();

}


Also attached a schematic of my connections for reference.

I look forward to any advice you can provide.

Chris
« Last Edit: May 05, 2017, 03:48:15 PM by cbrun17 »

 

NHD‐0420CW‐AB3 I2C Interface

Started by andersonpdBoard OLEDs

Replies: 1
Views: 2533
Last post January 23, 2015, 10:00:06 AM
by Michael_L
NHD‐0420CW‐AG3 Contrast question

Started by RichardRBoard OLEDs

Replies: 2
Views: 2028
Last post January 16, 2016, 09:52:02 AM
by RichardR
NHD‐0420CW‐AG3: blinking part of text?

Started by RichardRBoard OLEDs

Replies: 2
Views: 2150
Last post February 28, 2017, 03:27:02 PM
by BobG
NHD‐0420CW‐AG3 + I2C + PIC assembly code: trouble getting started

Started by RichardRBoard OLEDs

Replies: 4
Views: 2965
Last post December 17, 2015, 03:12:49 AM
by RichardR
MOVED: NHD-0420CW-AY3 display, text is mirror image

Started by Saurabh_BBoard Character LCDs

Replies: 0
Views: 1971
Last post March 11, 2016, 07:51:03 AM
by Saurabh_B