Last active
December 20, 2015 10:49
-
-
Save vampjaz/6118462 to your computer and use it in GitHub Desktop.
A simple python script for RASPBERRY PI to display prices and quantities of various SparkFun Products
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# Python library for Adafruit RGB-backlit LCD plate for Raspberry Pi. | |
# Written by Adafruit Industries. MIT license. | |
# This is essentially a complete rewrite, but the calling syntax | |
# and constants are based on code from lrvick and LiquidCrystal. | |
# lrvic - https://github.com/lrvick/raspi-hd44780/blob/master/hd44780.py | |
# LiquidCrystal - https://github.com/arduino/Arduino/blob/master/libraries/LiquidCrystal/LiquidCrystal.cpp | |
from Adafruit_I2C import Adafruit_I2C | |
from time import sleep | |
class Adafruit_CharLCDPlate(Adafruit_I2C): | |
# ---------------------------------------------------------------------- | |
# Constants | |
# Port expander registers | |
MCP23017_IOCON_BANK0 = 0x0A # IOCON when Bank 0 active | |
MCP23017_IOCON_BANK1 = 0x15 # IOCON when Bank 1 active | |
# These are register addresses when in Bank 1 only: | |
MCP23017_GPIOA = 0x09 | |
MCP23017_IODIRB = 0x10 | |
MCP23017_GPIOB = 0x19 | |
# Port expander input pin definitions | |
SELECT = 0 | |
RIGHT = 1 | |
DOWN = 2 | |
UP = 3 | |
LEFT = 4 | |
# LED colors | |
OFF = 0x00 | |
RED = 0x01 | |
GREEN = 0x02 | |
BLUE = 0x04 | |
YELLOW = RED + GREEN | |
TEAL = GREEN + BLUE | |
VIOLET = RED + BLUE | |
WHITE = RED + GREEN + BLUE | |
ON = RED + GREEN + BLUE | |
# LCD 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 on/off control | |
LCD_DISPLAYON = 0x04 | |
LCD_DISPLAYOFF = 0x00 | |
LCD_CURSORON = 0x02 | |
LCD_CURSOROFF = 0x00 | |
LCD_BLINKON = 0x01 | |
LCD_BLINKOFF = 0x00 | |
# Flags for display entry mode | |
LCD_ENTRYRIGHT = 0x00 | |
LCD_ENTRYLEFT = 0x02 | |
LCD_ENTRYSHIFTINCREMENT = 0x01 | |
LCD_ENTRYSHIFTDECREMENT = 0x00 | |
# Flags for display/cursor shift | |
LCD_DISPLAYMOVE = 0x08 | |
LCD_CURSORMOVE = 0x00 | |
LCD_MOVERIGHT = 0x04 | |
LCD_MOVELEFT = 0x00 | |
# ---------------------------------------------------------------------- | |
# Constructor | |
def __init__(self, busnum=-1, addr=0x20, debug=False): | |
self.i2c = Adafruit_I2C(addr, busnum, debug) | |
# I2C is relatively slow. MCP output port states are cached | |
# so we don't need to constantly poll-and-change bit states. | |
self.porta, self.portb, self.ddrb = 0, 0, 0b00010000 | |
# Set MCP23017 IOCON register to Bank 0 with sequential operation. | |
# If chip is already set for Bank 0, this will just write to OLATB, | |
# which won't seriously bother anything on the plate right now | |
# (blue backlight LED will come on, but that's done in the next | |
# step anyway). | |
self.i2c.bus.write_byte_data( | |
self.i2c.address, self.MCP23017_IOCON_BANK1, 0) | |
# Brute force reload ALL registers to known state. This also | |
# sets up all the input pins, pull-ups, etc. for the Pi Plate. | |
self.i2c.bus.write_i2c_block_data( | |
self.i2c.address, 0, | |
[ 0b00111111, # IODIRA R+G LEDs=outputs, buttons=inputs | |
self.ddrb , # IODIRB LCD D7=input, Blue LED=output | |
0b00111111, # IPOLA Invert polarity on button inputs | |
0b00000000, # IPOLB | |
0b00000000, # GPINTENA Disable interrupt-on-change | |
0b00000000, # GPINTENB | |
0b00000000, # DEFVALA | |
0b00000000, # DEFVALB | |
0b00000000, # INTCONA | |
0b00000000, # INTCONB | |
0b00000000, # IOCON | |
0b00000000, # IOCON | |
0b00111111, # GPPUA Enable pull-ups on buttons | |
0b00000000, # GPPUB | |
0b00000000, # INTFA | |
0b00000000, # INTFB | |
0b00000000, # INTCAPA | |
0b00000000, # INTCAPB | |
self.porta, # GPIOA | |
self.portb, # GPIOB | |
self.porta, # OLATA 0 on all outputs; side effect of | |
self.portb ]) # OLATB turning on R+G+B backlight LEDs. | |
# Switch to Bank 1 and disable sequential operation. | |
# From this point forward, the register addresses do NOT match | |
# the list immediately above. Instead, use the constants defined | |
# at the start of the class. Also, the address register will no | |
# longer increment automatically after this -- multi-byte | |
# operations must be broken down into single-byte calls. | |
self.i2c.bus.write_byte_data( | |
self.i2c.address, self.MCP23017_IOCON_BANK0, 0b10100000) | |
self.displayshift = (self.LCD_CURSORMOVE | | |
self.LCD_MOVERIGHT) | |
self.displaymode = (self.LCD_ENTRYLEFT | | |
self.LCD_ENTRYSHIFTDECREMENT) | |
self.displaycontrol = (self.LCD_DISPLAYON | | |
self.LCD_CURSOROFF | | |
self.LCD_BLINKOFF) | |
self.write(0x33) # Init | |
self.write(0x32) # Init | |
self.write(0x28) # 2 line 5x8 matrix | |
self.write(self.LCD_CLEARDISPLAY) | |
self.write(self.LCD_CURSORSHIFT | self.displayshift) | |
self.write(self.LCD_ENTRYMODESET | self.displaymode) | |
self.write(self.LCD_DISPLAYCONTROL | self.displaycontrol) | |
self.write(self.LCD_RETURNHOME) | |
# ---------------------------------------------------------------------- | |
# Write operations | |
# The LCD data pins (D4-D7) connect to MCP pins 12-9 (PORTB4-1), in | |
# that order. Because this sequence is 'reversed,' a direct shift | |
# won't work. This table remaps 4-bit data values to MCP PORTB | |
# outputs, incorporating both the reverse and shift. | |
flip = ( 0b00000000, 0b00010000, 0b00001000, 0b00011000, | |
0b00000100, 0b00010100, 0b00001100, 0b00011100, | |
0b00000010, 0b00010010, 0b00001010, 0b00011010, | |
0b00000110, 0b00010110, 0b00001110, 0b00011110 ) | |
# Low-level 4-bit interface for LCD output. This doesn't actually | |
# write data, just returns a byte array of the PORTB state over time. | |
# Can concatenate the output of multiple calls (up to 8) for more | |
# efficient batch write. | |
def out4(self, bitmask, value): | |
hi = bitmask | self.flip[value >> 4] | |
lo = bitmask | self.flip[value & 0x0F] | |
return [hi | 0b00100000, hi, lo | 0b00100000, lo] | |
# The speed of LCD accesses is inherently limited by I2C through the | |
# port expander. A 'well behaved program' is expected to poll the | |
# LCD to know that a prior instruction completed. But the timing of | |
# most instructions is a known uniform 37 mS. The enable strobe | |
# can't even be twiddled that fast through I2C, so it's a safe bet | |
# with these instructions to not waste time polling (which requires | |
# several I2C transfers for reconfiguring the port direction). | |
# The D7 pin is set as input when a potentially time-consuming | |
# instruction has been issued (e.g. screen clear), as well as on | |
# startup, and polling will then occur before more commands or data | |
# are issued. | |
pollables = ( LCD_CLEARDISPLAY, LCD_RETURNHOME ) | |
# Write byte, list or string value to LCD | |
def write(self, value, char_mode=False): | |
""" Send command/data to LCD """ | |
# If pin D7 is in input state, poll LCD busy flag until clear. | |
if self.ddrb & 0b00010000: | |
lo = (self.portb & 0b00000001) | 0b01000000 | |
hi = lo | 0b00100000 # E=1 (strobe) | |
self.i2c.bus.write_byte_data( | |
self.i2c.address, self.MCP23017_GPIOB, lo) | |
while True: | |
# Strobe high (enable) | |
self.i2c.bus.write_byte(self.i2c.address, hi) | |
# First nybble contains busy state | |
bits = self.i2c.bus.read_byte(self.i2c.address) | |
# Strobe low, high, low. Second nybble (A3) is ignored. | |
self.i2c.bus.write_i2c_block_data( | |
self.i2c.address, self.MCP23017_GPIOB, [lo, hi, lo]) | |
if (bits & 0b00000010) == 0: break # D7=0, not busy | |
self.portb = lo | |
# Polling complete, change D7 pin to output | |
self.ddrb &= 0b11101111 | |
self.i2c.bus.write_byte_data(self.i2c.address, | |
self.MCP23017_IODIRB, self.ddrb) | |
bitmask = self.portb & 0b00000001 # Mask out PORTB LCD control bits | |
if char_mode: bitmask |= 0b10000000 # Set data bit if not a command | |
# If string or list, iterate through multiple write ops | |
if isinstance(value, str): | |
last = len(value) - 1 # Last character in string | |
data = [] # Start with blank list | |
for i, v in enumerate(value): # For each character... | |
# Append 4 bytes to list representing PORTB over time. | |
# First the high 4 data bits with strobe (enable) set | |
# and unset, then same with low 4 data bits (strobe 1/0). | |
data.extend(self.out4(bitmask, ord(v))) | |
# I2C block data write is limited to 32 bytes max. | |
# If limit reached, write data so far and clear. | |
# Also do this on last byte if not otherwise handled. | |
if (len(data) >= 32) or (i == last): | |
self.i2c.bus.write_i2c_block_data( | |
self.i2c.address, self.MCP23017_GPIOB, data) | |
self.portb = data[-1] # Save state of last byte out | |
data = [] # Clear list for next iteration | |
elif isinstance(value, list): | |
# Same as above, but for list instead of string | |
last = len(value) - 1 | |
data = [] | |
for i, v in enumerate(value): | |
data.extend(self.out4(bitmask, v)) | |
if (len(data) >= 32) or (i == last): | |
self.i2c.bus.write_i2c_block_data( | |
self.i2c.address, self.MCP23017_GPIOB, data) | |
self.portb = data[-1] | |
data = [] | |
else: | |
# Single byte | |
data = self.out4(bitmask, value) | |
self.i2c.bus.write_i2c_block_data( | |
self.i2c.address, self.MCP23017_GPIOB, data) | |
self.portb = data[-1] | |
# If a poll-worthy instruction was issued, reconfigure D7 | |
# pin as input to indicate need for polling on next call. | |
if (not char_mode) and (value in self.pollables): | |
self.ddrb |= 0b00010000 | |
self.i2c.bus.write_byte_data(self.i2c.address, | |
self.MCP23017_IODIRB, self.ddrb) | |
# ---------------------------------------------------------------------- | |
# Utility methods | |
def begin(self, cols, lines): | |
self.currline = 0 | |
self.numlines = lines | |
self.clear() | |
# Puts the MCP23017 back in Bank 0 + sequential write mode so | |
# that other code using the 'classic' library can still work. | |
# Any code using this newer version of the library should | |
# consider adding an atexit() handler that calls this. | |
def stop(self): | |
self.porta = 0b11000000 # Turn off LEDs on the way out | |
self.portb = 0b00000001 | |
sleep(0.0015) | |
self.i2c.bus.write_byte_data( | |
self.i2c.address, self.MCP23017_IOCON_BANK1, 0) | |
self.i2c.bus.write_i2c_block_data( | |
self.i2c.address, 0, | |
[ 0b00111111, # IODIRA | |
self.ddrb , # IODIRB | |
0b00000000, # IPOLA | |
0b00000000, # IPOLB | |
0b00000000, # GPINTENA | |
0b00000000, # GPINTENB | |
0b00000000, # DEFVALA | |
0b00000000, # DEFVALB | |
0b00000000, # INTCONA | |
0b00000000, # INTCONB | |
0b00000000, # IOCON | |
0b00000000, # IOCON | |
0b00111111, # GPPUA | |
0b00000000, # GPPUB | |
0b00000000, # INTFA | |
0b00000000, # INTFB | |
0b00000000, # INTCAPA | |
0b00000000, # INTCAPB | |
self.porta, # GPIOA | |
self.portb, # GPIOB | |
self.porta, # OLATA | |
self.portb ]) # OLATB | |
def clear(self): | |
self.write(self.LCD_CLEARDISPLAY) | |
def home(self): | |
self.write(self.LCD_RETURNHOME) | |
row_offsets = ( 0x00, 0x40, 0x14, 0x54 ) | |
def setCursor(self, col, row): | |
if row > self.numlines: row = self.numlines - 1 | |
elif row < 0: row = 0 | |
self.write(self.LCD_SETDDRAMADDR | (col + self.row_offsets[row])) | |
def display(self): | |
""" Turn the display on (quickly) """ | |
self.displaycontrol |= self.LCD_DISPLAYON | |
self.write(self.LCD_DISPLAYCONTROL | self.displaycontrol) | |
def noDisplay(self): | |
""" Turn the display off (quickly) """ | |
self.displaycontrol &= ~self.LCD_DISPLAYON | |
self.write(self.LCD_DISPLAYCONTROL | self.displaycontrol) | |
def cursor(self): | |
""" Underline cursor on """ | |
self.displaycontrol |= self.LCD_CURSORON | |
self.write(self.LCD_DISPLAYCONTROL | self.displaycontrol) | |
def noCursor(self): | |
""" Underline cursor off """ | |
self.displaycontrol &= ~self.LCD_CURSORON | |
self.write(self.LCD_DISPLAYCONTROL | self.displaycontrol) | |
def ToggleCursor(self): | |
""" Toggles the underline cursor On/Off """ | |
self.displaycontrol ^= self.LCD_CURSORON | |
self.write(self.LCD_DISPLAYCONTROL | self.displaycontrol) | |
def blink(self): | |
""" Turn on the blinking cursor """ | |
self.displaycontrol |= self.LCD_BLINKON | |
self.write(self.LCD_DISPLAYCONTROL | self.displaycontrol) | |
def noBlink(self): | |
""" Turn off the blinking cursor """ | |
self.displaycontrol &= ~self.LCD_BLINKON | |
self.write(self.LCD_DISPLAYCONTROL | self.displaycontrol) | |
def ToggleBlink(self): | |
""" Toggles the blinking cursor """ | |
self.displaycontrol ^= self.LCD_BLINKON | |
self.write(self.LCD_DISPLAYCONTROL | self.displaycontrol) | |
def scrollDisplayLeft(self): | |
""" These commands scroll the display without changing the RAM """ | |
self.displayshift = self.LCD_DISPLAYMOVE | self.LCD_MOVELEFT | |
self.write(self.LCD_CURSORSHIFT | self.displayshift) | |
def scrollDisplayRight(self): | |
""" These commands scroll the display without changing the RAM """ | |
self.displayshift = self.LCD_DISPLAYMOVE | self.LCD_MOVERIGHT | |
self.write(self.LCD_CURSORSHIFT | self.displayshift) | |
def leftToRight(self): | |
""" This is for text that flows left to right """ | |
self.displaymode |= self.LCD_ENTRYLEFT | |
self.write(self.LCD_ENTRYMODESET | self.displaymode) | |
def rightToLeft(self): | |
""" This is for text that flows right to left """ | |
self.displaymode &= ~self.LCD_ENTRYLEFT | |
self.write(self.LCD_ENTRYMODESET | self.displaymode) | |
def autoscroll(self): | |
""" This will 'right justify' text from the cursor """ | |
self.displaymode |= self.LCD_ENTRYSHIFTINCREMENT | |
self.write(self.LCD_ENTRYMODESET | self.displaymode) | |
def noAutoscroll(self): | |
""" This will 'left justify' text from the cursor """ | |
self.displaymode &= ~self.LCD_ENTRYSHIFTINCREMENT | |
self.write(self.LCD_ENTRYMODESET | self.displaymode) | |
def createChar(self, location, bitmap): | |
self.write(self.LCD_SETCGRAMADDR | ((location & 7) << 3)) | |
self.write(bitmap, True) | |
self.write(self.LCD_SETDDRAMADDR) | |
def message(self, text): | |
""" Send string to LCD. Newline wraps to second line""" | |
lines = str(text).split('\n') # Split at newline(s) | |
for i, line in enumerate(lines): # For each substring... | |
if i > 0: # If newline(s), | |
self.write(0xC0) # set DDRAM address to 2nd line | |
self.write(line, True) # Issue substring | |
def backlight(self, color): | |
c = ~color | |
self.porta = (self.porta & 0b00111111) | ((c & 0b011) << 6) | |
self.portb = (self.portb & 0b11111110) | ((c & 0b100) >> 2) | |
# Has to be done as two writes because sequential operation is off. | |
self.i2c.bus.write_byte_data( | |
self.i2c.address, self.MCP23017_GPIOA, self.porta) | |
self.i2c.bus.write_byte_data( | |
self.i2c.address, self.MCP23017_GPIOB, self.portb) | |
# Read state of single button | |
def buttonPressed(self, b): | |
return (self.i2c.readU8(self.MCP23017_GPIOA) >> b) & 1 | |
# Read and return bitmask of combined button state | |
def buttons(self): | |
return self.i2c.readU8(self.MCP23017_GPIOA) & 0b11111 | |
# ---------------------------------------------------------------------- | |
# Test code | |
if __name__ == '__main__': | |
lcd = Adafruit_CharLCDPlate() | |
lcd.begin(16, 2) | |
lcd.clear() | |
lcd.message("Adafruit RGB LCD\nPlate w/Keypad!") | |
sleep(1) | |
col = (('Red' , lcd.RED) , ('Yellow', lcd.YELLOW), ('Green' , lcd.GREEN), | |
('Teal', lcd.TEAL), ('Blue' , lcd.BLUE) , ('Violet', lcd.VIOLET), | |
('Off' , lcd.OFF) , ('On' , lcd.ON)) | |
print "Cycle thru backlight colors" | |
for c in col: | |
print c[0] | |
lcd.clear() | |
lcd.message(c[0]) | |
lcd.backlight(c[1]) | |
sleep(0.5) | |
btn = ((lcd.SELECT, 'Select', lcd.ON), | |
(lcd.LEFT , 'Left' , lcd.RED), | |
(lcd.UP , 'Up' , lcd.BLUE), | |
(lcd.DOWN , 'Down' , lcd.GREEN), | |
(lcd.RIGHT , 'Right' , lcd.VIOLET)) | |
print "Try buttons on plate" | |
lcd.clear() | |
lcd.message("Try buttons") | |
prev = -1 | |
while True: | |
for b in btn: | |
if lcd.buttonPressed(b[0]): | |
if b is not prev: | |
print b[1] | |
lcd.clear() | |
lcd.message(b[1]) | |
lcd.backlight(b[2]) | |
prev = b | |
break |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
import smbus | |
# =========================================================================== | |
# Adafruit_I2C Class | |
# =========================================================================== | |
class Adafruit_I2C : | |
@staticmethod | |
def getPiRevision(): | |
"Gets the version number of the Raspberry Pi board" | |
# Courtesy quick2wire-python-api | |
# https://github.com/quick2wire/quick2wire-python-api | |
try: | |
with open('/proc/cpuinfo','r') as f: | |
for line in f: | |
if line.startswith('Revision'): | |
return 1 if line.rstrip()[-1] in ['1','2'] else 2 | |
except: | |
return 0 | |
@staticmethod | |
def getPiI2CBusNumber(): | |
# Gets the I2C bus number /dev/i2c# | |
return 1 if Adafruit_I2C.getPiRevision() > 1 else 0 | |
def __init__(self, address, busnum=-1, debug=False): | |
self.address = address | |
# By default, the correct I2C bus is auto-detected using /proc/cpuinfo | |
# Alternatively, you can hard-code the bus version below: | |
# self.bus = smbus.SMBus(0); # Force I2C0 (early 256MB Pi's) | |
# self.bus = smbus.SMBus(1); # Force I2C1 (512MB Pi's) | |
self.bus = smbus.SMBus( | |
busnum if busnum >= 0 else Adafruit_I2C.getPiI2CBusNumber()) | |
self.debug = debug | |
def reverseByteOrder(self, data): | |
"Reverses the byte order of an int (16-bit) or long (32-bit) value" | |
# Courtesy Vishal Sapre | |
byteCount = len(hex(data)[2:].replace('L','')[::2]) | |
val = 0 | |
for i in range(byteCount): | |
val = (val << 8) | (data & 0xff) | |
data >>= 8 | |
return val | |
def errMsg(self): | |
print "Error accessing 0x%02X: Check your I2C address" % self.address | |
return -1 | |
def write8(self, reg, value): | |
"Writes an 8-bit value to the specified register/address" | |
try: | |
self.bus.write_byte_data(self.address, reg, value) | |
if self.debug: | |
print "I2C: Wrote 0x%02X to register 0x%02X" % (value, reg) | |
except IOError, err: | |
return self.errMsg() | |
def write16(self, reg, value): | |
"Writes a 16-bit value to the specified register/address pair" | |
try: | |
self.bus.write_word_data(self.address, reg, value) | |
if self.debug: | |
print ("I2C: Wrote 0x%02X to register pair 0x%02X,0x%02X" % | |
(value, reg, reg+1)) | |
except IOError, err: | |
return self.errMsg() | |
def writeList(self, reg, list): | |
"Writes an array of bytes using I2C format" | |
try: | |
if self.debug: | |
print "I2C: Writing list to register 0x%02X:" % reg | |
print list | |
self.bus.write_i2c_block_data(self.address, reg, list) | |
except IOError, err: | |
return self.errMsg() | |
def readList(self, reg, length): | |
"Read a list of bytes from the I2C device" | |
try: | |
results = self.bus.read_i2c_block_data(self.address, reg, length) | |
if self.debug: | |
print ("I2C: Device 0x%02X returned the following from reg 0x%02X" % | |
(self.address, reg)) | |
print results | |
return results | |
except IOError, err: | |
return self.errMsg() | |
def readU8(self, reg): | |
"Read an unsigned byte from the I2C device" | |
try: | |
result = self.bus.read_byte_data(self.address, reg) | |
if self.debug: | |
print ("I2C: Device 0x%02X returned 0x%02X from reg 0x%02X" % | |
(self.address, result & 0xFF, reg)) | |
return result | |
except IOError, err: | |
return self.errMsg() | |
def readS8(self, reg): | |
"Reads a signed byte from the I2C device" | |
try: | |
result = self.bus.read_byte_data(self.address, reg) | |
if result > 127: result -= 256 | |
if self.debug: | |
print ("I2C: Device 0x%02X returned 0x%02X from reg 0x%02X" % | |
(self.address, result & 0xFF, reg)) | |
return result | |
except IOError, err: | |
return self.errMsg() | |
def readU16(self, reg): | |
"Reads an unsigned 16-bit value from the I2C device" | |
try: | |
hibyte = self.readU8(reg) | |
lobyte = self.readU8(reg+1) | |
result = (hibyte << 8) + lobyte | |
if (self.debug): | |
print "I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, result & 0xFFFF, reg) | |
return result | |
except IOError, err: | |
return self.errMsg() | |
def readS16(self, reg): | |
"Reads a signed 16-bit value from the I2C device" | |
try: | |
hibyte = self.readS8(reg) | |
lobyte = self.readU8(reg+1) | |
result = (hibyte << 8) + lobyte | |
if (self.debug): | |
print "I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, result & 0xFFFF, reg) | |
return result | |
except IOError, err: | |
return self.errMsg() | |
def readU16Rev(self, reg): | |
"Reads an unsigned 16-bit value from the I2C device with rev byte order" | |
try: | |
lobyte = self.readU8(reg) | |
hibyte = self.readU8(reg+1) | |
result = (hibyte << 8) + lobyte | |
if (self.debug): | |
print "I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, result & 0xFFFF, reg) | |
return result | |
except IOError, err: | |
return self.errMsg() | |
def readS16Rev(self, reg): | |
"Reads a signed 16-bit value from the I2C device with rev byte order" | |
try: | |
lobyte = self.readS8(reg) | |
hibyte = self.readU8(reg+1) | |
result = (hibyte << 8) + lobyte | |
if (self.debug): | |
print "I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, result & 0xFFFF, reg) | |
return result | |
except IOError, err: | |
return self.errMsg() | |
if __name__ == '__main__': | |
try: | |
bus = Adafruit_I2C(address=0) | |
print "Default I2C bus is accessible" | |
except: | |
print "Error accessing default I2C bus" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# Copyright 2012 Daniel Berlin (with some changes by Limor Fried, | |
# Adafruit Industries) | |
# 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. | |
from Adafruit_I2C import Adafruit_I2C | |
class Adafruit_MCP230XX(Adafruit_I2C): | |
INPUT = True | |
OUTPUT = False | |
MCP23017_IODIRA = 0x00 | |
MCP23017_IODIRB = 0x01 | |
MCP23017_GPPUA = 0x0C | |
MCP23017_GPPUB = 0x0D | |
MCP23017_GPIOA = 0x12 | |
MCP23017_GPIOB = 0x13 | |
MCP23017_OLATA = 0x14 | |
MCP23017_OLATB = 0x15 | |
MCP23008_IODIR = 0x00 | |
MCP23008_GPIO = 0x09 | |
MCP23008_GPPU = 0x06 | |
MCP23008_OLAT = 0x0A | |
def __init__(self, address, num_gpios=8, busnum=-1, debug=False): | |
assert 0 < num_gpios < 17, "Number of GPIOs must be between 1 and 16" | |
self.i2c = Adafruit_I2C(address, busnum, debug) | |
self.num_gpios = num_gpios | |
self.pullups = 0 | |
# Set default pin values -- all inputs with pull-ups disabled. | |
# Current OLAT (output) value is polled, not set. | |
if num_gpios <= 8: | |
self.direction = 0xFF | |
self.i2c.write8(self.MCP23008_IODIR, self.direction) | |
self.i2c.write8(self.MCP23008_GPPU , self.pullups) | |
self.outputvalue = self.i2c.readU8(self.MCP23008_OLAT) | |
else: | |
self.direction = 0xFFFF | |
self.i2c.write16(self.MCP23017_IODIRA, self.direction) | |
self.i2c.write16(self.MCP23017_GPPUA , self.pullups) | |
self.outputvalue = self.i2c.readU16(self.MCP23017_OLATA) | |
# Set single pin to either INPUT or OUTPUT mode | |
def config(self, pin, mode): | |
assert 0 <= pin < self.num_gpios, "Pin number %s is invalid, must be between 0 and %s" % (pin, self.num_gpios-1) | |
if mode is self.INPUT: self.direction |= (1 << pin) | |
else: self.direction &= ~(1 << pin) | |
if self.num_gpios <= 8: | |
self.i2c.write8(self.MCP23008_IODIR, self.direction) | |
elif pin < 8: | |
# Replace low bits (IODIRA) | |
self.i2c.write8(self.MCP23017_IODIRA, self.direction & 0xFF) | |
else: | |
# Replace high bits (IODIRB) | |
self.i2c.write8(self.MCP23017_IODIRB, self.direction >> 8) | |
return self.direction | |
# Enable pull-up resistor on single input pin | |
def pullup(self, pin, enable, check=False): | |
assert 0 <= pin < self.num_gpios, "Pin number %s is invalid, must be between 0 and %s" % (pin, self.num_gpios-1) | |
if check: | |
assert (self.direction & (1 << pin)) != 0, "Pin %s not set to input" % pin | |
if enable: self.pullups |= (1 << pin) | |
else: self.pullups &= ~(1 << pin) | |
if self.num_gpios <= 8: | |
self.i2c.write8(self.MCP23008_GPPU, self.pullups) | |
elif pin < 8: | |
# Replace low bits (GPPUA) | |
self.i2c.write8(self.MCP23017_GPPUA, self.pullups & 0xFF) | |
else: | |
# Replace high bits (GPPUB) | |
self.i2c.write8(self.MCP23017_GPPUB, self.pullups >> 8) | |
return self.pullups | |
# Read value from single input pin | |
def input(self, pin, check=True): | |
assert 0 <= pin < self.num_gpios, "Pin number %s is invalid, must be between 0 and %s" % (pin, self.num_gpios-1) | |
if check: | |
assert (self.direction & (1 << pin)) != 0, "Pin %s not set to input" % pin | |
if self.num_gpios <= 8: | |
value = self.i2c.readU8(self.MCP23008_GPIO) | |
return (value >> pin) & 1 | |
elif pin < 8: | |
# Read from low bits (GPIOA) | |
value = self.i2c.readU8(self.MCP23017_GPIOA) | |
return (value >> pin) & 1 | |
else: | |
# Read from high bits (GPIOB) | |
value = self.i2c.readU8(self.MCP23017_GPIOB) | |
return (value >> (pin - 8)) & 1 | |
# Write value to single output pin | |
def output(self, pin, value): | |
assert 0 <= pin < self.num_gpios, "Pin number %s is invalid, must be between 0 and %s" % (pin, self.num_gpios-1) | |
# assert self.direction & (1 << pin) == 0, "Pin %s not set to output" % pin | |
if value: new = self.outputvalue | (1 << pin) | |
else: new = self.outputvalue & ~(1 << pin) | |
# Only write if pin value has changed: | |
if new is not self.outputvalue: | |
self.outputvalue = new | |
if self.num_gpios <= 8: | |
self.i2c.write8(self.MCP23008_OLAT, new) | |
elif pin < 8: | |
# Write to low bits (OLATA) | |
self.i2c.write8(self.MCP23017_OLATA, new & 0xFF) | |
else: | |
# Write to high bits (OLATB) | |
self.i2c.write8(self.MCP23017_OLATB, new >> 8) | |
return new | |
# The following two methods (inputAll and outputAll) neither assert | |
# inputs nor invoke the base class methods that handle I/O exceptions. | |
# The underlying smbus calls are invoked directly for expediency, the | |
# expectation being that any I2C access or address type errors have | |
# already been identified during initialization. | |
# Read contiguous value from all input pins | |
def inputAll(self): | |
if self.num_gpios <= 8: | |
return self.i2c.bus.read_byte_data(self.i2c.address, | |
self.MCP23008_GPIO) | |
else: | |
return self.i2c.bus.read_word_data(self.i2c.address, | |
self.MCP23017_GPIOA) | |
# Write contiguous value to all output pins | |
def outputAll(self, value): | |
self.outputvalue = value | |
if self.num_gpios <= 8: | |
self.i2c.bus.write_byte_data(self.i2c.address, | |
self.MCP23008_OLAT, value) | |
else: | |
self.i2c.bus.write_word_data(self.i2c.address, | |
self.MCP23017_OLATA, value) | |
# RPi.GPIO compatible interface for MCP23017 and MCP23008 | |
class MCP230XX_GPIO(object): | |
OUT = 0 | |
IN = 1 | |
BCM = 0 | |
BOARD = 0 | |
def __init__(self, busnum, address, num_gpios): | |
self.chip = Adafruit_MCP230XX(busnum, address, num_gpios) | |
def setmode(self, mode): | |
pass # do nothing | |
def setup(self, pin, mode): | |
self.chip.config(pin, mode) | |
def input(self, pin): | |
return self.chip.input(pin) | |
def output(self, pin, value): | |
self.chip.output(pin, value) | |
def pullup(self, pin, value): | |
self.chip.pullup(pin, value) | |
if __name__ == '__main__': | |
# **************************************************** | |
# Set num_gpios to 8 for MCP23008 or 16 for MCP23017! | |
# If you have a new Pi you may also need to add: bus=1 | |
# **************************************************** | |
mcp = Adafruit_MCP230XX(address=0x20, num_gpios=16) | |
# Set pins 0, 1, 2 as outputs | |
mcp.config(0, mcp.OUTPUT) | |
mcp.config(1, mcp.OUTPUT) | |
mcp.config(2, mcp.OUTPUT) | |
# Set pin 3 to input with the pullup resistor enabled | |
mcp.pullup(3, True) | |
# Read pin 3 and display the results | |
print "%d: %x" % (3, mcp.input(3)) | |
# Python speed test on output 0 toggling at max speed | |
while True: | |
mcp.output(0, 1) # Pin 0 High | |
mcp.output(0, 0) # Pin 0 Low |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
import time | |
from Adafruit_CharLCDPlate import Adafruit_CharLCDPlate | |
import urllib | |
import csv | |
# Initialize the LCD plate. Should auto-detect correct I2C bus. If not, | |
# pass '0' for early 256 MB Model B boards or '1' for all later versions | |
lcd = Adafruit_CharLCDPlate(1) | |
# Clear display | |
lcd.clear() | |
#sparkfun product IDs | |
productid = [11546,11868,11589,11021,11286,9716,11215,11712,8938,709,569,8653] | |
val = 1 | |
while val == 1: | |
lcd.clear() | |
lcd.message('SparkFun @\nwww.sparkfun.com') | |
time.sleep(2) | |
for i in productid: | |
sdata = urllib.urlopen('https://204.144.132.37/products/'+str(i)+'.csv') | |
csvdata = [row for row in csv.reader(sdata)] | |
name = csvdata[1][2] | |
count = csvdata[1][7] | |
price = csvdata[1][5] | |
stock = csvdata[1][6] | |
lcd.clear() | |
if stock == '1': | |
lcd.message(name+'\n'+count+' $'+price) | |
else: | |
lcd.message(name+'\nout $'+price) | |
time.sleep(3) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment