这是我目前用于使用i2C从RaspberryPi向Arduino发送和接收int值的代码。它适用于0-255的值,但由于1字节限制,任何更大的值都会失败
为了避免这种情况,我想发送和接收字符串值,然后在必要时转换回int
我需要在下面做些什么改变?
这是我的RPi Python代码
import smbus
import time
# for RPI version 1, use "bus = smbus.SMBus(0)"
bus = smbus.SMBus(1)
# This is the address we setup in the Arduino Program
address = 0x04
def writeNumber(value):
bus.write_byte(address, value)
# bus.write_byte_data(address, 0, value)
return -1
def readNumber():
number = bus.read_byte(address)
# number = bus.read_byte_data(address, 1)
return number
while True:
try:
var = int(raw_input("Enter 1 - 9: "))
except ValueError:
print "Could you at least give me an actual number?"
continue
writeNumber(var)
print "RPI: Hi Arduino, I sent you ", var
# sleep one second
#time.sleep(1)
number = readNumber()
print "Arduino: Hey RPI, I received a digit ", number
print
这是我的Arduino代码
#include <Wire.h>
#define SLAVE_ADDRESS 0x04
int number = 0;
int state = 0;
void setup() {
pinMode(13, OUTPUT);
Serial.begin(9600); // start serial for output
// initialize i2c as slave
Wire.begin(SLAVE_ADDRESS);
// define callbacks for i2c communication
Wire.onReceive(receiveData);
Wire.onRequest(sendData);
Serial.println("Ready!");
}
void loop() {
delay(100);
}
// callback for received data
void receiveData(int byteCount){
while(Wire.available()) {
number = Wire.read();
if (Wire.available() > 1) // at least 2 bytes
{
number = Wire.read() * 256 + Wire.read();
}
Serial.print("data received: ");
Serial.println(number);
//sendData();
if (number == 1){
if (state == 0){
digitalWrite(13, HIGH); // set the LED on
state = 1;
}
else{
digitalWrite(13, LOW); // set the LED off
state = 0;
}
}
}
}
// callback for sending data
void sendData(){
Wire.write(number);
}
答案 0 :(得分:1)
检查以下链接:
当我使用I2C向前和向后发送数据时,我将字符串字符转换为bytearrays,反之亦然。所以,因为你总是发送字节。它始终有效,因为您发送的数字介于0-255之间。
不确定这会有所帮助,但至少可以给你一个想法。
答案 1 :(得分:1)
这个问题基本上有两个部分:将一个整数分成它的字节,然后从字节重组一个整数。必须在Pi和Arduino上复制这些部分。我将首先在Python中解决Pi端:
拆分整数:
def writeNumber(value):
# assuming we have an arbitrary size integer passed in value
for character in str(val): # convert into a string and iterate over it
bus.write_byte(address, ord(character)) # send each char's ASCII encoding
return -1
从字节重组整数:
def readNumber():
# I'm not familiar with the SMbus library, so you'll have to figure out how to
# tell if any more bytes are available and when a transmission of integer bytes
# is complete. For now, I'll use the boolean variable "bytes_available" to mean
# "we are still transmitting a single value, one byte at a time"
byte_list = []
while bytes_available:
# build list of bytes in an integer - assuming bytes are sent in the same
# order they would be written. Ex: integer '123' is sent as '1', '2', '3'
byte_list.append(bus.read_byte(address))
# now recombine the list of bytes into a single string, then convert back into int
number = int("".join([chr(byte) for byte in byte_list]))
return number
Arduino Side,在C
拆分整数:
void sendData(){
int i = 0;
String outString = String(number); /* convert integer to string */
int len = outString.length()+1 /* obtain length of string w/ terminator */
char ascii_num[len]; /* create character array */
outString.toCharArray(ascii_num, len); /* copy string to character array */
for (i=0; i<len); ++i){
Wire.write(ascii_num[i]);
}
}
重新组合收到的整数: 注意:我在理解你的其他代码在这个例程中正在做什么时遇到了一些麻烦,所以我要把它简化为只是组装整数。
void receiveData(int byteCount){
int inChar;
String inString = "";
/* As with the Python receive routine, it will be up to you to identify the
terminating condition for this loop - "bytes_available" means the same thing
as before */
while(bytes_available){
inChar = Wire.read();
inString += char(inChar);
}
number = inString.toInt();
}
我手头没有材料来测试这个,所以我可以在一个或另一个例程中翻转字节顺序。如果你发现有东西进出,最简单的修复方法是在Python脚本中使用字符串或列表上的内置函数reversed()。
引用(我使用了Arduino示例中的一些代码):
Arduino String objects
Arduino String Constructors
Python内置chr()和ord()
答案 2 :(得分:0)
您可以将数字转换为您所说的数字字符串。但你也可以发送原始字节。
<强>优点强>
<强>缺点强>
(digits + 1)
大小。<强>优点强>
struct
库,它将数字中的每个字节打包/解包到一个字符串中发送/接收,因此您不需要像在C ++中那样进行算术。<强>缺点强>
-2147483648
到2147483647
)。但这并不重要,因为没有Arduino无论如何都不能处理超过32位。所以我会使用raw bytes方法,我可以在这里提供一些未经测试的函数:
import struct
# '<i' stands for litle-endian signed integer
def writeNumber(value):
strout = struct.pack('<i', value)
for i in range(4):
bus.write_byte(address, strout[i])
return -1
def readNumber():
strin = ""
for _ in range(4):
strin += bus.read_byte(address)
return struct.unpack('<i', strin)[0]
Arduino部分:
void receiveData(int byteCount)
{
// Check if we have a 32-bit number (4 bytes) in queue
while(Wire.available() >= 4)
{
number = 0;
for(int i = 0; i < 32; i += 8)
{
// This is merging the bytes into a single integer
number |= ((int)Wire.read() << i);
}
Serial.print("data received: ");
Serial.println(number);
// ...
}
}
void sendData()
{
for(int i = 0; i < 32; i += 8)
{
// This is extracting each byte from the number
Wire.write((number >> i) & 0xFF);
}
}
我对I2C没有任何经验,但如果它的队列是FIFO,那么代码应该可以工作。