Using the I2C library to control 2x16 LCD Module, and other things
The Onion2 Maker Kit came with a backlit 2x16 LCD module with I2C interface.
![[IMG]]()
![[IMG]]()
The I2C LCD Example is completely documented here. I will simply summarize the steps required to get this up and running.
The LCD module requires four connections to the Expansion Dock. You will note that this reduces the number of GPIO pins as compared to the normal parallel interface to the Hitachi HD44780 LCD Controller.
GND
Vcc
SDA
SCL
Getting Started
From the Linux Terminal, enter:
opkg update
opkg install python-light pyOnionI2C
Note that you only have to do this once on your workstation PC.
Next, you will create a Python library file called lcdDriver.py with the following code:
With this file saved in your /root directory, you are now ready to create your test program.
Time Functions
You may notice in the code above a software delay function was created. This can also be accomplished using the time module as shown in the modified code below:
GPIO
One of the first software tests on a new MCU is to measure how fast one can toggle a GPIO pin. For this, we can run this simple code:
I measured this with an oscilloscope to be period of about 5ms, i.e. a repetition rate of 200Hz. This is surprisingly and disappointingly slow.
There are two reasons for this slow speed.
GPIO Side-track using time module
Let us briefly revisit our basic GPIO program. Here we add the time module in order to implement delays within the code. This program has been modified to flash the LED on GPIO0 once every second.
FAST GPIO
A workable solution for fast GPIO is yet to come.
For the time being, you can execute the following commands from the Linux shell (command line):
fast-gpio set 0 1
fast-gpio set 0 0
... more to come, sometime later, maybe much later!!!
... if you have some ideas that you would like to see implemented, simply leave a comment below.
The Onion2 Maker Kit came with a backlit 2x16 LCD module with I2C interface.
![[IMG]](http://forum.allaboutcircuits.com/proxy.php?image=https%3A%2F%2Fonion.io%2Fwp-content%2Fuploads%2F2017%2F03%2Fmaker-kit-icon.png&hash=b19b233d743ea1cf1e234216df742f98)
![[IMG]](http://forum.allaboutcircuits.com/proxy.php?image=https%3A%2F%2Fraw.githubusercontent.com%2FOnionIoT%2FOnion-Docs%2Fmaster%2FOmega2%2FKit-Guides%2Fimg%2Flcd-screen.jpg&hash=0bc36c036c09b4e12eaa0f1600f21864)
The I2C LCD Example is completely documented here. I will simply summarize the steps required to get this up and running.
The LCD module requires four connections to the Expansion Dock. You will note that this reduces the number of GPIO pins as compared to the normal parallel interface to the Hitachi HD44780 LCD Controller.
GND
Vcc
SDA
SCL
Getting Started
From the Linux Terminal, enter:
opkg update
opkg install python-light pyOnionI2C
Note that you only have to do this once on your workstation PC.
Next, you will create a Python library file called lcdDriver.py with the following code:
Code (Text):
- # lcdDriver.py
- from OmegaExpansion import onionI2C
- import time
- # sleep durations
- writeSleep = 0.0001 # 100 us
- initSleep = 0.2
- ## LCD Display commands
- # commands
- LCD_CLEARDISPLAY = 0x01
- LCD_RETURNHOME = 0x02
- LCD_ENTRYMODESET = 0x04
- LCD_DISPLAYCONTROL = 0x08
- LCD_CURSORSHIFT = 0x10
- LCD_FUNCTIONSET = 0x20
- LCD_SETCGRAMADDR = 0x40
- LCD_SETDDRAMADDR = 0x80
- LCD_LINE1 = 0x80
- LCD_LINE2 = 0xC0
- LCD_LINE3 = 0x94
- LCD_LINE4 = 0xD4
- # flags for display entry mode
- LCD_ENTRYRIGHT = 0x00
- LCD_ENTRYLEFT = 0x02
- LCD_ENTRYSHIFTINCREMENT = 0x01
- LCD_ENTRYSHIFTDECREMENT = 0x00
- # flags for display on/off control
- LCD_DISPLAYON = 0x04
- LCD_DISPLAYOFF = 0x00
- LCD_CURSORON = 0x02
- LCD_CURSOROFF = 0x00
- LCD_BLINKON = 0x01
- LCD_BLINKOFF = 0x00
- # flags for display/cursor shift
- LCD_DISPLAYMOVE = 0x08
- LCD_CURSORMOVE = 0x00
- LCD_MOVERIGHT = 0x04
- LCD_MOVELEFT = 0x00
- # flags for function set
- LCD_8BITMODE = 0x10
- LCD_4BITMODE = 0x00
- LCD_2LINE = 0x08
- LCD_1LINE = 0x00
- LCD_5x10DOTS = 0x04
- LCD_5x8DOTS = 0x00
- # flags for backlight control
- LCD_BACKLIGHT = 0x08
- LCD_NOBACKLIGHT = 0x00
- En = 0b00000100 # Enable bit
- Rw = 0b00000010 # Read/Write bit
- Rs = 0b00000001 # Register select bit
- class Lcd:
- # initializes objects and lcd
- def __init__(self,address, port=0):
- # i2c device parameters
- self.address = address
- self.i2c = onionI2C.OnionI2C(port)
- # lcd defaults
- self.lcdbacklight = LCD_BACKLIGHT #default status
- self.line1= "";
- self.line2= "";
- self.line3= "";
- self.line4= "";
- self.lcdWrite(0x03)
- self.lcdWrite(0x03)
- self.lcdWrite(0x03)
- self.lcdWrite(0x02)
- self.lcdWrite(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_4BITMODE)
- self.lcdWrite(LCD_DISPLAYCONTROL | LCD_DISPLAYON)
- self.lcdWrite(LCD_CLEARDISPLAY)
- self.lcdWrite(LCD_ENTRYMODESET | LCD_ENTRYLEFT)
- time.sleep(initSleep)
- # function to write byte to the screen via I2C
- def writeBytesToLcd(self, cmd):
- self.i2c.write(self.address, [cmd])
- time.sleep(writeSleep)
- # creates an EN pulse (using I2C) to latch previously sent command
- def lcdStrobe(self, data):
- self.writeBytesToLcd(data | En | self.lcdbacklight)
- time.sleep(writeSleep)
- self.writeBytesToLcd(((data & ~ En) | self.lcdbacklight))
- time.sleep(writeSleep)
- def lcdWriteFourBits(self, data):
- # write four data bits along with backlight state to the screen
- self.writeBytesToLcd(data | self.lcdbacklight)
- # perform strobe to latch the data we just sent
- self.lcdStrobe(data)
- # function to write an 8-bit command to lcd
- def lcdWrite(self, cmd, mode=0):
- # due to how the I2C backpack expects data, we need to send the top four and bottom four bits of the command separately
- self.lcdWriteFourBits(mode | (cmd & 0xF0))
- self.lcdWriteFourBits(mode | ((cmd << 4) & 0xF0))
- # function to display a string on the screen
- def lcdDisplayString(self, string, line):
- if line == 1:
- self.line1 = string;
- self.lcdWrite(LCD_LINE1)
- if line == 2:
- self.line2 = string;
- self.lcdWrite(LCD_LINE2)
- if line == 3:
- self.line3 = string;
- self.lcdWrite(LCD_LINE3)
- if line == 4:
- self.line4 = string;
- self.lcdWrite(LCD_LINE4)
- for char in string:
- self.lcdWrite(ord(char), Rs)
- # function to display multiple lines on the screen
- def lcdDisplayStringList(self, strings):
- for x in range(0, min(len(strings), 4)):
- self.lcdDisplayString(strings[x], x+1)
- # clear lcd and set to home
- def lcdClear(self):
- self.lcdWrite(LCD_CLEARDISPLAY)
- self.lcdWrite(LCD_RETURNHOME)
- # write the current lines to the screen
- def refresh(self):
- self.lcdDisplayString(self.line1,1)
- self.lcdDisplayString(self.line2,2)
- self.lcdDisplayString(self.line3,3)
- self.lcdDisplayString(self.line4,4)
- # turn on the backlight
- def backlightOn(self):
- self.lcdbacklight = LCD_BACKLIGHT
- self.refresh()
- # turn off the backlight
- def backlightOff(self):
- self.lcdbacklight = LCD_NOBACKLIGHT
- self.refresh()
With this file saved in your /root directory, you are now ready to create your test program.
Code (Text):
- # I2C LCD test program
- # software delay function
- def delay(d):
- while d > 0:
- d -= 1
- import onionGpio
- import lcdDriver
- # initialize LCD
- lcdAddress = 0x3F
- lcd = lcdDriver.Lcd(lcdAddress)
- lcd.backlightOn()
- gpio0 = onioGpio.OnionGpio(0)
- gpio0.setOutputDirection(0)
- value = 0
- n = 0
- lcd.lcdDisplayString("Hello",1) # display on line 1
- lcd.lcdDisplayString("World",2) # display on line 2
- delay(1000000)
- while 1:
- gpio0.setValue(value)
- lcd.lcdDisplayStringList(["Hello AAC", "n = " + str(n)])
- value = 1 - value
- n += 1
- delay(200000)
- # end of main loop
Time Functions
You may notice in the code above a software delay function was created. This can also be accomplished using the time module as shown in the modified code below:
Code (Text):
- # I2C LCD test program using time
- import onionGpio
- import lcdDriver
- import time
- # initialize LCD
- lcdAddress = 0x3F
- lcd = lcdDriver.Lcd(lcdAddress)
- lcd.backlightOn()
- gpio0 = onioGpio.OnionGpio(0)
- gpio0.setOutputDirection(0)
- value = 0
- n = 0
- lcd.lcdDisplayString("Hello",1) # display on line 1
- lcd.lcdDisplayString("World",2) # display on line 2
- time.sleep(5) # wait for 5 seconds
- while 1:
- gpio0.setValue(value)
- lcd.lcdDisplayStringList(["Hello AAC", "n = " + str(n)])
- value = 1 - value
- n += 1
- time.sleep(1) # delay for 1 second
- # end of main loop
GPIO
One of the first software tests on a new MCU is to measure how fast one can toggle a GPIO pin. For this, we can run this simple code:
Code (Text):
- # GPIO toggle test
- import onionGpio
- gpio0 = onioGpio.OnionGpio(0)
- gpio0.setOutputDirection(0)
- while 1:
- gpio0.setValue(1)
- gpio0.setValue(0)
- # end of while loop
There are two reasons for this slow speed.
- Python is an interpreted language, i.e., program script is not compiled into machine code.
- The GPIO functions are implemented as file transfer functions.
GPIO Side-track using time module
Let us briefly revisit our basic GPIO program. Here we add the time module in order to implement delays within the code. This program has been modified to flash the LED on GPIO0 once every second.
Code (Text):
- # GPIO toggle test
- import onionGpio
- import time
- DELAY_500ms = 0.5
- gpio0 = onioGpio.OnionGpio(0)
- gpio0.setOutputDirection(0)
- while 1:
- gpio0.setValue(1)
- time.sleep(DELAY_500ms)
- gpio0.setValue(0)
- time.sleep(DELAY_500ms)
- # end of while loop
FAST GPIO
A workable solution for fast GPIO is yet to come.
For the time being, you can execute the following commands from the Linux shell (command line):
fast-gpio set 0 1
fast-gpio set 0 0
... more to come, sometime later, maybe much later!!!
... if you have some ideas that you would like to see implemented, simply leave a comment below.