Problema datos dentro de una cadena. arduino - arduino y separar variables.

Estimados,

Espernado que tengan un buen día, mi consulta es la siguiente.

Estoy estableciendo una comunicación Serial entre 2 arduinos, uno me captura lo del sensor, y el otro lee la información y la muestra en la pantalla LCD, el tema es que cuando recibo los datos de Temp y Hum, el Display me muestra los valores de temp y humeda en el mismo lugar, para mejor compresión, el programa me lee la información pero no me separa las viables como yo quiero. Ejemplo. T: 20 H:23.

Si todavía no se entiende, recibo los datos por el puerto serial asignado, los datos recibidos los guardo en una cadena, y trato de separa en variables los datos de esa cadena, pero no logró separalos.

Adjunto el programa de recepción, a ver si me ayudan.

#include <SoftwareSerial.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

#define rxPin 2
#define txPin 3

SoftwareSerial mySerial(rxPin, txPin);

char datos[13];
int posicion = 0;


char *resultado = NULL;
char separador [] = "AB";
int valores[] = {0,0};
int temperatura;
int humedad;

unsigned long Tiempo_LCD;
unsigned long Tiempo_Tx;

void setup()  {
 
  mySerial.begin(9600);
  Serial.begin(9600);
  delay(1000);
  lcd.begin(16, 2); // Hay que inicializar el LCD
  lcd.print("Mediciones");
  lcd.setCursor(0,1);
  lcd.print("T=      H.R= ");
  
}

void loop() {
  boolean segmentacion;


  while (mySerial.available()>0){
    delay(5);
    datos[posicion] = mySerial.read();
    posicion++;
    segmentacion = true;
  }

posicion = 0;

  if (segmentacion == true){
    int index = 0;
    resultado = strtok( datos, separador );
    while ((resultado != NULL) && (index < 3)){
      valores[index++] = atoi(resultado);
      resultado = strtok( NULL, separador );
}
segmentacion = false;
}

temperatura = valores[0];
humedad = valores[1];

    if((millis() - Tiempo_LCD) > 500){
      Serial.print(temperatura);
      Serial.print(humedad);
      lcd.setCursor(2,1);
      lcd.print(temperatura);
      lcd.setCursor(12,1);
      lcd.print(humedad);
      delay (1000);
      Tiempo_LCD = millis();            
  }
}

Saludos, y agradesco su ayuda.

Cual es la duda? Esta:

el programa me lee la información pero no me separa las viables como yo quiero. Ejemplo. T: 20 H:23.

Disculpa me di cuenta luego.
Pero tampoco dices como envias los datos.
Indica como es la trama y el separador. que veo es

char separador [] = "AB";

Porque no pruebas con un delimitador de 1 caracter?

Nota: te felicito por usar bien los tags para presentar tu código.

Gracias, es solo leer las reglas del Foro,

Edite el programa, ya que puse anteriormente fue el que me guie, Ahora te explico mejor, cuando recibo los datos, y los almaceno en la cadena, no logro separar los datos en las 2 variables. Me llegan "Juntas", en las misma variable.

Mas graficamente, en el LCD me muestra en T: la temperatura y luego de 1 segundo la humedad ,

A su vez simultaneamente en H: muestra lo mismo siendo que separé los valores en variables distintas.

Espero logrado explicarme de mejor manera.

Agradecido por tú comentario

Saludos.

Con qué frecuencia el emisor envía esos datos?
Cuál es el formato de la cadena?

Lucario448:
Con qué frecuencia el emisor envía esos datos?
Cuál es el formato de la cadena?

Hola Lucario, en un principio estoy conectando los 2 arduinos directamente (Cruzando cables), y el formato de la cadena es en Char, cuando trato de separar los datos, los declaro en la variables como INT.

Ya cuando logre tener el programa, intentare transmitir a traves de este emisor,
http://olimex.cl/website_MCI/static/documents/Datasheet_M1_Smart_Series.pdf

Saludos,

NicoSuarez:
el formato de la cadena es en Char, cuando trato de separar los datos, los declaro en la variables como INT.

Bueno... no es esa la respuesta que yo esperaba. Por "formato" me refería a cómo está compuesta la cadena o trama de información.
Por ejemplo, de momento puedo deducir que es el siguiente:

#AB#

Donde # es un valor del rango de int.

Debido a que carece de delimitador (no es lo mismo que separador), es que preguntaba sobre la frecuencia del emisor.
Si el flujo es constante (o al menos más rápido que lo que tarda el receptor en procesar una trama); entonces sí deberías implementar uno.

Según lo que puedo apreciar en este fragmento de código:

while (mySerial.available()>0){
    delay(5);
    datos[posicion] = mySerial.read();
    posicion++;
    segmentacion = true;
  }

posicion = 0;

  if (segmentacion == true){
    int index = 0;
    resultado = strtok( datos, separador );
    while ((resultado != NULL) && (index < 3)){
      valores[index++] = atoi(resultado);
      resultado = strtok( NULL, separador );
}

Bastaría con un flujo de datos constante, para colgar el programa ("bloquearlo" o "paralizarlo").

PD:

NicoSuarez:
Ya cuando logre tener el programa, intentare transmitir a traves de este emisor,
http://olimex.cl/website_MCI/static/documents/Datasheet_M1_Smart_Series.pdf

Se ve interesante, porque no conocía otra manera de puerto serial inalámbrico aparte del Bluetooth.

Estimados,

Muchas gracias por su ayuda, agregue la misma funcion de tiempo en el emisor, y realice el cambio de constantes (de letras "AB" a una simple "," y me funcionó pude separa las constantes, pero ahora recibo devuelta un 0 entre algunas tomas de mediciones, ¿alguna idea?

Ahora trataré de conectar con los transmisores inalambricos para seguir con la configuración. Si puedo solucionar de ese 0 que me aparece, postearé las configuraciones de emision y recepcion, a más de alguno le puede servir.

Se agradece su ayuda.

Saludos.

Es que... vamos a lo mismo.
Si es flujo constante y continuo; sin delimitador pueden haber tramas fragmentadas (posible razón de imprimir cero en ciertas ocasiones).

Repito la pregunta: cada cuanto el emisor envía datos?

Disculpa, pero me es complicado todavía los terminos que emplean en Arduino, mejor adjunto el código emisor, así saco todas las dudas

#include <SoftwareSerial.h>

#define rxPin 2
#define txPin 3

unsigned long Tiempo_Tx;

                         /* SENSOR INICIO */
//////////////////////////////////////////////////////////////////

int gTempCmd  = 0b00000011;
int gHumidCmd = 0b00000101;

int shiftIn(int dataPin, int clockPin, int numBits)
{
   int ret = 0;
   int i;

   for (i=0; i<numBits; ++i)
   {
      digitalWrite(clockPin, HIGH);
      delay(10);  // I don't know why I need this, but without it I don't get my 8 lsb of temp
      ret = ret*2 + digitalRead(dataPin);
      digitalWrite(clockPin, LOW);
   }

   return(ret);
}

void sendCommandSHT(int command, int dataPin, int clockPin)
{
  int ack;


  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  digitalWrite(dataPin, HIGH);// protocolo para la transmision
  digitalWrite(clockPin, HIGH);
  digitalWrite(dataPin, LOW);
  digitalWrite(clockPin, LOW);
  digitalWrite(clockPin, HIGH);
  digitalWrite(dataPin, HIGH);
  digitalWrite(clockPin, LOW);
         
  // The command (3 msb are address and must be 000, and last 5 bits are command)
  shiftOut(dataPin, clockPin, MSBFIRST, command);

  // Verify we get the coorect ack
  digitalWrite(clockPin, HIGH);
  pinMode(dataPin, INPUT);
  ack = digitalRead(dataPin);
  if (ack != LOW)
    Serial.println("Ack Error 0");
  digitalWrite(clockPin, LOW);
  ack = digitalRead(dataPin);
  if (ack != HIGH)
     Serial.println("Ack Error 1");
}

void waitForResultSHT(int dataPin)
{
  int i;
  int ack;

  pinMode(dataPin, INPUT);

  for(i= 0; i < 100; ++i)
  {
    delay(10);
    ack = digitalRead(dataPin);

    if (ack == LOW)
      break;
  }

  if (ack == HIGH)
    Serial.println("Ack Error 2");
}

int getData16SHT(int dataPin, int clockPin)
{
  int val;

  // Get the most significant bits
  pinMode(dataPin, INPUT);
  pinMode(clockPin, OUTPUT);
  val = shiftIn(dataPin, clockPin, 8);
  val *= 256;

  // Send the required ack
  pinMode(dataPin, OUTPUT);
  digitalWrite(dataPin, HIGH);
  digitalWrite(dataPin, LOW);
  digitalWrite(clockPin, HIGH);
  digitalWrite(clockPin, LOW);
         
  // Get the lest significant bits
  pinMode(dataPin, INPUT);
  val |= shiftIn(dataPin, clockPin, 8);

  return val;
}

void skipCrcSHT(int dataPin, int clockPin)
{
  // Skip acknowledge to end trans (no CRC)
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);

  digitalWrite(dataPin, HIGH);
  digitalWrite(clockPin, HIGH);
  digitalWrite(clockPin, LOW);
}
              /* SENSOR FIN */
////////////////////////////////////////////////////////


SoftwareSerial mySerial(rxPin, txPin);

void setup()  {
  mySerial.begin(9600);
  Serial.begin(9600);
}

void loop(){

{
  int theDataPin  = 10;
  int theClockPin = 11;
  int ack;


           int val;
           int temperatura;
           int humedad;
         
           sendCommandSHT(gTempCmd, theDataPin, theClockPin);
           waitForResultSHT(theDataPin);
           val = getData16SHT(theDataPin, theClockPin);
           skipCrcSHT(theDataPin, theClockPin);
           temperatura = -40.1 + 0.01 * (float)val;
           
           Serial.print(",");
           Serial.print(temperatura);
           delay(5); //envia 3 caracteres 
     
           //lee el pin Data, con el comando de humedad y imprime el resultado
       
         
           sendCommandSHT(gHumidCmd, theDataPin, theClockPin);
           waitForResultSHT(theDataPin);
           val = getData16SHT(theDataPin, theClockPin);
           skipCrcSHT(theDataPin, theClockPin);
           humedad = -2.0468 + 0.0367 * val + -0.0000015955 * val * val;

           Serial.print(",");
           Serial.print(humedad);
           delay(5); //envia 3 caracteres 

 if ((millis()-Tiempo_Tx) > 500) {
  mySerial.print(temperatura);
  mySerial.print(",");
  mySerial.print(humedad);
  mySerial.print(",");
  
  
  Tiempo_Tx = millis();
}
}
}

Saludos, y disculpa, soy muy noob, todavía.
Gracias por toda la ayuda que me han brindado :slight_smile:

Traducido:
Flujo constante: estas enviando datos sin un delay por medio
Cada cuanto envias un dato? En todo momento cada 5 mseg o cada 1000 mseg?

surbyte:
Traducido:
Flujo constante: estas enviando datos sin un delay por medio
Cada cuanto envias un dato? En todo momento cada 5 mseg o cada 1000 mseg?

if ((millis() - Tiempo_Tx) > 500) {
  mySerial.print(temperatura);
  mySerial.print(",");
  mySerial.print(humedad);
  mySerial.print(",");

  Tiempo_Tx = millis();
}

Aparentemente cada medio segundo; el cuál debería ser tiempo suficiente para procesar una trama a la vez.

Si el receptor está conectado con el TX definido en mySerial del emisor, entonces no debería haber problemas de tramas fragmentadas; 500 ms es demasiado tiempo para un microprocesador de 16 MHz.

Del resto del código ni idea. Acaso estás intentando emular I2C me parece?

Lucario448:
Si el receptor está conectado con el TX definido en mySerial del emisor, entonces no debería haber problemas de tramas fragmentadas; 500 ms es demasiado tiempo para un microprocesador de 16 MHz.

Si tienes razon, baje la velocidad a 50 milis y el 0 desaparecio.

Lucario448:
Del resto del código ni idea. Acaso estás intentando emular I2C me parece?

No he leido mucho acerca de i2c, pero la verdad lo que quiero realizar es enviar caracter a caracter, un ejemplo: El sensor me lee que hay 25 grados, entonces eso lo quiero transmitir primero el 2 y luego el 5 por separado, no se si podrá realizar en verdad.

Saludos y gracias por la ayuda entregada

eso es lo que hace cualquier comunicación Serial.

Mira, lo que pasa es que lo anterior, solo fue para realizar la conexión directamente mediante cables, ahora le conecté los transmisores que mencione anteriormente, pero me llega la información así:

solo me llega correctamente el primer digito, los siguientes me los traduce en caracteres diferentes, pense que podría ser codigó ANSI, pero no lo es, no corresponden, por eso a la pregunta anterior, ya que si envió el 5 y el 8 por separado, el arduino receptor los recibe correctamente pero los tengo que enviar de esta manera.

mySerial.print(5);
delay(50);
mySerial.print(8);
delay(50);

Así por curiosidad, qué tal si lo envías así:

Creas un array de char para almacenar el resultado a imprimir.

char buffer[64]; // Variable preferiblemente global

Cuando vayas a imprimir los valores:

mySerial.write(buffer, sprintf(buffer, "%d,%d", temperatura, humedad));
//mySerial.write(buffer, sprintf(buffer, "[%d,%d]", temperatura, humedad)); // Usa este sólo si necesitaras marcar el inicio y fin de la trama

Si fuera el caso en que la frecuencia de actualización tuviera que ser la más rápida posible; tendrías que sí o sí utilizar la segunda línea; o mejor aún, enviar los valores de forma binaria.

Pero como estoy notando que el tiempo realmente no importa, entonces a como lo tienes será suficiente.

Lucario448:
Así por curiosidad, qué tal si lo envías así:

Creas un array de char para almacenar el resultado a imprimir.

char buffer[64]; // Variable preferiblemente global

Cuando vayas a imprimir los valores:

mySerial.write(buffer, sprintf(buffer, "%d,%d", temperatura, humedad));

//mySerial.write(buffer, sprintf(buffer, "[%d,%d]", temperatura, humedad)); // Usa este sólo si necesitaras marcar el inicio y fin de la trama

Realice lo que me comentaste, cableado directamente funciome de mejor manera que el anterior pero al conectar los transmisores m aparece esto

ya no se que podra ser ya que si imprimo los datos por separado, como te comentaba caracteres de 1 digito, los transmite sin problemas.

Saludos y gracias por la ayuda brindada.

PD: Encontre esta programación en C para un PIC con el mismo transmisor

void main () {

float restemp, truehumid;               // variables shtxx
int humedad;
float32 valor;                         //Dato a transmitir en float

char string[6];                        //Guarda el valor float como string
int i=0;                               //Número de caracteres del string

 sht_init();                                    //inicio de shtxx

    while(true){
    sht_rd (restemp, truehumid);               //lectura de variables SHTXX
    humedad=truehumid;
    valor=restemp;                             //con variable temperatura
 
    sprintf(string,"%01.1f",valor);           //Paso a string el valor float temperatura
   
    
    //Envío por RS232 del valor float como string
    putc('A');                             //envio cabecera
    delay_ms(500);
     for (i=0;i<=5;++i){
     output_high(pin_b0);
     putc(string[i]);                     //envio rs232 de temperatura caracter a caracter
     delay_ms(50);
     } 
     putc(humedad);                     // envio de humedad
     delay_ms(50);
     output_low(pin_b0);
     }
   
}

le modifique los nombres para que se entendiera, el tema es que si resulta con el pic sin ningun problema.

Edit: estube leyendo que para emplear el transmisor hc um96 en los PIC, se le debía decir a los puertos asignados que transmitieran por UART, si no se declaraba de tal forma, los caracteres se recibían como los recibo yo.

Saludos

Y qué tal si jugabas con la tasa de baudios?
No existe microcontrolador que atiempe 100% a la perfección todas las opciones de velocidad.

Posiblemente los transmisores no sean muy tolerantes a errores de atiempamiento que aparentemente provoca el enviar más de un byte consecutivo.
Quizá demasiado, porque al menos en el hardware UART (pines 0 y 1); el margen de error nunca alcanza ni el 1%.

O será acaso que estos transmisores esperan dos bits de parada y no uno? Es lo único que podría corromper los bytes a partir del segundo consecutivo.

La verdad es que yo al menos estoy totalmente perdido en este hilo. Creo que se está tomando un camino un poco raro. Quiero entender que esencialmente se trata de que dos arduinos se comuniquen un par de datos entre sí, ¿no?
¿Dónde está el problema? ¿Con qué finalidad se envían los caracteres que forman un dato con pausa entre ellos? ¿Para qué copiar primero la trama a un buffer en lugar de hacer parseInt directamente?
¿Alguien podría hacer un post de resumen?

Se trata de comunicación de Arduino a Arduino vía serial UART.

  • Primero tenía problemas al "parsear" porque las tramas no tenían delimitador.
  • Luego acabó bajándole el ritmo al emisor para que estas se procesaran correctamente.
  • Actualmente el problema está en que unos transmisores inalámbricos están corrompiendo los bytes cuando se envían "a bulto" (a partir del segundo); algo que no sucede si lo hace uno por uno. Le dije que intentara con write en vez de print; pero el problema persiste.

Lucario448:
Y qué tal si jugabas con la tasa de baudios?
No existe microcontrolador que atiempe 100% a la perfección todas las opciones de velocidad.

Posiblemente los transmisores no sean muy tolerantes a errores de atiempamiento que aparentemente provoca el enviar más de un byte consecutivo.
Quizá demasiado, porque al menos en el hardware UART (pines 0 y 1); el margen de error nunca alcanza ni el 1%.

O será acaso que estos transmisores esperan dos bits de parada y no uno? Es lo único que podría corromper los bytes a partir del segundo consecutivo.

Disculpa la tardansa, es que me accidente y no podia verlo,

Realice todo lo que mi mente en el estado que estaba pude realizar, pero sigue pasando lo mismo,

Ahora realice este mismo pero con PIC y me resulto,

Ya dentro de 2 semanas me llegan unos trx Xbee, asi que los probare con esos, deberia funcionarme.

Gracias por toda la ayuda brindada, Soy ing en Telecomunicaciones, pero me encanto esto de la programacion y la automatizacion.

PD: No agrege ningun tilde ya que estoy en teclado US.

Saludos y espero estar aportando mas adelante a esta comunidad como Ustedes lo hicieron conmigo.