Posting snippets from Nano
The ADC Pi is an Analogue to Digital converter for the Raspberry Pi
04/03/2018
Posted by:
Chris_H
Complicating matters is the fact that I cannot seem to attach either of the scripts to this post, nor can I copy / paste more than a few lines from Nano into the code snippet window or the description box :-(
I think it is something very fundamental that I am missing & any help would be appreciated!
04/03/2018
Posted by:
andrew
To read from four ADC chips on two ADC Pi boards you will need to create two instances of the ADCPi() class with the first instance using the two addresses on the first board and the second instance using the addresses on the second board. The code below is a modified version of the read voltage demo from the ADC Pi python library and I have added a second instance for the ADCPi class with addresses 0x6A and 0x6B. Hopefully, you can use this code to modify your own project.
#!/usr/bin/env python
from __future__ import absolute_import, division, print_function, \
unicode_literals
import time
import os
try:
from ADCPi import ADCPi
except ImportError:
print("Failed to import ADCPi from python system path")
print("Importing from parent folder instead")
try:
import sys
sys.path.append('..')
from ADCPi import ADCPi
except ImportError:
raise ImportError(
"Failed to import library from parent folder")
def main():
'''
Main program function
'''
adc1 = ADCPi(0x68, 0x69, 12)
adc2 = ADCPi(0x6A, 0x6B, 12)
while True:
# clear the console
os.system('clear')
# read from adc channels on the first ADC Pi board and print to screen
print("Board 1 Channel 1: %02f" % adc1.read_voltage(1))
print("Board 1 Channel 2: %02f" % adc1.read_voltage(2))
print("Board 1 Channel 3: %02f" % adc1.read_voltage(3))
print("Board 1 Channel 4: %02f" % adc1.read_voltage(4))
print("Board 1 Channel 5: %02f" % adc1.read_voltage(5))
print("Board 1 Channel 6: %02f" % adc1.read_voltage(6))
print("Board 1 Channel 7: %02f" % adc1.read_voltage(7))
print("Board 1 Channel 8: %02f" % adc1.read_voltage(8))
# read from adc channels on the second ADC Pi board and print to screen
print("Board 2 Channel 1: %02f" % adc2.read_voltage(1))
print("Board 2 Channel 2: %02f" % adc2.read_voltage(2))
print("Board 2 Channel 3: %02f" % adc2.read_voltage(3))
print("Board 2 Channel 4: %02f" % adc2.read_voltage(4))
print("Board 2 Channel 5: %02f" % adc2.read_voltage(5))
print("Board 2 Channel 6: %02f" % adc2.read_voltage(6))
print("Board 2 Channel 7: %02f" % adc2.read_voltage(7))
print("Board 2 Channel 8: %02f" % adc2.read_voltage(8))
# wait 0.2 seconds before reading the pins again
time.sleep(0.2)
if __name__ == "__main__":
main()
To post code on this forum there is an "Insert Code Snippet" button on the message box, the fourth icon from the right, which should show a popup window where you can paste your code. When you press OK it should put the code in the message, formatted properly to look like a code snippet.
05/03/2018
Posted by:
Chris_H
However, I have had success opening the .py script with leafpad and copy / paste from there - so here is the code I was trying to attach yesterday.
This code below only reads / logs from the first 4 channels of the first ADC board & it works nicely:
________________________________________________________________________________________________
#!/usr/bin/env python3
# read abelectronics ADC Pi V2 board inputs with repeating reading from each channel.
# uses quick2wire from http://quick2wire.com/ github: https://github.com/quick2wire/quick2wire-python-api
# Requries Python 3
# GPIO API depends on Quick2Wire GPIO Admin. To install Quick2Wire GPIO Admin, follow instructions at http://github.com/quick2wire/quick2wire-gpio-admin
# I2C API depends on I2C support in the kernel
#
#------------------------------------------------------------------------------
import quick2wire.i2c as i2c
import time
import datetime
#------------------------------------------------------------------------------
adc_address_1 = 0x6A
adc_address_2 = 0x6B
adc_address_3 = 0x6C
adc_address_4 = 0x6D
refresh_rate = 3 # seconds
log_ratio = 4 # logs every log_ratio cycles
varDivisior = 64 # from pdf sheet on adc addresses and config
varMultiplier = (1.0000/varDivisior)/1000
adcmonLog = "/home/pi/DATALOG/P4139-11.log"
#------------------------------------------------------------------------------
def writeLog(channel1mv, channel2mv, channel3mv, channel4mv):
try:
log = open(adcmonLog, "a")
currentdatetime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M')
log.write(currentdatetime)
log.write(",Channel_1_(mV)=%.0f" % channel1mv)
log.write(",Channel_2_(mV)=%.0f" % channel2mv)
log.write(",Channel_3_(mV)=%.0f" % channel3mv)
log.write(",Channel_4_(mV)=%.0f" % channel4mv)
log.write("\n")
except:
pass
#------------------------------------------------------------------------------
logCountDown = 1
with i2c.I2CMaster() as bus:
# Usage: changechannel(address, hexvalue)
# to change to new channel on adc chips
def changechannel(address, adcConfig):
bus.transaction(i2c.writing_bytes(address, adcConfig))
# Usage: getadcreading(address) to return value in volts from
# selected channel.
def getadcreading(address):
h, m, l ,s = bus.transaction(i2c.reading(address,4))[0]
while (s & 128):
h, m, l, s = bus.transaction(i2c.reading(address,4))[0]
# shift bits to product result
t = ((h & 0b00000001) << 16) | (m << 8) | l
# check if positive or negative number and invert if needed
if (h > 128):
t = ~(0x020000 - t)
return t * varMultiplier
while True:
# read first 4 channels and convert to millivolts
changechannel(adc_address_1, 0x9C)
channel1mv = 1000 * getadcreading(adc_address_1)
changechannel(adc_address_1, 0xBC)
channel2mv = 1000 * getadcreading(adc_address_1)
changechannel(adc_address_1, 0xDC)
channel3mv = 1000 * getadcreading(adc_address_1)
changechannel(adc_address_1, 0xFC)
channel4mv = 1000 * getadcreading(adc_address_1)
# Log
logCountDown -= 1
if (logCountDown == 0):
writeLog(channel1mv, channel2mv, channel3mv, channel4mv)
logCountDown = log_ratio
time.sleep(refresh_rate)
_________________________________________________________________________________________________
So then I modified it to what I believed would work, and this is the modified script below - intended to read 16 channels. (As mentioned earlier - I can see the presence of the 4 addresses when I query i2cdetect -y 1), so am satisfied the hardware is recognised). This code appears to be a bit messy in terms of text alignment - but it appears fine in Nano and Leafpad.
_________________________________________________________________________________________________
#!/usr/bin/env python3
# read abelectronics ADC Pi V2 board inputs with repeating reading from each channel.
# uses quick2wire from http://quick2wire.com/ github: https://github.com/quick2wire/quick2wire-python-api
# Requries Python 3
# GPIO API depends on Quick2Wire GPIO Admin. To install Quick2Wire GPIO Admin, follow instructions at http://github.com/quick2wire/quick2wire-gpio-admin
# I2C API depends on I2C support in the kernel
#
#------------------------------------------------------------------------------
import quick2wire.i2c as i2c
import time
import datetime
#------------------------------------------------------------------------------
adc_address_1 = 0x6A
adc_address_2 = 0x6B
adc_address_3 = 0x6C
adc_address_4 = 0x6D
refresh_rate = 3 # seconds
log_ratio = 4 # logs every log_ratio cycles
varDivisior = 64 # from pdf sheet on adc addresses and config
varMultiplier = (1.0000/varDivisior)/1000
adcmonLog = "/home/pi/DATALOG/P4139-11.log"
#------------------------------------------------------------------------------
def writeLog(channel1mv, channel2mv, channel3mv, channel4mv, channel5mv, channel6mv, channel7mv, channel8mv, channel9mv, channel10mv, channel11mv, channel12mv, channel13mv, channel14mv, channel15mv, channel16mv):
try:
log = open(adcmonLog, "a")
currentdatetime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M')
log.write(currentdatetime)
log.write(",Channel_1_(mV)=%.0f" % channel1mv)
log.write(",Channel_2_(mV)=%.0f" % channel2mv)
log.write(",Channel_3_(mV)=%.0f" % channel3mv)
log.write(",Channel_4_(mV)=%.0f" % channel4mv)
log.write(",Channel_5_(mV)=%.0f" % channel5mv)
log.write(",Channel_6_(mV)=%.0f" % channel6mv)
log.write(",Channel_7_(mV)=%.0f" % channel7mv)
log.write(",Channel_8_(mV)=%.0f" % channel8mv)
log.write(",Channel_9_(mV)=%.0f" % channel9mv)
log.write(",Channel_10_(mV)=%.0f" % channel10mv)
log.write(",Channel_11_(mV)=%.0f" % channel11mv)
log.write(",Channel_12_(mV)=%.0f" % channel12mv)
log.write(",Channel_13_(mV)=%.0f" % channel13mv)
log.write(",Channel_14_(mV)=%.0f" % channel14mv)
log.write(",Channel_15_(mV)=%.0f" % channel15mv)
log.write(",Channel_16_(mV)=%.0f" % channel16mv)
log.write("\n")
except:
pass
#------------------------------------------------------------------------------
logCountDown = 1
with i2c.I2CMaster() as bus:
# Usage: changechannel(address, hexvalue)
# to change to new channel on adc chips
def changechannel(address, adcConfig):
bus.transaction(i2c.writing_bytes(address, adcConfig))
# Usage: getadcreading(address) to return value in volts from
# selected channel.
def getadcreading(address):
h, m, l ,s = bus.transaction(i2c.reading(address,4))[0]
while (s & 128):
h, m, l, s = bus.transaction(i2c.reading(address,4))[0]
# shift bits to product result
t = ((h & 0b00000001) << 16) | (m << 8) | l
# check if positive or negative number and invert if needed
if (h > 128):
t = ~(0x020000 - t)
return t * varMultiplier
while True:
# read first 16 channels and convert to millivolts
changechannel(adc_address_1, 0x9C)
channel1mv = 1000 * getadcreading(adc_address_1)
changechannel(adc_address_1, 0xBC)
channel2mv = 1000 * getadcreading(adc_address_1)
changechannel(adc_address_1, 0xDC)
channel3mv = 1000 * getadcreading(adc_address_1)
changechannel(adc_address_1, 0xFC)
channel4mv = 1000 * getadcreading(adc_address_1)
changechannel(adc_address_2, 0x9C)
channel5mv = 1000 * getadcreading(adc_address_2)
changechannel(adc_address_2, 0xBC)
channel6mv = 1000 * getadcreading(adc_address_2)
changechannel(adc_address_2, 0xDC)
channel7mv = 1000 * getadcreading(adc_address_2)
changechannel(adc_address_2, 0xFC)
channel8mv = 1000 * getadcreading(adc_address_2)
changechannel(adc_address_3, 0x9C)
channel9mv = 1000 * getadcreading(adc_address_3)
changechannel(adc_address_3, 0xBC)
channel10mv = 1000 * getadcreading(adc_address_3)
changechannel(adc_address_3, 0xDC)
channel11mv = 1000 * getadcreading(adc_address_3)
changechannel(adc_address_3, 0xFC)
channel12mv = 1000 * getadcreading(adc_address_3)
changechannel(adc_address_4, 0x9C)
channel13mv = 1000 * getadcreading(adc_address_4)
changechannel(adc_address_4, 0xBC)
channel14mv = 1000 * getadcreading(adc_address_4)
changechannel(adc_address_4, 0xDC)
channel15mv = 1000 * getadcreading(adc_address_4)
changechannel(adc_address_4, 0xFC)
channel16mv = 1000 * getadcreading(adc_address_4)
# Log
logCountDown -= 1
if (logCountDown == 0):
writeLog(channel1mv, channel2mv, channel3mv, channel4mv, channel5mv, channel6mv, channel7mv, channel8mv, channel9mv, channel10mv, channel11mv, channel12mv, channel13mv, channel14mv, channel15mv, channel16mv)
logCountDown = log_ratio
time.sleep(refresh_rate)
I couldn't immediately see where the original code had a reference like that which you provided yesterday:
adc1 = ADCPi(0x68, 0x69, 12)
adc2 = ADCPi(0x6A, 0x6B, 12)
I could only see these references to addresses (which seemed to work fine on the first script reading only 4 channels - but not for the script to read 16 channels)
adc_address_1 = 0x6A
adc_address_2 = 0x6B
adc_address_3 = 0x6C
adc_address_4 = 0x6D
I feel I am getting closer to the solution, but being very new to all this, I am probably missing something very simple!
Any assistance would be greatly appreciated!
ChrisH
05/03/2018
Posted by:
andrew
with i2c.I2CMaster() as bus:
to
with i2c.I2CMaster(1) as bus:
For some reason, quick2wire wouldn't detect the I2C bus my Pi was using and showed an error saying it couldn't find /dev/i2c-0 but once I changed that the script started reading from all 16 channels.
It is possible that there is a problem with one of the ADC Pi boards. Can you try testing each board individually, setting them both to have the same I2C addresses? If one board works and the other does not then that would identify the problem board.
You could also try using our ADC Pi python library instead of quick2wire and see if that works any better. You can find it on our GitHub repository at ADC Pi Python Library.
The code I posted above is designed to work with our ADC Pi library, you will just need to put the ADCPi.py library file in the same folder as the script you want to run or install it using the instructions on the GitHub page.
07/03/2018
Posted by:
Chris_H
Thank you for your prompt reply -
Both ADC Boards work fine when tested as individual boards (same address) - generating a .log file with correct voltages - so I'm happy that they are behaving OK.
So then I tried both i2c code options:
12cI2CMaster() as bus:
12cI2CMaster(1) as bus:
But neither made any difference -
Then I tried with the ABElectronics ADCPi.py file in the same folder as my script - still no luck (with both i2c Master code options listed above).....
When you did some testing earlier and you found the script worked - did it create a .log file? That is currently the only means by which I determine the script to be working or not. I'm not sure how I would query individual channels to see values - I've only just used the command i2cdetect -y 1 to see that the 4 addresses are recognised.
I spent a good 5 or 6 hours on it today - doing lots of testing and googling. I was trying to find a generic python script that might read ADC boards without necessarily logging data - just displaying values. I'm starting to wonder if the problem isn't so much that the ADC boards aren't reading - but the generation of the log file is creating a problem? If I could find a generic Python script that just read and displayed values from the boards - I could prove that they are working and perhaps focus on the .log file generation if that is the sticking point?
Any help would be greatly appreciated - it's really exhausting work when it is all new!
07/03/2018
Posted by:
andrew
log.write(",Channel_1_(mV)=%.0f" % channel1mv)
would become
print(",Channel_1_(mV)=%.0f" % channel1mv)
I have written a new demo file for our ADC Pi python library which reads the values from two ADC Pi boards and writes it to a file in the same folder. You can find the script at demo_log2boards.py
In order for the script to work our ADCPi.py library will need to be in the same folder or the parent folder. The easiest way to run the demo would be to download the whole python library from GitHub using git with the command
git clone https://github.com/abelectronicsuk/ABElectronics_Python_Libraries.git
That way you will have all of the demos for the ADC Pi which you can read through to see how our library works and how you can use it with your project. If you get an error saying git is not found you can install it using
sudo apt-get install git
08/03/2018
Posted by:
Chris_H
Many thanks again for your help and prompt reply. I will try your suggestions tonight and see how I go!
Thanks again -
Chris.
08/03/2018
Posted by:
Chris_H
I retrieved the demo_log2boards.py script from the link you provided and it saved as a .py file - all good!
I downloaded the python libraries from github and copied the ADCPi.py file to the directory already containing the .py scripts I was testing & that went very smoothly.
However, when I try and navigate to the <demo_log2boards.py> script in my directory to run them via root terminal, I get the message:
"No such file or directory"
Even when they are in fact there. Several other .py scripts in the same directory run fine from root terminal, and so I did some searching and found some suggestions that it maybe a shebang issue - apparently common from scripts written / copied on PC/DOS instead of Linux? I'm not sure how this can be as I retrieved the file on a Linux system (Lubuntu dist.) and copied straight to my RPi. The only other thing I noticed that was different was that your .py script began with:
#!/usr/bin/env python
Whereas my other scripts (in the same directory that could be accessed via root terminal) began with:
#!/usr/bin/env python3
or in another script:
#!/usr/bin/python
I did try changing the first line in your script accordingly but it didn't seem make a difference.
Not sure if it makes any difference but I'm running Raspbian V 7 (Wheezy) on a Pi 2 B (quad core)
The strange thing is that my original 4 channel script still runs perfectly - the system just doesn't seem to like the 8ch version I had?
Thank you again for your help - I think we are getting closer to the solution!
Regards,
Chris.
08/03/2018
Posted by:
andrew
Can you try the code below and let me know if it works?
#!/usr/bin/env python3
# read abelectronics ADC Pi V2 board inputs with repeating reading from each channel.
# uses quick2wire from http://quick2wire.com/ github: https://github.com/quick2wire/quick2wire-python-api
# Requries Python 3
# GPIO API depends on Quick2Wire GPIO Admin. To install Quick2Wire GPIO Admin, follow instructions at http://github.com/quick2wire/quick2wire-gpio-admin
# I2C API depends on I2C support in the kernel
#
#------------------------------------------------------------------------------
import quick2wire.i2c as i2c
import time
import datetime
#------------------------------------------------------------------------------
adc_address_1 = 0x6A
adc_address_2 = 0x6B
adc_address_3 = 0x6C
adc_address_4 = 0x6D
refresh_rate = 1 # seconds
log_ratio = 4 # logs every log_ratio cycles
varDivisior = 64 # from pdf sheet on adc addresses and config
varMultiplier = ((1.0000/varDivisior)/1000) * 2.471
adcmonLog = "/home/pi/DATALOG/P4139-11.log"
#------------------------------------------------------------------------------
def writeLog(channel1mv, channel2mv, channel3mv, channel4mv, channel5mv, channel6mv, channel7mv, channel8mv, channel9mv, channel10mv, channel11mv, channel12mv, channel13mv, channel14mv, channel15mv, channel16mv):
try:
log = open(adcmonLog, "a")
currentdatetime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M')
log.write(currentdatetime)
log.write(",Channel_1_(mV)=%.0f" % channel1mv)
log.write(",Channel_2_(mV)=%.0f" % channel2mv)
log.write(",Channel_3_(mV)=%.0f" % channel3mv)
log.write(",Channel_4_(mV)=%.0f" % channel4mv)
log.write(",Channel_5_(mV)=%.0f" % channel5mv)
log.write(",Channel_6_(mV)=%.0f" % channel6mv)
log.write(",Channel_7_(mV)=%.0f" % channel7mv)
log.write(",Channel_8_(mV)=%.0f" % channel8mv)
log.write(",Channel_9_(mV)=%.0f" % channel9mv)
log.write(",Channel_10_(mV)=%.0f" % channel10mv)
log.write(",Channel_11_(mV)=%.0f" % channel11mv)
log.write(",Channel_12_(mV)=%.0f" % channel12mv)
log.write(",Channel_13_(mV)=%.0f" % channel13mv)
log.write(",Channel_14_(mV)=%.0f" % channel14mv)
log.write(",Channel_15_(mV)=%.0f" % channel15mv)
log.write(",Channel_16_(mV)=%.0f" % channel16mv)
log.write("\n")
except:
pass
#------------------------------------------------------------------------------
logCountDown = 1
with i2c.I2CMaster(1) as bus:
# Usage: changechannel(address, hexvalue)
# to change to new channel on adc chips
def changechannel(address, adcConfig):
bus.transaction(i2c.writing_bytes(address, adcConfig))
# Usage: getadcreading(address) to return value in volts from
# selected channel.
def getadcreading(address):
h, m, l ,s = bus.transaction(i2c.reading(address,4))[0]
while (s & 128):
h, m, l, s = bus.transaction(i2c.reading(address,4))[0]
# shift bits to product result
t = ((h & 0b00000001) << 16) | (m << 8) | l
# check if positive or negative number and invert if needed
if (h > 128):
t = ~(0x020000 - t)
return t * varMultiplier
while True:
# read first 16 channels and convert to millivolts
changechannel(adc_address_1, 0x9C)
channel1mv = 1000 * getadcreading(adc_address_1)
changechannel(adc_address_1, 0xBC)
channel2mv = 1000 * getadcreading(adc_address_1)
changechannel(adc_address_1, 0xDC)
channel3mv = 1000 * getadcreading(adc_address_1)
changechannel(adc_address_1, 0xFC)
channel4mv = 1000 * getadcreading(adc_address_1)
changechannel(adc_address_2, 0x9C)
channel5mv = 1000 * getadcreading(adc_address_2)
changechannel(adc_address_2, 0xBC)
channel6mv = 1000 * getadcreading(adc_address_2)
changechannel(adc_address_2, 0xDC)
channel7mv = 1000 * getadcreading(adc_address_2)
changechannel(adc_address_2, 0xFC)
channel8mv = 1000 * getadcreading(adc_address_2)
changechannel(adc_address_3, 0x9C)
channel9mv = 1000 * getadcreading(adc_address_3)
changechannel(adc_address_3, 0xBC)
channel10mv = 1000 * getadcreading(adc_address_3)
changechannel(adc_address_3, 0xDC)
channel11mv = 1000 * getadcreading(adc_address_3)
changechannel(adc_address_3, 0xFC)
channel12mv = 1000 * getadcreading(adc_address_3)
changechannel(adc_address_4, 0x9C)
channel13mv = 1000 * getadcreading(adc_address_4)
changechannel(adc_address_4, 0xBC)
channel14mv = 1000 * getadcreading(adc_address_4)
changechannel(adc_address_4, 0xDC)
channel15mv = 1000 * getadcreading(adc_address_4)
changechannel(adc_address_4, 0xFC)
channel16mv = 1000 * getadcreading(adc_address_4)
# Log
logCountDown -= 1
if (logCountDown == 0):
writeLog(channel1mv, channel2mv, channel3mv, channel4mv, channel5mv, channel6mv, channel7mv, channel8mv, channel9mv, channel10mv, channel11mv, channel12mv, channel13mv, channel14mv, channel15mv, channel16mv)
logCountDown = log_ratio
time.sleep(refresh_rate)
10/03/2018
Posted by:
Chris_H
The reason (or reasons) behind this are still unclear at this point - but fortunately I have copies of all the 'tried and failed' scripts - so some careful forensic analysis should reveal the cause (or possibly causes) of the problem.
Thank you very much for your assistance with this Andrew - greatly appreciated and a valuable learning experience!
Kind Regards,
Chris.
Note: documents in Portable Document Format (PDF) require Adobe Acrobat Reader 5.0 or higher to view.
Download Adobe Acrobat Reader or other PDF reading software for your computer or mobile device.