简体   繁体   中英

How to read pot connected to arduino from Rpi using python and i2c

I'm trying to write analog readings from a potentiometer connected to an Arduino and read those values using I2C from python on an RPi. I have gotten Arduino to Arduino to work using the code below. What I cannot seem to do correctly is write two bytes from the Arduino and read two bytes from the RPi.

Arduino Master code:

#include <Wire.h>
#define SLAVE_ADDRESS 0x2a

void setup()
{
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
}

void loop()
{
  Wire.requestFrom(SLAVE_ADDRESS, 2);    // request 2 bytes from slave
  byte loByte;
  byte hiByte;
  if(Wire.available() >= 2)    // slave may send less than requested
    { 
    hiByte = Wire.read();
    loByte = Wire.read();
    }
  int val = (hiByte << 8) + loByte;
  Serial.print("read value:");   
  Serial.println(val);
  delay(500);
}

Arduino Slave code:

#include <Wire.h>
#include <stdlib.h>
#define SLAVE_ADDRESS 0x2a
//#define potPin 0  
int readVal;
byte hi;
byte lo;


void setup()
{
// Communication I2C
  Wire.begin(SLAVE_ADDRESS);                
  Wire.onRequest(requestEvent); // register event

  Serial.begin(9600);
}

void loop()
{

readVal = analogRead(A2);
Serial.println(readVal);
hi = highByte(readVal);
lo = lowByte(readVal);
}

void requestEvent()
{

byte buf [2];

  buf [0] = hi;
  buf [1] = lo;

  Wire.write(buf, sizeof buf);  // send 2-byte response

}

The closest I have gotten reading from an RPi is:

RPi Master code:

import smbus
import time
bus = smbus.SMBus(1)
address = 0x2a

while True:
    bus.write_byte(address, 1)
    number = bus.read_byte(address)
    print(number)
    time.sleep(1)   

Arduino slave code:

#include <Wire.h>
#define SLAVE_ADDRESS 0x2a
int number = 0;
void setup() {
  Wire.begin(SLAVE_ADDRESS);
  Wire.onReceive(receiveData);
  Wire.onRequest(sendData);
  }
void loop() {
  }
void receiveData(int byteCount){
  while(Wire.available()) { 
    number = Wire.read();
    number = analogRead(A2);
  }
}
void sendData(){
  Wire.write(number);
  }

I seem to be able to get 0-255, but after 255 the value starts again. No doubt there is a more precise way to say I am only getting one byte of data or something along those lines. Ultimately I want to have 2 pots connected to the Arduino feeding readings into the RPi.

On Arduino, analogRead returns an int value in the range 0-1023. On this hardware, an int is two bytes. However, the form of Wire.write that you use in the sendData function only writes a single byte, discarding part of the integer.

There are basically two solutions.

The simplest would be to take the return value of analogRead , divide it by 4 and cast it into a byte. Send that out with Wire.write . This does reduce the resolution of the value of the pot-meter, but is it a very simple solution.

The other was is to send an integer value over the wire. Since you're reading bytes on the RPi, you cannot know if you are reading the first or second byte of an integer. So you would probably have to use a signal to indicate the start of a two-byte sequence. You would also have to take the endian-ness of both platform into account. All in all, this is much more complicated.

Thanks for the feedback. It helped me think through this a bit more and do more digging. This is what I have working.

Arduino side for writing:

#include <Wire.h>
#define SLAVE_ADDRESS 0x2a
#define pot1pin A2
#define pot2pin A3

byte pot1byte;
byte pot2byte;
void setup()
{
    Wire.begin(SLAVE_ADDRESS);
    Wire.onRequest(requestEvent);
}

void loop() {
    int pot1int = analogRead(pot1pin);
    int pot2int = analogRead(pot2pin);
    pot1byte = map(pot1int, 0, 1024, 0, 255);
    pot2byte = map(pot2int, 0, 1024, 0, 255);
}

void requestEvent()
{
    Wire.write(pot1byte);
    delay(30);
    Wire.write(pot2byte);
}

RPi side for reading:

import smbus
bus = smbus.SMBus(1)
address = 0x2a
while (1):
    block = bus.read_i2c_block_data(address, 0, 2) # Returned value is a list of 2 bytes
    print(block)

As you can see I am reading 2 pots, converting the output to 0-255, writing to the I2C bus and then reading the 2 bytes on the RPi side. I did have to change the Arduino delay value during testing because I was getting the error "IOError: [Errno 5] Input/output error" after a few minutes. Now maybe I will go back and write 2 bytes per pot and read 4 bytes so I don't lose and resolution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM