Problema comunicacion MDB y Arduino

Encontre un post en github (clic aquí) en donde elaboran un convertidor de MDB a RS232 usando un ARDUINO MEGA como maestro y Arduino Uno como esclavo MDB. Lo he probado con un validador de billetes y funciona bien.

He intentado modificar el código para que solo use un solo Arduino en la comunicación, el problema radica en que no logro poner el validador de billetes en estado
activo. El validador es de la marca MEI modelo CXB2. Estoy usando un arduino mega 2560. He estado enviando la siguiente secuencia para la intentar
activar el validador (la misma que la del proyecto).

  1. RESET
  2. POLL
  3. SETUP
  4. BILL TYPE
  5. POLL

Las 4 primeras instrucciones las envío desde el void setup, la quinta instrucción la estoy constantemente enviando desde el void loop, pero la respuesta que obtengo siempre es validador inactivo (06 09 0F). La verdad estoy atorado y no se en donde me estoy equivocando. Anexo codigo, por el momento, solo estoy leyendo datos HEX. De antemano gracias.


/* Instrucciones del validador de billetes */
#define RESET       0x30
#define SETUP       0x31
#define SECURITY    0x32
#define POLL        0x33
#define BILL_TYPE   0x34
#define ESCROW      0x35
#define STACKER     0x36
#define EXP_CMD     0x37


/* Estructura para manejar datos MDB */
struct MDB_Byte {
  byte datos;
  byte modo;
 };

struct MDB_Byte MDB_Buffer[37]; // Buffer para leer datos desde el dispositivo MDB 

struct MDB_Byte CMD_RST[2] =   { {0x30,0x1},{0x30,0x0} };
struct MDB_Byte CMD_POLL[2] =  { {0x33,0x1},{0x33,0x0} };
struct MDB_Byte CMD_SETUP[2] = { {0x31,0x1},{0x31,0x0} };
struct MDB_Byte CMD_BILL[6];
struct MDB_Byte CMD_STK[2] = {{0x36,0x1},{0x36,0x0}};

volatile int MDB_Buffer_Count=0;

// Indicadores de estado de la recepcion de datos de MDB
int rcvcomplete; // Mensaje MDB recibido
int mdboverflow; // Mensaje MDB incorrecto

byte MsgError = 0x00;
byte MsgAnt = 0x01;

void setup() {
  Serial.begin(9600); // PC
  MDB_Config();   // Hacia el MDB, Puerto Serial1
  /*Secuencia que debe seguir la activación del MDB*/

  // COMANDO RESET
  MDB_Buffer_Count = 0;
  for(int i =0; i < sizeof(CMD_RST); i++)
    { write_9bit(CMD_RST[i]);}
  delay(500);

 // COMANDO POLL
 for(int i =0; i<sizeof(CMD_POLL); i++)
    { write_9bit(CMD_POLL[i]); } 
    
 MDB_Buffer_Count = 0 ;
 if( Procesar_Respuesta() >= 1 )
   { for(int i =0; i < MDB_Buffer_Count; i++)  
      { Serial.write(MDB_Buffer[i].datos ); }
   } 
 delay(30);

 //COMANDO SETUP
  for(int i =0; i < sizeof(CMD_SETUP); i++)
    { write_9bit(CMD_SETUP[i]); }
  MDB_Buffer_Count = 0 ;
  
  if( Procesar_Respuesta() >= 1 )
   { for(int i =0; i < MDB_Buffer_Count; i++)  
      { Serial.write(MDB_Buffer[i].datos ); }  
   }

    // COMANDO BILL  
  CMD_BILL[0] = {0x34,0x1};
  CMD_BILL[1] = {0xFF,0x0};
  CMD_BILL[2] = {0xFF,0x0};
  CMD_BILL[3] = {0x00,0x0};
  CMD_BILL[4] = {0x00,0x0};
  CMD_BILL[5] = {0x32,0x0};
   
  for(int i =0; i < sizeof(CMD_BILL); i++)
    { write_9bit(CMD_BILL[i]);  } 
}
 
void loop() {
    
 MDB_Buffer_Count = 0 ;
 for(int i =0; i<sizeof(CMD_POLL); i++)
    { write_9bit(CMD_POLL[i]); } 

 if( Procesar_Respuesta() >= 1 )
   { for(int i =0; i < MDB_Buffer_Count; i++)  
      { Serial.write(MDB_Buffer[i].datos ); }
   }   
  delay(500);
  
}

void MDB_Config()
{
  /* Configuracion del Baud Rate a 9600 bps. Pags 223-226 hoja de datos ATMEGA2560
   vienen tablas con valores para valores conocidos de frecuencia de reloj */
  UBRR1H = 0; UBRR1L = 103;
  
  /* Configuracion del registro UCSR0A -> USART CONTROL AND STATUS REGISTER A 
     Elimina el double speed USART */
  UCSR1A &= ~(1<<U2X1);
  
  /* Configuracion de paridad, stop bits y modo de transmision asincrono
   Para ello se modifica el registro UCSR0C  (Pag 220-221 datasheet atmega2560):
   Modo asincrono: Bit UMSELn1 y Bit UMSELn0, ambos en 0
   Sin paridad : Bit UPMn1 y Bit UPMn0 ambos en 0
   1 Bit de Stop: Bit USBSn en 0
   Tamano de caracter :  Bits UCSZn1 - UCSZn0 Bits. Para 8 bits ambos en 0
   El noveno bit de tamano puede ser establecido poniendo 
   en 1  el bit UCSZn2 del registro UCSRnB */
     
 UCSR1C = (0<<UMSEL11)|(0<<UMSEL10)|(0<<UPM11)|(0<<UPM10)|(0<<USBS1)|(1<<UCSZ11)|(1<<UCSZ10);
 
 /* Se pone en 1 para que envie 9 bits de datos*/
 UCSR1B |= (1<<UCSZ12);
 
 /* Activacion de los pines TX y RX */
 UCSR1B |= (1<<RXEN1)|(1<<TXEN1);

}

// Escribe conjuntos de bytes MDB
void  write_9bit(struct MDB_Byte mdbb)
{ while( !(UCSR1A)&(1<<UDRE1)); //Espera a que se vacie el buffer de transmision  
    if(mdbb.modo == 0x1)
      UCSR1B |= (1<<TXB81);  // Escribe '1' en el 9no bit
    else
      UCSR1B &= ~(1<<TXB81); //Escribe '0' en el 9no bit
  
  UDR1 = mdbb.datos; // Se copia el dato a enviar
 }

/*Funcion para leer 9 bits de datos. */
unsigned int read_9bit()
{ unsigned char resh, resl;
  int rtr = 0;
  /*Espera para recibir los datos*/
 while( ( !(UCSR1A & (1<<RXC1)) ) and rtr <50 )
    { delay(1); //rtr ++; 
    }

  if(rtr == 50) {
   mdboverflow = 1; rcvcomplete = 1; }
  
  /*Obtiene el 9 bit, luego, los datos del buffer*/
  resh = UCSR1B; 
  resl = UDR1;
      
  resh = (resh>>1) & 0x01;        // Se filtra el 9 bit
  return ( (resh << 8) | resl );  // Se regresa los 8 bits de datos
}

void MDB_getByte(struct MDB_Byte* mdbb) {
 int b;
 b = 0;
 b = read_9bit();
 memcpy(mdbb,&b,2);
}


byte MDB_CHK() { // Validador de checksum de datos provenientes del MDB
  int sum = 0;
  for(int i=0; i<(MDB_Buffer_Count-1); i++)
    sum += MDB_Buffer[i].datos;
  if (MDB_Buffer[MDB_Buffer_Count-1].datos == (sum&0xFF))
    return 1;
  else
    return 0;
  }

void MDB_read(){
  MDB_getByte(&MDB_Buffer[MDB_Buffer_Count]);
  MDB_Buffer_Count++;
  if(MDB_Buffer_Count == 35)
  { rcvcomplete = 1;
    mdboverflow = 1; }

  if(MDB_Buffer[MDB_Buffer_Count -1].modo && MDB_CHK())
   {rcvcomplete = 1; } 
  }
  

int Procesar_Respuesta() 
{ byte state = 0;
  mdboverflow = 0; rcvcomplete = 0;
  while (!rcvcomplete) 
    { MDB_read(); }
    
  if( rcvcomplete && (!mdboverflow) )
  {   
    if(MDB_Buffer_Count>0)
    {
      if(MDB_Buffer_Count>1)
       { //Serial.print("MDB BUF: "); Serial.println(MDB_Buffer_Count);
         MDB_write(0x00);
        if(MDB_Buffer[0].datos == 0 )
          state = 0;
        else
          state = 1;
       }
    else {
      if(MDB_Buffer_Count == 1){ } }
    }
  } return state;
}

A mi me da error al querer compilar por la línea

MDB_write(0x00);

¿Te has dejado parte del código afuera?

Tengo mis dudas con

struct MDB_Byte MDB_Buffer[37]; // Buffer para leer datos desde el dispositivo MDB 

struct MDB_Byte CMD_RST[2] =   { {0x30,0x1},{0x30,0x0} };
struct MDB_Byte CMD_POLL[2] =  { {0x33,0x1},{0x33,0x0} };
struct MDB_Byte CMD_SETUP[2] = { {0x31,0x1},{0x31,0x0} };
struct MDB_Byte CMD_BILL[6];
struct MDB_Byte CMD_STK[2] = {{0x36,0x1},{0x36,0x0}};

Entiendo que no va la palabra struct delante de la tipificación de variables struct (o al menos es innecesaria).

Hola. Gracias por responder.

Blockquote ¿Te has dejado parte del código afuera?

Si. Se me olvido una función. Anexo el código nuevamente.

/* Instrucciones del validador de billetes */
#define RESET       0x30
#define SETUP       0x31
#define SECURITY    0x32
#define POLL        0x33
#define BILL_TYPE   0x34
#define ESCROW      0x35
#define STACKER     0x36
#define EXP_CMD     0x37


/* Estructura para manejar datos MDB */
struct MDB_Byte {
  byte datos;
  byte modo;
 };

struct MDB_Byte MDB_Buffer[37]; // Buffer para leer datos desde el dispositivo MDB 

struct MDB_Byte CMD_RST[2] =   { {0x30,0x1},{0x30,0x0} };
struct MDB_Byte CMD_POLL[2] =  { {0x33,0x1},{0x33,0x0} };
struct MDB_Byte CMD_SETUP[2] = { {0x31,0x1},{0x31,0x0} };
struct MDB_Byte CMD_BILL[6];
struct MDB_Byte CMD_STK[2] = {{0x36,0x1},{0x36,0x0}};

volatile int MDB_Buffer_Count=0;

// Indicadores de estado de la recepcion de datos de MDB
int rcvcomplete; // Mensaje MDB recibido
int mdboverflow; // Mensaje MDB incorrecto

byte MsgError = 0x00;
byte MsgAnt = 0x01;

void setup() {
  Serial.begin(9600); // PC
  MDB_Config();   // Hacia el MDB, Puerto Serial1
  /*Secuencia que debe seguir la activación del MDB*/

  // COMANDO RESET
  MDB_Buffer_Count = 0;
  for(int i =0; i < sizeof(CMD_RST); i++)
    { write_9bit(CMD_RST[i]);}
  delay(500);

 // COMANDO POLL
 for(int i =0; i<sizeof(CMD_POLL); i++)
    { write_9bit(CMD_POLL[i]); } 
    
 MDB_Buffer_Count = 0 ;
 if( Procesar_Respuesta() >= 1 )
   { for(int i =0; i < MDB_Buffer_Count; i++)  
      { Serial.write(MDB_Buffer[i].datos ); }
   } 
 delay(30);

 //COMANDO SETUP
  for(int i =0; i < sizeof(CMD_SETUP); i++)
    { write_9bit(CMD_SETUP[i]); }
  MDB_Buffer_Count = 0 ;
  
  if( Procesar_Respuesta() >= 1 )
   { for(int i =0; i < MDB_Buffer_Count; i++)  
      { Serial.write(MDB_Buffer[i].datos ); }  
   }

    // COMANDO BILL  
  CMD_BILL[0] = {0x34,0x1};
  CMD_BILL[1] = {0xFF,0x0};
  CMD_BILL[2] = {0xFF,0x0};
  CMD_BILL[3] = {0x00,0x0};
  CMD_BILL[4] = {0x00,0x0};
  CMD_BILL[5] = {0x32,0x0};
   
  for(int i =0; i < sizeof(CMD_BILL); i++)
    { write_9bit(CMD_BILL[i]);  } 
}
 
void loop() {
    
 MDB_Buffer_Count = 0 ;
 for(int i =0; i<sizeof(CMD_POLL); i++)
    { write_9bit(CMD_POLL[i]); } 

 if( Procesar_Respuesta() >= 1 )
   { for(int i =0; i < MDB_Buffer_Count; i++)  
      { Serial.write(MDB_Buffer[i].datos ); }
   }   
  delay(500);
  
}

void MDB_Config()
{
  /* Configuracion del Baud Rate a 9600 bps. Pags 223-226 hoja de datos ATMEGA2560
   vienen tablas con valores para valores conocidos de frecuencia de reloj */
  UBRR1H = 0; UBRR1L = 103;
  
  /* Configuracion del registro UCSR0A -> USART CONTROL AND STATUS REGISTER A 
     Elimina el double speed USART */
  UCSR1A &= ~(1<<U2X1);
  
  /* Configuracion de paridad, stop bits y modo de transmision asincrono
   Para ello se modifica el registro UCSR0C  (Pag 220-221 datasheet atmega2560):
   Modo asincrono: Bit UMSELn1 y Bit UMSELn0, ambos en 0
   Sin paridad : Bit UPMn1 y Bit UPMn0 ambos en 0
   1 Bit de Stop: Bit USBSn en 0
   Tamano de caracter :  Bits UCSZn1 - UCSZn0 Bits. Para 8 bits ambos en 0
   El noveno bit de tamano puede ser establecido poniendo 
   en 1  el bit UCSZn2 del registro UCSRnB */
     
 UCSR1C = (0<<UMSEL11)|(0<<UMSEL10)|(0<<UPM11)|(0<<UPM10)|(0<<USBS1)|(1<<UCSZ11)|(1<<UCSZ10);
 
 /* Se pone en 1 para que envie 9 bits de datos*/
 UCSR1B |= (1<<UCSZ12);
 
 /* Activacion de los pines TX y RX */
 UCSR1B |= (1<<RXEN1)|(1<<TXEN1);

}

// Escribe conjuntos de bytes MDB
void  write_9bit(struct MDB_Byte mdbb)
{ while( !(UCSR1A)&(1<<UDRE1)); //Espera a que se vacie el buffer de transmision  
    if(mdbb.modo == 0x1)
      UCSR1B |= (1<<TXB81);  // Escribe '1' en el 9no bit
    else
      UCSR1B &= ~(1<<TXB81); //Escribe '0' en el 9no bit
  
  UDR1 = mdbb.datos; // Se copia el dato a enviar
 }

/*Funcion para leer 9 bits de datos. */
unsigned int read_9bit()
{ unsigned char resh, resl;
  int rtr = 0;
  /*Espera para recibir los datos*/
 while( ( !(UCSR1A & (1<<RXC1)) ) and rtr <50 )
    { delay(1); //rtr ++; 
    }

  if(rtr == 50) {
   mdboverflow = 1; rcvcomplete = 1; }
  
  /*Obtiene el 9 bit, luego, los datos del buffer*/
  resh = UCSR1B; 
  resl = UDR1;
      
  resh = (resh>>1) & 0x01;        // Se filtra el 9 bit
  return ( (resh << 8) | resl );  // Se regresa los 8 bits de datos
}


void MDB_write(int dato){
 struct MDB_Byte b;
 memcpy(&b,dato,2);
 write_9bit(b); 
 }


void MDB_getByte(struct MDB_Byte* mdbb) {
 int b;
 b = 0;
 b = read_9bit();
 memcpy(mdbb,&b,2);
}


byte MDB_CHK() { // Validador de checksum de datos provenientes del MDB
  int sum = 0;
  for(int i=0; i<(MDB_Buffer_Count-1); i++)
    sum += MDB_Buffer[i].datos;
  if (MDB_Buffer[MDB_Buffer_Count-1].datos == (sum&0xFF))
    return 1;
  else
    return 0;
  }

void MDB_read(){
  MDB_getByte(&MDB_Buffer[MDB_Buffer_Count]);
  MDB_Buffer_Count++;
  if(MDB_Buffer_Count == 35)
  { rcvcomplete = 1;
    mdboverflow = 1; }

  if(MDB_Buffer[MDB_Buffer_Count -1].modo && MDB_CHK())
   {rcvcomplete = 1; } 
  }
  
int Procesar_Respuesta() 
{ byte state = 0;
  mdboverflow = 0; rcvcomplete = 0;
  while (!rcvcomplete) 
    { MDB_read(); }
    
  if( rcvcomplete && (!mdboverflow) )
  {   
    if(MDB_Buffer_Count>0)
    {
      if(MDB_Buffer_Count>1)
       { //Serial.print("MDB BUF: "); Serial.println(MDB_Buffer_Count);
         MDB_write(0x00);
        if(MDB_Buffer[0].datos == 0 )
          state = 0;
        else
          state = 1;
       }
    else {
      if(MDB_Buffer_Count == 1){ } }
    }
  } return state;
}

Blockquote Entiendo que no va la palabra struct delante de la tipificación de variables struct (o al menos es innecesaria).

También tienes razón, aunque quitándola o no, no veo alguna diferencia en el funcionamiento del código. Como dato adicional, al momento de inicializar el programa, los comandos de RESET, POLL Y SETUP Si son recibidos por el validador. Ya que recibo las siguientes respuestas:
RESET -> El dispositivo se reinicia
POLL -> 06 09 0F
SETUP -> 01 14 84 03 E8 02 01 90 FF FF FF 02 05 0A 14 32 6B
BILL TYPE -> Tengo entendido que este comando envía datos de configuración al validador, entre ellos activar la recepción de billetes.
SETUP -> Este comando esta dentro del loop y obtengo siempre la misma respuesta 06 09 0F

Primero un comentario: un Arduino que cuesta menos de 5 USD (dólares) en China te genera el esfuerzo de hacer esto?
Me parece que no lo vale, pero cada cual tiene derecho a hacer lo que desea.
Bajo esa premisa es que veré si puedo ayudar.

Ahora dime, el ejemplo de la librería funciona bien, según has dicho, entonces mi pregunta es, que has cambiado y te lo pregundo para ir directo al grano y no estar comparando códigos.

Lo que he estado intentando hacer es usar un solo Arduino para enviar datos entre el dispositivo MDB y la PC. El archivo original del proyecto usa dos Arduinos : El primero es el maestro (o interface), que se comunica con el bus MDB y el segundo Arduino se encarga de generar la secuencia de inicio del dispositivo, así como preguntar constantemente el estado del mismo.

Lo primero que veo es que tu usas Serial.begin(9600) y el usa

 EXT_UART_Setup();

Esta rutina tiene un manejo de 9 bits y no el habitual manejo de 8 bits que usamos en los puertos Seriales.
Lo has considerado o estoy equivocado en el enfoque?

La funcion EXT_UART_Setup(); inicializa el puerto serie 1 del Arduino Mega, para comunicarse con el dispositivo esclavo (Arduino pro mini ), a 8 bits, 9600 bits, No Parity, 1 Stop Bit. Para comunicarse al bus MDB, configura el puerto serie 2 del Arduino Mega.
Los comandos los genera el Arduino pro mini y los envía al Mega, una vez recibidos, el Mega los procesa y envía esos datos al bus (Usando el formato de 9 bits). De manera similar, cuando el dispositivo MDB le responde, Arduino Mega lee los datos y los envía al Pro mini, en formato de 8 bits, el cual a su vez, decodifica la información e imprime mensajes de acuerdo al estado del dispositivo MDB. Lo que quiero hacer es reducir este proceso en un arduino mega.