Python Developer's Guide
Posted: Sun Jul 26, 2009 2:32 pm
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
Breakdown
We import the serial module
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.
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.
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:
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.
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)
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
Code: Select all
import serial
display = serial.Serial(2, baud=19200 )
display.write(chr(254)+chr(88))
display.write("HELLO WORLD!")
Code: Select all
import serial
Code: Select all
display = serial.Serial(2, baud=19200)
Code: Select all
display.write(chr(254)+chr(88))
Code: Select all
display.write("HELLO WORLD!")
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'
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, ())
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, ())