I am trying to get temperature sensor to work on pico pi, using PIN 16. I got DS18X20 and onewire library from GitHub. I'm trying to get temperature reading but it shows an error.
I tried running this code:
import time
import machine
import ds18x20
import onewire
# the device is on GPIO12
dat = machine.Pin(22)
# create the onewire object
on = onewire.OneWire(dat)
ds = ds18x20.DS18X20(on)
# scan for devices on the bus
roms = ds.scan()
print('found devices:', roms)
# loop 10 times and print all temperatures
for i in range(10):
print('temperatures:', end=' ')
ds.convert_temp()
time.sleep_ms(750)
for rom in roms:
print(ds.read_temp(rom), end=' ')
print()
This is DS18X0 library:
"""
DS18x20 temperature sensor driver for MicroPython.
This driver uses the OneWire driver to control DS18S20 and DS18B20
temperature sensors. It supports multiple devices on the same 1-wire bus.
The following example assumes the ground of your DS18x20 is connected to
Y11, vcc is connected to Y9 and the data pin is connected to Y10.
>>> from pyb import Pin
>>> gnd = Pin('Y11', Pin.OUT_PP)
>>> gnd.low()
>>> vcc = Pin('Y9', Pin.OUT_PP)
>>> vcc.high()
>>> from ds18x20 import DS18X20
>>> d = DS18X20(Pin('Y10'))
Call read_temps to read all sensors:
>>> result = d.read_temps()
>>> print(result)
[20.875, 20.8125]
Call read_temp to read the temperature of a specific sensor:
>>> result = d.read_temp(d.roms[0])
>>> print(result)
20.25
If only one DS18x20 is attached to the bus, then you don't need to
pass a ROM to read_temp:
>>> result = d.read_temp()
>>> print(result)
20.25
"""
from onewire import OneWire
class DS18X20(object):
def __init__(self, pin):
self.ow = OneWire(pin)
# Scan the 1-wire devices, but only keep those which have the
# correct # first byte in their rom for a DS18x20 device.
self.roms = [rom for rom in self.ow.scan() if rom[0] == 0x10 or rom[0] == 0x28]
def read_temp(self, rom=None):
"""
Read and return the temperature of one DS18x20 device.
Pass the 8-byte bytes object with the ROM of the specific device you want to read.
If only one DS18x20 device is attached to the bus you may omit the rom parameter.
"""
rom = rom or self.roms[0]
ow = self.ow
ow.reset()
ow.select_rom(rom)
ow.write_byte(0x44) # Convert Temp
while True:
if ow.read_bit():
break
ow.reset()
ow.select_rom(rom)
ow.write_byte(0xbe) # Read scratch
data = ow.read_bytes(9)
return self.convert_temp(rom[0], data)
def read_temps(self):
"""
Read and return the temperatures of all attached DS18x20 devices.
"""
temps = []
for rom in self.roms:
temps.append(self.read_temp(rom))
return temps
def convert_temp(self, rom0, data):
"""
Convert the raw temperature data into degrees celsius and return as a float.
"""
temp_lsb = data[0]
temp_msb = data[1]
if rom0 == 0x10:
if temp_msb != 0:
# convert negative number
temp_read = temp_lsb >> 1 | 0x80 # truncate bit 0 by shifting, fill high bit with 1.
temp_read = -((~temp_read + 1) & 0xff) # now convert from two's complement
else:
temp_read = temp_lsb >> 1 # truncate bit 0 by shifting
count_remain = data[6]
count_per_c = data[7]
temp = temp_read - 0.25 + (count_per_c - count_remain) / count_per_c
return temp
elif rom0 == 0x28:
return (temp_msb << 8 | temp_lsb) / 16
else:
assert False
This is onewire library:
#!/usr/bin/env python
#
# Copyright (c) 2019, Pycom Limited.
#
# This software is licensed under the GNU GPL version 3 or any
# later version, with permitted additional terms. For more information
# see the Pycom Licence v1.0 document supplied with this file, or
# available at https://www.pycom.io/opensource/licensing
#
"""
OneWire library for MicroPython
"""
import time
import machine
class OneWire:
CMD_SEARCHROM = const(0xf0)
CMD_READROM = const(0x33)
CMD_MATCHROM = const(0x55)
CMD_SKIPROM = const(0xcc)
def __init__(self, pin):
self.pin = pin
self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP)
print("init")
def init(self, pin):
self.pin = pin
self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP)
print("init")
def reset(self):
"""
Perform the onewire reset function.
Returns True if a device asserted a presence pulse, False otherwise.
"""
sleep_us = time.sleep_us
disable_irq = machine.disable_irq
enable_irq = machine.enable_irq
pin = self.pin
pin(0)
sleep_us(480)
i = disable_irq()
pin(1)
sleep_us(60)
status = not pin()
enable_irq(i)
sleep_us(420)
return status
def read_bit(self):
sleep_us = time.sleep_us
enable_irq = machine.enable_irq
pin = self.pin
pin(1) # half of the devices don't match CRC without this line
i = machine.disable_irq()
pin(0)
sleep_us(1)
pin(1)
sleep_us(1)
value = pin()
enable_irq(i)
sleep_us(40)
return value
def read_byte(self):
value = 0
for i in range(8):
value |= self.read_bit() << i
return value
def read_bytes(self, count):
buf = bytearray(count)
for i in range(count):
buf[i] = self.read_byte()
return buf
def write_bit(self, value):
sleep_us = time.sleep_us
pin = self.pin
i = machine.disable_irq()
pin(0)
sleep_us(1)
pin(value)
sleep_us(60)
pin(1)
sleep_us(1)
machine.enable_irq(i)
def write_byte(self, value):
for i in range(8):
self.write_bit(value & 1)
value >>= 1
def write_bytes(self, buf):
for b in buf:
self.write_byte(b)
def select_rom(self, rom):
"""
Select a specific device to talk to. Pass in rom as a bytearray (8 bytes).
"""
self.reset()
self.write_byte(CMD_MATCHROM)
self.write_bytes(rom)
def crc8(self, data):
"""
Compute CRC
"""
crc = 0
for i in range(len(data)):
byte = data[i]
for b in range(8):
fb_bit = (crc ^ byte) & 0x01
if fb_bit == 0x01:
crc = crc ^ 0x18
crc = (crc >> 1) & 0x7f
if fb_bit == 0x01:
crc = crc | 0x80
byte = byte >> 1
return crc
def scan(self):
"""
Return a list of ROMs for all attached devices.
Each ROM is returned as a bytes object of 8 bytes.
"""
devices = []
diff = 65
rom = False
for i in range(0xff):
rom, diff = self._search_rom(rom, diff)
if rom:
devices += [rom]
if diff == 0:
break
return devices
def _search_rom(self, l_rom, diff):
if not self.reset():
return None, 0
self.write_byte(CMD_SEARCHROM)
if not l_rom:
l_rom = bytearray(8)
rom = bytearray(8)
next_diff = 0
i = 64
for byte in range(8):
r_b = 0
for bit in range(8):
b = self.read_bit()
if self.read_bit():
if b: # there are no devices or there is an error on the bus
return None, 0
else:
if not b: # collision, two devices with different bit meaning
if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i):
b = 1
next_diff = i
self.write_bit(b)
if b:
r_b |= 1 << bit
i -= 1
rom[byte] = r_b
return rom, next_diff
class DS18X20(object):
def __init__(self, onewire):
self.ow = onewire
self.roms = [rom for rom in self.ow.scan() if rom[0] == 0x10 or rom[0] == 0x28]
self.fp = True
try:
1/1
except TypeError:
self.fp = False # floatingpoint not supported
def isbusy(self):
"""
Checks wether one of the DS18x20 devices on the bus is busy
performing a temperature convertion
"""
return not self.ow.read_bit()
def start_conversion(self, rom=None):
"""
Start the temp conversion on one DS18x20 device.
Pass the 8-byte bytes object with the ROM of the specific device you want to read.
If only one DS18x20 device is attached to the bus you may omit the rom parameter.
"""
if (rom==None) and (len(self.roms)>0):
rom=self.roms[0]
if rom!=None:
rom = rom or self.roms[0]
ow = self.ow
ow.reset()
ow.select_rom(rom)
ow.write_byte(0x44) # Convert Temp
def read_temp_async(self, rom=None):
"""
Read the temperature of one DS18x20 device if the convertion is complete,
otherwise return None.
"""
if self.isbusy():
return None
if (rom==None) and (len(self.roms)>0):
rom=self.roms[0]
if rom==None:
return None
else:
ow = self.ow
ow.reset()
ow.select_rom(rom)
ow.write_byte(0xbe) # Read scratch
data = ow.read_bytes(9)
return self.convert_temp(rom[0], data)
def convert_temp(self, rom0, data):
"""
Convert the raw temperature data into degrees celsius and return as a fixed point with 2 decimal places.
"""
temp_lsb = data[0]
temp_msb = data[1]
if rom0 == 0x10:
if temp_msb != 0:
# convert negative number
temp_read = temp_lsb >> 1 | 0x80 # truncate bit 0 by shifting, fill high bit with 1.
temp_read = -((~temp_read + 1) & 0xff) # now convert from two's complement
else:
temp_read = temp_lsb >> 1 # truncate bit 0 by shifting
count_remain = data[6]
count_per_c = data[7]
if self.fp:
return temp_read - 25 + (count_per_c - count_remain) / count_per_c
else:
return 100 * temp_read - 25 + (count_per_c - count_remain) // count_per_c
elif rom0 == 0x28:
temp = None
if self.fp:
temp = (temp_msb << 8 | temp_lsb) / 16
else:
temp = (temp_msb << 8 | temp_lsb) * 100 // 16
if (temp_msb & 0xf8) == 0xf8: # for negative temperature
temp -= 0x1000
return temp
else:
assert False
This is the error I'm getting:
>>> %Run -c $EDITOR_CONTENT
init
Traceback (most recent call last):
File "<stdin>", line 11, in <module>
File "ds18x20.py", line 33, in __init__
File "onewire.py", line 30, in __init__
AttributeError: 'OneWire' object has no attribute 'OPEN_DRAIN'
>>>
I've tried multiple ways to resolve this and watched a bunch of videos on youtube, but not sure what causes this issue.
Related
I got an issue with this driver:
LM75_CHIP_ADDR = 0x48
LM75_I2C_SPEED = 100000
LM75_REGS = {
'TEMP' : 0x00,
'CONF' : 0x01,
'THYST' : 0x02,
'TOS' : 0x03,
'PRODID' : 0x07 # TI LM75A chips only?
}
LM75_REPORT_TIME = .8
# Temperature can be sampled at any time but the read aborts
# the current conversion. Conversion time is 300ms so make
# sure not to read too often.
LM75_MIN_REPORT_TIME = .5
class MLM75:
def __init__(self, config):
self.printer = config.get_printer()
self.name = config.get_name().split()[-1]
self.reactor = self.printer.get_reactor()
self.i2c_sen = bus.MCU_I2C_from_config(config, LM75_CHIP_ADDR,
LM75_I2C_SPEED)
self.mcu = self.i2c_sen.get_mcu()
self.report_time = config.getfloat('lm75_report_time',LM75_REPORT_TIME, minval=LM75_MIN_REPORT_TIME)
self.temp = self.min_temp = self.max_temp = 0.0
self.sample_timer = self.reactor.register_timer(self._sample_mlm75)
self.printer.add_object("mlm75 " + self.name, self)
self.printer.register_event_handler("klippy:connect",
self.handle_connect)
############# MUX HANDLER ############
self.gcode = self.printer.lookup_object('gcode')
self.mux = self.printer.load_object(config, "PCA9545A %s" % (self.name,))
self.mux.init_route = config.getint( "mux_ch", 0, minval=0, maxval=3 )
self.mux.address = config.getint( "mux_i2c_address", 112 )
self.mux.change_i2c_addr( self.mux.address )
# _mux_iic_addr = self.mux.get_info()[0]
# _mux_out_chan = self.mux.get_info()[1]
# self.gcode.respond_info('sensor: '+self.name+ '\n' +
# ' addr:'+str(_mux_iic_addr)+
# ' chan:'+str(_mux_out_chan))
self.mux_channel = 0
############# MUX HANDLER ############
def handle_connect(self):
self._init_mlm75()
self.reactor.update_timer(self.sample_timer, self.reactor.NOW)
def setup_minmax(self, min_temp, max_temp):
self.min_temp = min_temp
self.max_temp = max_temp
def setup_callback(self, cb):
self._callback = cb
def get_report_time_delta(self):
return self.report_time
def degrees_from_sample(self, x):
# The temp sample is encoded in the top 9 bits of a 16-bit
# value. Resolution is 0.5 degrees C.
return x[0] + (x[1] >> 7) * 0.5
def _init_mlm75(self):
# Check and report the chip ID but ignore errors since many
# chips don't have it
try:
prodid = self.read_register('PRODID', 1)[0]
logging.info("mlm75: Chip ID %#x" % prodid)
except:
pass
def _sample_mlm75(self, eventtime):
# self.gcode.respond_info( str(self.i) )
self.mux_channel += 1
self.mux_channel %= 4
self.mux.route( self.mux_channel ) # <<<<
# self.gcode.respond_info('mx c:'+str(self.mux.get_info()[1])) # <<<<
try:
sample = self.read_register('TEMP', 2)
self.temp = self.degrees_from_sample(sample)
except Exception:
logging.exception("mlm75: Error reading data")
self.temp = 0.0
return self.reactor.NEVER
if self.temp < self.min_temp or self.temp > self.max_temp:
self.printer.invoke_shutdown(
"MLM75 temperature %0.1f outside range of %0.1f:%.01f"
% (self.temp, self.min_temp, self.max_temp))
measured_time = self.reactor.monotonic()
self._callback(self.mcu.estimated_print_time(measured_time), self.temp)
return measured_time + self.report_time
def read_register(self, reg_name, read_len):
# read a single register
regs = [LM75_REGS[reg_name]]
params = self.i2c_sen.i2c_read(regs, read_len)
return bytearray(params['response'])
def write_register(self, reg_name, data):
if type(data) is not list:
data = [data]
reg = LM75_REGS[reg_name]
data.insert(0, reg)
self.i2c_sen.i2c_write(data)
def get_status(self, eventtime):
return {
'temperature': round(self.temp, 2),
}
def load_config(config):
# Register sensor
pheaters = config.get_printer().load_object(config, "heaters")
pheaters.add_sensor_factory("MLM75", MLM75)
This code is supposed to read, write and change the address of a MUX. For some reason I can't read part of the sensors.
That's the log:
mcu 'mcu': Starting serial connect
Loaded MCU 'mcu' 100 commands (v0.10.0-388-gd9daeb08-dirty-20220429_121230-raspberrypi / gcc: (GCC) 5.4.0 binutils: (GNU Binutils) 2.26.20160125)
MCU 'mcu' config: BUS_PINS_spi=PB3,PB2,PB1 PWM_MAX=255 CLOCK_FREQ=16000000 BUS_PINS_twi=PD0,PD1 MCU=atmega32u4 ADC_MAX=1023 STATS_SUMSQ_BASE=256
mcu 'mcu': got {u'count': 229, '#receive_time': 3173.116210849, u'sum': 315145, u'sumsq': 3550500, '#name': u'stats', '#sent_time': 3173.115847275}
Configured MCU 'mcu' (165 moves)
lm75: Chip ID 0x1e
Starting heater checks for plateHeater1
lm75: Chip ID 0x22
Starting heater checks for plateHeater2
Starting heater checks for blockHeater1
Starting heater checks for blockHeater2
mlm75: Error reading data
Traceback (most recent call last):
File "/home/heater/klipper/klippy/extras/mlm75.py", line 104, in _sample_mlm75
sample = self.read_register('TEMP', 2)
File "/home/heater/klipper/klippy/extras/mlm75.py", line 123, in read_register
params = self.i2c.i2c_read(regs, read_len) #dobaveno ot lm75.py
AttributeError: MLM75 instance has no attribute 'i2c'
mlm75: Error reading data
Traceback (most recent call last):
File "/home/heater/klipper/klippy/extras/mlm75.py", line 104, in _sample_mlm75
sample = self.read_register('TEMP', 2)
File "/home/heater/klipper/klippy/extras/mlm75.py", line 123, in read_register
params = self.i2c.i2c_read(regs, read_len) #dobaveno ot lm75.py
AttributeError: MLM75 instance has no attribute 'i2c'
I am trying to figure this thing out for 2 weeks now and my hair is starting to fall. Can someone tell me what I do wrong?
Thanks for the help
Here in California, I have purchased some Nova SDS011 PM sensors. When attempting to read from these sensors using Ivan Kalchev's git repo, I get mixed results. I can send commands to the sensor. e.g. sensor.sleep(sleep=<True/False>) will turn the fan on and off. However attempting to query the sensor to return PM2.5 and PM10 data returns a byte string that does not match the check sum. A couple examples are in the code snip-it below. As you can see, bytes 2 and 6 appear to be corrupt, and furthermore, the response is two bytes shorter than what is expected from the documentation.
Any Idea whats going on here? Im hoping this is simply a problem with pyserial. I have produced the same results with two sensors.
>>> sensor.sleep(sleep=False)
>>> cmd
'\xaa\xb4\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x02\xab'
>>> sensor.ser.write(cmd)
19
>>> sensor.ser.readline()
'\xaa\xc0]\x01\xba\x01\xc2*\x05\xab'
>>> sensor.ser.write(cmd)
19
>>> sensor.ser.readline()
'\xaa\xc0c\x01\xbc\x01\xc2*\r\xab'
>>> sensor.ser.write(cmd)
19
>>> sensor.ser.readline()
'\xaa\xc0d\x01\xbf\x01\xc2*\x11\xab'
So this occurred because the python was written for python 3, and my raspberry pi had 2.7. below is the code for 2.7. Thanks to Ivan for putting the original together.
"""This module provides an abstraction for the SDS011 air partuclate densiry sensor.
"""
import struct
import serial
#TODO: Commands against the sensor should read the reply and return success status.
class SDS011(object):
"""Provides method to read from a SDS011 air particlate density sensor
using UART.
"""
HEAD = b'\xaa'
TAIL = b'\xab'
CMD_ID = b'\xb4'
# The sent command is a read or a write
READ = b"\x00"
WRITE = b"\x01"
REPORT_MODE_CMD = b"\x02"
ACTIVE = b"\x00"
PASSIVE = b"\x01"
QUERY_CMD = b"\x04"
# The sleep command ID
SLEEP_CMD = b"\x06"
# Sleep and work byte
SLEEP = b"\x00"
WORK = b"\x01"
# The work period command ID
WORK_PERIOD_CMD = b'\x08'
def __init__(self, serial_port, baudrate=9600, timeout=2,
use_query_mode=True):
"""Initialise and open serial port.
"""
self.ser = serial.Serial(port=serial_port,
baudrate=baudrate,
timeout=timeout)
self.ser.flush()
self.set_report_mode(active=not use_query_mode)
def _execute(self, cmd_bytes):
"""Writes a byte sequence to the serial.
"""
self.ser.write(cmd_bytes)
def _get_reply(self):
"""Read reply from device."""
raw = self.ser.read(size=10)
data = raw[2:8]
if len(data) == 0:
return None
if (sum(ord(d) for d in data) & 255) != ord(raw[8]):
return None #TODO: also check cmd id
return raw
def cmd_begin(self):
"""Get command header and command ID bytes.
#rtype: list
"""
return self.HEAD + self.CMD_ID
def set_report_mode(self, read=False, active=False):
"""Get sleep command. Does not contain checksum and tail.
#rtype: list
"""
cmd = self.cmd_begin()
cmd += (self.REPORT_MODE_CMD
+ (self.READ if read else self.WRITE)
+ (self.ACTIVE if active else self.PASSIVE)
+ b"\x00" * 10)
cmd = self._finish_cmd(cmd)
self._execute(cmd)
self._get_reply()
def query(self):
"""Query the device and read the data.
#return: Air particulate density in micrograms per cubic meter.
#rtype: tuple(float, float) -> (PM2.5, PM10)
"""
cmd = self.cmd_begin()
cmd += (self.QUERY_CMD
+ b"\x00" * 12)
cmd = self._finish_cmd(cmd)
self._execute(cmd)
raw = self._get_reply()
if raw is None:
return None #TODO:
data = struct.unpack('<HH', raw[2:6])
pm25 = data[0] / 10.0
pm10 = data[1] / 10.0
return (pm25, pm10)
def sleep(self, read=False, sleep=True):
"""Sleep/Wake up the sensor.
#param sleep: Whether the device should sleep or work.
#type sleep: bool
"""
cmd = self.cmd_begin()
cmd += (self.SLEEP_CMD
+ (self.READ if read else self.WRITE)
+ (self.SLEEP if sleep else self.WORK)
+ b"\x00" * 10)
cmd = self._finish_cmd(cmd)
self._execute(cmd)
self._get_reply()
def set_work_period(self, read=False, work_time=0):
"""Get work period command. Does not contain checksum and tail.
#rtype: list
"""
assert work_time >= 0 and work_time <= 30
cmd = self.cmd_begin()
cmd += (self.WORK_PERIOD_CMD
+ (self.READ if read else self.WRITE)
+ bytes([work_time])
+ b"\x00" * 10)
cmd = self._finish_cmd(cmd)
self._execute(cmd)
self._get_reply()
def _finish_cmd(self, cmd, id1=b"\xff", id2=b"\xff"):
"""Add device ID, checksum and tail bytes.
#rtype: list
"""
cmd += id1 + id2
checksum = sum(d for d in bytearray(cmd[2:])) % 256
cmd += chr(checksum) + self.TAIL
return cmd
def _process_frame(self, data):
"""Process a SDS011 data frame.
Byte positions:
0 - Header
1 - Command No.
2,3 - PM2.5 low/high byte
4,5 - PM10 low/high
6,7 - ID bytes
8 - Checksum - sum of bytes 2-7
9 - Tail
"""
raw = struct.unpack('<HHxxBBB', data[2:])
checksum = sum(v for v in bytearray(data[2:8])) % 256
if checksum != data[8]:
return None
pm25 = raw[0] / 10.0
pm10 = raw[1] / 10.0
return (pm25, pm10)
def read(self):
"""Read sensor data.
#return: PM2.5 and PM10 concetration in micrograms per cude meter.
#rtype: tuple(float, float) - first is PM2.5.
"""
byte = 0
while byte != self.HEAD:
byte = self.ser.read(size=1)
d = self.ser.read(size=10)
if d[0:1] == b"\xc0":
data = self._process_frame(byte + d)
return data
I have a matrix keypad and a hd44780 lcd connected into raspberry pi.
The below code are in python. It will take 4 digit password from the user, but when the user enter the digit through the keypad, nothing was display on the lcd. I would like when the user enter a digit a * display on the lcd. I can only manage to get the * print in the same place,but not in 4 separate place.
Code
import RPi.GPIO as GPIO
import time
import lcd
import os
import subprocess
from subprocess import call
mylcd = lcd.lcd()
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
MATRIX = [['1', '2', '3', 'A'],
['4', '5', '6', 'B'],
['7', '8', '9', 'C'],
['*', '0', '#', 'D']]
ROW = [5,6,13,19]
COL = [26,16,20,21]
for j in range(4):
GPIO.setup(COL[j], GPIO.OUT)
GPIO.output(COL[j], 1)
for i in range(4):
GPIO.setup(ROW[i], GPIO.IN, pull_up_down=GPIO.PUD_UP)
password = "1234"
attempt = ""
try:
while (True):
mylcd.lcd_display_string("Enter pw",1)
for j in range(4):
GPIO.output(COL[j], 0)
for i in range(4):
if GPIO.input(ROW[i]) == 0:
mylcd.lcd_display_string("*",2,0)
time.sleep(0.01)
while (GPIO.input(ROW[i]) == 0):
pass
attempt += MATRIX[i][j]
if len(attempt) == len(password):
if attempt == password:
mylcd.lcd_clear()
print "Password OK"
mylcd.lcd_display_string("Password",1 ,4 )
mylcd.lcd_display_string("Ok!",2 ,6 )
time.sleep(2)
mylcd.lcd_clear()
os.chdir('/home/pi/nfc/py532lib')
call('./nfc.sh')
mylcd.lcd_clear()
else:
print(attempt)
print "Password incorrect"
mylcd.lcd_display_string("Password",1,4)
mylcd.lcd_display_string("Incorrect!",2,3)
time.sleep(2)
mylcd.lcd_clear()
attempt = ""
time.sleep(0.01)
GPIO.output(COL[j], 1)
except KeyboardInterrupt:
GPIO.cleanup()
LCD Library
# -*- coding: utf-8 -*-
# Original code found at:
# https://gist.github.com/DenisFromHR/cc863375a6e19dce359d
"""
Compiled, mashed and generally mutilated 2014-2015 by Denis Pleic
Made available under GNU GENERAL PUBLIC LICENSE
# Modified Python I2C library for Raspberry Pi
# as found on http://www.recantha.co.uk/blog/?p=4849
# Joined existing 'i2c_lib.py' and 'lcddriver.py' into a single library
# added bits and pieces from various sources
# By DenisFromHR (Denis Pleic)
# 2015-02-10, ver 0.1
"""
# i2c bus (0 -- original Pi, 1 -- Rev 2 Pi)
I2CBUS = 0
# LCD Address
ADDRESS = 0x27
import smbus
from time import sleep
class i2c_device:
def __init__(self, addr, port=I2CBUS):
self.addr = addr
self.bus = smbus.SMBus(port)
# Write a single command
def write_cmd(self, cmd):
self.bus.write_byte(self.addr, cmd)
sleep(0.0001)
# Write a command and argument
def write_cmd_arg(self, cmd, data):
self.bus.write_byte_data(self.addr, cmd, data)
sleep(0.0001)
# Write a block of data
def write_block_data(self, cmd, data):
self.bus.write_block_data(self.addr, cmd, data)
sleep(0.0001)
# Read a single byte
def read(self):
return self.bus.read_byte(self.addr)
# Read
def read_data(self, cmd):
return self.bus.read_byte_data(self.addr, cmd)
# Read a block of data
def read_block_data(self, cmd):
return self.bus.read_block_data(self.addr, cmd)
# 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 entry mode
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00
# 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/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT = 0x00
# flags for function set
LCD_8BITMODE = 0x10
LCD_4BITMODE = 0x00
LCD_2LINE = 0x08
LCD_1LINE = 0x00
LCD_5x10DOTS = 0x04
LCD_5x8DOTS = 0x00
# flags for backlight control
LCD_BACKLIGHT = 0x08
LCD_NOBACKLIGHT = 0x00
En = 0b00000100 # Enable bit
Rw = 0b00000010 # Read/Write bit
Rs = 0b00000001 # Register select bit
class lcd:
#initializes objects and lcd
def __init__(self):
self.lcd_device = i2c_device(ADDRESS)
self.lcd_write(0x03)
self.lcd_write(0x03)
self.lcd_write(0x03)
self.lcd_write(0x02)
self.lcd_write(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_4BITMODE)
self.lcd_write(LCD_DISPLAYCONTROL | LCD_DISPLAYON)
self.lcd_write(LCD_CLEARDISPLAY)
self.lcd_write(LCD_ENTRYMODESET | LCD_ENTRYLEFT)
sleep(0.2)
# clocks EN to latch command
def lcd_strobe(self, data):
self.lcd_device.write_cmd(data | En | LCD_BACKLIGHT)
sleep(.0005)
self.lcd_device.write_cmd(((data & ~En) | LCD_BACKLIGHT))
sleep(.0001)
def lcd_write_four_bits(self, data):
self.lcd_device.write_cmd(data | LCD_BACKLIGHT)
self.lcd_strobe(data)
# write a command to lcd
def lcd_write(self, cmd, mode=0):
self.lcd_write_four_bits(mode | (cmd & 0xF0))
self.lcd_write_four_bits(mode | ((cmd << 4) & 0xF0))
# write a character to lcd (or character rom) 0x09: backlight | RS=DR<
# works!
def lcd_write_char(self, charvalue, mode=1):
self.lcd_write_four_bits(mode | (charvalue & 0xF0))
self.lcd_write_four_bits(mode | ((charvalue << 4) & 0xF0))
# put string function with optional char positioning
def lcd_display_string(self, string, line=1, pos=0):
if line == 1:
pos_new = pos
elif line == 2:
pos_new = 0x40 + pos
elif line == 3:
pos_new = 0x14 + pos
elif line == 4:
pos_new = 0x54 + pos
self.lcd_write(0x80 + pos_new)
for char in string:
self.lcd_write(ord(char), Rs)
# clear lcd and set to home
def lcd_clear(self):
self.lcd_write(LCD_CLEARDISPLAY)
self.lcd_write(LCD_RETURNHOME)
# define backlight on/off (lcd.backlight(1); off= lcd.backlight(0)
def backlight(self, state): # for state, 1 = on, 0 = off
if state == 1:
self.lcd_device.write_cmd(LCD_BACKLIGHT)
elif state == 0:
self.lcd_device.write_cmd(LCD_NOBACKLIGHT)
# add custom characters (0 - 7)
def lcd_load_custom_chars(self, fontdata):
self.lcd_write(0x40);
for char in fontdata:
for line in char:
self.lcd_write_char(line)
Your code may be not correct. For each output you test all inputs:
for i in range(4):
if GPIO.input(ROW[i]) == 0:
Check if for sure exactly one proper input is active. If not, you have to rewrite it.
Moreover, the number of * should depend on external counter j, not i (my mistake in the comment, sorry):
mylcd.lcd_display_string((j+1) * "*", 2, 0)
I'm new to Python and currently working on a project on my Pi 3 mod b. I use an Adafruit ADC1015 to convert analogue signal. However, even if i have the code to get some volt measurments, i get an error of " AttributeError: 'int' object has no attribute 'readADCSingleEnded'".
To explain that, the python script i'm trying to run is the following:
#!/usr/bin/python
import time, signal, sys
from Adafruit_ADS1x15 import ADS1x15
def signal_handler(signal, frame):
print 'You pressed Ctrl+C!'
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
ADS1015 = 0x00
ADS1115 = 0x01
gain = 4096 # +/- 4.096V
sps = 250 # 250 samples per second
# Initialise the ADC using the default mode (use default I2C address)
# Set this to ADS1015 or ADS1115 depending on the ADC you are using!
adc = ADS1015(ic=ADS1015)
# Read channel 0 in single-ended mode using the settings above
volts=adc.readADCSingleEnded(0, gain, sps) / 1000
# To read channel 3 in single-ended mode, +/- 1.024V, 860 sps use:
# volts = adc.readADCSingleEnded(3, 1024, 860)
print "%.6f" % (volts)
The "ADS1x15" file we import contains the following code related to the error:
# Constructor
def __init__(self, address=0x48, ic=__IC_ADS1015, debug=False):
# Depending on if you have an old or a new Raspberry Pi, you
# may need to change the I2C bus. Older Pis use SMBus 0,
# whereas new Pis use SMBus 1. If you see an error like:
# 'Error accessing 0x48: Check your I2C address '
# change the SMBus number in the initializer below!
self.i2c = Adafruit_I2C(address)
self.address = address
self.debug = debug
# Make sure the IC specified is valid
if ((ic < self.__IC_ADS1015) | (ic > self.__IC_ADS1115)):
if (self.debug):
print "ADS1x15: Invalid IC specfied: %h" % ic
return -1
else:
self.ic = ic
# Set pga value, so that getLastConversionResult() can use it,
# any function that accepts a pga value must update this.
self.pga = 6144
def readADCSingleEnded(self, channel=0, pga=6144, sps=250):
"Gets a single-ended ADC reading from the specified channel in mV. \
The sample rate for this mode (single-shot) can be used to lower the noise \
(low sps) or to lower the power consumption (high sps) by duty cycling, \
see datasheet page 14 for more info. \
The pga must be given in mV, see page 13 for the supported values."
# With invalid channel return -1
if (channel > 3):
if (self.debug):
print "ADS1x15: Invalid channel specified: %d" % channel
return -1
# Disable comparator, Non-latching, Alert/Rdy active low
# traditional comparator, single-shot mode
config = self.__ADS1015_REG_CONFIG_CQUE_NONE | \
self.__ADS1015_REG_CONFIG_CLAT_NONLAT | \
self.__ADS1015_REG_CONFIG_CPOL_ACTVLOW | \
self.__ADS1015_REG_CONFIG_CMODE_TRAD | \
self.__ADS1015_REG_CONFIG_MODE_SINGLE
# Set sample per seconds, defaults to 250sps
# If sps is in the dictionary (defined in init) it returns the value of the constant
# othewise it returns the value for 250sps. This saves a lot of if/elif/else code!
if (self.ic == self.__IC_ADS1015):
config |= self.spsADS1015.setdefault(sps, self.__ADS1015_REG_CONFIG_DR_1600SPS)
else:
if ( (sps not in self.spsADS1115) & self.debug):
print "ADS1x15: Invalid pga specified: %d, using 6144mV" % sps
config |= self.spsADS1115.setdefault(sps, self.__ADS1115_REG_CONFIG_DR_250SPS)
# Set PGA/voltage range, defaults to +-6.144V
if ( (pga not in self.pgaADS1x15) & self.debug):
print "ADS1x15: Invalid pga specified: %d, using 6144mV" % sps
config |= self.pgaADS1x15.setdefault(pga, self.__ADS1015_REG_CONFIG_PGA_6_144V)
self.pga = pga
# Set the channel to be converted
if channel == 3:
config |= self.__ADS1015_REG_CONFIG_MUX_SINGLE_3
elif channel == 2:
config |= self.__ADS1015_REG_CONFIG_MUX_SINGLE_2
elif channel == 1:
config |= self.__ADS1015_REG_CONFIG_MUX_SINGLE_1
else:
config |= self.__ADS1015_REG_CONFIG_MUX_SINGLE_0
# Set 'start single-conversion' bit
config |= self.__ADS1015_REG_CONFIG_OS_SINGLE
# Write config register to the ADC
bytes = [(config >> 8) & 0xFF, config & 0xFF]
self.i2c.writeList(self.__ADS1015_REG_POINTER_CONFIG, bytes)
# Wait for the ADC conversion to complete
# The minimum delay depends on the sps: delay >= 1/sps
# We add 0.1ms to be sure
delay = 1.0/sps+0.0001
time.sleep(delay)
# Read the conversion results
result = self.i2c.readList(self.__ADS1015_REG_POINTER_CONVERT, 2)
if (self.ic == self.__IC_ADS1015):
# Shift right 4 bits for the 12-bit ADS1015 and convert to mV
return ( ((result[0] << 8) | (result[1] & 0xFF)) >> 4 )*pga/2048.0
else:
# Return a mV value for the ADS1115
# (Take signed values into account as well)
val = (result[0] << 8) | (result[1])
if val > 0x7FFF:
return (val - 0xFFFF)*pga/32768.0
else:
return ( (result[0] << 8) | (result[1]) )*pga/32768.0
I believed this would run smmothly, as it is a part something that is related to the ADC, but i haven't managed to solve this problem, even if i tried a lot.
Found it. Line
adc = ADS1015(ic=ADS1015)
Should be
adc = ADS1x15(ic=ADS1015)
A month ago, i asked this about multiplexing a string of numbers with 4 7-segment displays. But now, I'm trying to update the code to multiplex a string of letters using 7 7-segment displays in python.
This is the new circuit. When i send data using the parallel port, the Latch Enable receives the most significant bit (pin 9). In the second latch, the Latch Enable receives it also but negated, that is the reason of the 7404.
That is either address is set (/LE==False) or data is set (/LE=True).
This is what I'm trying to do. The 'X' represents that the 7-segment display is off. But can't archive it.
XXXXXXX
XXXXXXS
XXXXXST
XXXXSTA
XXXSTAC
XXSTACK
XSTACKX
STACKX0
TACKX0V
ACKX0V3
CKX0V3R
KX0V3RF
X0VERFL
0VERFL0
VERFL0W
ERFL0WX
RFL0WXX
FL0WXXX
L0WXXXX
0WXXXXX
WXXXXXX
XXXXXXX
That would be the output for the string "STACK 0V3RFL0W".
Also the past code:
import sys
import parallel
class Display(object):
def __init__(self):
'''Init and blank the "display".'''
self.display = [' '] * 4
self._update()
def setData(self,data):
'''Bits 0-3 are the "value".
Bits 4-7 are positions 0-3 (first-to-last).
'''
self.display = [' '] * 4
value = data & 0xF
if data & 0x10:
self.display[0] = str(value)
if data & 0x20:
self.display[1] = str(value)
if data & 0x40:
self.display[2] = str(value)
if data & 0x80:
self.display[3] = str(value)
self._update()
def _update(self):
'''Write over the same four terminal positions each time.'''
sys.stdout.write(''.join(self.display) + '\r')
if __name__ == '__main__':
p = Display()
pp=parallel.Parallel()
nums = raw_input("Enter a string of numbers: ")
# Shift over the steam four-at-a-time.
stream = 'XXXX' + nums + 'XXXX'
data = [0] * 4
for i in range(len(stream)-3):
# Precompute data
for pos in range(4):
value = stream[i+pos]
data[pos] = 0 if value == 'X' else (1<<(pos+4)) + int(value)
# "Flicker" the display...
for delay in xrange(1000):
# Display each position briefly.
for d in data:
pp.setData(d)
# Clear the display when done
p.setData(0)
Algorithm outline:
string = "07831505"
while True:
for i in range(7):
# switch display `i` on
notlatch.set(True)
data.set(1 << i)
notlatch.set(False)
time.sleep(<very little>)
notlatch.set(True)
# display character on display `i`
data.set(char_to_7segment(string[i]))
time.sleep(0.01)