Wednesday, 10 December 2014

RaspberryPi + wiringPi + Gambas + 16x2LCD module

There are plenty of 16 character, 2 line LCD modules available for home projects using controllers like PICs or Arduino.


In this post I'm using a RaspberryPi with Gambas, while relying on Gordon's wiringPi api to do the heavy lifting.


It turned out to be a bit tricky using the existing wiringPi libraries, but I think I've found a usable work-around.

Although I didn't have an application for an LCD module, when I saw this offer on Amazon I just had to place my order.

£1.29 for a 16x2 LCD, including tax, postage & packaging!

That's no money. I found more than that in loose coins down the back of our sofa when I last did a 'collection' (actually £1.37 plus 10 Kenyan Shillingi).

Search the net and you will find lots of examples of how to wire and run these modules with a RaspberryPi. All of the examples I found use Python, but my language of choice is Gambas.


The Hardware


This module is supplied in basic, but adequate, packaging. It does not include any technical documentation (did I tell you it was only £1.29?). Fortunately this module controller appears to be very similar to the Hitachi HD44780.

The LCD module has a row of 16 holes labeled with their functions. To make it easier to wire using a bread board, I bought a strip of pins from Spiratronics and soldered these to the module.



Since this is a 5 Volt module, it is very important not to allow the modules data drivers to output 5Volts onto the RaspberryPi GPIO pins. The R/W line (read/write) should be held low at all times, so I have soldered a link directly on the module between pin 1 and pin 5.

Please excuse my soldering...I need new glasses!


The module has 8 data lines, but I'm only using the upper 4.


The 10k Ohm variable resistor needs to be adjusted for best contrast. Initially set this fully one way so you can see 32 white blocks where the characters should be. Once your program is sending characters to the display, adjust the resistor back a bit so that the blocks fade to black and then just disappear.

I added the 220 Ohm resistor because I'd read somewhere that some cheap displays do not include a back-light LED series resistor. However it looks like this one has an integral resistor, although the display is plenty bright enough, even running with reduced drive current like this.

Measuring the current to the display module:-
  • with back-light disconnected: 1mA
  • with 220R feeding back-light (as my circuit): 7mA
  • with back-light connected directly to 5V: 17mA

Naturally you can choose different GPIO pins from the ones that I'm using. You just have to change the pin details in software.

Final warning: make sure you have connected LCD pin 5 to 0V before turning on the power!


Gambas Test Software

Just a reminder that you need root access rights to use the RaspberryPi GPIO. So run Gambas from the command line like this:-

gksu gambas3

A few days before my module arrived, I created a simple Gambas project on a RaspberryPi running Raspbian Jessie and Gambas 3.5.4 (but this would work just as well on Raspbian Wheezy with Gambas 3.4.x).

I downloaded the latest version of wiringPi, unzipped it and built it as previously described.

Initially I added code to my test project to specify the wiringPi library and required functions like this:-

' Gambas class file

Library "/usr/local/lib/libwiringPi"

Public Extern wiringPiSetup() As Integer        

Public Extern lcdInit(iRows As Integer, iCol As Integer, iBits As Integer, iRS As Integer, iStrobe As Integer, iD0 As Integer, iD1 As Integer, iD2 As Integer, iD3 As Integer, iD4 As Integer, iD5 As Integer, iD6 As Integer, iD7 As Integer) As Integer
 

Public Extern lcdHome(iDisplay As Integer)
Public Extern lcdClear(iDisplay As Integer)
Public Extern lcdPuts(iDisplay As Integer, strText As String)


Then I basically ran two commands to setup wiringPi and initialise the LCD:-

wiringPiSetup()
intLCD = lcdInit(2, 16, 4, 5, 6, 0, 1, 2, 3, 0, 0, 0, 0)

However, this resulted in error 127 and the following message from Gambas IDE:-

"Cannot find symbol 'lcdInit' in dynamic library '/usr/local/lib/libwiringPi'"

At this point Gordon was kind enough to point out that a second library was required to drive the LCD. The wiringPiDev library is also created by the build process and appears in the same directory as the wiringPi library, so I added a reference like this:-

Library "/usr/local/lib/libwiringPi"

Public Extern wiringPiSetup() As Integer


Library "/usr/local/lib/libwiringPiDev"
 
Public Extern lcdInit(iRows As Integer, iCol As Integer, iBits As Integer, iRS As Integer, iStrobe As Integer, iD0 As Integer, iD1 As Integer, iD2 As Integer, iD3 As Integer, iD4 As Integer, iD5 As Integer, iD6 As Integer, iD7 As Integer) As Integer

...

This arrangement fixed the first problem, but I was then presented with a new error:-

LCD16x2: symbol lookup error: /usr/local/lib/libwiringPiDev.so: undefined symbol: digitalWrite

This error seemed to indicate that the function lcdInit() did not have access to digitalWrite() in the wiringPi library.

I have no idea how to fix this in Gambas, so I decided to combine the source code to create a single library by copying the contents of lcd.c into wiringPi.c, and the contents of lcd.h into wiringPi.h

It is then a simple matter to re-run ./build once again, and modify the Gambas declarations back to the first example.

It Works!


My complete test program includes 2 command buttons, 2 text boxes and looks like this:-

' Gambas class file

Library "/usr/local/lib/libwiringPi"

Public Extern wiringPiSetup() As Integer
Public Extern lcdInit(iRows As Integer, iCol As Integer, iBits As Integer, iRS As Integer, iStrobe As Integer, iD0 As Integer, iD1 As Integer, iD2 As Integer, iD3 As Integer, iD4 As Integer, iD5 As Integer, iD6 As Integer, iD7 As Integer) As Integer
Public Extern lcdHome(iDisplay As Integer)
Public Extern lcdClear(iDisplay As Integer)
Public Extern lcdDisplay(iDisplay As Integer, iState As Integer)
Public Extern lcdCursor(iDisplay As Integer, iState As Integer)
Public Extern lcdCursorBlink(iDisplay As Integer, iState As Integer)
Public Extern lcdPosition(iDisplay As Integer, xPos As Integer, yPos As Integer)
Public Extern lcdPuts(iDisplay As Integer, strText As String)

Public intLCD As Integer    'handle for lcd

Public Sub Form_Open()
Dim iReply As Integer

  iReply = wiringPiSetup()
  Me.Text = "wiringPi Setup: " & CStr(iReply)
 
Catch
  Me.Text = "Failed to setup wiringPi. This program must be run as root" 
End

Public Sub Button1_Click()
'initialise display


  intLCD = lcdInit(2, 16, 4, 5, 6, 0, 1, 2, 3, 0, 0, 0, 0)
  Me.text = "intLCD handle: " & intLCD

Catch
  Me.Text = Error.Text
End

Public Sub Button2_Click()
'write text to display


  lcdClear(intLCD)
  lcdCursor(intLCD, 0)
  lcdPosition(intLCD, 0, 0)
  lcdPuts(intLCD, TextBox1.Text)
  lcdPosition(intLCD, 0, 1)
  lcdPuts(intLCD, TextBox2.Text) 

End


Anything you write in the text boxes will be displayed, although it might be a bit of a mess if you exceed 16 characters per line!

Please note that I have declared the 2nd argument for lcdPuts as a string. This is really a pointer (see wiringPi LCD documentation and Gambas notes on datatype mapping).

I seem to get away with this when passing single characters from a sting by adding a NULL, as in this example where I send one character of a string at a time to the display:-

Public Sub Button5_Click()
'display 1 char at a time with a short delay
Dim strMessage As String
Dim intLetters As Integer
Dim index As Integer
Dim strChar As String

  strMessage = "Hello World!"
  intLetters = Len(strMessage)
  For index = 1 To intLetters
    lcdPosition(intLCD, index - 1, 0)
    strChar = Mid(strMessage, index, 1)
    lcdPuts(intLCD, strChar & Null)
    Wait 0.3
  Next
 
End


...that should put the "B" back into Bodgit.




Further Reading:-
wiringPi DevLib
wiringPi LCD Library

No comments:

Post a Comment