Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

4X20 LCD display with I2C Interface

LCD I2C HD4478 LCD I2C

  • Please log in to reply
36 replies to this topic

#21 ShVerni

ShVerni

    Advanced Member

  • Members
  • PipPipPip
  • 138 posts
  • LocationNew York, New York

Posted 27 February 2013 - 04:09 AM

Awesome, thanks for the code, even though it's not exactly what I'm looking for, it's a great place to start!



#22 ShVerni

ShVerni

    Advanced Member

  • Members
  • PipPipPip
  • 138 posts
  • LocationNew York, New York

Posted 05 March 2013 - 05:32 PM

So after playing around with my project a bit, I eventually decided to go with the Micro Liquid Crystal library. It doesn't work right out of the box, but I managed to find the pinout for the SainSmart LCD with backpack to get it to work. There was one other oddity, the LCD needed to be turned off until just before starting the library (see the code sample below). If the LCD was on before then, the micro liquid crystal library would throw exceptions.
 
I used an NPN-transistor with the ground form the LCD connected to the emitter, the collector connected to ground, and the base connected to an OutputPort that would keep the LCD off until it should be truned on. I've included a basic example below that shows how to configure the micro liquid crystal library to work with the SainSmart I2C LCD (I should note that I'm using a Netduino 2):
 

using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
using MicroLiquidCrystal;
using FusionWare.SPOT.Hardware;
namespace LCD
{
    public class Program
    {
        private static OutputPort power = new OutputPort(Pins.GPIO_PIN_D0, false);
        private static I2CBus bus = new I2CBus();
        private static BaseShifterLcdTransferProvider.ShifterSetup shifter = new BaseShifterLcdTransferProvider.ShifterSetup();

        public static void Main()
        {
            shifter.RS = ShifterPin.GP0;
            shifter.RW = ShifterPin.GP1;
            shifter.Enable = ShifterPin.GP2;
            shifter.BL = ShifterPin.GP3;
            shifter.D4 = ShifterPin.GP4;
            shifter.D5 = ShifterPin.GP5;
            shifter.D6 = ShifterPin.GP6;
            shifter.D7 = ShifterPin.GP7;
            power.Write(true);
            MCP23008LcdTransferProvider lcdProvider = new MCP23008LcdTransferProvider(bus, 0x3F, shifter);
            Lcd lcd = new Lcd(lcdProvider);
            lcd.Begin(20, 4);
            // LCD is now ready, let's test it!            
            lcd.SetCursorPosition(0, 0);
            lcd.Write("Hello, world!");
        }
    }
}


#23 matthew.lazarow

matthew.lazarow

    New Member

  • Members
  • Pip
  • 4 posts

Posted 25 April 2013 - 08:03 PM

Hello AxelG,

 

Thanks for the driver!

 

I'm sorry if this is a dumb question but how are you intending for us to instantiate the class?  I tried making a child class but keep getting argument count errors even though intellisense is showing the three expected arguments.

 

    public class Display : LiquidCrystal_I2C    {        LiquidCrystal_I2C _lcd = new LiquidCrystal_I2C(0x3F, 20, 4);             }


#24 matthew.lazarow

matthew.lazarow

    New Member

  • Members
  • Pip
  • 4 posts

Posted 30 April 2013 - 11:52 AM

After some digging online regarding implimenting protected constructors, I am able to get it to compile now but I have my doubts I'm calling the methods correctly.  I'm not getting anything (not even a flicker) on the LCD.  I'm not getting any runtime errors either so I'm assuming it is 'sensing' the screen.  Or do I2C ports fail quietly?

 

    public class Display : LiquidCrystal_I2C    {        public Display(byte address, byte cols, byte rows)            : base(address, cols, rows)        {        }        public void writeValue(string s)        {            this.setCursor(0, 0);            this.blink();            this.write(Tools.GetBytes(s));        }


#25 hanzibal

hanzibal

    Advanced Member

  • Members
  • PipPipPip
  • 1287 posts
  • LocationSweden

Posted 02 May 2013 - 11:35 AM

Here's my contribution to I2C driven LCDs:

 

http://forums.netdui...-and-ir-remote/

 

This one also works very well and is pretty fast since all LCD pins (not just the data pins) are driven over I2C. Brightness and contrast adjustment is controlled using PWM which omits the need for any potentiometers.



#26 JoopC

JoopC

    Advanced Member

  • Members
  • PipPipPip
  • 148 posts

Posted 30 May 2013 - 12:55 PM

Thanks for the quick replies.

 

I wrote a reset() method in the driver, and I have attached it to the onboard switch.  Hitting the switch resets the screen.  Seems like there should be a better way...

 

Maybe I will remove the i2c interface and go to a native HD4478 8 bit driver...

The class works well, however i have made some changes in the write function so it can handle strings. 

Also a non wrapper to handle the maximum chars on the rows.

 

Also, usually it is Row, Column and not  Column and then Rows  for instance in the change position function.

ChangePosition(Row, Column)



#27 JoopC

JoopC

    Advanced Member

  • Members
  • PipPipPip
  • 148 posts

Posted 20 June 2013 - 10:03 AM

I have convert the LCD class to Visual Basic and make some changes i found

required for correct functioning. Just copy paste the Class in your program (I tested it well)

 

so now in de code:

 

dim Display As VBLiquidCrystal_I2C = New VBLiquidCrystal_I2C(lcdAddress, col, row)

 

edit: 21-06-2013 I have made some modifications in de class.

Public Class VBLiquidCrystal_I2C    Private Const cnstClearDisplay As Integer = &H1    Private Const cnstReturnHome As Integer = &H2    Private Const cnstEntryModeSet As Integer = &H4    Private Const cnstDisplayControl As Integer = &H8    Private Const cnstCursorShift As Integer = &H10    Private Const cnstFunctionSet As Integer = &H20    Private Const cnstSETCGRAMADDR As Integer = &H40    Private Const cnstSETDDRAMADDR As Integer = &H80    Private Const cnstEntryRight As Integer = &H0    Private Const cnstEntryLeft As Integer = &H2    Private Const cnstEntryShiftIncrement As Integer = &H1    Private Const cnstEntryShiftDecrement As Integer = &H0    Private Const cnstDisplayOn As Integer = &H4    Private Const cnstDisplayOff As Integer = &H0    Private Const cnstCursorOn As Integer = &H2    Private Const cnstCursorOff As Integer = &H0    Private Const cnstBlinkOn As Integer = &H1    Private Const cnstBlonkOff As Integer = &H0    Private Const cnstDisplayMove As Integer = &H8    Private Const cnstCursorMove As Integer = &H0    Private Const cnstMoveRight As Integer = &H4    Private Const cnstMoverLeft As Integer = &H0    Private Const cnst8BitMode As Integer = &H10    Private Const cnst4BitMode As Integer = &H0    Private Const cnst2Line As Integer = &H8    Private Const cnst1Line As Integer = &H0    Private Const cnst5x10Dots As Integer = &H4    Private Const cnst5x8Dots As Integer = &H0    Private Const cnstBackLight As Integer = &H8    Private Const cnstNoBackLight As Integer = &H0    Private Const cnstMaxFreq As Integer = 100    Private _Addr As Byte    Private _displayfunction As Byte    Private _displaycontrol As Byte    Private _displaymode As Byte    Private _numlines As Byte    Private _cols As Byte    Private _rows As Byte    Private _backlightval As Byte    Private _I2C As MultiI2C    ' 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).#Region "Constructors and Initializers"    Public Sub New(ByVal lcd_Addr As Byte, ByVal lcd_cols As Byte, ByVal lcd_rows As Byte)        Me._Addr = lcd_Addr        Me._cols = lcd_cols        Me._rows = lcd_rows        Me._backlightval = cnstNoBackLight        Me._I2C = New MultiI2C(lcd_Addr, cnstMaxFreq)        Me.begin(Me._cols, Me._rows)    End Sub    Public Sub reset()        Me.begin(Me._cols, Me._rows)    End Sub    ''' <summary>    ''' Sends the initialization sequence for the device    ''' </summary>    ''' <param name="cols">Number of columns</param>    ''' <param name="lines">Number of rows</param>    ''' <param name="dotsize">Optional cursor size</param>    Public Sub begin(ByVal cols As Byte, ByVal lines As Byte, Optional dotsize As Byte = cnst5x8Dots)        Me._displayfunction = cnst4BitMode Or cnst1Line Or cnst5x8Dots        If lines > 1 Then            Me._displayfunction = CByte(Me._displayfunction Or cnst2Line)        End If        Me._numlines = lines        ' for some 1 line displays you can select a 10 pixel high font        If (dotsize <> 0) AndAlso (lines = 1) Then            Me._displayfunction = CByte(Me._displayfunction Or cnst5x10Dots)        End If        ' 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 befer 4.5V so we'll wait 50        'Thread.Sleep(50);        ' Now we pull both RS and R/W low to begin commands        Me.expanderWrite(Me._backlightval)        ' reset expander and turn backlight off (Bit 8 =1)        Thread.Sleep(1000)        'put the LCD into 4 bit mode        ' this is according to the hitachi HD44780 datasheet        ' figure 24, pg 46        'UShort * 2^8 for left shifting 8 bit (<< 8)        ' we start in 8bit mode, try to set 4 bit mode        Me.write4bits(CByte(&H3 * 2 ^ 4))        Thread.Sleep(8)        ' wait min 4.1ms        ' second try        Me.write4bits(CByte(&H3 * 2 ^ 4))        Thread.Sleep(8)        ' wait min 4.1ms        ' third go!        Me.write4bits(CByte(&H3 * 2 ^ 4))        Thread.Sleep(4)        ' finally, set to 4-bit interface        Me.write4bits(CByte(&H2 * 2 ^ 4))        ' set # lines, font size, etc.        Me.command(CByte(cnstFunctionSet Or Me._displayfunction))        ' turn the display on with no cursor or blinking default        Me._displaycontrol = cnstDisplayOn Or cnstCursorOff Or cnstBlonkOff        Me.display()        ' clear it off        Me.clear()        ' Initialize to default text direction (for roman languages)        Me._displaymode = cnstEntryLeft Or cnstEntryShiftDecrement        ' set the entry mode        Me.command(CByte(cnstEntryModeSet Or Me._displaymode))        Me.home()    End Sub#End Region#Region "High Level me.commands"    Public Sub clear()        Me.command(cnstClearDisplay)        Thread.Sleep(2)    End Sub    Public Sub home()        Me.command(cnstReturnHome)        Thread.Sleep(2)    End Sub    Public Sub noDisplay()        Dim display As Byte = cnstDisplayOn        Me._displaycontrol = Me._displaycontrol And CByte(Not display)        Me.command(CByte(cnstDisplayControl Or Me._displaycontrol))    End Sub    Public Sub display()        Me._displaycontrol = CByte(_displaycontrol Or cnstDisplayOn)        Me.command(CByte(cnstDisplayControl Or Me._displaycontrol))    End Sub    Public Sub noBlink()        Dim blink As Byte = cnstBlinkOn        Me._displaycontrol = Me._displaycontrol And CByte(Not blink)        Me.command(CByte(cnstDisplayControl Or Me._displaycontrol))    End Sub    Public Sub blink()        Me._displaycontrol = CByte(Me._displaycontrol Or cnstBlinkOn)        Me.command(CByte(cnstDisplayControl Or Me._displaycontrol))    End Sub    Public Sub noCursor()        Dim cursor As Byte = cnstCursorOn        Me._displaycontrol = Me._displaycontrol And CByte(Not cursor)        Me.command(CByte(cnstDisplayControl Or Me._displaycontrol))    End Sub    Public Sub cursor()        Me._displaycontrol = CByte(Me._displaycontrol Or cnstCursorOn)        Me.command(CByte(cnstDisplayControl Or Me._displaycontrol))    End Sub    Public Sub scrollDisplayLeft()        Me.command(cnstCursorShift Or cnstDisplayMove Or cnstMoverLeft)    End Sub    Public Sub scrollDisplayRight()        Me.command(cnstCursorShift Or cnstDisplayMove Or cnstMoveRight)    End Sub    Public Sub leftToRight()        Me._displaymode = CByte(Me._displaymode Or cnstEntryLeft)        Me.command(CByte(cnstEntryModeSet Or Me._displaymode))    End Sub    Public Sub rightToLeft()        Dim entry As Byte = cnstEntryLeft        Me._displaymode = _displaymode And CByte(Not entry)        Me.command(CByte(cnstEntryModeSet Or Me._displaymode))    End Sub    Public Sub noBacklight()        Me._backlightval = cnstNoBackLight        expanderWrite(0)    End Sub    Public Sub backlight()        Me._backlightval = cnstBackLight        expanderWrite(0)    End Sub    Public Sub autoscroll()        Me._displaymode = CByte(Me._displaymode Or cnstEntryShiftIncrement)        Me.command(CByte(cnstEntryModeSet Or Me._displaymode))    End Sub    Public Sub noAutoscroll()        Dim entry As Byte = cnstEntryShiftIncrement        Me._displaymode = Me._displaymode And CByte(Not entry)        Me.command(CByte(cnstEntryModeSet Or Me._displaymode))    End Sub#End Region#Region "Charaters and writing"    ''' <summary>    ''' Allows us to fill the first 8 CGRAM locations with custom characters    ''' </summary>    ''' <param name="location"> 0-7 locations</param>    ''' <param name="charmap"> byte[8] containg charater map</param>    Public Sub createChar(ByVal location As Byte, ByVal charmap As Byte())        'SyncLock LCDLock        location = CByte(location And &H7)        ' we only have 8 locations 0-7        Me.command(CByte(cnstSETCGRAMADDR Or (CLng(location * 2 ^ 3))))        For i As Integer = 0 To 7            Me.write(charmap(i))        Next        'End SyncLock    End Sub    Public Sub setCursor(ByVal col As Byte, ByVal row As Byte)        Dim row_offsets As Integer() = {&H0, &H40, &H14, &H54}        If row > Me._numlines Then            ' we count rows starting w/0            row = CByte(Me._numlines - 1)        End If        Me.command(CByte(cnstSETDDRAMADDR Or (col + row_offsets(row))))    End Sub    Public Sub write(ByVal value As Byte())        For position As Integer = 0 To value.Length - 1            Me.write(value(position))        Next    End Sub    Public Sub write(ByVal value As String)        Dim writeVal As Byte() = Encoding.UTF8.GetBytes(value)        For position As Integer = 0 To value.Length - 1            Me.write(writeVal(position))        Next    End Sub    Public Sub write(ByVal value As Byte)        Me.send(value, &H1)    End Sub    Public ReadOnly Property Rows As Integer        Get            Return Me._rows        End Get    End Property    Public ReadOnly Property Cols As Integer        Get            Return Me._cols        End Get    End Property#End Region#Region "Mid level commands"    '********** mid level commands, for sending data/cmds     Private Sub command(ByVal value As Byte, ByVal vv As Byte)        Me.send(value, vv)    End Sub    Private Sub command(ByVal value As Byte)        Me.send(value, 0)    End Sub    '''/compatibility API function aliases    Public Sub blink_on()        Me.blink()    End Sub    Public Sub blink_off()        Me.noBlink()    End Sub    Public Sub cursor_on()        Me.cursor()    End Sub    Public Sub cursor_off()        Me.noCursor()    End Sub    Public Sub setBacklight(ByVal new_val As Boolean)        If new_val Then            Me.backlight()        Else            Me.noBacklight()        End If    End Sub    Public Sub load_custom_character(ByVal char_num As Byte, ByVal charMap As Byte())        Me.createChar(char_num, charMap)    End Sub#End Region#Region "Low Level commands"    ''' <summary>    ''' write either command or data to the devide    ''' </summary>    ''' <param name="value">byte to send</param>    ''' <param name="mode">0 = command, 1 = data</param>    Private Sub send(ByVal value As Byte, ByVal mode As Byte)        Dim highnib As Byte = CByte(value And &HF0)        Dim lownib As Byte = CByte((CLng(value * 2 ^ 4)) And &HF0)        Me.write4bits(CByte((highnib) Or mode))        Me.write4bits(CByte((lownib) Or mode))    End Sub    Private Sub write4bits(ByVal value As Byte)        expanderWrite(value)        pulseEnable(value)    End Sub    ''' <summary>    ''' Lowest level command to send data to the I2C port    ''' </summary>    ''' <param name="_data"></param>    Private Sub expanderWrite(ByVal data As Byte)        Me._I2C.Write(New Byte() {CByte(data Or Me._backlightval)})    End Sub    Private Sub pulseEnable(ByVal data As Byte)        expanderWrite(CByte(data Or &H4))        ' En high        'Thread.Sleep(1); // enable pulse must be >450ns        Me.expanderWrite(CByte(data And Not &H4))        ' En low        'Thread.Sleep(50); // commands need > 37us to settle    End Sub#End RegionEnd Class

  • carb likes this

#28 TinkeringTurtle

TinkeringTurtle

    Advanced Member

  • Members
  • PipPipPip
  • 55 posts

Posted 22 September 2013 - 12:05 AM

Thanks for sharing this AxelG. Your library works great!



#29 swordfish45

swordfish45

    New Member

  • Members
  • Pip
  • 1 posts

Posted 13 October 2013 - 07:23 PM

 

After some digging online regarding implimenting protected constructors, I am able to get it to compile now but I have my doubts I'm calling the methods correctly.  I'm not getting anything (not even a flicker) on the LCD.  I'm not getting any runtime errors either so I'm assuming it is 'sensing' the screen.  Or do I2C ports fail quietly?

    public class Display : LiquidCrystal_I2C    {        public Display(byte address, byte cols, byte rows)            : base(address, cols, rows)        {        }        public void writeValue(string s)        {            this.setCursor(0, 0);            this.blink();            this.write(Tools.GetBytes(s));        }

 

Matthew,

 

I found that i had nearly identical code as you did, with the same outcome. No exceptions, no worky. If you still are having issues with this / anyone googling this post is, i changed my i2c address back to 0x27 and it worked.



#30 alesbedac

alesbedac

    Advanced Member

  • Members
  • PipPipPip
  • 63 posts

Posted 15 October 2013 - 07:12 PM

I have an example project, now is communication working without exceptions,

but still is not working 100%.

 

Text is not still displayed...only backlight is working. Bellow is my testing implementation :

 

 

Declaration class :

 public class HD44780_I2C_Driver : LiquidCrystal_I2C    {        public HD44780_I2C_Driver(byte address, byte cols, byte rows) : base(address, cols, rows)        {        }                         public void WriteString(string s)        {                        this.setCursor(0, 0);            this.blink();            byte[] byteArray = Encoding.UTF8.GetBytes(s);            this.write(byteArray);        }    }

program class :

 public class Program    {        private static HD44780_I2C_Driver myLCD = new HD44780_I2C_Driver(0x27, 20, 4);        private static OutputPort DA_Led = new OutputPort(Pins.ONBOARD_LED, false);        private static bool ledStatus = false;        public static void Main()        {            while (true)            {                myLCD.setBacklight(true);                ledStatus = !ledStatus;                DA_Led.Write(ledStatus);                myLCD.WriteString("FIRST MESSAGE");                Thread.Sleep(1000);                myLCD.WriteString("SECOND MESSAGE");                                Thread.Sleep(1000);                myLCD.setBacklight(false);                Thread.Sleep(1000);            }        }    }


#31 alesbedac

alesbedac

    Advanced Member

  • Members
  • PipPipPip
  • 63 posts

Posted 20 October 2013 - 02:16 PM

 

After some digging online regarding implimenting protected constructors, I am able to get it to compile now but I have my doubts I'm calling the methods correctly.  I'm not getting anything (not even a flicker) on the LCD.  I'm not getting any runtime errors either so I'm assuming it is 'sensing' the screen.  Or do I2C ports fail quietly?

    public class Display : LiquidCrystal_I2C    {        public Display(byte address, byte cols, byte rows)            : base(address, cols, rows)        {        }        public void writeValue(string s)        {            this.setCursor(0, 0);            this.blink();            this.write(Tools.GetBytes(s));        }

 

Hello,

i have same issue  (with one advantage - backlight is working) ... did you get sollution.?



#32 iced98lx

iced98lx

    Advanced Member

  • Members
  • PipPipPip
  • 134 posts
  • LocationSouth Dakota

Posted 22 October 2013 - 04:15 PM

This is still working great for me on my N+2 but can anyone clue me in on how to get a degree symbol to show up?



#33 iced98lx

iced98lx

    Advanced Member

  • Members
  • PipPipPip
  • 134 posts
  • LocationSouth Dakota

Posted 22 October 2013 - 04:33 PM

This has a character map on it, but I do not know how to get that to display via C# code.

 

http://forum.arduino...38699#msg138699

 

 

printing this: LCD.write("x00A1", 19, 0); ("x00A1" is a string) gives me 1010001 on the map, and with x00D9 I get 3 over and 8 down, so I'm in the right "Column" but I can't figure out how to get below the 10th (0+9) "row"...



#34 iced98lx

iced98lx

    Advanced Member

  • Members
  • PipPipPip
  • 134 posts
  • LocationSouth Dakota

Posted 22 October 2013 - 04:43 PM

Silly me. Convert binary (11011111) to Hex (DF) and print that out:

 

LCD.write("x00DF", 19, 0);



#35 GT89

GT89

    New Member

  • Members
  • Pip
  • 2 posts

Posted 30 July 2014 - 04:15 PM

Howdy, quick question please:

 

I am getting errors in deployment with AxelG code at initial post and I think it is because my Netduino *classic* firmware is 4.1.  (I've upgraded NETMF to 4.2 already, didn't help).

 

Must I upgrade the netduino firmware to deploy?  upgrading looks daunting to me and I'm worried about it breaking my other functioning projects.  I have thought i might just purchase a new Netduino to get the upgraded firmware etc.

 

thanks much!



#36 danorum

danorum

    New Member

  • Members
  • Pip
  • 1 posts

Posted 10 September 2014 - 09:55 PM

I am having trouble getting the code in the first post working with my LCD (same sainsmart 2004 as linked in the first post). I have added 1.8k resistors to both the sda and scl lines. When my project start, I see "blocks" in lines 1 and 3 and never get text on the LCD.

 

I am using a Netduino Plus 2.



#37 gismo

gismo

    Advanced Member

  • Members
  • PipPipPip
  • 110 posts

Posted 02 June 2015 - 07:47 PM

I attached the driver code to the first post.

 

Can you post some sample code that uses your driver?

 

I can't seem to get it to work or initialize the device.







Also tagged with one or more of these keywords: LCD I2C, HD4478, LCD, I2C

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.