simple Crystalfontz python class

James Paige

New member
I know there is already a fair amount of python code for the crystalfontz display floating around out there, but since none of it was quite what I was looking for, I threw together something myself. I am posting it here in case others may find it useful too.

It is a pure-python implementation which does not require any C code or drivers. The only dependency is pyserial.

Code:
"""
A class for working with Crystalfontz USB display devices
(C) Copyright 2009 James Paige & West Coast Aerospace, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""

#######################################################################

import serial
import time

#######################################################################

class Crystalfontz(object):

  def __init__(self, port="/dev/ttyUSB0", baud=19200):
    self.ser = serial.Serial(port, baud)
  
  def __del__(self):
    self.ser.close()
  
  def cmd(self, byte, *args):
    self.write("%c" % (byte))
    for arg in args:
      self.write("%c" % (arg))

  def write(self, str):
    for char in str:
      time.sleep(.0005)
      self.ser.write(char)

  def home(self):
    self.cmd(1)
  
  def hide_display(self):
    self.cmd(2)
  
  def unhide_display(self):
    self.cmd(3)

  def hide_cursor(self):
    self.cmd(4)
  
  def show_underline_cursor(self):
    self.cmd(5)
  
  def show_blinking_block_cursor(self):
    self.cmd(6)
  
  def show_invert_block_cursor(self):
    self.cmd(7)
  
  def backspace(self):
    self.cmd(8)
  
  def set_boot_mode(self, mode):
    if not mode in xrange(7):
      raise ValueError("boot mode %d not supported." % (mode))
    self.cmd(9, mode)
    if mode == 5:
      time.sleep(.8)
    elif mode == 6:
      time.sleep(.091)
    else:
      time.sleep(.0051)

  def boot_to_logo(self, timed=True):
    if timed:
      self.set_boot_mode(0)
    else:
      self.set_boot_mode(1)

  def boot_to_saved_logo(self, timed=True):
    if timed:
      self.set_boot_mode(2)
    else:
      self.set_boot_mode(3)

  def boot_to_saved_state(self):
    self.set_boot_mode(4)

  def save_state(self):
    self.set_boot_mode(5)

  def load_state(self):
    self.set_boot_mode(6)

  def del_at_cursor(self):
    self.cmd(11)
  
  def set_backlight(self, value=100):
    if not value in xrange(101):
      raise ValueError("Backlight value must be from 0-100, %d is not valid." % (value))
    self.cmd(14, value)

  def set_contrast(self, value=50):
    if not value in xrange(101):
      raise ValueError("Contrast value must be from 0-100, %d is not valid." % (value))
    self.cmd(15, value)

  def set_cursor(self, col, row):
    if not col in xrange(20):
      raise ValueError("Column value must be 0-19, %d is not valid." % (col))
    if not row in xrange(4):
      raise ValueError("Row value must be 0-3, %d is not valid." % (row))
    self.cmd(17, col, row)

  def set_scroll(self, value):
    if value:
      self.cmd(19)
    else:
      self.cmd(20)

  def set_wrap(self, value):
    if value:
      self.cmd(23)
    else:
      self.cmd(24)

  def set_marquee_char(self, index, char):
    if not index in xrange(20):
      raise ValueError("Marquee char index must be 0-19, %d is not valid." % (index))
    if len(char) <> 1:
      raise ValueError("Marquee char should be a single character, not '%s'" % (char))
    self.cmd(21, index, ord(char))

  def clear_marquee(self):
    for i in xrange(20):
      self.set_marquee_char(i, " ")

  def set_marquee_string(self, str):
    self.clear_marquee()
    for i in xrange(len(str)):
      self.set_marquee_char(i, str[i])

  def start_marquee(self, line, step=1, delay=20):
    if not line in xrange(4):
      raise ValueError("Marquee line must be 0-3, %d is not valid." % (line))
    if not step in xrange(1, 7):
      raise ValueError("Marquee step must be 1-6, %d is not valid." % (step))
    if not delay in xrange(5, 101):
      raise ValueError("Marquee delay must be 5-100, %d is not valid." % (delay))
    self.cmd(22, line, step, delay)

  def stop_marquee(self):
    self.cmd(22, 255, 1, 5)

  def reboot(self):
    # First flush any possible pending command
    self.write(" " * 9)
    # Then send the reboot code
    self.cmd(26, 26)
    time.sleep(1.5)

  def cursor_up(self):
    self.cmd(27, 91, 65)
    
  def cursor_down(self):
    self.cmd(27, 91, 66)
    
  def cursor_right(self):
    self.cmd(27, 91, 67)

  def cursor_left(self):
    self.cmd(27, 91, 68)

  def big_digit(self, n, start_col=0, mode=0):
    if not mode in xrange(2):
      raise ValueError("Mode must be 0-1, %d is invalid." % (mode))
    if not start_col in xrange(18-mode):
      raise ValueError("Start column must be 0-%d, %d is invalid." % (17-mode, start_col))
    if not n in xrange(10):
      raise ValueError("%d is not a valid digit." % (n))
    self.cmd(28, mode, start_col, "%d" % (n))

  def big_number(self, n, start_col=0, mode=0, spacing=1):
    pos = start_col
    skip = 3 + mode + spacing
    for char in "%d" % (n):
      self.big_digit(int(char), pos, mode)
      pos += skip

  def huge_digit(self, n, start_col=0):
    self.big_digit(n, start_col, 1)

  def huge_number(self, n, start_col=0, spacing=1):
    self.big_number(n, start_col, 1, spacing)

  def show_info(self):
    self.cmd(31)

  def clear_row(self, row):
    if not row in xrange(4):
      raise ValueError("Row value must be 0-3, %d is not valid." % (row))
    for col in xrange(20):
      self.set_cursor(col, row)
      self.del_at_cursor()
    self.set_cursor(0, row)

  def clear_screen(self):
    for row in xrange(4):
      self.clear_row(row)
    self.home()

#######################################################################
Looking for additional LCD resources? Check out our LCD blog for the latest developments in LCD technology.
 

Zephrant

New member
Thank you, that looks very useful.

I don't suppose anyone has some code examples using the above? Just something that sends a string or two would help me understand the syntax.
 

James Paige

New member
Here is a simple example

Code:
from crystalfontz import Crystalfontz
lcd = Crystalfontz()
lcd.clear_screen()
lcd.write("Hello, World!")
 
Top