De dar em doido com o seguinte código

Boas

Estou a tentar brincar aqui com um PLC em rs485, só que estou a dar em doido.
Se chamar a função fdx() na função “loop” o código faz o que eu quero a 100% se a chamar através da função " Timer1.attachInterrupt( fdx );" nada se passa mas eu tenho a certeza que o timer chama bem a função por causa do Serial.println("\n\r *** DEBUG fim F fdx ...\n\r"); e do piscar do led.

Alguém me pode explicar o porque ?

#include <TimerOne.h>

const byte etx = 2; // saida activar tx Max485
const byte LED = 13; // saida LED

byte aTrama_rx[18] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
byte aTrama_tx[13] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void setup(void)
{
  Serial.begin(19200);
  Serial1.begin(19200);
  pinMode(etx, OUTPUT);  
  pinMode(LED, OUTPUT);

   //Timer1.initialize(500000);// Inicializa o Timer1 e configura para um período de 0,5 segundos
    Timer1.initialize (900000);
    Timer1.attachInterrupt( fdx ); // Configura a função fdx() como a função para ser chamada a cada interrupção do Timer1

      Serial.println("\n\r  Init. OK ...\n\r");

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void fdx ()
{
 //Serial1.flush(); 
 tx_trama(aTrama_tx);

 digitalWrite(13, digitalRead(13) ^ 1);
 Serial.println("\n\r *** DEBUG fim F fdx ...\n\r");
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void loop()
{
delay(1000);
//fdx();

}  
   
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                 Envia trama 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void tx_trama (byte *data)
{
    byte i =0;
    byte checksum =0;
  
    delay(100);
    digitalWrite(etx, HIGH);  // Activa MAX485
  
    Serial1.write(0xF1); // Inicio trama n°1
    Serial1.write(0xF2); // Inicio trama n°2 
    Serial1.write(0xF3); // Inicio trama n°3
    Serial1.write(0xF4); // Inicio trama n°4     

  
            for (i=0; i<13; i++) 
            {
              Serial1.write(data[i]); 
              checksum ^= aTrama_tx[i];
            }

    Serial1.write(checksum);
   
    //delay (9);//delay(50);
    delay (10);//delay(50);
    digitalWrite(etx, LOW);
   // Serial.println("\n\r ** DEBUG **  fim tx_trama     \n\r");
}

Ps: testado num arduino Mega

Tens a certeza que o timer está a chamar a função de segundo a segundo?

Boas,

Sim, por causa do piscar do led, e do Serial.println("\n\r *** DEBUG fim F fdx ...\n\r"); porque estou o serial port monitor e vejo essa string a passar todos os segundos.

Cpts,

Zé tretas

Boas,

Acabo de dar com o gato

 digitalWrite(etx, HIGH);  // Activa MAX485
  digitalWrite(etx, LOW);

O problema esta aqui, pois quando meto o pin do max485 ao +5v da alimentação, tudo funciona mesmo através do Timer.

Agora a solução é que não estou a ver qual é. Espero pela vossa ajuda :stuck_out_tongue:

Cpts

Zé tretas

Um delay após activar o chip?

Porque desactivas o chip?

Apaga o delay na função loop... existe a possibilidade de correres um delay dentro de outro.

Boas,

Apaga o delay na função loop... existe a possibilidade de correres um delay dentro de outro.

Ja tentei tirar o delay do loop mas é igual.

Porque desactivas o chip?

Para poder ler as entradas do PLC

 delay (10);
         digitalWrite(etx, LOW);

Já testei vários delay aqui e sem resultado :(, se comentar o digitalWrite(etx, LOW); o programa tem o resultado esperado, o problema deve estar na interrupção do timer1 que deve ter alguma influencia no delay do timer0, mas qual é que eu não sei

Cpts

Zé tretas

Muito possivelmente as interrupções são desactivadas quando entras na interrupção do timer1...

Podes usar estes delays

http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html

Eu ia jurar que é isto que o Arduino usa, mas pode realmente estar a usar algo com o Timer0.

Eu dei uma experimentadela aqui em casa e o código funciona... mais ou menos de segundo a segundo ele envia uma trama com dados pela porta série 1.

Uma coisa que notei é que a tua trama de dados está vazia... Mas deve ser assim que pretendes.

Como disse anteriormente, um delay logo após activares o chip parece-me ideal e não sei porque é que em vez de corrigires o que tens dizes que não é esse o problema:

Estas instruções estão trocadas... tu queres activar o chip, dar-lhe tempo para ficar pronto a comunicar e depois enviar dados.

    delay(100);
    digitalWrite(etx, HIGH);  // Activa MAX485

Outra coisa que se calhar beneficiarias seria em controlares os dois pinos de Enable do MAX485. Ou seja, quando queres enviar, colocas esse pino em HIGH e o pino de RE em Low para garantir que o chip não fica confuso. Possivelmente agora tens um fio directo ao GND, mas no futuro isso era uma melhoria a implementar.

A parte disso e sem saber porque é que dizes que não funciona, não consigo dar muito mais ajuda porque o código está a enviar as tramas de 900 em 900 ms.

Boas,

Acabei de testar isto e nada :(, achei a tua ideia boa visto ter saídas de sobra. Mas o resultado não foi o esperado

const byte enable_tx = 2;
const byte enable_rx = 4;
void tx_trama (byte *data)
{
    byte i =0;
    byte checksum =0;
 
   
    digitalWrite(enable_tx, HIGH);  
    digitalWrite(enable_rx, LOW);  
    delay(100);
 
    Serial1.write(0xF1); // Inicio trama n°1
    Serial1.write(0xF2); // Inicio trama n°2
    Serial1.write(0xF3); // Inicio trama n°3
    Serial1.write(0xF4); // Inicio trama n°4     

 
            for (i=0; i<13; i++)
            {
              Serial1.write(data[i]);
              checksum ^= aTrama_tx[i];
            }

    Serial1.write(checksum);
   
    
    delay (10);;
    digitalWrite(enable_tx, LOW);
    digitalWrite(enable_rx, HIGH);

   // Serial.println("\n\r ** DEBUG **  fim tx_trama     \n\r");
}

Esquema de ligação actual.

arduino pino 19 (rx) ---- pino 1 max485

arduino pino 4 ---- pino 2 max485

arduino pino 2 ---- pino 3 max485

arduino pino 18 (tx) ---- pino 4 max485

GND ---- pino 5 max485
PLC ---- pino 6 max485
PLC ---- pino 7 max485
+5v ---- pino 8 max485

resistência 120 ohms entre pino 6/7 max485 e outra no plc ( resistências fim de linha)
resistência 470 omhs em pull-up pino 6 max485
resistência 470 omhs em pull-down pino 7 max485

O enable rx tem de ser colocado em high... porque é activo em low.

Os pull up e down são necessários?

Porque dizes que isto funcionou e agora com a interrupção não funciona?

Boas,

Obrigado o gato estava ai :slight_smile:

Agora vou tentar ler o que o PLC envia.

Cpts

Zé Tretas

Boas,

Com o seguinte código, o envio da trama esta OK para o PLC, mas agora o problema é que não recebo nada
e o problema não deve vir do código pois meti um sniffer no pino rx do arduino e também não apanho nada,

void tx_trama (byte *data)
{
    byte i =0;
    byte checksum =0;
 
   
    digitalWrite(enable_tx, HIGH); 
    digitalWrite(enable_rx, HIGH); 
    delay(100);
 
    Serial1.write(0xF1); // Inicio trama n°1
    Serial1.write(0xF2); // Inicio trama n°2
    Serial1.write(0xF3); // Inicio trama n°3
    Serial1.write(0xF4); // Inicio trama n°4     

 
            for (i=0; i<13; i++)
            {
              Serial1.write(data[i]);
              checksum ^= aTrama_tx[i];
            }

    Serial1.write(checksum);
   
   
    delay (10);;
    digitalWrite(enable_tx, LOW);
   

   // Serial.println("\n\r ** DEBUG **  fim tx_trama     \n\r");
}

Mas o problema aí vem do PLC, não?

A função que colocaste é a de envio...

Boas,

O PLC esta bom pois quando uso a a motherboard dele na vez do arduino, e meto o sniffer vejo bem a resposta da entradas/saídas.

Não sei se será um problema na minha montagem, mas visto como é tão simples não vejo como é que me possa enganar

A função de leitura é a seguinte

void rx_trama ()                 
{
byte index = 0; 
byte controle_checksum = 0;
  // Serial.println("\n\r Debug -> ENTROU Rx_trama() \n\r");  
    
    while (Serial1.available() > 0)
        {
           
                              for (index=0; index<18; index++)                              
                                {     
                                  aRX_Trama[index] = Serial1.read(); // 
                                        
                                          if (index == 4)
                                          {
                                                if (aRX_Trama[0]==0x1C && aRX_Trama[1]==0x2C && aRX_Trama[0]==0x3C && aRX_Trama[1]==0x4C )
                                                {
                                                 trama_OK = true;
                                                  continue;
                                                }
                                                 else
                                                   {
                                                     trama_OK = false;
                                                     Serial1.flush();
                                                    break;
                                                   }
                                    
                                          }
                               }
        }
};

Essa rotina de recepção é horrível...

Apaga o for e o while. Testa se recebeste 18 caracteres com um if e trata logo tudo duma vez.

Da maneira que está não vai funcionar muito bem.

Aquele if para testar a trama não faz sentido... uma variável não pode ter dois valores diferentes para a condição ser verdadeira.

Boas,

E algo assim gostas mais ?

byte aRX_Trama[18]   = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
void rx_trama()// (byte *trama)
{
byte cpt, i = 0; 
byte checksum = 0;
static byte cpt_erro =0;

      if (Serial.available() > 17 ) 
       {
//-----------------------------------------------------------------------             
            for (cpt = 0; cpt < 18; cpt ++ )
             {
               aRX_Trama[cpt] = Serial.read();
             
             }
//-----------------------------------------------------------------------             
             // calcula checksum - XOR 
             for (i = 4; i < 16; i ++ )
             {               
               checksum ^= aRX_Trama[i];
             }
             
//-----------------------------------------------------------------------
                
                //Serial.println ("DEBUG fdx");               
                //Serial.println (checksum, HEX);
                  
                   if( checksum == aRX_Trama[17] && aRX_Trama[17] > 0) //testa se o checksum é valido 
                   {
                    // Serial.print("\n\r DEBUG - CRC"); 
                     trama_OK = true;
                     cpt_erro = 0;                                     
                     return 1;   
                   }       
                    else
                      {                                                 
                        cpt_erro ++;
                        
                          if ( cpt_erro > 30)
                           {
                            Serial.print ("\n\r DEBUG cpt_erro  -> ");  
                            Serial.print (cpt_erro);  
                            Serial.println ("");  
                            limpa_buffer_rs232();
                            trama_OK = false;
                            cpt_erro =0;
                            return 0; 
                           }
                     }
                 
       } 
         
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                  LIMPAR / ESVAZIAR BUFFER RS232
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void limpa_buffer_rs232()
{

 unsigned char temp = Serial.available(); 

    for (int i = temp; i >=0; i--) 
    {
     Serial.read();
    }
 }

PS: este código compila sem erros mas não o testei na realidade.

Não notei nada de óbvio... mas pode sempre não funcionar.