Pages: [1]   Go Down
Author Topic: Enviar y recibir multiples bytes por puerto serial [SOLUCIONADO] [COMO]  (Read 5669 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 32
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Estoy tratando de escribir un intérprete de comandos con diversas funciones:
- escribir en una eeprom
- encender/apagar relay
- obtener status
- etc

Resulta que hice varios intentos y hasta ahora lo único que logré es un 50%:

Code:
byte EntradaByte[10];   // almacenador de entrada
int contador = 0;


void setup() {
        Serial.begin(9600);     // abre puerto serial
}

void loop() {
  
  
  
}

void serialEvent() {

  byte ByteCarga = Serial.read();
  
  if (contador < 9) {
    EntradaByte[contador] =  ByteCarga;
    contador++;
  }
  else
  {
    if (EntradaByte[0] == 33 ) { // si la cabecera es "!"
    Serial.println("OK"); // Ok de prueba
    }
    contador = 0;
  }
  
}

Entonces funciona así:
Yo envío: "!234567890" y recibo "OK"
Si envío: "1234567890" no recibo nada.

Hasta ahí estamos bien, pero resulta que si envío:
"123"
El programa espera el resto de la cadena para procesar y responder (en caso de que la cabecera sea !). No logro aplicar un timeout, para que, en caso de error, si alguien envía "!125" en lugar de la cadena completa se "resetee" el intérprete.

He visto varios ejemplos, pero la verdad es que no se me ocurre como aplicarlo al código. Considero que esto es de máxima imporantica si quiero interactura con la PC. Estaré muy agradecido por la ayuda.
« Last Edit: May 05, 2012, 01:35:22 am by DrJuano » Logged

Ciudad Real
Offline Offline
God Member
*****
Karma: 1
Posts: 751
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

con un temporizador basado en millis() puedes hacer el timeout

cada vez que lees un caracter reseteas el tiempo por debajo del cual sigue interpretando el array completo, en caso de que se supere el tiempo de espera pones el contador a 0
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 32
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Descubrí una solución sin temporizador y muy efectiva por cierto. En estos momentos no estoy en frente de mi equipo, cuando regrese a casa lo publicaré.
Logged

0
Offline Offline
Edison Member
*
Karma: 8
Posts: 1040
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

La opcion del @Srdongato es muy buena.
Logged

Trabajando en ...

    * Control Domotico (En montaje ...)
    http://casitadomotica.blogspot.com/
 

[url=https://bitbucket.org/fmalpartida

Offline Offline
Newbie
*
Karma: 0
Posts: 32
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

He aqui como lo he resuelto, podemos mejorarlo, claro está.

Code:
// ## PUERTO SERIE ##
  while (Serial.available() > 0) {
    EntradaByte[contador] = Serial.read(); // Lee el byte y lo mete en la String[]
    contador++; // Suma un valor
  }
 
  if (contador == 12) { // Si el valor llega a 12
    if (EntradaByte[0] == 0x21 && EntradaByte[11] == 0x21) { // Si el primer byte y el ultimo es 0x21 (!)
      switch (EntradaByte[1]) { // Ve el segundo byte, que es la orden
        case 82: //Letra R // Si el segundo byte es R entonces hace...
         // HAZ ALGO
         Serial.write(0x21); //Responde 0x21 (!)
         break;
      }
    }
    contador = 0; // Vuelve a poner el contador a cero
    Serial.flush(); // vacía el buffer del puerto serie
  }
  // ## FIN PUERTO SERIE ##

Todo dentro de void loop().
Logged

0
Offline Offline
Edison Member
*
Karma: 8
Posts: 1040
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Buen trabajo @DrJuano.
Logged

Trabajando en ...

    * Control Domotico (En montaje ...)
    http://casitadomotica.blogspot.com/
 

[url=https://bitbucket.org/fmalpartida

Ciudad Real
Offline Offline
God Member
*****
Karma: 1
Posts: 751
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

no es el timeout que pretendías hacer, esperas a que se llene con 12 bites para interpretar la linea completa.
en el caso de que pierdas comunicación y se pierdan caracteres y recibas luego otra trama completa no funcionaría
por ejemplo si recibes
!123 y despumes de un tiempo recibes !123456789

tu programa interpretaría la linea completa !123!1234567

y no como lo que he entendido que pretendías que desechara !123 y empezara de nuevo por !1234567890 que es la siguiente trama correcta que recibes

como te he comentado es lo suyo

Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 32
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Efectivamente, no produce el efecto completo que mencionas de desechar. Por un momento creí que si, pero no desecha. Aunque no sé porqué no lo hace, ya que al final de la secuencia el contador se pone en cero y el buffer del puerto serial se elimina, haya no haya comando en la string[].
Logged

Ciudad Real
Offline Offline
God Member
*****
Karma: 1
Posts: 751
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

eso lo hace siempre y cuando el contador llegue a 12 y no antes.

un timeout la unicaforma de hacerlo en controlando tiempos

cada vez que lees un caracter pones

referencia_timeout=millis();

el if que tienes con contrador  ==  12 está bien , quita la ultima parte de

    Serial.flush(); // vacía el buffer del puerto serie

si mientras el micro procesa la linea que pretendes llega una trama buena, un caracter por ejemplo, con esa linea la borras, por lo que pierdes informacion.

y ahora haces el reset del contador si se supera cierto tiempo

if (( millis()-referenciatimeout ) > tiempotimeout){ contador=0;}


Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 32
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quedaría algo así:

Code:
void loop() {

  while (Serial.available() > 0) {
    EntradaByte[contador] = Serial.read(); // Lee el byte y lo mete en la String[]
    contador++; // Suma un valor
    timeout = millis();  // carga timeout
  }

  if (( millis() - timeout ) > 800) { contador=0; }  // si pasaron más de 800 milisegundos, entonces, vuelve a poner el contador a cero

  if (contador == 12) { // Si el valor llega a 12 // si el contador llego exitosamente a 12, entonces ejecuta el proceso del comando
    if (EntradaByte[0] == 0x21 && EntradaByte[11] == 0x21) { // Si el primer byte y el ultimo es 0x21 (!)
      switch (EntradaByte[1]) { // Ve el segundo byte, que es la orden
        case 82: //Letra R // Si el segundo byte es R entonces hace...
         // HAZ ALGO
         Serial.println(0x21); //Responde 0x21 (!)
         break;
      }
    }
    contador = 0; // Pone el contador a cero para evitar repeticiones
  }
  
}

Probado y funciona perfecto. Gracias SrDonGato. Es dificil a veces comprender el tema del loop. Recién empiezo con Arduino y estoy experimentando bastante. Tengo en mente algun proyecto comercial. Espero que esto ayude a otro que venga por lo mismo. Ahora voy a tratar de generar algo que verifique la secuencia recibida (CRC).
« Last Edit: May 04, 2012, 12:14:24 pm by DrJuano » Logged

Ciudad Real
Offline Offline
God Member
*****
Karma: 1
Posts: 751
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Has entendido perfectamente la filosofía de la que te hablé  smiley

lo bordas si en vez de 800 pones una variable , de manera que la puedas modificar al principio del codigo fácilmente

Un saludo
Logged

Madrid
Offline Offline
Sr. Member
****
Karma: 5
Posts: 481
Life isn't about finding yourself, life is about creating yourself!!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

@DrJuano

no seria mejor ir procesando los datos a medida que entre y no esperar a tener EntradaByte[12] para procesar?
inicio del mensaje sera :  <
fin del mensaje sera :  >

Code:
//Pseudocodigo

if Serial.avaiable();
Entradabyte = Serial.read()
switch (Entradabyte)
{
case '<':
    clean buffer
case'>':
   procesarDatos();

default: //todo lo demas
    if (contador <= numero de datos deseados)
             grabar dato en cDatos[x]
    else
        cleanBuffer;
}
procesarDatos()
{
     verificar longitud();
      hacerAlgoConLosDatosEn_cDatos();
}
   
« Last Edit: May 04, 2012, 05:45:05 pm by yOPERO » Logged

Engineering is the art of
making what you want from
things you can get.

     

[SOLUCIONADO]

Offline Offline
Newbie
*
Karma: 0
Posts: 32
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

yOPERO:

Como lo planteas se ve un poco más complicado, especialmente si uno quiere recibir un paquete de datos. Se me hace que es mas facil tener un paquete completo y luego ver que se hace con él. Por lo menos, he visto dispositivos que se comunican con protocolos en forma de paquetes.
Logged

Madrid
Offline Offline
Sr. Member
****
Karma: 5
Posts: 481
Life isn't about finding yourself, life is about creating yourself!!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

 El cliente siempre tiene la razón y si con eso te vale, perfecto.

Como cultura general el serial recibe los datos uno por uno y lo que llamamos paquete de datos son  series de bytes individuales que se procesan<almacenan/cumplen condiciones> en el receptor.
Logged

Engineering is the art of
making what you want from
things you can get.

     

[SOLUCIONADO]

Offline Offline
Newbie
*
Karma: 0
Posts: 32
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

yOPERO: creo que cantamos la misma canción con diferente música. smiley

En realidad me refería a que, para mi, lo más sencillo sería "armar el paquete" y luego interpretarlo en lugar de ir interpretandolo a medida que se recibe byte por byte. Me suena más complicada la segunda opción.
Logged

Pages: [1]   Go Up
Jump to: