[SOLVED]Serial communication between Uno and Leonardo

Hello,

I have a Uno making a random number, separate it in 4 nibbles, and adding 0xB to it (This is just to match the behavior of a sensor). The Leonardo sends 0x61 and 0x62 as a request for the data, gets the data and finally the random number from the Uno.

This works sometimes, in a pattern, wrong data 2 times, and correct data 5 times, in a loop. Can you help me with this error? I have the Uno’s Tx connected to the Leonardos Rx, and viceversa.

Master code (Leonardo):

#include <LiquidCrystal.h> //Libreria para el manejor del LCD
#include <SdFat.h>//Libreria para el manejo de la Tarjeta SD
SdFat sd;
SdFile myFile;
#include "Wire.h"
#define DS1307_I2C_ADDRESS 0x68  // Direccion I2C del RTC DS1307


// Global Variables
const int chipSelect = 4; //ChipSelect de la memoria SD
const int SensorAl = 6;     // Numero de Pin para la conexion AL del sensor.
const int SwitchInit = 5;     // Numero de Pin para la conexion de switch de inicializacion. 
const int SwitchStart = A0;     // Numero de Pin para la conexion de switch de inicio. Se hace luego de completar el proceso de inicializacion.

int command = 0;       // This is the command char, in ascii form, sent from the serial port     
int altura=250; //Variable para guardar la altura del cilindro a medir. Se inicializa en 250 mm, ya que el sistema nocuanta con el sensor, para poder realizar los movimientos sin problemas
int radioextra=3; //VAriable para almacenar el radio extra debido al movimiento en el eje X del sensor para alcanzar la pared del cilindro
int second, minute, hour, dayOfWeek, dayOfMonth, month, year; //Varibles para guardar los datos del RTC

byte zero=0x00; //Reset de la direccion de I2C
char nombrearchivo[13]; //Guarda el nombre del archivo con el formato DDMMYYYY.txt
int medicion; //Variable para guardar el resultado enviado por el sensor
byte med[4]; //Arreglo de bytes para recibir los datos que manda el sensor

// Inicializacion de los pines requeridos por el LCD
LiquidCrystal lcd(13,12, 11, 9, 8, 7);

// Convierte numeros decimales normales a BCD
byte decToBcd(byte val)
{  return ( (val/10*16) + (val%10) );}

// Convierte BCD a numeros decimales normales
byte bcdToDec(byte val)
{  return ( (val/16*10) + (val%16) );}
 

// setDateDs1307() solo se necesita una vez, se mantiene en el codigo, por si se debe cambiar la bateria del RTC o modificar la fecha u hora. 

void setDateDs1307()                
{  //Asume el uso de numeros validos.Formato 24h.
   /* Comandos para la parte RTC
   // * String a enviar por el monitor serial:
   * T(00-59)(00-59)(00-23)(1-7)(01-31)(01-12)(00-99) - T(sec)(min)(hour)(dayOfWeek)(dayOfMonth)(month)(year) -
   * T - Sets the date of the RTC DS1307 Chip. 
   * Example to set the time for 25-Jan-2012 @ 19:57:11 for the 4 day of the week, use this command - T1157194250112
   * --------------------------------------------------------------------------------------------------------------  
   * R - Read/display the time, day and date
   */
   second = (byte) ((Serial.read() - 48) * 10 + (Serial.read() - 48)); // Use of (byte) type casting and ascii math to achieve result.  
   minute = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
   hour  = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
   dayOfWeek = (byte) (Serial.read() - 48);
   dayOfMonth = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
   month = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
   year= (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
   Wire.beginTransmission(DS1307_I2C_ADDRESS);
   Wire.write(zero);
   Wire.write(decToBcd(second) & 0x7f);    // 0 to bit 7 starts the clock
   Wire.write(decToBcd(minute));
   Wire.write(decToBcd(hour));      // If you want 12 hour am/pm you need to set
                                   // bit 6 (also need to change readDateDs1307)
   Wire.write(decToBcd(dayOfWeek));
   Wire.write(decToBcd(dayOfMonth));
   Wire.write(decToBcd(month));
   Wire.write(decToBcd(year));
   Wire.endTransmission();
}

// Toma la fecha del RTC y la guarda en la variable nombrearchivo, con el formato DDMMYYYY.txt
void getDateDs1307(){
  // Reset al puntero de registro
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(zero);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
  //Toma los datos del RTC en orden.
  second     = bcdToDec(Wire.read() & 0x7f);
  minute     = bcdToDec(Wire.read());
  hour       = bcdToDec(Wire.read() & 0x3f);  // Need to change this if 12 hour am/pm
  dayOfWeek  = bcdToDec(Wire.read());
  dayOfMonth = bcdToDec(Wire.read());
  month      = bcdToDec(Wire.read());
  year       = bcdToDec(Wire.read());
  //Guarda el nombre del archivo en el formato deseado.
  snprintf(nombrearchivo,13,"%02d%02d20%02d.txt", dayOfMonth, month, year);
}



float MedicionSensor(){
  byte test[4];
  Serial.println("Inicio de medicion");
  int medsens=0;
  int medsens1=0;
  float medicion=0.0;
  byte comando0='a';
  byte comando1='b';
  Serial.print("Comando0:");
  Serial.print(comando0,HEX);
  Serial.print("Comando2:");
  Serial.println(comando1,HEX);
  //Serial.print(comando0);// manda los comandos de "Inquiring for result"
  //Serial.print(comando1);
  Serial1.write(comando0);// manda los comandos de "Inquiring for result"
  Serial1.write(comando1);
  while(!Serial1.available()){}//Lectura de los 4 bytes enviados por el sensor
  med[0]=Serial1.read();
  Serial.print("med[0]: ");
  Serial.println(med[0],HEX);
  test[0]=med[0]&0x0F;
  Serial.print("test[0]: ");
  Serial.println(test[0],HEX);
  med[1]=Serial1.read();
  Serial.print("med[1]: ");
  Serial.println(med[1],HEX);
  test[1]=med[1]&0x0F;
  Serial.print("test[1]: ");
  Serial.println(test[1],HEX);
  med[2]=Serial1.read();
  Serial.print("med[2]: ");
  Serial.println(med[2],HEX);
  test[2]=med[2]&0x0F;
  Serial.print("test[2]: ");
  Serial.println(test[2],HEX);
  med[3]=Serial1.read();
  Serial.print("med[3]: ");
  Serial.println(med[3],HEX);
  test[3]=med[3]&0x0F;
  Serial.print("test[3]: ");
  Serial.println(test[3],HEX);
  //Se eliminan los primeros 4 bits de cada byte, y se concatenan de LSB a MSB.
  medsens=((med[3] & 0x0F)<<12)|((med[2] & 0x0F)<<8)|((med[1] & 0x0F)<<4)|((med[0] & 0x0F));
  medsens1=(test[3]<<12)|(test[2]<<8)|(test[1]<<4)|test[0];
  Serial.print("Enviado por el sensor: ");
  Serial.println(medsens,HEX);
  medicion=(medsens*5.0)/16384;
  Serial.print("Resultado de la medicion: ");
  Serial.println(medicion);
  Serial.print("Enviado por el sensor: ");
  Serial.println(medsens1,HEX);
  medicion=(medsens1*5.0)/16384;
  Serial.print("Resultado de la medicion: ");
  Serial.println(medicion);
  return medicion;
  
}
//Inicializacion del sistema 
void setup() {
  
  Serial.begin(9600);//Inicializa el puerto serial de software para debugging
  while(!Serial){}
  Serial1.begin(9600);//Inicializa el puerto serial para la comunicacion con el sensor (UNO)
  
  pinMode(SensorAl, INPUT);//Inicializa el pin SensorAL para saber si el sensor esta midiendo algo en el rango

  Serial.print("Inicializando...");
  delay(500);
  // Initialize SdFat or print a detailed error message and halt
  // Use half speed like the native library.
  // change to SPI_FULL_SPEED for more performance.
  while (!sd.begin(chipSelect, SPI_HALF_SPEED)){ 
    sd.initErrorHalt();
    Serial.print("SD Error!!!     ");
    delay(500);
    Serial.print("Revisar SD      ");
  }
  Serial.print("SD Lista!"); 
  Wire.begin(); //Inicia la libreria Wire para la comunicacion I2C

  getDateDs1307();

  Serial.print("Archivo: ");
 
  Serial.println(nombrearchivo);


}
 
void loop() {
  float resultado=0;
  if(digitalRead(SensorAl)==HIGH){

    Serial.println("Preguntando resultado:");
    resultado=MedicionSensor();
    Serial.print("El resultado es: ");
    Serial.println(resultado);  
    Serial.print("**********************************************************************************");
  }
  delay(2000);

}

I know test and med and that is the same thing, just did it to try and debug it.

Slave code (Uno)

int command,command0, command1; //Variables para guardar los comandos de entrada. Deben ser 0x01 y 0x86, que corresponden a los comandos de "Inquiring for result" segun la hoja de datos del sensor
int distancia; //Variable para guardar el valor generado por la funcion random entre 7864 y 8520, que equivalen a 2,4 y 2,6 mm
byte dist1, dist2, dist3, dist4;//dist1 es el byte lsb... y dist4 el msb: Son los grupos de 4 bits de datos de distancia para enviar al Leonardo (Controlador principal)
byte data1,data2,data3,data4; // Bytes completos para enviar al Leonardo (Controlador principal), con el formato acorde a a hoja de datos del sensor


void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  // make the pushbutton's pin an input:
  
  //UCSR0C=0x36; //Chang parity enable and set to odd parity.
}


void loop() {
  //int cantidadbytes=Serial.available();
  //Serial.println(cantidadbytes);
  if(Serial.available()>0){
    command0=Serial.read();
    command1=Serial.read();
    //Serial.println(command0,HEX);
    //Serial.println(command1,HEX);
    if(command0==0x61 & command1==0x62){
      distancia=random(7864,8520); //Calculo random de la distancia medida desde 2,4mm hasta 2,6 mi
      //Serial.println(distancia);
      //Dividir la variable de distancia de 2 bytes en 4 bits (nibbles)
      dist1=(distancia & 0x000F);//4 bits menos significativos
      dist2=(distancia & 0x00F0)>>4;
      dist3=(distancia & 0x0F00)>>8;
      dist4=(distancia & 0xF000)>>12;

      //Se les agrega 0xB, aunque se omite el aumentar el contador, ya que por ser datos tomados por request y no en stream, se sabe que todos pertenecen a la misma medicion
      data1=0xB0|dist1;
      data2=0xB0|dist2;
      data3=0xB0|dist3;
      data4=0xB0|dist4;
      //Serial.println("Bytes de salida");
      //Envio de los datos empezando por el LSB hasta el MSB
      
      Serial.write(data1);
      Serial.write(data2);
      Serial.write(data3);
      Serial.write(data4);
        
      }
  }
  delay(25); //Da tiempo para que los bytes de los comandos de entrada queden en el buffer, asi se guardan bien en las variables.
}

And this is the result in the Serial Monitor.

Inicio de medicion Comando0:61Comando2:62 med[0]: B7 test[0]: 7 med[1]: FF test[1]: F med[2]: B8 test[2]: 8 med[3]: FF test[3]: F Enviado por el sensor: FFFFF8F7 Resultado de la medicion: -0.55 Enviado por el sensor: FFFFF8F7 Resultado de la medicion: -0.55 El resultado es: -0.55 *******************************************************************************Preguntando resultado: Inicio de medicion Comando0:61Comando2:62 med[0]: BF test[0]: F med[1]: B1 test[1]: 1 med[2]: FF test[2]: F med[3]: FF test[3]: F Enviado por el sensor: FFFFFF1F Resultado de la medicion: -0.07 Enviado por el sensor: FFFFFF1F Resultado de la medicion: -0.07 El resultado es: -0.07 ****************************************************************************Preguntando resultado: Inicio de medicion Comando0:61Comando2:62 med[0]: BC test[0]: C med[1]: B0 test[1]: 0 med[2]: BF test[2]: F med[3]: B1 test[3]: 1 Enviado por el sensor: 1F0C Resultado de la medicion: 2.43 Enviado por el sensor: 1F0C Resultado de la medicion: 2.43 El resultado es: 2.43 ****************************************************************************Preguntando resultado: Inicio de medicion Comando0:61Comando2:62 med[0]: B9 test[0]: 9 med[1]: B3 test[1]: 3 med[2]: BF test[2]: F med[3]: B1 test[3]: 1 Enviado por el sensor: 1F39 Resultado de la medicion: 2.44 Enviado por el sensor: 1F39 Resultado de la medicion: 2.44 El resultado es: 2.44 ****************************************************************************Preguntando resultado: Inicio de medicion Comando0:61Comando2:62 med[0]: B6 test[0]: 6 med[1]: B3 test[1]: 3 med[2]: B1 test[2]: 1 med[3]: B2 test[3]: 2 Enviado por el sensor: 2136 Resultado de la medicion: 2.59 Enviado por el sensor: 2136 Resultado de la medicion: 2.59 El resultado es: 2.59 ****************************************************************************Preguntando resultado: Inicio de medicion Comando0:61Comando2:62 med[0]: B1 test[0]: 1 med[1]: B0 test[1]: 0 med[2]: B1 test[2]: 1 med[3]: B2 test[3]: 2 Enviado por el sensor: 2101 Resultado de la medicion: 2.58 Enviado por el sensor: 2101 Resultado de la medicion: 2.58 El resultado es: 2.58 *******************************************************************************Preguntando resultado: Inicio de medicion Comando0:61Comando2:62 med[0]: B5 test[0]: 5 med[1]: BF test[1]: F med[2]: B0 test[2]: 0 med[3]: B2 test[3]: 2 Enviado por el sensor: 20F5 Resultado de la medicion: 2.57 Enviado por el sensor: 20F5 Resultado de la medicion: 2.57 El resultado es: 2.57


Also, i'm powering both Arduinos via USB, but using the serial monitor with the Master(Leonardo).

  if(Serial.available()>0){
    command0=Serial.read();
    command1=Serial.read();

If there is a byte to read, read them both. Hmmm, I think I found your problem.

I send 2 bytes, so isn't that supposed to store the first byte in command0 and the second byte in command1?

I added a delay(2) between that Serial.read() statements an I just have the first 2 requests return the error, and then everything works...

I send 2 bytes, so isn't that supposed to store the first byte in command0 and the second byte in command1?

Watch me type. You can read a lot faster than I can type. The same is true of the Arduino. It can read serial data orders of magnitude faster than it can arrive.

I added a delay(2) between that Serial.read() statements an I just have the first 2 requests return the error, and then everything works...

No delay() is needed. Just don't do anything unless there are two bytes to read.

That simple… You’re right.

That fixed it. Just changed to if(Serial.available()>1) in the Uno, and While(Serial.available<3){} in the Leonardo.

Thank you.