Merge branch 'master' of github.com:jamesbowman/i2cdriver
This commit is contained in:
commit
651dec5ac2
|
@ -5,8 +5,9 @@
|
||||||
I2CDriver is a tool for controlling any I2C device from your PC's USB port,
|
I2CDriver is a tool for controlling any I2C device from your PC's USB port,
|
||||||
and can also monitor and capture I2C traffic.
|
and can also monitor and capture I2C traffic.
|
||||||
It connects as a standard USB serial device, so there are no drivers to install.
|
It connects as a standard USB serial device, so there are no drivers to install.
|
||||||
The serial protocol is [very simple](/protocol.md),
|
On the main site
|
||||||
and there are included drivers for
|
[i2cdriver.com](https://i2cdriver.com),
|
||||||
|
there are drivers for
|
||||||
|
|
||||||
* Windows/Mac/Linux GUI
|
* Windows/Mac/Linux GUI
|
||||||
* Windows/Mac/Linux command-line
|
* Windows/Mac/Linux command-line
|
||||||
|
|
|
@ -4,13 +4,11 @@ import time
|
||||||
import struct
|
import struct
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
__version__ = '0.0.2'
|
__version__ = '0.0.3'
|
||||||
|
|
||||||
PYTHON2 = (sys.version_info < (3, 0))
|
PYTHON2 = (sys.version_info < (3, 0))
|
||||||
|
|
||||||
from lm75b import *
|
|
||||||
import EDS
|
import EDS
|
||||||
import bargraph
|
|
||||||
|
|
||||||
class I2CTimeout(Exception):
|
class I2CTimeout(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -1,24 +1,17 @@
|
||||||
|
"""
|
||||||
|
Example for Bi-Color (Red/Green) 24-Bar Bargraph, based on HT16K33.
|
||||||
|
Available from Adafruit.
|
||||||
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import serial
|
|
||||||
import time
|
import time
|
||||||
import struct
|
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
from i2cdriver import I2CDriver
|
||||||
|
|
||||||
from ht16k33 import HT16K33
|
from ht16k33 import HT16K33
|
||||||
|
|
||||||
class bargraph(HT16K33):
|
class bargraph(HT16K33):
|
||||||
def image(self, bb):
|
|
||||||
def swiz(b):
|
|
||||||
bs = [str((b >> n) & 1) for n in range(8)]
|
|
||||||
return int(bs[7] + bs[0] + bs[1] + bs[2] + bs[3] + bs[4] + bs[5] + bs[6], 2)
|
|
||||||
bb = [swiz(b) for b in bb]
|
|
||||||
self.load([b for s in zip(bb,bb) for b in s])
|
|
||||||
|
|
||||||
def char(self, c):
|
|
||||||
n = ord(c)
|
|
||||||
ch = font[n * 8:n * 8 + 8]
|
|
||||||
self.image(ch)
|
|
||||||
|
|
||||||
def set(self, pix):
|
def set(self, pix):
|
||||||
rr = pix
|
rr = pix
|
||||||
def paint(r, i):
|
def paint(r, i):
|
||||||
|
@ -33,3 +26,12 @@ class bargraph(HT16K33):
|
||||||
[paint(red, i) for i in range(24) if (pix[i] & 1)]
|
[paint(red, i) for i in range(24) if (pix[i] & 1)]
|
||||||
[paint(grn, i) for i in range(24) if (pix[i] & 2)]
|
[paint(grn, i) for i in range(24) if (pix[i] & 2)]
|
||||||
self.load([red[0], grn[0], red[1], grn[1], red[2], grn[2]])
|
self.load([red[0], grn[0], red[1], grn[1], red[2], grn[2]])
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
i2 = I2CDriver(sys.argv[1])
|
||||||
|
|
||||||
|
d0 = bargraph(i2)
|
||||||
|
|
||||||
|
for i in range(60):
|
||||||
|
d0.set([random.choice((0,1,2,3)) for i in range(24)])
|
||||||
|
time.sleep(.08)
|
|
@ -0,0 +1,210 @@
|
||||||
|
"""
|
||||||
|
Example for BNO080 integrated IMU.
|
||||||
|
Available from Sparkfun.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import serial
|
||||||
|
import time
|
||||||
|
import struct
|
||||||
|
import random
|
||||||
|
import math
|
||||||
|
|
||||||
|
from i2cdriver import I2CDriver
|
||||||
|
def hexdump(s):
|
||||||
|
def toprint(c):
|
||||||
|
if 32 <= c < 127:
|
||||||
|
return chr(c)
|
||||||
|
else:
|
||||||
|
return "."
|
||||||
|
def hexline(s):
|
||||||
|
return (" ".join(["%02x" % c for c in s]).ljust(49) +
|
||||||
|
"|" +
|
||||||
|
"".join([toprint(c) for c in s]).ljust(16) +
|
||||||
|
"|")
|
||||||
|
return "\n".join([hexline(s[i:i+16]) for i in range(0, len(s), 16)])
|
||||||
|
|
||||||
|
CHANNEL_COMMAND = 0
|
||||||
|
CHANNEL_EXECUTABLE = 1
|
||||||
|
CHANNEL_CONTROL = 2
|
||||||
|
CHANNEL_REPORTS = 3
|
||||||
|
CHANNEL_WAKE_REPORTS = 4
|
||||||
|
CHANNEL_GYRO = 5
|
||||||
|
|
||||||
|
# All the ways we can configure or talk to the BNO080, figure 34, page 36 reference manual
|
||||||
|
# These are used for low level communication with the sensor, on channel 2
|
||||||
|
SHTP_REPORT_COMMAND_RESPONSE = 0xF1
|
||||||
|
SHTP_REPORT_COMMAND_REQUEST = 0xF2
|
||||||
|
SHTP_REPORT_FRS_READ_RESPONSE = 0xF3
|
||||||
|
SHTP_REPORT_FRS_READ_REQUEST = 0xF4
|
||||||
|
SHTP_REPORT_PRODUCT_ID_RESPONSE = 0xF8
|
||||||
|
SHTP_REPORT_PRODUCT_ID_REQUEST = 0xF9
|
||||||
|
SHTP_REPORT_BASE_TIMESTAMP = 0xFB
|
||||||
|
SHTP_REPORT_SET_FEATURE_COMMAND = 0xFD
|
||||||
|
|
||||||
|
# All the different sensors and features we can get reports from
|
||||||
|
# These are used when enabling a given sensor
|
||||||
|
SENSOR_REPORTID_ACCELEROMETER = 0x01
|
||||||
|
SENSOR_REPORTID_GYROSCOPE = 0x02
|
||||||
|
SENSOR_REPORTID_MAGNETIC_FIELD = 0x03
|
||||||
|
SENSOR_REPORTID_LINEAR_ACCELERATION = 0x04
|
||||||
|
SENSOR_REPORTID_ROTATION_VECTOR = 0x05
|
||||||
|
SENSOR_REPORTID_GRAVITY = 0x06
|
||||||
|
SENSOR_REPORTID_GAME_ROTATION_VECTOR = 0x08
|
||||||
|
SENSOR_REPORTID_GEOMAGNETIC_ROTATION_VECTOR = 0x09
|
||||||
|
SENSOR_REPORTID_TAP_DETECTOR = 0x10
|
||||||
|
SENSOR_REPORTID_STEP_COUNTER = 0x11
|
||||||
|
SENSOR_REPORTID_STABILITY_CLASSIFIER = 0x13
|
||||||
|
SENSOR_REPORTID_PERSONAL_ACTIVITY_CLASSIFIER = 0x1E
|
||||||
|
|
||||||
|
# Record IDs from figure 29, page 29 reference manual
|
||||||
|
# These are used to read the metadata for each sensor type
|
||||||
|
FRS_RECORDID_ACCELEROMETER = 0xE302
|
||||||
|
FRS_RECORDID_GYROSCOPE_CALIBRATED = 0xE306
|
||||||
|
FRS_RECORDID_MAGNETIC_FIELD_CALIBRATED = 0xE309
|
||||||
|
FRS_RECORDID_ROTATION_VECTOR = 0xE30B
|
||||||
|
|
||||||
|
# Command IDs from section 6.4, page 42
|
||||||
|
# These are used to calibrate, initialize, set orientation, tare etc the sensor
|
||||||
|
COMMAND_ERRORS = 1
|
||||||
|
COMMAND_COUNTER = 2
|
||||||
|
COMMAND_TARE = 3
|
||||||
|
COMMAND_INITIALIZE = 4
|
||||||
|
COMMAND_DCD = 6
|
||||||
|
COMMAND_ME_CALIBRATE = 7
|
||||||
|
COMMAND_DCD_PERIOD_SAVE = 9
|
||||||
|
COMMAND_OSCILLATOR = 10
|
||||||
|
COMMAND_CLEAR_DCD = 11
|
||||||
|
|
||||||
|
CALIBRATE_ACCEL = 0
|
||||||
|
CALIBRATE_GYRO = 1
|
||||||
|
CALIBRATE_MAG = 2
|
||||||
|
CALIBRATE_PLANAR_ACCEL = 3
|
||||||
|
CALIBRATE_ACCEL_GYRO_MAG = 4
|
||||||
|
CALIBRATE_STOP = 5
|
||||||
|
|
||||||
|
def normalize(v, tolerance=0.00001):
|
||||||
|
mag2 = sum(n * n for n in v)
|
||||||
|
if abs(mag2 - 1.0) > tolerance:
|
||||||
|
mag = math.sqrt(mag2)
|
||||||
|
v = tuple(n / mag for n in v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
class BNO080:
|
||||||
|
def __init__(self, i2, a = 0x4b):
|
||||||
|
self.i2 = i2
|
||||||
|
self.a = a
|
||||||
|
self.seqno = [0] * 8
|
||||||
|
|
||||||
|
if 1:
|
||||||
|
self.sendPacket(CHANNEL_EXECUTABLE, [1])
|
||||||
|
time.sleep(0.150)
|
||||||
|
while True:
|
||||||
|
if not self.receivePacket():
|
||||||
|
break
|
||||||
|
|
||||||
|
self.setFeature(SENSOR_REPORTID_ROTATION_VECTOR, 50000)
|
||||||
|
|
||||||
|
def read_quaternion(self):
|
||||||
|
while True:
|
||||||
|
r = self.receivePacket()
|
||||||
|
while r:
|
||||||
|
tag = r[0]
|
||||||
|
r = r[1:]
|
||||||
|
if tag == 0xfb:
|
||||||
|
# print("Time %d" % struct.unpack("I", r[:4]))
|
||||||
|
r = r[4:]
|
||||||
|
elif tag == SHTP_REPORT_COMMAND_RESPONSE:
|
||||||
|
r = r[16:]
|
||||||
|
elif tag == 0xfc:
|
||||||
|
# print("Get Feature Response")
|
||||||
|
r = r[17:]
|
||||||
|
elif tag == SENSOR_REPORTID_ACCELEROMETER:
|
||||||
|
r = r[10:]
|
||||||
|
elif tag == SENSOR_REPORTID_ROTATION_VECTOR:
|
||||||
|
(_,_,_,i,j,k,w,_) = struct.unpack("<BBBhhhhh", r[:14])
|
||||||
|
Q14 = 2 ** -14
|
||||||
|
# print((i * Q14, j * Q14, k * Q14, w * Q14))
|
||||||
|
return (w * Q14, i * Q14, j * Q14, k * Q14)
|
||||||
|
r = r[14:]
|
||||||
|
else:
|
||||||
|
assert 0, "Bad tag %#x" % tag
|
||||||
|
|
||||||
|
def setFeature(self, reportID, timeBetweenReports, specificConfig = 0):
|
||||||
|
p = struct.pack("<BBBHIII",
|
||||||
|
SHTP_REPORT_SET_FEATURE_COMMAND,
|
||||||
|
reportID,
|
||||||
|
0, 0,
|
||||||
|
timeBetweenReports,
|
||||||
|
0, specificConfig)
|
||||||
|
# print(hexdump(p))
|
||||||
|
|
||||||
|
self.sendPacket(CHANNEL_CONTROL, p)
|
||||||
|
|
||||||
|
def sendPacket(self, channel, data):
|
||||||
|
# print('send on', channel, 'seq', self.seqno[channel])
|
||||||
|
self.i2.start(self.a, 0)
|
||||||
|
self.i2.write(struct.pack("<HBB", 4 + len(data), channel, self.seqno[channel]))
|
||||||
|
self.i2.write(data)
|
||||||
|
self.i2.stop()
|
||||||
|
self.seqno[channel] += 1
|
||||||
|
|
||||||
|
def receivePacket(self):
|
||||||
|
if not self.i2.start(self.a, 1):
|
||||||
|
self.i2.stop()
|
||||||
|
return None
|
||||||
|
hdr = self.i2.read(4)
|
||||||
|
self.i2.stop()
|
||||||
|
length, channel, sequence = (struct.unpack("<HBB", hdr))
|
||||||
|
length &= 0x7fff
|
||||||
|
# print()
|
||||||
|
# print('length', length)
|
||||||
|
# print('channel', channel)
|
||||||
|
# print('sequence', sequence)
|
||||||
|
if length == 0 or channel not in range(8):
|
||||||
|
return None
|
||||||
|
|
||||||
|
# self.seqno[channel] = sequence + 1
|
||||||
|
|
||||||
|
self.i2.start(self.a, 1)
|
||||||
|
data = self.i2.read(length)
|
||||||
|
self.i2.stop()
|
||||||
|
# print(len(data), repr(data))
|
||||||
|
# print(hexdump(data[4:]))
|
||||||
|
return data[4:]
|
||||||
|
|
||||||
|
def showpacket(self, data):
|
||||||
|
tag = data[0]
|
||||||
|
print('tag', tag)
|
||||||
|
r = data[1:]
|
||||||
|
if tag == 0:
|
||||||
|
self.showpacket_00(r)
|
||||||
|
else:
|
||||||
|
assert False, "Cannot show packet %02x" % tag
|
||||||
|
|
||||||
|
def showpacket_00(self, ad):
|
||||||
|
while ad:
|
||||||
|
(T, L) = struct.unpack("BB", ad[:2])
|
||||||
|
V = ad[2:2+L]
|
||||||
|
decoder = {
|
||||||
|
1: lambda: ("GUID", struct.unpack("I", V)),
|
||||||
|
2: lambda: ("MaxCargoPlusHeaderWrite", struct.unpack("H", V)),
|
||||||
|
3: lambda: ("MaxCargoPlusHeaderRead", struct.unpack("H", V)),
|
||||||
|
4: lambda: ("MaxTransferWrite", struct.unpack("H", V)),
|
||||||
|
5: lambda: ("MaxTransferRead", struct.unpack("H", V)),
|
||||||
|
6: lambda: ("NormalChannel", struct.unpack("B", V)),
|
||||||
|
7: lambda: ("WakeChannel", struct.unpack("B", V)),
|
||||||
|
8: lambda: ("AppName", (V[:-1].decode(), )),
|
||||||
|
9: lambda: ("ChannelName", (V[:-1].decode(), )),
|
||||||
|
0x80: lambda: ("SHTP Version", (V[:-1].decode(), )),
|
||||||
|
}.get(T, lambda: (str(T), (V,)))
|
||||||
|
(nm,f) = decoder()
|
||||||
|
print("%5d %-26s: %r" % ((len(ad), nm, ) + f))
|
||||||
|
ad = ad[2+L:]
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
i2 = I2CDriver(sys.argv[1])
|
||||||
|
|
||||||
|
d = BNO080(i2)
|
||||||
|
while True:
|
||||||
|
print('quaternion:', d.read_quaternion())
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
python led8x8.py /dev/ttyUSB0
|
||||||
|
# python EDS-take-a-ticket.py /dev/ttyUSB0
|
||||||
|
# python i2cgui.py
|
|
@ -240,7 +240,6 @@ class Frame(wx.Frame):
|
||||||
def read(self, e):
|
def read(self, e):
|
||||||
n = int(self.rxCount.GetValue())
|
n = int(self.rxCount.GetValue())
|
||||||
if self.addr is not None:
|
if self.addr is not None:
|
||||||
print("read", n)
|
|
||||||
self.start(1)
|
self.start(1)
|
||||||
r = self.sd.read(n)
|
r = self.sd.read(n)
|
||||||
bb = struct.unpack("B"*n, r)
|
bb = struct.unpack("B"*n, r)
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
"""
|
||||||
|
Example for LCD1602, in which a PCF8574 I/O expander drives a HD44780.
|
||||||
|
Available from various vendors.
|
||||||
|
|
||||||
|
Note that the modules require a 5V VCC; they don't function using the
|
||||||
|
3.3V VCC of I2CDriver.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import struct
|
||||||
|
|
||||||
|
from i2cdriver import I2CDriver
|
||||||
|
|
||||||
|
class HD44780:
|
||||||
|
|
||||||
|
def __init__(self, i2, a = 0x27):
|
||||||
|
self.i2 = i2
|
||||||
|
self.a = a
|
||||||
|
|
||||||
|
self.nybble(3) # Enter 4-bit mode
|
||||||
|
self.nybble(3)
|
||||||
|
self.nybble(3)
|
||||||
|
self.nybble(2)
|
||||||
|
|
||||||
|
self.cmd(0x28) # 2 lines, 5x8 dot matrix
|
||||||
|
self.cmd(0x0c) # display on
|
||||||
|
self.cmd(0x06) # inc cursor to right when writing and don't scroll
|
||||||
|
self.cmd(0x80) # set cursor to row 1, column 1
|
||||||
|
|
||||||
|
self.clear()
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
""" Clear the screen """
|
||||||
|
self.cmd(0x01)
|
||||||
|
time.sleep(.003)
|
||||||
|
|
||||||
|
def show(self, line, text):
|
||||||
|
""" Send string to LCD. Newline wraps to second line"""
|
||||||
|
self.cmd({0:0x80, 1:0xc0}[line])
|
||||||
|
for c in text:
|
||||||
|
self.data(ord(c))
|
||||||
|
|
||||||
|
def cmd(self, b):
|
||||||
|
self.nybble(b >> 4)
|
||||||
|
self.nybble(b & 0xf)
|
||||||
|
time.sleep(.000053)
|
||||||
|
|
||||||
|
def data(self, b):
|
||||||
|
self.nybble(b >> 4, 1)
|
||||||
|
self.nybble(b & 0xf, 1)
|
||||||
|
|
||||||
|
# The PCF8574 outputs are connected to the HD44780
|
||||||
|
# pins as follows:
|
||||||
|
|
||||||
|
# P0 RS (0: command, 1: data)
|
||||||
|
# P1 R/W (0: write, 1: read)
|
||||||
|
# P2 Enable/CLK
|
||||||
|
# P3 Backlight control
|
||||||
|
# P4-7 D4-D7
|
||||||
|
|
||||||
|
def nybble(self, n, rs = 0):
|
||||||
|
bl = 8 | rs
|
||||||
|
self.port(
|
||||||
|
bl | (n << 4),
|
||||||
|
bl | (n << 4) | 4,
|
||||||
|
bl | (n << 4)
|
||||||
|
)
|
||||||
|
|
||||||
|
def port(self, *bb):
|
||||||
|
# Write bytes to port, setting the PCF8574 outputs
|
||||||
|
self.i2.start(self.a, 0)
|
||||||
|
self.i2.write(bb)
|
||||||
|
self.i2.stop()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
i2 = I2CDriver(sys.argv[1])
|
||||||
|
d = HD44780(i2)
|
||||||
|
d.show(0, "HELLO WORLD")
|
||||||
|
time.sleep(.5)
|
||||||
|
d.show(1, "0123456789012345")
|
|
@ -0,0 +1,37 @@
|
||||||
|
"""
|
||||||
|
Example for 8x8 LED Matrix modules, based on HT16K33.
|
||||||
|
Available from multiple vendors.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
from i2cdriver import I2CDriver
|
||||||
|
|
||||||
|
font = open("cp437-8x8", "rb").read()
|
||||||
|
|
||||||
|
from ht16k33 import HT16K33
|
||||||
|
|
||||||
|
class led8x8(HT16K33):
|
||||||
|
def image(self, bb):
|
||||||
|
""" Set the pixels to the bytes bb """
|
||||||
|
def swiz(b):
|
||||||
|
bs = [str((b >> n) & 1) for n in range(8)]
|
||||||
|
return int(bs[7] + bs[0] + bs[1] + bs[2] + bs[3] + bs[4] + bs[5] + bs[6], 2)
|
||||||
|
bb = [swiz(b) for b in bb]
|
||||||
|
self.load([b for s in zip(bb,bb) for b in s])
|
||||||
|
|
||||||
|
def char(self, c):
|
||||||
|
""" Set the pixels to character c """
|
||||||
|
n = ord(c)
|
||||||
|
ch = font[n * 8:n * 8 + 8]
|
||||||
|
self.image(ch)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
i2 = I2CDriver(sys.argv[1])
|
||||||
|
|
||||||
|
d = led8x8(i2)
|
||||||
|
|
||||||
|
for c in "I2C":
|
||||||
|
d.char(c)
|
||||||
|
time.sleep(1)
|
Binary file not shown.
After Width: | Height: | Size: 342 B |
|
@ -0,0 +1,35 @@
|
||||||
|
"""
|
||||||
|
Example Xtrinsic MAG3110 Three-Axis Digital Magnetometer
|
||||||
|
Breakout available from Sparkfun.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import struct
|
||||||
|
import time
|
||||||
|
|
||||||
|
from i2cdriver import I2CDriver, EDS
|
||||||
|
|
||||||
|
class MAG3110:
|
||||||
|
def __init__(self, i2, a = 0x0e):
|
||||||
|
self.i2 = i2
|
||||||
|
self.a = a
|
||||||
|
self.i2.regwr(self.a, 0x10, 0b00000001) # CTRL_REG1. ACTIVE mode, 80 Hz conversions
|
||||||
|
|
||||||
|
def rd(self):
|
||||||
|
""" Read the measurement STATUS_REG and OUT_X,Y,Z """
|
||||||
|
return self.i2.regrd(self.a, 0x00, ">B3h")
|
||||||
|
|
||||||
|
def measurement(self):
|
||||||
|
""" Wait for a new field reading, return the (x,y,z) """
|
||||||
|
while True:
|
||||||
|
(status, x, y, z) = self.rd()
|
||||||
|
if status & 8:
|
||||||
|
return (x, y, z)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
i2 = I2CDriver(sys.argv[1])
|
||||||
|
i2.scan()
|
||||||
|
|
||||||
|
d = MAG3110(i2)
|
||||||
|
while 1:
|
||||||
|
print(d.measurement())
|
|
@ -0,0 +1,107 @@
|
||||||
|
"""
|
||||||
|
Example for 128X64OLED Module
|
||||||
|
Available from multiple vendors, e.g. DIYMall
|
||||||
|
|
||||||
|
This example loads the I2CDriver logo onto the display,
|
||||||
|
and flashes it four times.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
from PIL import Image, ImageChops
|
||||||
|
|
||||||
|
from i2cdriver import I2CDriver
|
||||||
|
|
||||||
|
SETCONTRAST = 0x81
|
||||||
|
DISPLAYALLON_RESUME = 0xA4
|
||||||
|
DISPLAYALLON = 0xA5
|
||||||
|
NORMALDISPLAY = 0xA6
|
||||||
|
INVERTDISPLAY = 0xA7
|
||||||
|
DISPLAYOFF = 0xAE
|
||||||
|
DISPLAYON = 0xAF
|
||||||
|
SETDISPLAYOFFSET = 0xD3
|
||||||
|
SETCOMPINS = 0xDA
|
||||||
|
SETVCOMDETECT = 0xDB
|
||||||
|
SETDISPLAYCLOCKDIV = 0xD5
|
||||||
|
SETPRECHARGE = 0xD9
|
||||||
|
SETMULTIPLEX = 0xA8
|
||||||
|
SETLOWCOLUMN = 0x00
|
||||||
|
SETHIGHCOLUMN = 0x10
|
||||||
|
SETSTARTLINE = 0x40
|
||||||
|
MEMORYMODE = 0x20
|
||||||
|
COLUMNADDR = 0x21
|
||||||
|
PAGEADDR = 0x22
|
||||||
|
COMSCANINC = 0xC0
|
||||||
|
COMSCANDEC = 0xC8
|
||||||
|
SEGREMAP = 0xA0
|
||||||
|
CHARGEPUMP = 0x8D
|
||||||
|
|
||||||
|
class OLED:
|
||||||
|
def __init__(self, i2, a = 0x3c):
|
||||||
|
self.i2 = i2
|
||||||
|
self.a = a
|
||||||
|
|
||||||
|
self.command(DISPLAYOFF)
|
||||||
|
self.command(SETDISPLAYCLOCKDIV, 0x80) # the suggested ratio 0x80
|
||||||
|
|
||||||
|
self.command(SETMULTIPLEX, 0x3f)
|
||||||
|
|
||||||
|
self.command(SETDISPLAYOFFSET, 0)
|
||||||
|
self.command(SETSTARTLINE | 0x0)
|
||||||
|
self.command(CHARGEPUMP, 0x14)
|
||||||
|
self.command(MEMORYMODE, 0)
|
||||||
|
self.command(SEGREMAP | 0x1)
|
||||||
|
self.command(COMSCANDEC)
|
||||||
|
|
||||||
|
self.command(SETCOMPINS, 0x12)
|
||||||
|
self.command(SETCONTRAST, 0xcf)
|
||||||
|
|
||||||
|
self.command(SETVCOMDETECT, 0x40)
|
||||||
|
self.command(DISPLAYALLON_RESUME)
|
||||||
|
self.command(NORMALDISPLAY)
|
||||||
|
|
||||||
|
self.im = Image.new("1", (128,64), 1)
|
||||||
|
self.cls()
|
||||||
|
|
||||||
|
def command(self, *c):
|
||||||
|
assert(self.i2.start(self.a, 0))
|
||||||
|
assert(self.i2.write((0,) + c))
|
||||||
|
self.i2.stop()
|
||||||
|
|
||||||
|
def image(self, im):
|
||||||
|
for p in range(8):
|
||||||
|
pr = self.im.crop((0,8*p,128,8*p+8)).transpose(Image.ROTATE_270)
|
||||||
|
bb = im.crop((0,8*p,128,8*p+8)).transpose(Image.ROTATE_270)
|
||||||
|
diff = ImageChops.difference(pr, bb)
|
||||||
|
di = diff.getbbox()
|
||||||
|
if di is not None:
|
||||||
|
(x0, y0, x1, y1) = di
|
||||||
|
self.command(COLUMNADDR)
|
||||||
|
self.command(y0)
|
||||||
|
self.command(y1 - 1)
|
||||||
|
self.command(PAGEADDR)
|
||||||
|
self.command(p)
|
||||||
|
self.command(p + 1)
|
||||||
|
self.i2.start(self.a, 0)
|
||||||
|
self.i2.write([0x40])
|
||||||
|
self.i2.write(bb.tobytes()[y0:y1])
|
||||||
|
self.i2.stop()
|
||||||
|
self.im = im
|
||||||
|
self.command(DISPLAYON)
|
||||||
|
|
||||||
|
def cls(self):
|
||||||
|
self.image(Image.new("1", (128,64), 0))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
i2 = I2CDriver(sys.argv[1])
|
||||||
|
d = OLED(i2)
|
||||||
|
|
||||||
|
d.image(Image.open("logo.png").convert("1"))
|
||||||
|
|
||||||
|
for i in range(4):
|
||||||
|
d.command(INVERTDISPLAY)
|
||||||
|
time.sleep(.5)
|
||||||
|
d.command(NORMALDISPLAY)
|
||||||
|
time.sleep(.5)
|
|
@ -0,0 +1,43 @@
|
||||||
|
"""
|
||||||
|
Example for Qwiic Joystick
|
||||||
|
Available from Sparkfun.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import struct
|
||||||
|
|
||||||
|
from i2cdriver import I2CDriver
|
||||||
|
|
||||||
|
class Joystick:
|
||||||
|
def __init__(self, i2, a = 0x20):
|
||||||
|
self.i2 = i2
|
||||||
|
self.a = a
|
||||||
|
|
||||||
|
def axis(self, i):
|
||||||
|
self.i2.start(self.a, 0)
|
||||||
|
self.i2.write([i])
|
||||||
|
self.i2.stop() # Note: their firmware cannot handle an I2C restart
|
||||||
|
self.i2.start(self.a, 1)
|
||||||
|
(r,) = struct.unpack(">H", self.i2.read(2))
|
||||||
|
self.i2.stop()
|
||||||
|
return r
|
||||||
|
|
||||||
|
def read(self):
|
||||||
|
"""
|
||||||
|
return the joystick (x,y) position. The range is 0-1023.
|
||||||
|
The center position of the joystick is approximately 512.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Note: their firmware requires two separate reads
|
||||||
|
|
||||||
|
return (self.axis(0), self.axis(2))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
i2 = I2CDriver(sys.argv[1])
|
||||||
|
|
||||||
|
d = Joystick(i2)
|
||||||
|
|
||||||
|
while 1:
|
||||||
|
print(d.read())
|
||||||
|
time.sleep(.1)
|
|
@ -0,0 +1,44 @@
|
||||||
|
"""
|
||||||
|
Example for Qwiic Keypad
|
||||||
|
Available from Sparkfun.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import struct
|
||||||
|
|
||||||
|
from i2cdriver import I2CDriver
|
||||||
|
|
||||||
|
class Keypad:
|
||||||
|
def __init__(self, i2, a = 0x4b):
|
||||||
|
self.i2 = i2
|
||||||
|
self.a = a
|
||||||
|
|
||||||
|
def read_ts(self):
|
||||||
|
"""
|
||||||
|
Return (key, timestamp) if pressed, or None.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.i2.start(self.a, 1)
|
||||||
|
(k, age_in_ms) = struct.unpack(">BH", self.i2.read(3))
|
||||||
|
self.i2.stop()
|
||||||
|
if k != 0:
|
||||||
|
return (chr(k), time.time() - age_in_ms * .001)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def read(self):
|
||||||
|
r = self.read_ts()
|
||||||
|
if r:
|
||||||
|
return r[0]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
i2 = I2CDriver(sys.argv[1])
|
||||||
|
|
||||||
|
d = Keypad(i2)
|
||||||
|
|
||||||
|
while 1:
|
||||||
|
print(d.read())
|
||||||
|
time.sleep(.1)
|
|
@ -0,0 +1,33 @@
|
||||||
|
"""
|
||||||
|
Example for MPR121 Capacitive Touch Sensor.
|
||||||
|
Available from multiple vendors.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import serial
|
||||||
|
import time
|
||||||
|
import struct
|
||||||
|
import random
|
||||||
|
|
||||||
|
from i2cdriver import I2CDriver
|
||||||
|
|
||||||
|
class MPR121:
|
||||||
|
def __init__(self, i2, a = 0x5a):
|
||||||
|
self.i2 = i2
|
||||||
|
self.a = a
|
||||||
|
self.i2.regwr(self.a, 0x5e, 0x0c)
|
||||||
|
|
||||||
|
def read(self):
|
||||||
|
""" Return 12 touch detection flags """
|
||||||
|
(tb,) = struct.unpack("<H", self.i2.regrd(0x5a, 0, 2))
|
||||||
|
return [((tb >> i) & 1) for i in range(12)]
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
i2 = I2CDriver(sys.argv[1])
|
||||||
|
|
||||||
|
i2.reset()
|
||||||
|
|
||||||
|
d = MPR121(i2)
|
||||||
|
while 1:
|
||||||
|
print(d.read())
|
||||||
|
time.sleep(.1)
|
|
@ -19,9 +19,6 @@ setup(name='i2cdriver',
|
||||||
install_requires=['pyserial'],
|
install_requires=['pyserial'],
|
||||||
py_modules = [
|
py_modules = [
|
||||||
'i2cdriver',
|
'i2cdriver',
|
||||||
'lm75b',
|
|
||||||
'EDS',
|
'EDS',
|
||||||
'ht16k33',
|
|
||||||
'bargraph',
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue