如何使用python和i2c从Rpi读取连接到arduino的pot

时间:2017-02-04 19:04:52

标签: python arduino raspberry-pi i2c

我试图从连接到Arduino的电位计写入模拟读数,并在RPi上使用来自python的I2C读取这些值。我已经让Arduino到Arduino使用下面的代码工作。我似乎无法正确做的是从Arduino写两个字节并从RPi读取两个字节。

Arduino主码:

#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奴隶代码:

#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

}

我从RPi中读到的最接近的是:

RPi主码:

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奴隶代码:

#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);
  }

我似乎能够获得0-255,但是在255之后,该值再次开始。毫无疑问,有一种更精确的方式可以说我只获得一个字节的数据或类似的东西。最后,我希望将两个连接到Arduino的读数连接到RPi中。

2 个答案:

答案 0 :(得分:1)

在Arduino上,analogRead返回0-1023范围内的int值。在此硬件上,int是两个字节。 但是,您在Wire.write函数中使用的sendData形式只会写入单个字节,从而丢弃整数的一部分。

基本上有两种解决方案。

最简单的方法是取analogRead的返回值,除以4并将其转换为一个字节。使用Wire.write发送出去。这确实降低了电位计的值的分辨率,但这是一个非常简单的解决方案。

另一个是通过线路发送整数值。由于您正在读取RPi上的字节,因此您无法知道是否正在读取整数的第一个或第二个字节。所以你可能不得不使用一个信号来指示一个双字节序列的开始。您还必须考虑两个平台的endian-ness。总而言之,这要复杂得多。

答案 1 :(得分:0)

感谢您的反馈。它帮助我思考了这一点,并做了更多的挖掘。这就是我的工作。

Arduino一面写作:

#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方面的阅读:

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)

正如您所看到的,我正在读取2个电位器,将输出转换为0-255,写入I2C总线,然后读取RPi侧的2个字节。我确实必须在测试期间更改Arduino延迟值,因为我收到了错误&#34; IOError:[Errno 5]输入/输出错误&#34;几分钟后。现在也许我会回去为每个锅写2个字节并读取4个字节,这样我就不会失去和解决。