diff --git a/kladd/LCD-1602-I2C/.gitignore b/kladd/LCD-1602-I2C/.gitignore new file mode 100644 index 0000000..894a44c --- /dev/null +++ b/kladd/LCD-1602-I2C/.gitignore @@ -0,0 +1,104 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ diff --git a/kladd/LCD-1602-I2C/LCD.py b/kladd/LCD-1602-I2C/LCD.py new file mode 100644 index 0000000..03eea42 --- /dev/null +++ b/kladd/LCD-1602-I2C/LCD.py @@ -0,0 +1,95 @@ +import smbus +import time + +class LCD: + def __init__(self, pi_rev = 2, i2c_addr = 0x3F, backlight = True): + + # device constants + self.I2C_ADDR = i2c_addr + self.LCD_WIDTH = 16 # Max. characters per line + + self.LCD_CHR = 1 # Mode - Sending data + self.LCD_CMD = 0 # Mode - Sending command + + self.LCD_LINE_1 = 0x80 # LCD RAM addr for line one + self.LCD_LINE_2 = 0xC0 # LCD RAM addr for line two + self.LCD_LINE_3 = 0x94 # LCD RAM addr for line three + self.LCD_LINE_4 = 0xD4 # LCD RAM addr for line four + + if backlight: + # on + self.LCD_BACKLIGHT = 0x08 + else: + # off + self.LCD_BACKLIGHT = 0x00 + + self.ENABLE = 0b00000100 # Enable bit + + # Timing constants + self.E_PULSE = 0.0005 + self.E_DELAY = 0.0005 + + # Open I2C interface + if pi_rev == 2: + # Rev 2 Pi uses 1 + self.bus = smbus.SMBus(1) + elif pi_rev == 1: + # Rev 1 Pi uses 0 + self.bus = smbus.SMBus(0) + else: + raise ValueError('pi_rev param must be 1 or 2') + + # Initialise display + self.lcd_byte(0x33, self.LCD_CMD) # 110011 Initialise + self.lcd_byte(0x32, self.LCD_CMD) # 110010 Initialise + self.lcd_byte(0x06, self.LCD_CMD) # 000110 Cursor move direction + self.lcd_byte(0x0C, self.LCD_CMD) # 001100 Display On,Cursor Off, Blink Off + self.lcd_byte(0x28, self.LCD_CMD) # 101000 Data length, number of lines, font size + self.lcd_byte(0x01, self.LCD_CMD) # 000001 Clear display + + def lcd_byte(self, bits, mode): + # Send byte to data pins + # bits = data + # mode = 1 for data, 0 for command + + bits_high = mode | (bits & 0xF0) | self.LCD_BACKLIGHT + bits_low = mode | ((bits<<4) & 0xF0) | self.LCD_BACKLIGHT + + # High bits + self.bus.write_byte(self.I2C_ADDR, bits_high) + self.toggle_enable(bits_high) + + # Low bits + self.bus.write_byte(self.I2C_ADDR, bits_low) + self.toggle_enable(bits_low) + + def toggle_enable(self, bits): + time.sleep(self.E_DELAY) + self.bus.write_byte(self.I2C_ADDR, (bits | self.ENABLE)) + time.sleep(self.E_PULSE) + self.bus.write_byte(self.I2C_ADDR,(bits & ~self.ENABLE)) + time.sleep(self.E_DELAY) + + def message(self, string, line = 1): + # display message string on indicated LCD line + if line == 1: + lcd_line = self.LCD_LINE_1 + elif line == 2: + lcd_line = self.LCD_LINE_2 + elif line == 3: + lcd_line = self.LCD_LINE_3 + elif line == 4: + lcd_line = self.LCD_LINE_4 + else: + raise ValueError('line number out of range') + + string = string.ljust(self.LCD_WIDTH," ") + + self.lcd_byte(lcd_line, self.LCD_CMD) + + for i in range(self.LCD_WIDTH): + self.lcd_byte(ord(string[i]), self.LCD_CHR) + + def clear(self): + # clear LCD display + self.lcd_byte(0x01, self.LCD_CMD) diff --git a/kladd/LCD-1602-I2C/LICENSE b/kladd/LCD-1602-I2C/LICENSE new file mode 100644 index 0000000..23b0f31 --- /dev/null +++ b/kladd/LCD-1602-I2C/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Sterling Beason + +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. diff --git a/kladd/LCD-1602-I2C/README.md b/kladd/LCD-1602-I2C/README.md new file mode 100644 index 0000000..520a52a --- /dev/null +++ b/kladd/LCD-1602-I2C/README.md @@ -0,0 +1,31 @@ +# LCD-1602-I2C +A simple Python library for displaying text on the LCD 1602 w/ I2C. Implemented on the **Raspberry Pi** 3 B. + +## Simple Example +```python +import time +from LCD import LCD + +lcd = LCD() # params available for rPi revision, I2C Address, and backlight on/off + # lcd = LCD(2, 0x3F, True) + +lcd.message("Hello World!", 1) # display 'Hello World!' on line 1 of LCD + +time.sleep(5) # wait 5 seconds + +lcd.clear() # clear LCD display +``` + +## Install/Setup +``` +sudo apt-get install i2c-tools +sudo apt-get install python-smbus +``` + +#### Enable I2C +`sudo raspi-config` +Advanced Options > I2C > Enable + +#### Determine I2C Address +`i2cdetect -y 0` +default is 0x3F diff --git a/kladd/LCD-1602-I2C/__init__.py b/kladd/LCD-1602-I2C/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/kladd/decoder_samle b/kladd/decoder_samle new file mode 100644 index 0000000..1e8b61b --- /dev/null +++ b/kladd/decoder_samle @@ -0,0 +1 @@ +dec = decoder(pi, 27, 17, callback) diff --git a/kladd/pigpio_example.py b/kladd/pigpio_example.py new file mode 100644 index 0000000..b693b1f --- /dev/null +++ b/kladd/pigpio_example.py @@ -0,0 +1,3 @@ +import pigpio +pi = pigpio.pi() +pi.hardware_PWM(12, 10, 100000) diff --git a/kladd/pins b/kladd/pins new file mode 100644 index 0000000..bf7f45b --- /dev/null +++ b/kladd/pins @@ -0,0 +1,9 @@ +GPIO pins: + +17, 27: rotary encoder + +14, 15: UART + +2, 3: display + +23, 24: misc buttons diff --git a/kladd/rotary_encoder.py b/kladd/rotary_encoder.py new file mode 100644 index 0000000..884ff61 --- /dev/null +++ b/kladd/rotary_encoder.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python + +import pigpio + +class decoder: + + """Class to decode mechanical rotary encoder pulses.""" + + def __init__(self, pi, gpioA, gpioB, callback): + + """ + Instantiate the class with the pi and gpios connected to + rotary encoder contacts A and B. The common contact + should be connected to ground. The callback is + called when the rotary encoder is turned. It takes + one parameter which is +1 for clockwise and -1 for + counterclockwise. + + EXAMPLE + + import time + import pigpio + + import rotary_encoder + + pos = 0 + + def callback(way): + + global pos + + pos += way + + print("pos={}".format(pos)) + + pi = pigpio.pi() + + decoder = rotary_encoder.decoder(pi, 7, 8, callback) + + time.sleep(300) + + decoder.cancel() + + pi.stop() + + """ + + self.pi = pi + self.gpioA = gpioA + self.gpioB = gpioB + self.callback = callback + + self.levA = 0 + self.levB = 0 + + self.lastGpio = None + + self.pi.set_mode(gpioA, pigpio.INPUT) + self.pi.set_mode(gpioB, pigpio.INPUT) + + self.pi.set_pull_up_down(gpioA, pigpio.PUD_UP) + self.pi.set_pull_up_down(gpioB, pigpio.PUD_UP) + + self.cbA = self.pi.callback(gpioA, pigpio.EITHER_EDGE, self._pulse) + self.cbB = self.pi.callback(gpioB, pigpio.EITHER_EDGE, self._pulse) + + def _pulse(self, gpio, level, tick): + + """ + Decode the rotary encoder pulse. + + +---------+ +---------+ 0 + | | | | + A | | | | + | | | | + +---------+ +---------+ +----- 1 + + +---------+ +---------+ 0 + | | | | + B | | | | + | | | | + ----+ +---------+ +---------+ 1 + """ + + if gpio == self.gpioA: + self.levA = level + else: + self.levB = level; + + if gpio != self.lastGpio: # debounce + self.lastGpio = gpio + + if gpio == self.gpioA and level == 1: + if self.levB == 1: + self.callback(1) + elif gpio == self.gpioB and level == 1: + if self.levA == 1: + self.callback(-1) + + def cancel(self): + + """ + Cancel the rotary encoder decoder. + """ + + self.cbA.cancel() + self.cbB.cancel() + +if __name__ == "__main__": + + import time + import pigpio + + import rotary_encoder + + pos = 0 + + def callback(way): + + global pos + + pos += way + + print("pos={}".format(pos)) + + pi = pigpio.pi() + + decoder = rotary_encoder.decoder(pi, 7, 8, callback) + + time.sleep(300) + + decoder.cancel() + + pi.stop() +