Commit 961cd86c authored by Anton Sarukhanov's avatar Anton Sarukhanov
Browse files

initial commit

parents
File added
File added
File added
#!/usr/bin/python
"""
================================================
ABElectronics ADC Pi V2 8-Channel ADC
Version 1.0 Created 09/05/2014
Version 1.1 16/11/2014 updated code and functions to PEP8 format
Requires python smbus to be installed
================================================
"""
class ADCPi:
# internal variables
__address = 0x68 # default address for adc 1 on adc pi and delta-sigma pi
__address2 = 0x69 # default address for adc 2 on adc pi and delta-sigma pi
__config1 = 0x1C # PGAx1, 18 bit, one-shot conversion, channel 1
__currentchannel1 = 1 # channel variable for adc 1
__config2 = 0x1C # PGAx1, 18 bit, one-shot conversion, channel 1
__currentchannel2 = 1 # channel variable for adc2
__bitrate = 18 # current bitrate
__pga = float(0.5) # current pga setting
__lsb = float(0.0000078125) # default lsb value for 18 bit
# create byte array and fill with initial values to define size
__adcreading = bytearray()
__adcreading.append(0x00)
__adcreading.append(0x00)
__adcreading.append(0x00)
__adcreading.append(0x00)
global _bus
# local methods
def __updatebyte(self, byte, bit, value):
# internal method for setting the value of a single bit within a
# byte
if value == 0:
return byte & ~(1 << bit)
elif value == 1:
return byte | (1 << bit)
def __checkbit(self, byte, bit):
# internal method for reading the value of a single bit within a
# byte
bitval = ((byte & (1 << bit)) != 0)
if (bitval == 1):
return True
else:
return False
def __twos_comp(self, val, bits):
if((val & (1 << (bits - 1))) != 0):
val = val - (1 << bits)
return val
def __setchannel(self, channel):
# internal method for updating the config to the selected channel
if channel < 5:
if channel != self.__currentchannel1:
if channel == 1:
self.__config1 = self.__updatebyte(self.__config1, 5, 0)
self.__config1 = self.__updatebyte(self.__config1, 6, 0)
self.__currentchannel1 = 1
if channel == 2:
self.__config1 = self.__updatebyte(self.__config1, 5, 1)
self.__config1 = self.__updatebyte(self.__config1, 6, 0)
self.__currentchannel1 = 2
if channel == 3:
self.__config1 = self.__updatebyte(self.__config1, 5, 0)
self.__config1 = self.__updatebyte(self.__config1, 6, 1)
self.__currentchannel1 = 3
if channel == 4:
self.__config1 = self.__updatebyte(self.__config1, 5, 1)
self.__config1 = self.__updatebyte(self.__config1, 6, 1)
self.__currentchannel1 = 4
else:
if channel != self.__currentchannel2:
if channel == 5:
self.__config2 = self.__updatebyte(self.__config2, 5, 0)
self.__config2 = self.__updatebyte(self.__config2, 6, 0)
self.__currentchannel2 = 5
if channel == 6:
self.__config2 = self.__updatebyte(self.__config2, 5, 1)
self.__config2 = self.__updatebyte(self.__config2, 6, 0)
self.__currentchannel2 = 6
if channel == 7:
self.__config2 = self.__updatebyte(self.__config2, 5, 0)
self.__config2 = self.__updatebyte(self.__config2, 6, 1)
self.__currentchannel2 = 7
if channel == 8:
self.__config2 = self.__updatebyte(self.__config2, 5, 1)
self.__config2 = self.__updatebyte(self.__config2, 6, 1)
self.__currentchannel2 = 8
return
# init object with i2caddress, default is 0x68, 0x69 for ADCoPi board
def __init__(self, bus, address=0x68, address2=0x69, rate=18):
self._bus = bus
self.__address = address
self.__address2 = address2
self.setBitRate(rate)
def read_voltage(self, channel):
# returns the voltage from the selected adc channel - channels 1 to
# 8
raw = self.read_raw(channel)
if (self.__signbit):
return float(0.0) # returned a negative voltage so return 0
else:
voltage = float(
(raw * (self.__lsb / self.__pga)) * 2.448579823702253)
return float(voltage)
def read_raw(self, channel):
# reads the raw value from the selected adc channel - channels 1 to 8
h = 0
l = 0
m = 0
s = 0
# get the config and i2c address for the selected channel
self.__setchannel(channel)
if (channel < 5):
config = self.__config1
address = self.__address
else:
config = self.__config2
address = self.__address2
# keep reading the adc data until the conversion result is ready
while True:
__adcreading = self._bus.read_i2c_block_data(address, config)
if self.__bitrate == 18:
h = __adcreading[0]
m = __adcreading[1]
l = __adcreading[2]
s = __adcreading[3]
else:
h = __adcreading[0]
m = __adcreading[1]
s = __adcreading[2]
if self.__checkbit(s, 7) == 0:
break
self.__signbit = False
t = 0.0
# extract the returned bytes and combine in the correct order
if self.__bitrate == 18:
t = ((h & 0b00000011) << 16) | (m << 8) | l
self.__signbit = bool(self.__checkbit(t, 17))
if self.__signbit:
t = self.__updatebyte(t, 17, 0)
if self.__bitrate == 16:
t = (h << 8) | m
self.__signbit = bool(self.__checkbit(t, 15))
if self.__signbit:
t = self.__updatebyte(t, 15, 0)
if self.__bitrate == 14:
t = ((h & 0b00111111) << 8) | m
self.__signbit = self.__checkbit(t, 13)
if self.__signbit:
t = self.__updatebyte(t, 13, 0)
if self.__bitrate == 12:
t = ((h & 0b00001111) << 8) | m
self.__signbit = self.__checkbit(t, 11)
if self.__signbit:
t = self.__updatebyte(t, 11, 0)
return t
def set_pga(self, gain):
"""
PGA gain selection
1 = 1x
2 = 2x
4 = 4x
8 = 8x
"""
if gain == 1:
self.__config1 = self.__updatebyte(self.__config1, 0, 0)
self.__config1 = self.__updatebyte(self.__config1, 1, 0)
self.__config2 = self.__updatebyte(self.__config2, 0, 0)
self.__config2 = self.__updatebyte(self.__config2, 1, 0)
self.__pga = 0.5
if gain == 2:
self.__config1 = self.__updatebyte(self.__config1, 0, 1)
self.__config1 = self.__updatebyte(self.__config1, 1, 0)
self.__config2 = self.__updatebyte(self.__config2, 0, 1)
self.__config2 = self.__updatebyte(self.__config2, 1, 0)
self.__pga = 1
if gain == 4:
self.__config1 = self.__updatebyte(self.__config1, 0, 0)
self.__config1 = self.__updatebyte(self.__config1, 1, 1)
self.__config2 = self.__updatebyte(self.__config2, 0, 0)
self.__config2 = self.__updatebyte(self.__config2, 1, 1)
self.__pga = 2
if gain == 8:
self.__config1 = self.__updatebyte(self.__config1, 0, 1)
self.__config1 = self.__updatebyte(self.__config1, 1, 1)
self.__config2 = self.__updatebyte(self.__config2, 0, 1)
self.__config2 = self.__updatebyte(self.__config2, 1, 1)
self.__pga = 4
self._bus.write_byte(self.__address, self.__config1)
self._bus.write_byte(self.__address2, self.__config2)
return
def setBitRate(self, rate):
"""
sample rate and resolution
12 = 12 bit (240SPS max)
14 = 14 bit (60SPS max)
16 = 16 bit (15SPS max)
18 = 18 bit (3.75SPS max)
"""
if rate == 12:
self.__config1 = self.__updatebyte(self.__config1, 2, 0)
self.__config1 = self.__updatebyte(self.__config1, 3, 0)
self.__config2 = self.__updatebyte(self.__config2, 2, 0)
self.__config2 = self.__updatebyte(self.__config2, 3, 0)
self.__bitrate = 12
self.__lsb = 0.0005
if rate == 14:
self.__config1 = self.__updatebyte(self.__config1, 2, 1)
self.__config1 = self.__updatebyte(self.__config1, 3, 0)
self.__config2 = self.__updatebyte(self.__config2, 2, 1)
self.__config2 = self.__updatebyte(self.__config2, 3, 0)
self.__bitrate = 14
self.__lsb = 0.000125
if rate == 16:
self.__config1 = self.__updatebyte(self.__config1, 2, 0)
self.__config1 = self.__updatebyte(self.__config1, 3, 1)
self.__config2 = self.__updatebyte(self.__config2, 2, 0)
self.__config2 = self.__updatebyte(self.__config2, 3, 1)
self.__bitrate = 16
self.__lsb = 0.00003125
if rate == 18:
self.__config1 = self.__updatebyte(self.__config1, 2, 1)
self.__config1 = self.__updatebyte(self.__config1, 3, 1)
self.__config2 = self.__updatebyte(self.__config2, 2, 1)
self.__config2 = self.__updatebyte(self.__config2, 3, 1)
self.__bitrate = 18
self.__lsb = 0.0000078125
self._bus.write_byte(self.__address, self.__config1)
self._bus.write_byte(self.__address2, self.__config2)
return
#!/usr/bin/python
import smbus
import re
"""
================================================
ABElectronics Python Helper Functions
Version 1.0 Created 15/11/2014
Python 2 only
Requires python 2 smbus to be installed with: sudo apt-get install python-smbus
This file contains functions to load puthon smbus into an instance variable.
The bus object can then be used by multiple devices without conflicts.
================================================
"""
class ABEHelpers:
def get_smbus(self):
# detect i2C port number and assign to i2c_bus
i2c_bus = 0
for line in open('/proc/cpuinfo').readlines():
m = re.match('(.*?)\s*:\s*(.*)', line)
if m:
(name, value) = (m.group(1), m.group(2))
if name == "Revision":
if value[-4:] in ('0002', '0003'):
i2c_bus = 0
else:
i2c_bus = 1
break
return smbus.SMBus(i2c_bus)
AB Electronics UK ADC Pi Python Library
=====
Python Library to use with ADC Pi Raspberry Pi expansion board from http://www.abelectronics.co.uk
Install
====
To download to your Raspberry Pi type in terminal:
```
git clone https://github.com/abelectronicsuk/ABElectronics_Python_Libraries.git
```
The ADC Pi library is located in the ADCPi directory
The library requires python-smbus to be installed.
```
sudo apt-get update
sudo apt-get install python-smbus
```
Add the location where you downloaded the python libraries into PYTHONPATH e.g. download location is Desktop
```
export PYTHONPATH=${PYTHONPATH}:~/Desktop/ABElectronics_Python_Libraries/ADCPi/
```
The example python files in /ABElectronics_Python_Libraries/ADCPi/ will now run from the terminal.
Functions:
----------
```
read_voltage(channel)
```
Read the voltage from the selected channel
**Parameters:** channel - 1 to 8
**Returns:** number as float between 0 and 5.0
```
read_raw(channel)
```
Read the raw int value from the selected channel
**Parameters:** channel - 1 to 8
**Returns:** number as int
```
set_pga(gain)
```
Set the gain of the PDA on the chip
**Parameters:** gain - 1, 2, 4, 8
**Returns:** null
```
set_bit_rate(rate)
```
Set the sample bit rate of the adc
**Parameters:** rate - 12, 14, 16, 18
**Returns:** null
12 = 12 bit (240SPS max)
14 = 14 bit (60SPS max)
16 = 16 bit (15SPS max)
18 = 18 bit (3.75SPS max)
Usage
====
To use the ADC Pi library in your code you must first import the library:
```
from ABE_ADCPi import ADCPi
```
Now import the helper class
```
from ABE_helpers import ABEHelpers
```
Next you must initialise the adc object and smbus:
```
i2c_helper = ABEHelpers()
bus = i2c_helper.get_smbus()
adc = ADCPi(bus, 0x68, 0x69, 18)
```
The first argument is the smbus object folled by the two I2C addresses of the ADC chips. The values shown are the default addresses of the ADC board.
The forth argument is the sample bit rate you want to use on the adc chips. Sample rate can be 12, 14, 16 or 18
You can now read the voltage from channel 1 with:
```
adc.read_voltage(1)
```
2014-11-17 18:03:35.131787 Channel 1: 0.000000
2014-11-17 18:03:35.378950 Channel 2: 0.000000
2014-11-17 18:03:35.627068 Channel 3: 0.000000
2014-11-17 18:03:35.874092 Channel 4: 0.000000
2014-11-17 18:03:35.878367 Channel 5: 0.000000
2014-11-17 18:03:36.125992 Channel 6: 0.000000
2014-11-17 18:03:37.064214 Channel 7: 0.000000
2014-11-17 18:03:37.312133 Channel 8: 0.000000
#!/usr/bin/python
from ABE_ADCPi import ADCPi
from ABE_helpers import ABEHelpers
import time
import os
"""
================================================
ABElectronics ADC Pi ACS712 30 Amp current sensor demo
Version 1.0 Created 15/07/2014
Version 1.1 16/11/2014 updated code and functions to PEP8 format
Requires python smbus to be installed
run with: python demo-acs712-30.py
================================================
Initialise the ADC device using the default addresses and sample rate,
change this value if you have changed the address selection jumpers
Sample rate can be 12,14, 16 or 18
"""
i2c_helper = ABEHelpers()
bus = i2c_helper.get_smbus()
adc = ADCPi(bus, 0x68, 0x69, 12)
# change the 2.5 value to be half of the supply voltage.
def calcCurrent(inval):
return ((inval) - 2.5) / 0.066
while (True):
# clear the console
os.system('clear')
# read from adc channels and print to screen
print ("Current on channel 1: %02f" % calcCurrent(adc.read_voltage(1)))
# wait 0.5 seconds before reading the pins again
time.sleep(0.5)
#!/usr/bin/python
from ABE_ADCPi import ADCPi
from ABE_helpers import ABEHelpers
import datetime
import time
"""
================================================
ABElectronics ADC Pi 8-Channel ADC data-logger demo
Version 1.0 Created 11/05/2014
Version 1.1 16/11/2014 updated code and functions to PEP8 format
Requires python smbus to be installed
run with: python demo-read_voltage.py
================================================
Initialise the ADC device using the default addresses and sample rate, change
this value if you have changed the address selection jumpers
Sample rate can be 12,14, 16 or 18
"""
i2c_helper = ABEHelpers()
bus = i2c_helper.get_smbus()
adc = ADCPi(bus, 0x68, 0x69, 18)
def writetofile(texttowrtite):
f = open('adclog.txt', 'a')
f.write(str(datetime.datetime.now()) + " " + texttowrtite)
f.closed
while (True):
# read from adc channels and write to the log file
writetofile("Channel 1: %02f\n" % adc.read_voltage(1))
writetofile("Channel 2: %02f\n" % adc.read_voltage(2))
writetofile("Channel 3: %02f\n" % adc.read_voltage(3))
writetofile("Channel 4: %02f\n" % adc.read_voltage(4))
writetofile("Channel 5: %02f\n" % adc.read_voltage(5))
writetofile("Channel 6: %02f\n" % adc.read_voltage(6))
writetofile("Channel 7: %02f\n" % adc.read_voltage(7))
writetofile("Channel 8: %02f\n" % adc.read_voltage(8))
# wait 1 second before reading the pins again
time.sleep(1)
#!/usr/bin/python
from ABE_ADCPi import ADCPi
from ABE_helpers import ABEHelpers
import time
import os
"""
================================================
ABElectronics ADC Pi 8-Channel ADC demo
Version 1.0 Created 09/05/2014
Version 1.1 16/11/2014 updated code and functions to PEP8 format
Requires python smbus to be installed
run with: python demo-read_voltage.py
================================================
Initialise the ADC device using the default addresses and sample rate,
change this value if you have changed the address selection jumpers
Sample rate can be 12,14, 16 or 18
"""
i2c_helper = ABEHelpers()
bus = i2c_helper.get_smbus()
adc = ADCPi(bus, 0x68, 0x69, 12)
while (True):
# clear the console
os.system('clear')
# read from adc channels and print to screen
print ("Channel 1: %02f" % adc.read_voltage(1))
print ("Channel 2: %02f" % adc.read_voltage(2))
print ("Channel 3: %02f" % adc.read_voltage(3))
print ("Channel 4: %02f" % adc.read_voltage(4))
print ("Channel 5: %02f" % adc.read_voltage(5))
print ("Channel 6: %02f" % adc.read_voltage(6))
print ("Channel 7: %02f" % adc.read_voltage(7))
print ("Channel 8: %02f" % adc.read_voltage(8))
# wait 0.5 seconds before reading the pins again
time.sleep(0.5)
import time
import os
import RPi.GPIO as GPIO
from ADCPi.ABE_ADCPi import ADCPi
from ADCPi.ABE_helpers import ABEHelpers
class Meter():
# Config
def __init__(self, channels=None):
self.adc_channels = {
1: {'internal_resistance': 2.13, 'gpio_pin': 5},
2: {'internal_resistance': 2.48, 'gpio_pin': 6},
3: {'internal_resistance': 2.13, 'gpio_pin': 13},
4: {'internal_resistance': 2.25, 'gpio_pin': 19},
5: {'internal_resistance': 2.13, 'gpio_pin': 26},
6: {'internal_resistance': 2.13, 'gpio_pin': 12},
8: {'internal_resistance': 2.13, 'gpio_pin': 16},
}
if channels:
for ch in self.adc_channels.keys():
if ch not in channels:
del self.adc_channels[ch]
self.calibration_channel = 8
self.repeat_measurements = 3
self.r1 = 67.1
self.margin_of_error_volts = 0.001
self.max_ohms = 3000
self.system_voltage = 5
# ADCPi Setup
self.i2c_helper = ABEHelpers()
self.bus = self.i2c_helper.get_smbus()
self.adc = ADCPi(self.bus, 0x68, 0x69, 14)
# GPIO Setup
GPIO.setmode(GPIO.BCM)
for channel in self.adc_channels:
GPIO.setup(self.adc_channels[channel]['gpio_pin'], GPIO.OUT)
def measure(self):
# Measure each channel
measurements = {}
for channel in self.adc_channels:
# Get system voltage.
# We do this with each channel, because it fluctuates.
GPIO.output(self.adc_channels[self.calibration_channel]['gpio_pin'], True)
time.sleep(.01)
self.system_voltage = self.adc.read_voltage(self.calibration_channel)
GPIO.output(self.adc_channels[self.calibration_channel]['gpio_pin'], False)
GPIO.output(self.adc_channels[channel]['gpio_pin'], True)
time.sleep(.01)
voltage = 0
for n in range(self.repeat_measurements):
voltage += self.adc.read_voltage(channel)
voltage = voltage / self.repeat_measurements
GPIO.output(self.adc_channels[channel]['gpio_pin'], False)
if voltage < self.margin_of_error_volts:
measurements[channel] = None
continue
if voltage == self.system_voltage:
measurements[channel] = (0, voltage)
continue
r2 = self.r1 * (1 / ((self.system_voltage / voltage) - 1))
r2 -= self.adc_channels[channel]['internal_resistance']
if r2 > self.max_ohms or r2 < 0:
measurements[channel] = None
continue
measurements[channel] = (r2, voltage)
os.system('clear')