/ adafruit_pcf8591 / pcf8591.py
pcf8591.py
1 # SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries 2 # SPDX-FileCopyrightText: Copyright (c) 2020 Bryan Siepert for Adafruit Industries 3 # 4 # SPDX-License-Identifier: MIT 5 """ 6 `pcf8591` 7 ================================================================================ 8 9 ADC+DAC Combo 10 11 * Author(s): Bryan Siepert 12 13 Implementation Notes 14 -------------------- 15 16 **Hardware:** 17 18 * `Adafruit PCF8591 Breakout <https://www.adafruit.com/products/45XX>`_ 19 20 **Software and Dependencies:** 21 22 * Adafruit CircuitPython firmware for the supported boards: 23 https://github.com/adafruit/circuitpython/releases 24 25 * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice 26 * Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register 27 """ 28 29 __version__ = "0.0.0-auto.0" 30 __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_PCF8591.git" 31 # from time import sleep 32 from struct import unpack_from 33 from micropython import const 34 import adafruit_bus_device.i2c_device as i2c_device 35 36 _PCF8591_DEFAULT_ADDR = const(0x48) # PCF8591 Default Address 37 _PCF8591_ENABLE_DAC = const(0x40) # control bit for having the DAC active 38 39 # Pin constants 40 A0 = const(0) 41 A1 = const(1) 42 A2 = const(2) 43 A3 = const(3) 44 45 OUT = const(0) 46 47 48 class PCF8591: 49 """Driver for the PCF8591 DAC & ADC Combo breakout. 50 51 :param ~busio.I2C i2c_bus: The I2C bus the PCF8591 is connected to. 52 :param address: The I2C device address for the sensor. Default is ``0x28``. 53 54 """ 55 56 def __init__(self, i2c_bus, address=_PCF8591_DEFAULT_ADDR, reference_voltage=3.3): 57 self.i2c_device = i2c_device.I2CDevice(i2c_bus, address) 58 self._dacval = 0 59 self._dac_enabled = False 60 # this is the range supported by the PCF8591 61 if 2.5 <= reference_voltage <= 6.0: 62 self._reference_voltage = reference_voltage 63 else: 64 raise ValueError("reference_voltage must be from 2.5 - 6.0") 65 self._buffer = bytearray(2) 66 print("self.reference_voltage = ", self.reference_voltage) 67 # possibly measure each channel here to prep readings for 68 # user calls to `read` 69 70 @property 71 def reference_voltage(self): 72 """The voltage level that ADC signals are compared to. 73 An ADC value of 65535 will equal `reference_voltage`""" 74 return self._reference_voltage 75 76 def _half_read(self, channel): 77 if self._dac_enabled: 78 self._buffer[0] = _PCF8591_ENABLE_DAC 79 self._buffer[1] = self._dacval 80 else: 81 self._buffer[0] = 0 82 self._buffer[1] = 0 83 84 self._buffer[0] |= channel & 0x3 85 86 with self.i2c_device as i2c: 87 i2c.write_then_readinto(self._buffer, self._buffer) 88 89 def read(self, channel): 90 """Read an analog value from one of the four ADC inputs 91 92 param: :channel The single-ended ADC channel to read from, 0 thru 3 93 """ 94 if channel < 0 or channel > 3: 95 raise ValueError("channel must be from 0-3") 96 # reads are started on the ACK of the WRITE to the 'register' and 97 # not returned until the read after the _next_ WRITE so we have to 98 # do it twice to get the actual value 99 self._half_read(channel) 100 self._half_read(channel) 101 102 return unpack_from(">B", self._buffer[1:])[0] 103 104 @property 105 def dac_enabled(self): 106 """ Enables the DAC when True, or sets it to tri-state / high-Z when False""" 107 return self._dac_enabled 108 109 @dac_enabled.setter 110 def dac_enabled(self, enable_dac): 111 112 self._dac_enabled = enable_dac 113 self.write(self._dacval) 114 115 def write(self, value): 116 """Writes a uint8_t value to the DAC output 117 118 param: :output The value to write: 0 is GND and 65535 is VCC 119 120 """ 121 122 self._buffer = bytearray(2) 123 if self._dac_enabled: 124 self._buffer[0] = _PCF8591_ENABLE_DAC 125 self._buffer[1] = value 126 self._dacval = value 127 with self.i2c_device as i2c: 128 i2c.write_then_readinto(self._buffer, self._buffer)