Sincronizar el envió de una trama CAN

Hola,
Quiero enviar una trama CAN y que esta este sincronizada con una trama ya existente.

Me explico: Necesito leer la trama que manda una maquina (con una ID especifica ) y saber el intervalo de tiempo en que manda esta ( en mseg), para después mandar yo una con el mismo intervalo y a sin queden sincronizadas.

EJ: La maquina manda estas tres tramas con estas ID:

0x0FA , 0x77A y 0x49A , pues me hace falta saber el intervalo de tiempo con que se envía la 0x49A para después lanzar yo una a la maquina con el mismo intervalo.

No se si me he explicado bien.

Gracias

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

const int SPI_CS_PIN = 10;  // Pin para el CS del CAN
MCP_CAN CAN(SPI_CS_PIN);


// Buffer para las tramas CAN
unsigned char len = 0;
unsigned char buf[8];


unsigned char stmp[6] = { 0x02, 0x00, 0x31, 0x6B, 0xE8, 0x00 };  // Trama para enviar

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

  while (CAN_OK != CAN.begin(CAN_250KBPS))  // velocidad del can a 250kb
  {
    Serial.println("CAN BUS Shield init fail");
    Serial.println(" Init CAN BUS Shield again");
    delay(100);
  }
  Serial.println("CAN BUS Shield init ok!");
}

void loop() {
  if (CAN_MSGAVAIL == CAN.checkReceive()) {    //chequeamos la entra CAN
    CAN.readMsgBuf(&len, buf);                // leemos la trama

unsigned long canId = CAN.getCanId();  // Para saber la ID que queremos sincronizar

  }

  // Una vez calculado el intervalo de tiempo de la lectura de la trama, se enviara la trama con el mismo intervalo de tiempo
  // La trama estara enviandose sin parar hasta que se quite la alimentacion de arduino. 

  CAN.sendMsgBuf(0x386, 0, 6, stmp);
}

Los datos recibidos son aleatorios? Porque si vienen en secuencia 0x0FA , 0x77A y luego llega 0x49A ya lo tienes, pero si fuera asi de fácil, no preguntarías no es así?

Te lo explico con fotos surbyte que creo que no me explique bien.

En esta Foto esta la trama que manda la maquina, la trama importante es la 0x49A.

En esta otra Foto, esta la trama que envía la maquina y la que yo tengo que emular (que la manda un especie de emulador que trae el técnico para hacer comprobaciones) ya sincronizada,
que es la 0x386, se ve que coincide donde pone Delta.

Y esta ultima es lo que yo he intentado con ardunio, lance la trama 0x386, pero no funciona, si te fijas el DELTA va diferente.

Podria probar a lanzarla cada 100ms, por si el delta es eso.

El objetivo es que arduino me detecte esa velocidad y que a su vez me lance la trama que yo quiera sincronizada con esta.

Lo quiero hacer automatico, por que hay otra maquinas con diferentes tramas y me gustaría realizarlo todo automatico.

Me parece o previo a una trama 0x49A tenes siermpre una 0x77A?

Buenas Surbyte,
Ya creo que se como funciona:
La maquina siempre esta enviado estas tramas:

0x0FA = { 0x00, 0x00, 0xFF, 0xFF, 0x40, 0xFF, 0xFF }
0x77A = { 0xFF, 0x00, 0xFF, 0x21, 0xA0, 0xFF, 0xFF, 0x00, 0xFF }
0x49A = { 0x04, 0xFF, 0xC3, 0x04, 0x79, 0x90, 0x05 }

El emulador envía esta trama:

0x386 = { 0x02, 0x00, 0x31, 0x6B, 0xE8, 0x00 }

En cuanto el emulador manda esa trama, en las tramas de la maquina se modifica la 0x49A y queda a sin, el primer dato de la trama lo pone a 00 y la maquina empieza a funcionar.

0x49A = { 0x00, 0xFF, 0xC3, 0x04, 0x79, 0x90, 0x05 }

Todas están mandadas en intervalos de 100ms.

Ahora viene lo que no entiendo:

Si yo envió con arduino la trama (la 0x386, que es la que envía el emulador) cada 100 ms (use delay solo para hacer la prueba), no funciona, no se modifica la dirección 0x49A


#include <mcp_can.h>
#include <SPI.h>

const int SPI_CS_PIN = 17;

MCP_CAN CAN(SPI_CS_PIN);

unsigned char REN[6] = { 0x02, 0x00, 0x31, 0x6B, 0xE8, 0x00 };

void setup() {

  CAN_OK == CAN.begin(CAN_250KBPS);  // Asignamos velocidad del CAN = 250kbps
}

void loop() {
  CAN.sendMsgBuf(0x386, 0, 6, REN);
  delay(100);
  CAN.sendMsgBuf(0x386, 0, 6, REN);
  delay(100);
  CAN.sendMsgBuf(0x386, 0, 6, REN);
  delay(100);
  CAN.sendMsgBuf(0x386, 0, 6, REN);
  delay(100);
  CAN.sendMsgBuf(0x386, 0, 6, REN);
  delay(100);
  CAN.sendMsgBuf(0x386, 0, 6, REN);
  delay(100);
}

Entonces averigüe lo siguiente:
Si yo enciendo la maquina sin el emulador puesto y luego enchufo el emulador no se modifica la trama 0x49A y la maquina no funciona, por el contrario si enchufo el emulador y luego enciendo la maquina ( que esta a su vez alimenta el emulador ) si se modifica dicha trama y la maquina funciona.

Hice la prueba con Arduino, conectándolo a la maquina y que se alimente en el momento de encender la maquina y no hay manera de que me modifique la dirección 0x49A.

No entiendo por que no funciona la verdad.

Lo que si me di cuenta que si alimento solo emulador y leo lo que envía, este no envía nada, solo envía la trama cuando esta conectado a la maquina, por lo cual creo que el emulador detecta cuando hay alguna trama y envía la suya para que la maquina funcione.

Siento que el Post se tan largo, pero tenia que explicar todo lo que hice.

Gracias

Hola. Cuando leí tu posteo. Lo primero que me vino a la mente es lo cobarde que sigo siendo por no comprarme mi osciloscopio.

Bueno vamos al punto. te ruego que te olvides de la trama por un instante. Y leas mi historia.

Tengo mi netbook en la mesa y mi impresora en otra mesa. Y un día me dije que pasa por el cable?
Como puedo ver lo que pasa por el cable?
Podría rescatar esa trama y verla mientras se imprime una nota?
Podré capturar esa "trama" de datos y luego engañar a mi impresora y enviarsela luego y así imprimir la misma nota desde mi microcontrolador?

Fue así que puse manos a la obra y logré (sin osciloscopio, ni otra cosa) ver como había logrado intervenir sobre el cable sin problema alguno.
Le agregué un par de leds y parpadeaban como locos mientras se imprimía la nota del otro lado.

Conclusión no te encierres en la trama deja la trama por un instante y ponete como escucha de la trama (de ese modo) no necesitas interferir sobre ella si no escucharla para luego replicarla. sin necesidad de coordinaciones previas.

Por lo menos esa experiencia personal me dió ese aprendizaje. No interfiero, no copio sino escucho y luego la replico. Suerte.

Yo lo que haría sería recibir toda la trama CAN y reenviarla. Cuando se de el ID 0x49 la modifico y de ese modo siempre estaré en tiempo.
Es decir, reconstruyo todo.
Recibo cada trama

0x0FA = { 0x00, 0x00, 0xFF, 0xFF, 0x40, 0xFF, 0xFF }
0x77A = { 0xFF, 0x00, 0xFF, 0x21, 0xA0, 0xFF, 0xFF, 0x00, 0xFF }
0x49A = { 0x04, 0xFF, 0xC3, 0x04, 0x79, 0x90, 0x05 }

cuando recibo el Id 0x49A entonces lo cambio y envio lo que corresponda.
Requiere dos interfaces CAN que supongo tienes.

Gracias Surbyte, lo probé y tampoco funciono.
Así que después de leer el post de Humberto02, estudie toda la trama que envía el llamémoslo emulador, que es todo lo del recuadro Rojo de la foto.

Pues después de ver no se cuantas líneas me di cuenta que el emulador no solo envía la trama que se ve a la derecha de la foto con la ID 386, si no que con esa ID envía 3 tramas mas cada 100ms, lo replique igual y funciona.

Así que probé con este Sketch y funciona.

#include <mcp_can.h>
#include <SPI.h>

const int SPI_CS_PIN = 17;

MCP_CAN CAN(SPI_CS_PIN);

unsigned char REN[6] = { 0x01, 0x00, 0xE3, 0x6B, 0xE2, 0xFF };
unsigned char REN1[6] = { 0x0A, 0x23, 0xFF, 0x0F, 0xEF, 0x00 };
unsigned char REN2[6] = { 0x06, 0xFF, 0x06, 0x3E, 0xB0, 0xFF };
unsigned char REN3[6] = { 0x02, 0x00, 0x31, 0x6B, 0xE8, 0x00 };

void setup() {

  CAN_OK == CAN.begin(CAN_250KBPS);  // Asignamos velocidad del CAN = 250kbps
}

void loop() {
  CAN.sendMsgBuf(0x386, 0, 6, REN);
  delay(100);
  CAN.sendMsgBuf(0x386, 0, 6, REN1);
  delay(100);
  CAN.sendMsgBuf(0x386, 0, 6, REN2);
  delay(100);
  CAN.sendMsgBuf(0x386, 0, 6, REN3);

}

Pero me gustaría eliminar los delay, así que hice esto, pero no me funciona.
Si envio solo una trama si lo hace a 100ms, pero con las cuatro es evidente que no hago el intervalo.

unsigned long previousMillis = 0;
const long interval = 100;  // intervalo de 100ms

void loop() {
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    CAN.sendMsgBuf(0x386, 0, 6, REN);
    CAN.sendMsgBuf(0x386, 0, 6, REN1);
    CAN.sendMsgBuf(0x386, 0, 6, REN2);
    CAN.sendMsgBuf(0x386, 0, 6, REN3);
  }
}

Como hago para eliminar delay y envíar las tramas en ese orden con intervalos de 100ms.
Con los delay que puse en el primer código me es valido, por que funciona y no hay problema, pero me gustaría sabercomo hacerlo sin delay.

Gracias

Yo estoy haciendo algo similar pero con un DUE y este me permite capturar las tramas y cambiar bits a la trama. Pero en la librería que usas no esta esta posibilidad.

El DUE lo estuve viendo hace tiempo para otros proyectos que hice con CAN BUS, pero es un micro algo grande para este proyecto, tengo que meter todo en una caja de un mando de garaje.
Pensé es usar un STM32F, pero se me queda algo grande aun.
No sabia que había librerías CAN solo para el DUE