[Solucionado] Como puedo guardar una trama CAN en una variable

Buenas a todos

Estoy estudiando un poco la comunicación CAN con arduino, estoy usando este ejemplo de las librerias,
En en cual veo todas las tramas que leo desde una maquina.

Pero me surge una duda haber si ustedes me la pueden resolver, viendo el código creo que las tramas que lee las guarda en las variable unsigned char len y buf.

Entonces como puede hacer que me guarde las tramas de cada ID en diferentes bufer, para después gestionarlas a mi manera:

Gracias

Las tramas que capturo son estas:

ID Len data

14EFE100 8 03 0A 17 00 20 00 10 00

14EFE101 8 01 53 12 00 20 05 00 0A

14EFE102 8 01 51 12 00 BA 00 03 00

14EFE103 8 01 53 12 00 2B 00 00 01

#include <SPI.h>
#include "mcp_can_Err.h"


const int SPI_CS_PIN = 10;

MCP_CAN CAN(SPI_CS_PIN);                                   

unsigned char len = 0;
unsigned char buf[8];

void setup()
{
    Serial.begin(115200);

START_INIT:

    if(CAN_OK == CAN.begin(CAN_500KBPS))                   
    {
        Serial.println("CAN BUS Shield init ok!");
    }
    else
    {
        Serial.println("CAN BUS Shield init fail");
        Serial.println("Init CAN BUS Shield again");
        delay(100);
        goto START_INIT;
    }
}


void loop()
{
    

    if(CAN_MSGAVAIL == CAN.checkReceive())            // check if data coming
    {
        CAN.readMsgBuf(&len, buf);    // read data,  len: data length, buf: data buf

        unsigned long canId = CAN.getCanId();
        
        Serial.println("-----------------------------");
        Serial.print("get data from ID: ");
        Serial.println(canId, HEX);

        for(int i = 0; i<len; i++)    // print the data
        {
            Serial.print(buf[i]);
            Serial.print("\t");
        }
        Serial.println();
    }
}

Una forma rápida y sencilla sería crear una matriz doble (n,3) posiciones donde n es un contador de señales entrantes y los 3 datos a guardar de cada posición sería ID, LEN y DATA, recomiendo exportar a un SD si los datos son importantes o desbordarás rápido la memoria.

Gracias arkarash por la rápida respuesta, voy a intentar buscar un ejemplo de lo que me dice para entenderlo.

En principio solo me haría falta guardar los datos del DATA, pero de una manera ordenada.

Por ejemplo esta trama:

14EFE100 8 03 0A 17 00 20 00 10 00

Yo lo que quiero hacer es. Si la ID es 14EFE100 los datos de esta ID se guarden el la variable Nº1

Por que a la hora de enviarlos otra vez por CAN, seria asín :

CAN.sendMsgBuf (0xID, 0, 8, variable Nº1)

Con lo cual solo me hace falta guardar los datos, la ID y el LEN ya se lo puedo poner manualmente.

Lo primero es saber si vas a querer guardar 4 o 4000 líneas de datos en la base de datos. Es importante para saber si lo guardas en un fichero externo o en una variable.

Si es en una variable te aconsejo crear una estructura:

struct DATACAN
   { unsigned long ID ; // ID del CAN
      unsigned char len ;       // Longitud
      unsigned char buf[8] data ;       // Data
   } ;

Luego accederías crearías una variable

DATACAN variable [10];

Y luego para acceder a los datos

Serial.println(variable [1].ID) ;

Más o menos y sin mirar si me he equivocado en algo, estudia un poco más del tema y si tienes alguna duda pregunta.

Enlace para consulta

La idea es la siguiente. La maquina genera 20 tramas can, las cuales las quiero guardar y después enviar a mi gusto cambiado la ID de la trama.

Por eso me hace falta saber los Datos guardados en una variable a que ID corresponden.

Porque luego yo mandare eso datos cambiando la ID

EJ:

Esta trama

14EFE101 8 01 53 12 00 20 05 00 0A

Yo ahora la quiero mandar con la ID 15FFF201, pero eso mismos datos de esa ID lo mismo dentro de un dia los tengo que mandar con la IDXXXXXX

Voy ha estudiar lo que me mandas

Gracias

Buenas, he estado leyendo lo de las estructuras y no parece difícil, pero quería ver como puedo guardar los datos leído dependiendo de la ID de la trama, así que hice este codigo para probar antes de liarme con la estructura.

Pero no me funciona, no logro guardar los datos de la trama, use switch para saber que ID esta leyendo.

Alguna sugerencia.

Gracias

#include <SPI.h>
#include "mcp_can_Err.h"

const int SPI_CS_PIN = 9;
MCP_CAN CAN(SPI_CS_PIN);


unsigned char len1 = 0;
unsigned char buf1[8];
unsigned char len2 = 0;
unsigned char buf2[8];
unsigned char len3 = 0;
unsigned char buf3[8];

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

START_INIT:

  if (CAN_OK == CAN.begin(CAN_500KBPS))                  // init can bus : baudrate = 500k
  {
    Serial.println("CAN BUS Shield init ok!");
  }
  else
  {
    Serial.println("CAN BUS Shield init fail");
    Serial.println("Init CAN BUS Shield again");
    delay(100);
    goto START_INIT;
  }
}


void loop() {

  CAN_MSGAVAIL == CAN.checkReceive();

  switch (CAN.getCanId()) {
    case 0x14EFE100:
      CAN.readMsgBuf(&len1, buf1);
      for (int i = 0; i < len1; i++) 
      {
        Serial.print(buf1[i]);
        Serial.print("\t");
      }
      break;

    case 0x14EFE101:
      CAN.readMsgBuf(&len2, buf1);
      for (int i = 0; i < len2; i++) 
      {
        Serial.print(buf2[i]);
        Serial.print("\t");
      }
      break;

    case 0x14EFE102:
      CAN.readMsgBuf(&len3, buf3);
      for (int i = 0; i < len3; i++) 
      {
        Serial.print(buf3[i]);
        Serial.print("\t");
      }
      break;
  }
}

El codigo que pones no tiene nada que ver con el que tu mismo posteaste mas arriba,que supongo es el ejemplo de la libreria y es el "bueno".Esto:

CAN_MSGAVAIL == CAN.checkReceive();

no es lo mismo que esto:

if(CAN_MSGAVAIL == CAN.checkReceive())

La lectura de una trama debe estar condicionada a que haya algo que leer.
Aqui y segun el ejemplo ,getCanId() devuelve un unsigned long:

unsigned long canId = CAN.getCanId();

Sin embargo tu comparas con un hexadecimal:

case 0x14EFE100:

y esto no se si es correcto.
Edito porque acabo de hacer la prueba y se puede comparar.
Mira de poner Serial.println a modo de logs para ver los valores que recoges,por ejemplo una vez que compruebes que hay datos disponibles:

unsigned long canId = CAN.getCanId();
Serial.println(canId,HEX);

No estas usando las estructuras por ningún sitio en el código pero bueno, si este código funcionase sólo guardarías el último dato de cada ID, los demás se machacarían.

Aparte de eso, comprueba que el switch case funciona bien que, creo que no con el 0x14EFE100 como condición, tu que has ejecutado el programa ¿entra en el case? ¿imprime por el puerto serial lo que debe? Si no imprime en el serial es que no entra en el case y podría ser por la condicion.

Edit: Como te han dicho más arriba el problema es que no entra en los case por la condicion

Edit: Como te han dicho más arriba el problema es que no entra en los case por la condicion

No,lo acabo de comprobar y si que se puede comparar.

arkarash no usado aun las estructuras por que quería primero saber como guardar los dato según la ID, pero las usare cuando resuelva este problema y te agradezco mucho tu ayuda.

Mira jose si este comando lo saco del switch

CAN.readMsgBuf(&len, buf);

Y solo creo una variable para LEN y DATA, si funciona y veo los datos por el puerto serie

unsigned char len = 0;
unsigned char buf[8];

El codigo quedaria asin, mas o menos asin:

unsigned char len = 0;
unsigned char buf[8];


void loop() {

  CAN_MSGAVAIL == CAN.checkReceive();

  CAN.readMsgBuf(&len, buf);

  switch (CAN.getCanId()) {
    case 0x14EFE100:
  
      for (int i = 0; i < len; i++) // print the data
      {
        Serial.print(buf[i]);
        Serial.print("\t");
      }
      break;

    case 0x14EFE101:
   
      for (int i = 0; i < len; i++) // print the data
      {
        Serial.print(buf[i]);
        Serial.print("\t");
      }
      break;

    case 0x14EFE102:
      
      for (int i = 0; i < len; i++) // print the data
      {
        Serial.print(buf[i]);
        Serial.print("\t");
      }
      break;
  }
}

Pero no es lo que yo pretendo hacer, yo lo que quiero hacer es esto, mas o menos.
En este ejemplo lo que hago es capturar una trama con una ID y lanzar esa misma trama con una ID diferente y funciona perfectamente.

case 0x14EFE101:
     for (int i = 0; i < len; i++) {
     Serial.print(buf[i], HEX);
     Serial.print("\t");
     CAN.sendMsgBuf(0x15FEE103, 1, 8, buf);
     }
     Serial.println();
     break;

El problema esta en que no se como meter en cada variable los datos da cada ID para luego mandarlos con otra ID que yo quiera.
Por eso hice la prueba del post de arriba, y pensé si leo La IDXXXXXX que me guarde los datos en una Variable “Y” y después poder lanzarla con este comando:

CAN.sendMsgBuf(0x15FEE103, 1, 8, Variable Y);

Gracias a los dos por la ayuda.

Desconozco esa libreria y que tipo de parametros hay que pasar,deduzco que son arrays de bytes.si sabes cuales son los 20 Id y las 20 tramas ,podrias probar algo como esto ,pero no se si funcionara:

#define ID1 0x15FEE103
#define ID2 0x14EFE101
// Asi hasta los 20
#define TRAMA1 0x015312002005000A
#define TRAMA2 0x0153180F2006000A
// Asi hasta los 20
void setup(){ // Codigo que sea....}
void loop(){
// Quiero enviar ID1 con TRAMA2
  CAN.sendMsgBuf(ID1, 1, 8, TRAMA2);
}

JoseGD:
arkarash no usado aun las estructuras por que quería primero saber como guardar los dato según la ID, pero las usare cuando resuelva este problema y te agradezco mucho tu ayuda.

Mira jose si este comando lo saco del switch

CAN.readMsgBuf(&len, buf);

Y solo creo una variable para LEN y DATA, si funciona y veo los datos por el puerto serie

unsigned char len = 0;

unsigned char buf[8];




El codigo quedaria asin, mas o menos asin:



unsigned char len = 0;
unsigned char buf[8];

void loop() {

CAN_MSGAVAIL == CAN.checkReceive();

CAN.readMsgBuf(&len, buf);

switch (CAN.getCanId()) {
    case 0x14EFE100:
 
      for (int i = 0; i < len; i++) // print the data
      {
        Serial.print(buf[i]);
        Serial.print("\t");
      }
      break;

case 0x14EFE101:
 
      for (int i = 0; i < len; i++) // print the data
      {
        Serial.print(buf[i]);
        Serial.print("\t");
      }
      break;

case 0x14EFE102:
     
      for (int i = 0; i < len; i++) // print the data
      {
        Serial.print(buf[i]);
        Serial.print("\t");
      }
      break;
  }
}






Pero no es lo que yo pretendo hacer, yo lo que quiero hacer es esto, mas o menos.
En este ejemplo lo que hago es capturar una trama con una ID y lanzar esa misma trama con una ID diferente y funciona perfectamente.



case 0x14EFE101:
    for (int i = 0; i < len; i++) {
    Serial.print(buf[i], HEX);
    Serial.print("\t");
    CAN.sendMsgBuf(0x15FEE103, 1, 8, buf);
    }
    Serial.println();
    break;




El problema esta en que no se como meter en cada variable los datos da cada ID para luego mandarlos con otra ID que yo quiera.
Por eso hice la prueba del post de arriba, y pensé si leo La IDXXXXXX que me guarde los datos en una Variable "Y" y después poder lanzarla con este comando:



CAN.sendMsgBuf(0x15FEE103, 1, 8, Variable Y);




Gracias a los dos por la ayuda.

A ver, creo que Jose no te ha entendido o no te he entendido yo.

Si funciona con el CAN.Receive fuera del switch déjalo fuera, de hecho es donde debería estar, guardas en variables “temporales” ID, len y buf[8], creas la estructura y haces el switch case para almacenarla. Yo es que lo veo claro así, pero es un enfoque diferente del que le da Jose

Desconozco esa libreria y que tipo de parametros hay que pasar,deduzco que son arrays de bytes.si sabes cuales son los 20 Id y las 20 tramas ,podrias probar algo como esto ,pero no se si funcionara:
Code: [Select]

#define ID1 0x15FEE103
#define ID2 0x14EFE101
// Asi hasta los 20
#define TRAMA1 0x015312002005000A
#define TRAMA2 0x0153180F2006000A
// Asi hasta los 20
void setup(){ // Codigo que sea....}
void loop(){
// Quiero enviar ID1 con TRAMA2
CAN.sendMsgBuf(ID1, 1, 8, TRAMA2);
}

Esto no funcionaria jose ya que simpre mandaria en caso de la trama 1 015312002005000A y no seria correcto, pues la trama va cambiando, me explico la que yo capturo de la maquina son esos valores, pero en van variando constantemente y si yo solo mando es array no funcionara, por eso lo de guardarla con sus respectivos cambio, no se si m he explicado,

A ver, creo que Jose no te ha entendido o no te he entendido yo.

Si funciona con el CAN.Receive fuera del switch déjalo fuera, de hecho es donde debería estar, guardas en variables “temporales” ID, len y buf[8], creas la estructura y haces el switch case para almacenarla. Yo es que lo veo claro así, pero es un enfoque diferente del que le da Jose

arkarash entiendo lo que dices, pero no entiendo como hago para guardar en variables los Datos de cada ID, ya que este comado

CAN.readMsgBuf(&len, buf);

Lee todo a la vez y guarda los datos en

unsigned char len = 0;
unsigned char buf[8];

No entiendo o no lo veo como hago para separa los datos de cada ID en una variable.

Gracias

Buenas, no te había aclarado esa parte porque me habías dicho que controlabas las estructuras.

Creas la estructura:

typedef struct 
   { unsigned long ID ; // ID del CAN
      unsigned char len ;       // Longitud
      unsigned char [8] data ;       // Data
   } DATACAN;

Luego lees como ya sabes y se almacena en las variables, y después se almacena en la estructura:

DATACAN Datos [20] ;
Datos[a].ID = ID ;
Datos[a].len = len ;
For ....{
Datos[a].data [i]= buf[i] };
a++ ;

Espero que esto resuelva tus dudas

Bueno,espero que saques conclusiones ,cuanto mas preciso seas explicando tu proyecto ,menos mataremos moscas a cañonazos...De hecho sigo sin acabar de comprenderlo ,asi que hasta que no lo tenga claro yo me bajo aqui.

jose:
Bueno,espero que saques conclusiones ,cuanto mas preciso seas explicando tu proyecto ,menos mataremos moscas a cañonazos...De hecho sigo sin acabar de comprenderlo ,asi que hasta que no lo tenga claro yo me bajo aqui.

jose creí que en el mensaje nº 4 lo explique, te pido disculpas si no lo hice bien, y agradezco muchísimo tu ayuda.

El proyecto es el siguiente, tengo una maquina industrial la cual genera 20 tramas CAN de 8 bytes cada una, estos bytes tiene información de temperatura, humedad, etc... e iran cambiado a medida que lanza la trama.

EL objetivo es leer y guardar los datos de cada ID y después lanzarlos a otra maquina modificando solo la ID de cada trama.

Los lanzare pulsando un teclado por ejemplo:

La ID 14FEE101 con sus datos, si pulso la tecla 'A' mando eso datos que estoy leyendo de esa ID pero cambiamos la direccion ID, lo mandaríamos ahora con 15FEE201 por ejemplo.

Te pido disculpas _jose_si te sentó mal que no me explicara bien.

Un Saludo

Y mi respuesta te sirve o no?

arkarash:
Y mi respuesta te sirve o no?

Gracias arkarash por tu repuesta, la estaba estudiando ahora, voy a hacer una pruebas y si no te importa, si me surge algun problema o duda te lo digo.

Gracias

estos bytes tiene información de temperatura, humedad, etc... e iran cambiado a medida que lanza la trama.

Este era un detalle importante ,porque lo que yo entendi hasta ahora es que la maquina trabaja con 20 tramas iguales.En ese caso ya te han dado una solucion.