Comunicación Arduino Mega

Hola a todos, es la primera vez que estoy tratando la placa arduino y necesito establecer unas comunicaciones para un proyecto:

Hay un dispositivo que envía un paquete de datos a mi Arduino Mega por comunicación serial a través de TX1 y RX1 (pines 18 y 19) cada 5 segundos. Este paquete de datos consiste en un paquete de 326 tramas seguidas con 1 bit de inicio, 8 de datos y uno de parada cada una. Cada una de esas tramas representa un caracter ASCII. Mi necesidad es leer y almacenar todo ese paquete (paquete en mi ejemplo ) en una variable y posteriormente seleccionar desde la posición 273 hasta la 280 del paquete y almacenarla en otra variable distinta (bis. Además debo convertir los caracteres ASCII leídos a valores decimales para poder operar con ellos, ya que también tengo que hacer operaciones con números posteriormente. Me gustaría resolver esto antes atender a la necesidad de leer cada 5 segundos, que lo dejaré para más adelante. Muchísimas gracias, les adjunto mi código, que sólo está empezado. Saludos!

Paraelforo.txt (632 Bytes)

Pues te queda hacer un bucle con los 326 Serial1.read() y para pasar a decimal, debes hacer la operación sobre cada elemento del vector, no sobre 'bis' directamente.

Entonces todo esto parece coherente? Si ven algo que yo no haya identificado me lo comunican? Gracias!!

int pin16 = 16; // Transmisión de la placa al dispositivo
int pin17 = 17; // Recepción en la placa del dispositivo
int i = 0;
int j = 0;
byte paquete [328];
byte bis [8];

void setup() {
Serial1.begin(9600); // Se habilita el puerto serie 1 y establece la velocidad en 9600 bps
Serial2.begin(9600); // Se habilita el puerto serie 2 y establece la velocidad en 9600 bps
}

void loop() {

for (i=0;i<329;i++) { // Para i positivo menor estricto que 329, leer la entrada serial y almacenarla en
// la variable "paquete", pasar cada elemento del vector a decimal, seleccionar
// la franja deseada y guardarla en la variable "bis"

paquete = Serial1.read();
paquete = paquete - '0';
* if (i>272 && i<281)*
bis = paquete ;
* }*

* ...*

Has cometido el mismo fallo que antes, tienes que guardar los datos en cada posición de 'bis', no sobre 'bis' directamente, estate seguro de que es y como funcionan los vectores.

Fue un fallo al copiar aquí el código, por lo visto no reconocío los corchetes y la i de dentro, lo adjunto como .txt. Saludos!

Paraelforo-2.txt (792 Bytes)

OK, la próxima vez usa el botón de # para meter código, así no se come nada :wink:

Entonces no debería haber ningún problema más :smiley:

mira como se cogen datos del puerto serie, de la manera que lo haces siempre lee del puerto aunque no tenga nada recibido.
en los ejemplo de comunicacion serie puedes ver como se utiliza

 if (Serial1.available() > 0) {
   paquete[i]= Serial.read();
i++;
}

si en el puerto serie hay un byte lo mete en paquete y luego lo mete en el vector paquete. en otra parte del programa tienes que hacer lo que quieras con el bis[] y resetear el i

por ejemplo puedes añadir luego

if (i==328)
{
(aqui metes lo  que quieres hacer con el paquete, copiar lo que te interese a bis)
  for (int x=271;x<381;x++){
bis[x]=paquete[x];
}

i=0; // reseteas el indice de manera que lo siguiente que te entre por el puerto serie lo vuelva a meter en paquete[i] 
}

un saludo

he modificado algo, despues de fiesta uno no se explica muy bien :smiley:

Gracias por responder!! Yo he estado haciendo unas modificaciones en función de la información que he obtenido por ahí. Cambié la forma de leer el puerto serie tal y como me dijiste Srdongato, y también me di cuenta de que puedo despreciar 3 bytes de los que leí y almacené en bis. Sólo necesito leer 5, de los cuáles 1 es un '.' que representa una coma flotante. Lo que necesito para operar después es ese valor en flotante, así que lo hice de la forma que les pongo en el código. Ya verifiqué que las operaciones están bien (ignoré el punto y "lo introduje" al dividir por 10 la suma de a, b, c y d). Pero me queda una duda, yo cuando resto '0' a los caracteres ascii que me llegan por el puerto serie, cuando se trata de números enteros me va bien porque obtengo el valor que necesito en decimal, pero cuando le resto '0' (48 en decimal) al punto '.' (46 en decimal) me da -2, valor que no es reconocido en ascii, ¿cómo afecta eso a mi código? ¿Qué obtengo, un NULL, un 0, ...?

#include <SoftwareSerial.h>

int pin16 = 16; 
int pin17 = 17; 

void setup() {
  Serial1.begin(9600);	// Se habilita el puerto serie 1 y establece la velocidad en 9600 bps
}

void loop() {
  int i = 0;
  int a = 0;
  int b = 0;
  int c = 0;
  int d = 0;
  float aux;
  float bis;
  char paquete [328];
  
  for (i=0;i<329;i++){   // Para i menor estricto que 329, leer la entrada serial y almacenarla en
                         // la variable "paquete" y pasar cada elemento del vector a decimal
    if (Serial1.available() > 0) {
      paquete[i] = Serial1.read(); // Leo y grabo en paquete la entrada serial 1      
      paquete[i] = paquete [i] - '0'; // Convierto todos los valores a decimal
    }
  }  

  a = paquete [276]*1000;  // Opero para convertir ese número decimal en flotante
  b = paquete [277]*100;
  c = paquete [278]*10;
  d = paquete [280];
  aux = a+b+c+d;
  bis = aux/10;
      
  // ... continuará ... 
}

Saludos gente!!

échale un vistazo a los tipos de datos, en que formato se guardan en memoria, rangos etc y fíjate también en los conversores de datos, se asemeja a que no puedes sumar peras con manzanas, deben ser del mismo tipo para operar bien , si no salen cosas raras, ademas de posibles overflows.
intentas meter en un entero una constante por un char, y luego una suma de enteros en un float, debes hacer bien las conversiones de tipos para no tener errores.

lo del punto lo solucionas haciendo un if, (si paquete esta entre 0 y 9 (incluidos estos) le restas 48 (decimal) ) , si es un char creo que -2 equivale a 254, caracter que depende del idioma, caracteres especiales etc ...
Un saludo

Ya lo revisé. Tampoco es necesario transformar todo el código a decimal, sólo paso la parte que me interesa, es decir, los enteros de las posiciones del paquete 276, 277, 278 y 280, ignorando el punto, porque como no lo voy a usar no tengo necesidad de convertirlo restándole '0', así me ahorro problemas.

Muy bien, ahora me tengo que poner con otra parte del proyecto, ya les iré informando. Saludos!!

Hola a todos, aquí estoy otra vez para dar la lata!!

He avanzado un poco con el código:

  1. Logré hacer una subrutina que me imprima cualquier parámetro por una pantalla lcd de 16 caracteres por 4 líneas que adquirí.
  2. He enchufado mi placa arduino al dispositivo que envía los paquetes y estuve probando el código. Este es el más cercano al objetivo:
#include <SoftwareSerial.h>
#include <LiquidCrystal.h>


LiquidCrystal lcd(7, 8, 9, 10, 11, 12); // Ensamblar arduino con lcd
int pin16 = 16; 
int pin17 = 17; 

int i = 0;
int a = 0;
int b = 0;
int c = 0;
int d = 0;
int vinf;
float aux;
float bis;
char paquete [328];

void setup() {
  Serial1.begin(9600);	// Se habilita el puerto serie 1 y establece la velocidad en 9600 bps
  lcd.begin(16, 4); // Inicializo el display LCD
}

void loop() {
  
  for (i=0;i<329;i++){   // Para i menor estricto que 329, leer la entrada serial y almacenarla en
                               // la variable "paquete".

    if (Serial1.available() > 0) {
      paquete[i] = Serial1.read(); // Leo y grabo en paquete la entrada serial 1
      if (i>275 && i<281 && i!=279)      
        paquete[i] = paquete [i] - '0'; // Convierto los valores que me interesan a decimal
    }
  } 
  
  a = paquete[276]*1000;  // Opero hasta convertir ese número decimal en flotante
  b = paquete[277]*100;
  c = paquete[278]*10;
  d = paquete[280];
  aux = a+b+c+d;
  bis = aux/10;
  
  vinf = 1200; 
  flcd(bis, vinf); // Llama a la función flcd para imprimir en la pantalla los valores indicados
}  


// Función flcd:

void flcd(float bis, int vinf){
  lcd.home(); 
  lcd.print("Bis=");
  lcd.setCursor(4, 0);
  lcd.noCursor();
  lcd.print(bis);
  lcd.setCursor(0, 1);
  lcd.noCursor();
  lcd.print("v.infus=");
  lcd.setCursor(9, 1);
  lcd.noCursor();
  lcd.print(vinf);  
}

Existe un problema, y es que mirando en las especificaciones de la función Serial1.available(), sólo recoge en su buffer 127 bytes, y sin embargo el dispositivo envía 328 bytes, y justo los pocos que me interesan están entre las posiciones 276 y 280. ¿Existe alguna forma de desplazar posiciones en ese buffer de una manera rápida para así poder leer estos bytes? Siendo rápida en menos de 5 segundos...

Nota: La función del LCD funciona correctamente, para aquellos que la necesiten.

Un saludo y disculpen por no haber mantenido fresco el tema, he tenido mucho trabajo. GRACIAS!!

los demás caracteres del buffer son siempre iguales ?

lo que puedes hacer es dividir la trama en varias partes y comprobar la cabecera del trozo y si es igual al que te interesa procesar el trozo donde vengan los datos que quieres.

otra opcion es vaciar el buffer 2 veces y procesar la tercera vez, es decir, recives los 100 primeros, vacias el buffer, recives los 100 siguientes, vaciar el buffer, reciber los 100 siguientes, en estos 100 tienes los datos que requieres asi que lo procesas, copias las posiciones que necesitas y ya está. Debes tener en cuenta el numero total de la trama o contar hasta el retorno de carro.

para vaciar el buffer es con Serial.flush()

Un saludo