Python Developer's Guide

LK/ELK/VK/PK/OK/MX/GLK/EGLK/GVK/GLT Series

Moderators: Henry, Mods

Post Reply
leetrout
LCD?
Posts: 3
Joined: Sun Jul 26, 2009 12:20 am

Python Developer's Guide

Post by leetrout »

I had a hard time finding a source for all this info, so I thought I would make my contribution and put all the info I found in one location.

Assuming you have python running on your box (looks like Windows only at this point...), you will need the following:

1. pySerial... http://pyserial.sourceforge.net/ (7/09)
2. pywin32... http://starship.python.net/crew/mhammon ... loads.html (7/09)

(Hopefully those links remain accurate and alive for a while)

You could optionally check out PyUSB (http://bleyer.org/pyusb/) if you really wanted a challenge, but I found Matrix Orbital's FTDI driver and COM Port emulation to be much easier. (And it works in Windows 7).

I bought the screen way back in '02 or '03 and I know it's an MX2, but I didn't know which section had the correct manual online since there's no MX section, so I went with the LK204 for reference and that worked for me. (MO Admins, is there any way this could be fixed in your Manuals section?)

http://www.matrixorbital.ca/manuals/LK_ ... 04-24-USB/

With these tools in hand I spent over 2 hours trying to figure out why any of the commands I sent to the screen weren't working. Then I realized, it's all about the baud. (Maybe everyone else knows this already?) In hopes of saving other people some frustration, here's my quick start guide.

pySerial and the MX2 LCD Quickstart

Overview
  • 1. Find the right port (mine has always been COM 3). There are examples on the pySerial page (http://pyserial.sourceforge.net/example ... rial-ports)
    2. Import serial
    3. Connect at the screen's default baud (in the manual, but you can try 19200)
    4. Set up some constants to make life easier
Once you have serial and pywin32 set up you can fire up idle or your prefered IDE / shell and try the following:

Code: Select all

import serial
display = serial.Serial(2, baud=19200 )
display.write(chr(254)+chr(88))
display.write("HELLO WORLD!")
Breakdown

Code: Select all

import serial
We import the serial module

Code: Select all

display = serial.Serial(2, baud=19200)
We instantiate Serial as display, connecting to COM 3 (ports are zero based, ids are not, COM 1 = 0, COM 2 = 1, so on and so forth) and we set the baud to the default from out manual, 19200 in my case. If it is too low it won't work properly.

Code: Select all

display.write(chr(254)+chr(88))
This is the command to clear the screen. Commands for the LK begin with the byte 0xFE (hex) which is 254 in decimal, so we use chr([DECIMAL_VALUE]) to convert it. The following byte is the clear command, 0x58 or chr(88). You could also use display.write('\xfe\x58') \x## is hex notation within a string in python.

Code: Select all

display.write("HELLO WORLD!")
This should print the text to your LCD :)

As you continue to code, it's much easier if you define some constants to use. I used the following for my screen:

Code: Select all

#constants
## basic utils
NULL = '\x00'
CLEAR = '\xfe\x58'
CMD = '\xfe'
BACKLIGHT_ON = '\xfe\x42\x00'
BACKLIGHT_OFF = '\xfe\x46'
## bar graphs
INIT_VBG_THIN = '\xfe\x73'
INIT_VBG_THICK = '\xfe\x76'
INIT_HBG = '\xfe\x68'
I decided to use the hex string literals, but you could also use chr with the decimal values for the commands.

Key Presses
There are lots of ways you can watch for key presses if your screen has input buttons. I hacked together some code just so I could get it working. You might find this code isn't as elegant as you may need, but it works for me. I also haven't optimized it to work with Queues, which would be the ideal situation instead of just pushing to an array.

Code: Select all

import thread

LISTEN_FOR_KEYS = True
KEYS_IN = []

def thread_key_listen():
        while LISTEN_FOR_KEYS:
           key = display.read()
           KEYS_IN.append(key)
        #clean up on fail or exit
        key_listen_thread = None

def key_listen():
        key_listen_thread = thread.start_new_thread(thread_key_listen, ())
The code above is started by calling key_listen() which spawns a new thread that, as long as LISTEN_FOR_KEYS is True will constantly wait for a read on the serial port. When a key is pressed, the read closes, the key is pushed to an array, KEYS_IN and the loop continues, waiting on read again. All you have to do is check KEY_IN with a polling function (probably another thread, and should really use a Queue object) or whenever you need to look for a key press. Like I said, that was just a hack example I'm using.

Sample Display Class
Here's all the code from above wrapped in a class. The txt file is also attached to this post for easy downloading. You instantiate it by calling myDisplay = Display(PORT [baud=BAUD]), i.e. myDisplay = Display(2)

Code: Select all

import thread, serial

class Display():

    #constants
    ## basic utils
    NULL = '\x00'
    CLEAR = '\xfe\x58'
    CMD = '\xfe'
    BACKLIGHT_ON = '\xfe\x42\x00'
    BACKLIGHT_OFF = '\xfe\x46'
    ## bar graphs
    INIT_VBG_THIN = '\xfe\x73'
    INIT_VBG_THICK = '\xfe\x76'
    INIT_HBG = '\xfe\x68'
    ## input
    KEYS_IN = []
    LISTEN_FOR_KEYS = True

    def clear(self):
        '''Clears the screen'''
        self.send(self.CLEAR)
    
    def __init__(self, port, baud=19200):
        self._serial = serial.Serial(port, baud)
        self.clear()

    def send(self, data):
        '''Wrapper for our serial instance's write method'''
        self._serial.write(data)

    def close(self):
        '''Wrapper for our serial instance's close method'''
        self._serial.close()

    def draw_vbg(self, cols=[], kind="thin"):
        '''Method to draw a vertical bar graph
            cols is an array of two-tuples [(column, height)]
            example usage:
                my_display.draw_vbg([(1,2),(2,4),(3,6)])
            The example would draw a bar graph with bars on
            columns 1, 2, & 3 with heights 2, 4, & 6 (respectively)
        '''
        if kind == "thin":
            self.send(self.INIT_VBG_THIN)
        else:
            self.send(self.INIT_VBG_THICK)

        for col in cols:
            c = int(col[0]) # column to draw
            h = int(col[1]) # height of bar (0-14?)
            try:
                self.send(self.CMD+'\x3d'+chr(c)+chr(h))
            except:
                raise

    def clear_keys(self):
        '''Clears out the KEYS_IN array'''
        self.KEYS_IN = []

    # should not be called outside of class! use key_listen()
    def _thread_key_listen(self):
        while self.LISTEN_FOR_KEYS:
            key = self._serial.read()
            self.KEYS_IN.append(key)
            self.key_in(key)
        #clean up on fail or exit
        self.key_listen_thread = None
  
    def key_listen(self):
        '''starts a new thread to listen for key presses and
            inserts them into the KEYS_IN array'''
        self.key_listen_thread = thread.start_new_thread(self._thread_key_listen, ())

Attachments
display_class_for_lcdforums.txt
Sample python class that implements all the above methods.
(2.2 KiB) Downloaded 424 times

leetrout
LCD?
Posts: 3
Joined: Sun Jul 26, 2009 12:20 am

Post by leetrout »

BUMP

Is there a reason this is not included as an official dev guide?

BTW, I got it working on my mac. Have to manually load the kernel extension before plugging it in. I'll post a tutorial soon.

Post Reply