Duvida para ler uma trama

Boas pessoal,

Estou aqui com umas duvidas para ler uma trama vinda de um modulo E/S em que eu lhe envio uma trame como uma ordem

para activar as saídas e ele envia-me logo de seguida uma trama com o valor das entradas ... o problema é que não

apanho nada dele ...

a trama tem 18 bytes e começa sempre pelos 2 seguintes bytes 0xBB , 0xCC , xx xx xx xx xx xx xx xx xx xx xx xx

xx xx xx xx

Com outro código consigo ler de vez em quando ... ou melhor em 30 e tais tramas enviadas apanho 1, mas com este

código 0 que estou a fazer mal ?

void rx_trame ()                 
{

 byte controle_checksum = 0;
 byte byte_recebido = 0xFF;
 byte index = 0;
 
// Serial.println("\n\r Debug -> ENTROU rx_trame() \n\r");  //debug

 while (Serial.available() > 0)
    {        
 //-------------------------------------------------------------------                           
       byte_recebido = Serial.read();
      
       if ( byte_recebido == 0xBB )
        {
          tableau_rx_trame[0]== byte_recebido;
          Serial.println("\n\r Debug -> fdx \n\r");  //debug

//----------------------------------------------------------------------         

               for (index=1; index<18; index++)                              
                {     
                 tableau_rx_trame[index] = Serial.read(); // save
                }
       
//----------------------------------------------------------------------
  
                 
                      if (tableau_rx_trame[0]==0xBB && tableau_rx_trame[1]==0xCC)
                       {
                         trame_OK = true;
                         Serial.println("\n\r Debug -> 2  \n\r");  //debug                      
                       }
                         else
                          {
                           trame_OK = false;
                           Serial.flush();                           
                          }                                      
        }
        
       
    }
    
}

Estás a usar que IDE?

Esse código já foi testado nessa mesma IDE? O motivo pelo qual estou a dizer isto é a instrução flush que há tempos mudou de significado. Isso está até numa thread do fórum bem recente.
Investiga isso. :wink:

a trama tem 18 bytes e começa sempre pelos 2 seguintes bytes 0xBB , 0xCC , xx xx xx xx xx xx xx xx xx xx xx xx

xx xx xx xx

Como é que estas a garantir que recebes o startByte 0xBB e depois o 0xCC??
Outra coisa como é que a funçao void rx_trame () é chamada na tua loop?

while (Serial.available() > 0)
{
//-------------------------------------------------------------------
byte_recebido = Serial.read();

if ( byte_recebido == 0x5A )
{
tableau_rx_trame[0]== byte_recebido;
Serial.println("\n\r Debug -> fdx \n\r"); //debug

//----------------------------------------------------------------------

for (index=1; index<18; index++)
{
tableau_rx_trame[index] = Serial.read(); // save
}

Como garantes que recebeste todos os bytes para correres esse ciclo for?

Boas pessoal,

Continuo com este problema por resolver, alguém me pode dar uma forma de ler eficaz, e esquecer todo o meu código que eu meti para aqui...

o objectivo e ler uma trama vindo de uma carta de E/S externa que responde a cada comando (trama) que eu envio com o arduino.

Cpts

Zé tretas

#define RX_FRAME_SIZE    18

unsigned char receive(char * str){
unsigned char temp=0; 

if (Serial.available()> RX_FRAME_SIZE) {//temos bytes suficientes...
   while(Serial.read() != 0xBB); //encontrar o inicio da trama.
     if (Serial.read() != 0xCC) {
         return 0;
     } else { //inicio da trama
        for (temp = 0; temp<RX_FRAME_SIZE-2; temp++) {
            str[temp] = Serial.read();
        }
}

Algo assim?

Boas,

Estou a ver a tua função e a coisas que não percebo :frowning: pois não sei usar ponteiros muitos menos em arrays.

Ja agora como é que a posso chamar através da função loop ?

Cpts

Zé tretas

void loop(){
   char trama[18];
   
   if ( 0 == receive(trama)) {
      Serial.print("ERRO");
   }else{
      //o teu programa.

   }
}

#define RX_FRAME_SIZE    18

unsigned char receive(char * str){
unsigned char temp=0; 

if (Serial.available()> RX_FRAME_SIZE) {//temos bytes suficientes...
   while(Serial.read() != 0xBB); //encontrar o inicio da trama.
     if (Serial.read() != 0xCC) {
         return 0;
     } else { //inicio da trama
        for (temp = 0; temp<RX_FRAME_SIZE-2; temp++) {
            str[temp] = Serial.read();
        }
return temp; //faltou-me isto.
}

Boas estou a testar o teu codigo e estou com problemas

 while(Serial.read() != 0xBB); //encontrar o inicio da trama.

penso que seja nesta linha pois deve demorar muito tempo e se não enviar todos 1seg uma trama a carta de E/S ele reseta

O meu código não envia nada... apenas recebe.

Se tu envias e ele responde, os dados ficam no buffer e depois esse código deve encontrar os dados uqe pretendes.

Já meteste um serial.print para veres se recebes realmente alguma coisa após enviares o comando?

Do que percebi tu entao envias lhe uma trama de 18 Bytes e depois ele devolve -te outros 18 bytes correcto.
Se assim é tens de criar uma funçao para enviar os 18 bytes e outra para receber os 18 bytes.
Para enviares podes usar assim:

unsigned char txBuffer[17];//Variavel com todos os elementos que queres enviar
txBuffer[0] = 0xbb;//Pelo que entendi este e sempre o startByte
txBuffer[1] = 0xcc;//Segundo byte
//... carregas os restantes com o que queres

depois para enviares no programa passas o vector para o procedimento e o numero de bytes que contem

sendBytes(txBuffer,17);
o procedimento é este:
 
void sendBytes(unsigned char * bufferToSend , uint8_t lenght)// Isto recebe um vector de char que conteem a informaçao que queres enviar 
{
for(uint8_t i = 0; i<= lengh; i++)
    {
    Serial.write(bufferToSend[i]);
    }
}

Se declarares a variavel txBuffer como global podes fugir ao uso dos ponteiros se nao te sentires a vontade com eles, no entanto é bom estudares ponteiros.

Para receberes do modulo tens de ficar a espera do startByte 0xbb e quando o receberes entao carregas tudo o que tens no buffer para um outro vector rxBuffer.

void receivedData()
{
unsigned char temp = 0;

  if(Serial.available > 0){
    temp = Serial.read();
    if (temp == 0xbb)//Comprova que recebeste o startByte e estas pronto para receber os restantes 17 bytes, o que tens de esperar que eles entrem no buffer da Serial Port
        {
        while(Serial.available() <16);//Espera pelos 17 bytes restantes, nao sai desta linha ate que eles entrem
        for(uint8_t i = 0; i<= 16; i++)rxBuffer[i] = Serial.read();//Carrega os bytes para cada posiçao no vector
        }
        
    }


}

Nao testei o codigo mas a teoria será algo assim +-

Boas,

penso que percebi em parte de onde vem o problema

if (temp == 0xbb)//Comprova que recebeste o startByte e estas pronto para receber os restantes 17 bytes, o que tens de esperar que eles entrem no buffer da Serial Port

para que o teste seja verdadeiro tenho que meter 0xBB em decimal

if (temp == 187)//Comprova que recebeste o startByte e estas pronto para receber os restantes 17 bytes, o que tens de esperar que eles entrem no buffer da Serial Port

Agora a pergunta é como é que posso ler os dados em hex directamente da porta COM com o Serial.read()

isso não importa... para o arduino os dados serão sempre binários. Hex, ou decimal ou octal ou binario é como te dá mais jeito a ti ver.

queres explicar o que é a carta de entrada\saida que estás a usar para ver se conseguimos ajudar mais?

Isto:

if (temp == 0xbb)//

é igual a isto:

if (temp == 187)//

Boas,

isso não importa... para o arduino os dados serão sempre binários. Hex, ou decimal ou octal ou binario é como te dá mais jeito a ti ver.

queres explicar o que é a carta de entrada\saida que estás a usar para ver se conseguimos ajudar mais?

Isto:

Code:
if (temp == 0xbb)//

é igual a isto:

Code:
if (temp == 187)//

o problema é que

 if (temp == 187)//Comprova que recebeste o startByte e estas pronto para receber os restantes 17 bytes, o que tens de esperar que eles entrem no buffer da Serial Port
        {
          rx_trama[0]=187 ;
          Serial.print("DEBUG - entrou\n\r ");  
          
         while(Serial.available() <16);//Espera pelos 17 bytes restantes, nao sai desta linha ate que eles entrem
            
             for(uint8_t i = 1; i<= 17; i++) 
             {
              rx_trama[i] = Serial.read();//Carrega os bytes para cada posiçao no vector
              Serial.print (" DEBUG - rx_trama");
              Serial.print (rx_trama[i]);
             }
        }

Se não meter if (temp == 187) na vez de if (temp == 0xBB) nunca obtenho o print "debug - entrou" ... logo tem que haver algo ... será porque a tabela rx_trama estar declarada como char ?

PS : E carta E/S funciona bem pois com ligo direcetamente a uma porta COM do pc e recebo a trama como deve ser

Cpts

ZÉ tretas

char a = 65; //Teste a variavel a

void setup() 
{                
Serial.begin(9600);   
}
void loop() 
{
if(a == 'a')Serial.println("Variavel a e igual ao carater a"); //este If nao e corrido por ser falso por estar a comparar o valor de a (65) ao CARACTER e nao ao seu valor
if(a == 65)Serial.println("Variavel a e igual a 65"); //este IF é corrido por ser verdadeiro
if(a == 0x41)Serial.println("Variavel a e igual a 0x41");//este IF tambem é corrido por ser verdadeiro
delay(2000);
}

Porque nao tentas carregar os 18 bytes para um array apenas uma vez e depois olhares para ver o que la tens dentro de cada elemento.
Depois para veres o que esta dentro de cada elemento usas

Serial.print(rxBuffer[n_elemento],HEX);

Desta forma ira ser imprimido na porta serie nao em caracteres mas em codigo hexadecimal para teres a certeza com o que estas a lidar

Boas,

byte tabela_rx_trama[18] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};


byte rx_trama (byte *trama)
{
byte cpt = 0; 

      if (Serial.available() > 17 ) 
       {
           
            for (cpt = 0; cpt < 18; cpt ++ )
             {
               trama[cpt] = Serial.read();
             }
             
          trame_OK = true;
          return 1; 
       }
       
}
}

Com a vossa ajuda este código esta a funcionar ... penso que o erro era estar a usar uma array de char ... na vez de uma de bytes

Cpts

Zé tretas

Podias melhorar fazendo com que essa funcão verificasse se a trama é válida ou não.

Mas em todo o caso, ainda bem que servimos de ajuda. :slight_smile:

Boas,

para ter a certeza que estou a receber a boa trama calculo o checksum, aqui fica o codigo ... sempre pode dar jeito a alguém

byte rx_trama (byte *trama)
{
byte cpt, i = 0; 
byte checksum = 0;


      if (Serial.available() > 17 ) 
       {
//-----------------------------------------------------------------------             
            for (cpt = 0; cpt < 18; cpt ++ )
             {
               trama[cpt] = Serial.read();
             
             }
//-----------------------------------------------------------------------             
             // calcula checksum - XOR 
             for (i = 2; i < 16; i ++ )
             {               
               checksum ^= trama[i];
             }
             
//-----------------------------------------------------------------------
                
                //Serial.println ("DEBUG fdx");               
                //Serial.println (checksum, HEX);
                  
                   if( checksum == trama[17])
                   {
                    // Serial.print("\n\r DEBUG - CRC"); 
                     trama_OK = true;
                     return 1; 
                   }       
                    else
                      {
                       trama_OK = false;
                       return 0; 
                      }
//-----------------------------------------------------------------------                      
       }             
}

PS : isto de usar ponteiros até é fixe :stuck_out_tongue:

Cpts

Zé tretas