Arduino: ¿Cuál es la mejor manera de enviar y recibir datos con I2C?

0

Estoy usando I2C para enviar y recibir valores int de una RaspberryPi a un Arduino y luego se remite al Pi.

El problema principal que tengo es con valores int más grandes que 255.

Un problema secundario es cuando se intenta transmitir valores constantemente. Mi objetivo es enviar las coordenadas MouseX, Y constantemente desde el Pi a un Arduino. Aquí está mi código de prueba que muestra la capacidad básica para enviar valores int. 0-255 desde un RPi a un Arduino.

Mi primera pregunta es, ¿debo mantener los valores como ints o convertir todo a String ANTES de enviarlos por serial?

Mi segunda pregunta es, si se mantiene como int, ¿qué modificaciones debo hacer a la siguiente para que los valores mayores a 255 funcionen?

Primero el código 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

código 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);
}
    
pregunta Bachalo

1 respuesta

1

Como han dicho otros, es necesario definir un pequeño protocolo. Un ejemplo de protocolo podría ser algo como lo siguiente:

[LONGITUD] [INSTR] [DATOS] [BCC]

donde INSTR sería un comando y datos de cierta carga útil asociada a ese dato. LENGTH_DATA sería la cantidad de bytes para el paquete (incluidos INSTR & BCC) y BCC, un tipo de suma de comprobación de todos los datos del paquete.

Si desea un comando que encienda / apague un led, puede tener este comando:

[0x04] [0x01] [LED_STATE] [BCC]

Para enviar datos del mouse:

[0x07] [0x02] [X_H] [X_L] [Y_H] [H_L] [BCC]

Básicamente, no puedes enviar nada más de 8 bits a la vez con un Arduino, pero puedes dividir tu número en partes más pequeñas. No sé mucho sobre el código de Arduino, pero la implementación real podría ser algo así:

estructura    {     sin firmar largo int X;     sin firmar largo int Y;    } ratón;

unsigned char buffer[20];
unsigned char bufferIndex=0;

void validatePacket(void)
{
 int i;
 unsigned char bcc=0;

 for(i=0;i<bufferIndex;bcc^=buffer[i++]);
 return ~(bcc+1);
}

void dataReceived(int byteCount)
{
 int i;

 while(Wire.available()>0)
 {
  buffer[bufferIndex++]=Wire.read();
  if(bufferIndex==buffer[0]) // Check if we received "length" bytes.
  {
   if(validatePacket())
   {
    switch(buffer[1])
    {
     case 0x01: // Led toggle command.
      digitalWrite(13,buffer[2]?HIGH:LOW);
     break;
     case 0x02: // Mouse data.
      mouse.X=(unsigned long int)buffer[2]<<8+buffer[3];
      mouse.Y=(unsigned long int)buffer[4]<<8+buffer[5];
     break;
     default: // Unknown command.
      Serial.print("Bad packet");
     break;
    }
   }
   else
   {
    Serial.print("Bad checksum");
   }
   bufferIndex=0;
  }
 }
}

Bueno, algo parecido. El protocolo es de mala calidad y no es tan a prueba de balas (si la longitud está dañada, podría bloquear su canal de comunicación), pero es un ejemplo. Puedes modificarlo tanto como quieras. Por cierto, no está probado ni compilado, por lo que ni siquiera sé si es un código de Arduino válido.

    
respondido por el Mishyoshi

Lea otras preguntas en las etiquetas