0

Building a device to read Analog to Digital Voltages using PCF8591 Analog to Digital Converter (ADC).

The ADC connects via i2c and successfully provides HEX values that correspond to values between 0 and 255 for various input voltages when connected via terminal:

pi@raspberrypi:~ $ sudo i2cget -y 0 0x48
0x38
pi@raspberrypi:~ $ sudo i2cget -y 0 0x48
0x3a
pi@raspberrypi:~ $ sudo i2cget -y 0 0x48
0x44
pi@raspberrypi:~ $ sudo i2cget -y 0 0x48
0x3d

0x38 = 56 ; 0x3a = 58 .. etc.

When running the same application through Python, I obtain an error.

Below is my source Code:

import time
import smbus

i2c_ch = 0   #channel we're running on with i2c
#address on the I2C bus of the ADC 
i2c_address = 0x48

bus = smbus.SMBus(i2c_ch)

# Print out temperature every second
while True:
    temperature = bus.read_i2c_block_data(i2c_address, 0)
    print(temperature)
    time.sleep(1)

This is the Ouput:

[0, 0, 16, 12, 9, 7, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 5, 3, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 12, 8, 6, 5, 3, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 12, 9, 7, 5, 3, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 6, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 5, 3, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 9, 7, 6, 4, 3, 3, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

What are these errors, what do they mean and how can I update my Python script to correctly read the Analog to Digital Converter over I2C?

2 Answers 2

1

According to the docs, read_i2c_block_data will return an array containing 32 bytes.

To read a single byte at a time you need to use read_byte_data

while True:
    temperature = bus.read_byte_data(i2c_address, 0)
    print(f"byte: {temperature}, hex: {temperature.hex()}")
    time.sleep(1)
Sign up to request clarification or add additional context in comments.

5 Comments

ok. wow. that's very helpful. So; in that case, do you know what "Block_data" is and what the 32 bytes represent? I can see that there are definitely 32 bytes, so I think you're 100% correct. Can you link me @Teejay to what f"byte: or hex does in this context?
I keep getting an error that "HEX" has no attribute. If I just do 'print(temperature)` i just get a 0 response every time.
The 32 bytes doesn't represent anything, it's just the default for that method. If you were sending messages with a fixed length of 16 bytes instead, you would use that same method and just set the size to 16.
I don't have a way to simulate the i2c objects so I cannot play around with it -- I was assuming it would return a byte literal object. hex() is just a way of converting a byte object to hexadecimal.
Hello @Teejay - I'm meaning that the green: "hex:" throws an error as python doesn't seem to know what it means... Also - strange thing is that the data coming back in Mu is in decimal while the data coming back in the terminal is Hex format.
0

The below codes works, issue was threefold:

  1. You must use read_byte_data and NOT block_data
  2. You need to ensure that you first write to a pin before you read it
  3. You need to ensure that all unused pins are grounded as are reference pins

Some documentation also suggests that you first read the pin once, before reading it again, something to do with the first read just reads what is there previously.

Code below will successfully read voltage on a scale from 0 - 255:

 bus = smbus.SMBus(0)                    # (0) Ensures the i2c bus used in the Pi
 bus.write_byte(0x48, 0x02)              # Before you can read, you need to write
                                         # 0x02 represents Analog in Pin #2

 while True:
        temperature = bus.read_byte_data(i2c_address, 0x02)  
        print(temperature)                          
        time.sleep(1)

This works for all inputs on PCF8591 Analog to Digital Converter (ADC).

  • I still have no understanding why Console reads in HEX and Mu/Thonny reads in int data
  • I still have no idea what the Block_data represents

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.