Source code for output.drivers.hd44780

#!/usr/bin/python

#
# based on code from Adafruit, lrvick and LiquidCrystal
# lrvick - https://github.com/lrvick/raspi-hd44780/blob/master/hd44780.py
# LiquidCrystal - https://github.com/arduino/Arduino/blob/master/libraries/LiquidCrystal/LiquidCrystal.cpp
# Adafruit - https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code
#

from time import sleep

def delayMicroseconds(microseconds):
    seconds = microseconds / float(1000000)  # divide microseconds by 1 million for seconds
    sleep(seconds)

def delay(milliseconds):
    seconds = milliseconds / float(1000)  # divide microseconds by 1 million for seconds
    sleep(seconds)


[docs]class HD44780(): """An object that provides high-level functions for interaction with display. It contains all the high-level logic and exposes an interface for system and applications to use.""" # 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 # 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 # 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 row_offsets = [0x00, 0x40, 0x14, 0x54] display_function = LCD_FUNCTIONSET | LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS displaycontrol = 0x0c displaymode = 0x07 busy_flag = False buffer = " " redraw_coefficient = 0.5 type = ["char"] #Variable for future compatibility with graphical displays
[docs] def __init__(self, cols = 16, rows=2, do_init = True, debug = False, buffering = True, **kwargs): """ Sets variables for high-level functions. Kwargs: * ``rows`` (default=2): rows of the connected display * ``cols`` (default=16): columns of the connected display * ``debug`` (default=False): debug mode which prints out the commands sent to display * ``**kwargs``: all the other arguments, get passed further to HD44780.init_display() function""" self.cols = cols self.rows = rows self.debug = debug self.buffering = buffering if self.buffering: #Init the buffer self.buffer = [" "*self.cols for i in range(self.rows)] if do_init: self.init_display(**kwargs)
[docs] def init_display(self, autoscroll=False, **kwargs): """Initializes HD44780 controller. Kwargs: * ``autoscroll``: Controls whether autoscroll-on-char-print is enabled upon initialization. """ self.write_byte(0x30) # initialization delay(20) self.write_byte(0x30) # initialization delay(20) self.write_byte(0x30) # initialization delay(20) self.home() self.write_byte(self.display_function) self.noDisplay() if autoscroll: self.autoscroll() else: self.noAutoscroll() self.clear() self.display()
[docs] def display_data(self, *args): """Displays data on display. This function checks if the display contents can be redrawn faster by buffering them and checking the output, then either changes characters one-by-one or redraws the screen completely. ``*args`` is a list of strings, where each string corresponds to a row of the display, starting with 0.""" #Formatting the args list to simplify the processing args = list(args[:self.rows]) #Cut it to our max length and convert to list so we can change it for i, string in enumerate(args): #Pad each string args[i] = string[:self.cols].ljust(self.cols) if len(args) < self.rows: #Pad with empty strings if it's not yet padded for i in range(self.rows-len(args)): args.append(" "*self.cols) diffs = [[] for i in range(self.rows)] for i, string in enumerate(args): for j, char in enumerate(string): if self.buffer[i][j] != char: diffs[i].append(j) if float(sum([len(diff) for diff in diffs]))/(self.rows*self.cols) > self.redraw_coefficient: self._display_data(*args) #Redrawing the display self.buffer = args else: for row_num, row_diffs in enumerate(diffs): for i, char_cpos in enumerate(row_diffs): self.setCursor(row_num, char_cpos) self.write_byte(ord(args[row_num][char_cpos]), char_mode=True) self.buffer = args
def _display_data(self, *args): """Displays data on display. This function does the actual work of printing things to display. ``*args`` is a list of strings, where each string corresponds to a row of the display, starting with 0.""" while self.busy_flag: sleep(0.01) self.busy_flag = True self.clear() args = args[:self.rows] for line, arg in enumerate(args): self.setCursor(line, 0) self.println(arg[:self.cols].ljust(self.cols)) self.busy_flag = False
[docs] def println(self, line): """Prints a line on the screen (assumes position is set as intended)""" for char in line: self.write_byte(ord(char), char_mode=True)
[docs] def home(self): """Returns cursor to home position. If the display is being scrolled, reverts scrolled data to initial position..""" self.write_byte(self.LCD_RETURNHOME) # set cursor position to zero delayMicroseconds(3000) # this command takes a long time!
[docs] def clear(self): """Clears the display.""" self.write_byte(self.LCD_CLEARDISPLAY) # command to clear display delayMicroseconds(3000) # 3000 microsecond sleep, clearing the display takes a long time
[docs] def setCursor(self, row, col): """ Set current input cursor to ``row`` and ``column`` specified """ self.write_byte(self.LCD_SETDDRAMADDR | (col + self.row_offsets[row]))
[docs] def createChar(self, char_num, char_contents): """Stores a character in the LCD memory so that it can be used later. char_num has to be between 0 and 7 (including) char_contents is a list of 8 bytes (only 5 LSBs are used)""" if type(char_num) != int or not char_num in range(8): raise ValueError("Invalid char_num!") self.write_byte(self.LCD_SETCGRAMADDR | (char_num << 3)) try: for i in range(8): self.write_byte(char_contents[i], char_mode=True) except IndexError: raise ValueError("Invalid char_contents!") finally: self.setCursor(0, 0)
[docs] def noDisplay(self): """ Turn the display off (quickly) """ self.displaycontrol &= ~self.LCD_DISPLAYON self.write_byte(self.LCD_DISPLAYCONTROL | self.displaycontrol)
[docs] def display(self): """ Turn the display on (quickly) """ self.displaycontrol |= self.LCD_DISPLAYON self.write_byte(self.LCD_DISPLAYCONTROL | self.displaycontrol)
[docs] def noCursor(self): """ Turns the underline cursor off """ self.displaycontrol &= ~self.LCD_CURSORON self.write_byte(self.LCD_DISPLAYCONTROL | self.displaycontrol)
[docs] def cursor(self): """ Turns the underline cursor on """ self.displaycontrol |= self.LCD_CURSORON self.write_byte(self.LCD_DISPLAYCONTROL | self.displaycontrol)
[docs] def scrollDisplayLeft(self): """ These commands scroll the display without changing the RAM """ self.write_byte(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVELEFT)
[docs] def scrollDisplayRight(self): """ These commands scroll the display without changing the RAM """ self.write_byte(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVERIGHT)
[docs] def leftToRight(self): """ This is for text that flows Left to Right """ self.displaymode |= self.LCD_ENTRYLEFT self.write_byte(self.LCD_ENTRYMODESET | self.displaymode)
[docs] def rightToLeft(self): """ This is for text that flows Right to Left """ self.displaymode &= ~self.LCD_ENTRYLEFT self.write_byte(self.LCD_ENTRYMODESET | self.displaymode)
[docs] def autoscroll(self): """ This will 'right justify' text from the cursor """ self.displaymode |= self.LCD_ENTRYSHIFTINCREMENT self.write_byte(self.LCD_ENTRYMODESET | self.displaymode)
[docs] def noAutoscroll(self): """ This will 'left justify' text from the cursor """ self.displaymode &= ~self.LCD_ENTRYSHIFTINCREMENT self.write_byte(self.LCD_ENTRYMODESET | self.displaymode)