Skip to content

Instantly share code, notes, and snippets.

@mattbrailsford
Last active August 29, 2015 14:16
Show Gist options
  • Save mattbrailsford/c262d0074683a2442d0d to your computer and use it in GitHub Desktop.
Save mattbrailsford/c262d0074683a2442d0d to your computer and use it in GitHub Desktop.
#!/usr/bin/python
#
# OLED Library for Raspberry Pi
#
# Author : Matt Brailsford/Robert Coward/Paul Carpenter (based on driver by Matt Hawkins/)
# Site : http://www.raspberrypi-spy.co.uk
# http://www.pcserviceslectronics.co.uk
# http://www.circuitbeard.co.uk
#
# Date : 06/03/2015
#
# The wiring for the OLED is as follows:
# 1 : GND
# 2 : 5V
# 3 : Contrast (0-5V)* - NOT USED
# 4 : RS (Register Select)
# 5 : R/W (Read Write) - GROUND THIS PIN
# 6 : Enable or Strobe
# 7 : Data Bit 0 - NOT USED
# 8 : Data Bit 1 - NOT USED
# 9 : Data Bit 2 - NOT USED
# 10: Data Bit 3 - NOT USED
# 11: Data Bit 4
# 12: Data Bit 5
# 13: Data Bit 6
# 14: Data Bit 7
# 15: LCD Backlight +5V** - NOT USED
# 16: LCD Backlight GND - NOT UDES
import RPi.GPIO as GPIO
import time
class OLED:
# Timing constants for low level write operations
# NOTE: Enable cycle time must be at least 1 microsecond
# NOTE2: Actually, these can be zero and the LCD will typically still work OK
EDEL_TAS = 0.00001 # Address setup time (TAS)
EDEL_PWEH = 0.00001 # Pulse width of enable (PWEH)
EDEL_TAH = 0.00001 # Address hold time (TAH)
# Timing constraints for initialisation steps - IMPORTANT!
# Note that post clear display must be at least 6.2ms for OLEDs, as opposed
# to only 1.4ms for HD44780 LCDs. This has caused confusion in the past.
DEL_INITMID = 0.01 # middle of initial write (min 4.1ms)
DEL_INITNEXT = 0.0002 # post second initial write (min 100ns)
DEL_POSTCLEAR = 0.01 # post clear display step (busy, min 6.2ms)
ROW_OFFSETS = [ 0x00, 0x40, 0x14, 0x54 ]
LCD_CLEAR = 0x01
LCD_HOME = 0x02
LCD_CGRAM = 0x40
LCD_DGRAM = 0x80
LCD_CHR = True
LCD_CMD = False
def __init__(self, pinmap, columns = 16, rows = 2):
# Store values
self.pinmap = pinmap
self.lcdPins = [ self.pinmap['D7'], self.pinmap['D6'], self.pinmap['D5'], self.pinmap['D4'] ]
self.columns = columns
self.rows = rows
# Configure the GPIO to drive the LCD display correctly
GPIO.setmode(GPIO.BCM) # Use BCM GPIO numbers
GPIO.setwarnings(False)
# setup all output pins for driving LCD display
GPIO.setup(self.pinmap['E'], GPIO.OUT) # E
# PC - better safe starting state
GPIO.output(self.pinmap['E'], 0) # set low as idle state
GPIO.setup(self.pinmap['RS'], GPIO.OUT) # RS
# PC - more maintainable initialisation
for val in self.lcdPins: # enable DB7 to DB4
GPIO.setup(val, GPIO.OUT)
GPIO.output(val, 0) # set low
# Initialise display into 4 bit mode, using recommended delays
self.write_byte(0x33, self.LCD_CMD, self.DEL_INITNEXT, self.DEL_INITMID)
self.write_byte(0x32, self.LCD_CMD, self.DEL_INITNEXT)
# Now perform remainder of display init in 4 bit mode - IMPORTANT!
# These steps MUST be exactly as follows, as OLEDs in particular are rather fussy
self.write_byte(0x28, self.LCD_CMD, self.DEL_INITNEXT) # two lines and correct font
self.write_byte(0x08, self.LCD_CMD, self.DEL_INITNEXT) # display OFF, cursor/blink off
self.write_byte(0x01, self.LCD_CMD, self.DEL_POSTCLEAR) # clear display, waiting for longer delay
self.write_byte(0x06, self.LCD_CMD, self.DEL_INITNEXT) # entry mode set
# extra steps required for OLED initialisation (no effect on LCD)
self.write_byte(0x17, self.LCD_CMD, self.DEL_INITNEXT) # character mode, power on
# now turn on the display, ready for use - IMPORTANT!
self.write_byte(0x0C, self.LCD_CMD, self.DEL_INITNEXT) # display on, cursor/blink off
# ==============================================================================
# Defines a new custom character in the CGRAM
# The index specifies the CGRAM character index you wish to define
# The data specifies the character patern
def define_char(self, index, data):
self.write_byte(self.LCD_CGRAM | ((index & 7) << 3), self.LCD_CMD, 0.002)
for i in range(0, 8):
self.write_byte(data[i], self.LCD_CHR)
# ==============================================================================
# Puts the cursor back in the home position
def home(self):
self.write_byte(self.LCD_HOME, self.LCD_CMD, 0.005)
# ==============================================================================
# Clears the LCD screen
def clear(self):
self.write_byte(self.LCD_HOME, self.LCD_CMD)
self.write_byte(self.LCD_CLEAR, self.LCD_CMD, 0.005)
# ==============================================================================
# Sets the cursor to a specific position
def set_position(self, x, y):
if ((x > self.columns) or (x < 0)):
return
if ((y > self.rows) or (y < 0)):
return
self.write_byte(x + (self.LCD_DGRAM | self.ROW_OFFSETS[y]), self.LCD_CMD)
# ==============================================================================
# Outputs string of characters to the LCD display line
# NOTE: Incoming string MUST be a string of simple characters with no complex
# unicode types present, as otherwise incorrect encoding will occur.
def write_string(self, message):
for i in range(len(message)):
self.write_char(ord(message[i])R)
# ==============================================================================
# Outputs char to the LCD display line
# NOTE: Incoming char MUST be a simple character and not a complex
# unicode type, as otherwise incorrect encoding will occur.
def write_char(self, char):
self.write_byte(char, self.LCD_CHR)
# ==============================================================================
# Low level routine to output a byte of data to the LCD display
# over the 4 bit interface. Two nybbles are sent, one after the other.
# The post_delay specifies optional delay to cover busy periods
# The mid_delay specifies optional delay between the 4 bit nibbles (special case)
def write_byte(self, byteVal, mode, post_delay = 0, mid_delay = 0):
# convert incoming value into 8 bit array, padding as required
bits = bin(byteVal)[2:].zfill(8)
# set mode = True for character, False for command
GPIO.output(self.pinmap['RS'], mode) # RS
# Output the four High bits
for i in range(4):
GPIO.output(self.lcdPins[i], int(bits[i]))
# Toggle 'Enable' pin, wrapping with minimum delays
time.sleep(self.EDEL_TAS)
GPIO.output(self.pinmap['E'], True)
time.sleep(self.EDEL_PWEH)
GPIO.output(self.pinmap['E'], False)
time.sleep(self.EDEL_TAH)
# Wait for extra mid delay if specified (special case)
if mid_delay > 0:
time.sleep(mid_delay)
# Output the four Low bits
for i in range(4,8):
GPIO.output(self.lcdPins[i-4], int(bits[i]))
# Toggle 'Enable' pin, wrapping with minimum delays
time.sleep(self.EDEL_TAS)
GPIO.output(self.pinmap['E'], True)
time.sleep(self.EDEL_PWEH)
GPIO.output(self.pinmap['E'], False)
time.sleep(self.EDEL_TAH)
# Wait for extra post delay if specified (covers busy period)
if post_delay > 0:
time.sleep(post_delay)
#!/usr/bin/python
import sys
import time
import RPi.GPIO as GPIO
from oled import OLED
# Define GPIO to LCD mapping (USES BCM MODE NUMBERING scheme)
oled_pinmap = {
'RS': 22,
'E': 17,
'D4': 25,
'D5': 18,
'D6': 24,
'D7': 23
}
oled = OLED(oled_pinmap, 20, 2)
oled.set_position(0, 0)
oled.write_string("Hello world!")
time.sleep(3)
oled.set_position(0, 0)
oled.write_string("circuitbeard.co.uk")
oled.set_position(0, 1)
oled.write_string("@circuitbeard")
time.sleep(3)
oled.set_position(0, 0)
oled.write_string("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
oled.set_position(0, 1)
oled.write_string("1234567890!$%^&*()")
time.sleep(3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment