Support Forum

Share your projects and post your questions

Register   or   Sign In
The Forum

Posting snippets from Nano

The ADC Pi is an Analogue to Digital converter for the Raspberry Pi

04/03/2018

Posted by:
Chris_H

Chris_H Avatar

Hello, I'm very new to this field, and I had the assistance of a friend who wrote the initial python script for me that read and logged 4 channels (one address) from an ADC board to a .log file on my RPi. I now need to read and log 16 channels from 4 addresses (2 ADC boards). It appears that both boards are recognised as I can query them with i2cdetect -y 1 and the 4 addresses show up OK. The original script still works fine, and I have modified it to how I think it should be to read the 16 channels on two boards - but it does not seem to work.

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

andrew Avatar

Hello

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

Chris_H Avatar

Hello Andrew and thank you very much for your prompt reply. I have been experiencing strange limitations when trying to copy code from Nano and pasting into the code snippet window on the forum (both on my RPi and my Ubuntu distribution on my PC). It seems to only allow a small amount to be copied - even when setting a mark with Alt>Shift>A and scrolling to highlight all the text. I tried copying with keystrokes and the mouse but to no avail. Interestingly, this problem also occurs when pasting into a text file or any other type of file / window - which leads me to believe maybe the limitation is in the copying rather than the pasting.

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

andrew Avatar

I tried running your scripts on a Raspberry Pi with two ADC Pi boards and it appears to be reading from both boards correctly. The only change I had to make on my Pi was to change


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

Chris_H Avatar

Hi Andrew -

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

andrew Avatar

I tested your script with it writing to the log file and printing to the screen. To make it print to the screen instead of logging to a file you just need to change all instances of "log.write" to "print" so


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

Chris_H Avatar

Hi Andrew -

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

Chris_H Avatar

Hi Andrew -

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

andrew Avatar

Hi Chris

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

Chris_H Avatar

And we have success!!!!!!!!!!!!!

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.

Sign in to post your reply


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.

Home

Shop

Learn

Forum

FAQ

Contact

0 item

Your cart is empty

Please browse our shop to order from the wide range of Raspberry Pi boards and accessories.

Subtotal:£0.00
View Basket Continue to Checkout