diff --git a/software/trespassed/lcd.py b/software/trespassed/lcd.py index 42a1431..c5884a6 100644 --- a/software/trespassed/lcd.py +++ b/software/trespassed/lcd.py @@ -1,5 +1,6 @@ import time from smbus import SMBus +from twisted.internet import reactor ADDR = 0x20 BUS = 1 @@ -7,8 +8,8 @@ BUS = 1 LCD_DATA = 1 LCD_CMD = 0 -LCD_LINE_ADDR = {0: 0x80, - 1: 0xc0} +LCD_LINE_ADDR = {0: 0x0, + 1: 0x40} # Timing constants E_PULSE = 0.0005 @@ -36,7 +37,31 @@ DB7 = (1 << 6) LCD_BACKLIGHT = (1 << 7) # HD44780 Commands +LCD_CLEAR = 1 +LCD_HOME = (1 << 1) + +LCD_ENTRY_MODE = (1 << 2) +CURSOR_INCR = (1 << 1) +CURSOR_DECR = (0 << 1) +SHIFT_ENABLE = (1 << 0) +SHIFT_DISABLE = (0 << 0) + +DISPLAY_CTRL = (1 << 3) +DISPLAY_ON = (1 << 2) +DISPLAY_OFF = (0 << 2) +CURSOR_ON = (1 << 1) +CURSOR_OFF = (0 << 1) +BLINK_ON = (1 << 0) +BLINK_OFF = (0 << 0) + +FUNC_SET = (1 << 4) +DATA_4BIT = (1 << 3) +DATA_8BIT = (0 << 3) +TWO_LINES = (1 << 2) +ONE_LINE = (0 << 2) + +SET_ADDRESS = (1 << 7) class LCD(object): def __init__(self, addr=ADDR): @@ -48,58 +73,71 @@ class LCD(object): def _init_mcp(self): # Set MCP23008 pins as outputs self._write_reg(IODIR, 0x00) - # Disable incrementing pointer - self._write_reg(IOCON, IOCON_SREAD) # Enable Backlight self._write_reg(0x09, 1 << 7) - def _write4(self, bits): - message = (bits << 3) | LCD_BACKLIGHT - self.bus.write_byte(self.addr, message) - self._latch(message) - - def write_cmd(self, byte): - self._write4((byte & 0xf0) >> 4) - self._write4((byte & 0x0f)) - def _init_hd44780(self): # Initialize, set to 4bit mode + self._write4(DB4|DB5) + # Again, this time with feeling! + self._write4(DB4|DB5) + # Again, this time with feeling! + self._write4(DB4|DB5) self._write4(DB5) - self.write_cmd((DB5 << 4) | DB7) - self.write_cmd(1) # Clear Display - self.write_cmd(0 | (DB4 | DB5 | DB6 | DB7)) # Display ON, Cursor ON, Cursor Blinking - self.write_cmd(0 | (DB5 | DB6)) # Entry Mode + # Now we're in 4bit mode, move up to normal commands + # Function Set + self.write_cmd(FUNC_SET | TWO_LINES | DATA_4BIT) # 2 lines, 4bit + # Clear Display + self.write_cmd(LCD_CLEAR) # Clear Display + self.write_cmd(LCD_HOME) # Home Display + self.write_cmd(DISPLAY_CTRL | DISPLAY_ON) # Display ON + self.write_cmd(LCD_ENTRY_MODE | CURSOR_INCR) # Entry Mode + + def _write4(self, bits, data=False): + # No shift, use DB* macros + message = bits | LCD_BACKLIGHT + if data: + message |= RS + else: + message &= ~RS + self._write_reg(GPIO, message | ENABLE) + self._latch(message) + + def write_cmd(self, byte, data=False): + # Shifts the bytes up, DB* macros don't work + high = (byte & 0xf0) >> 4 + low = byte & 0x0f + assert byte == (high << 4) | low + self._write4(high << 3, data) + self._write4(low << 3, data) + + def _write_data(self, byte): + self.write_cmd(byte, data=True) def _write_reg(self, reg, val): self.bus.write_byte_data(self.addr, reg, val) - # def _write(self, byte, backlight=LCD_BACKLIGHT_ON, mode=0): - # bits_high = (mode << 1) | ((byte & 0xF0) << 3) | backlight - # bits_low = (mode << 1) | ((byte & 0xf) << 3) | backlight - - # self.bus.write(self.addr, bits_high) - # self._latch(bits_high) - - # self.bus.write(self.addr, bits_low) - # self._latch(bits_low) - def _latch(self, bits): - time.sleep(E_DELAY) - self.bus.write_byte(self.addr, bits | ENABLE) time.sleep(E_PULSE) - self.bus.write_byte(self.addr, (bits & ~ENABLE)) + self._write_reg(GPIO, bits & ~ENABLE) time.sleep(E_DELAY) - # def write(self, line, string): - # string = string.ljust(LCD_WIDTH, " ")[:LCD_WIDTH] - # self._write(line) - # for i in range(LCD_WIDTH): - # self.write_cmd(ord(string[i]) | RS) + def write(self, line, string): + self.write_cmd(SET_ADDRESS | LCD_LINE_ADDR[line]) + string = string.ljust(LCD_WIDTH, " ")[:LCD_WIDTH] + for i in range(LCD_WIDTH): + self._write_data(ord(string[i])) + + def shutdown(self): + self.write_cmd(DISPLAY_CTRL|DISPLAY_OFF) + self._write_reg(GPIO, 0) # Turn off backlight LCD_SINGLETON = LCD() def lcd_write_status(status): - return lines = status.split('\n')[:2] for i in range(len(lines)): - LCD_SINGLETON.write(LCD_LINE_ADDR[i], lines[i]) + LCD_SINGLETON.write(i, lines[i]) + +reactor.addSystemEventTrigger('before', 'shutdown', + LCD_SINGLETON.shutdown)