Go Down

Topic: Problema com comunicação RS485 Master / Slave (Read 2 times) previous topic - next topic

LegendBR

Olá,

Já postei a dúvida no fórum Network, Protocols and Devices, mas como estão demorando um pouco para entender, posso ter um pouco de dificuldade em entender a resposta em inglês, e o pessoal do fórum em português são muito prestativos, decidi postar aqui também.

Resumindo: consigo fazer a comunicação Master -> Slave utilizando as funções do Nick Gammon, mas não consigo enviar o feedback. Tenho um loop no Master que fica aguardando a resposta, mas o Master fica parado neste loop.

Seguem os códigos:

Master:
Code: [Select]
#include "RS485_protocol.h"
//#include <NewSoftSerial.h>

const byte ENABLE_PIN = 4;
const byte LED_PIN = 13;
int led;
byte msg[2];

// callback routines

void fWrite (const byte what)
{
 Serial.write (what);  
}

int fAvailable ()
{
 return Serial.available ();  
}

int fRead ()
{
 return Serial.read ();  
}

void setup ()
{
 Serial.begin (28800);
 pinMode (ENABLE_PIN, OUTPUT);  // driver output enable
 pinMode (LED_PIN, OUTPUT);  // built-in LED
 led = 0;
}  // end of setup

void loop ()
{

 if (led == 0)
   memcpy (msg, (byte[]){1,1}, sizeof msg);  // device 1, turn on
 else if (led == 1)
   memcpy (msg, (byte[]){2,1}, sizeof msg);  // device 2, turn on
 else if (led == 2)
   memcpy (msg, (byte[]){1,0}, sizeof msg);  // device 1, turn off
 else if (led == 3) {
   memcpy (msg, (byte[]){2,0}, sizeof msg);  // device 2, turn off
   led = -1;
 }

 led++;

 // send to slave  
 digitalWrite (ENABLE_PIN, HIGH);  // enable sending
 sendMsg (fWrite, msg, sizeof msg);

 while (!(UCSR0A & (1 << UDRE0)))  // Wait for empty transmit buffer
   UCSR0A |= 1 << TXC0;  // mark transmission not complete
 while (!(UCSR0A & (1 << TXC0)));   // Wait for the transmission to complete
 
 digitalWrite (ENABLE_PIN, LOW);  // disable sending

 // receive response  
 byte buf [10];
 byte received = recvMsg (fAvailable, fRead, buf, sizeof buf);

 digitalWrite (LED_PIN, received == 0);  // turn on LED if error   */

 delay (500);

}  // end of loop


Slave 1:
Code: [Select]
#include "RS485_protocol.h"

const byte ENABLE_PIN = 4;
const byte LED_PIN = 13;
const byte ERROR_PIN = 9;
const byte SLAVE_NUMBER = 1;
const byte GREEN_PIN = 8;

void fWrite (const byte what)
{
 Serial.print (what);  
}
 
int fAvailable ()
{
 return Serial.available ();  
}

int fRead ()
{
 return Serial.read ();  
}
 
void setup()
{
 Serial.begin (28800);
 pinMode (ENABLE_PIN, OUTPUT);  // driver output enable
 pinMode (ERROR_PIN, OUTPUT);
 pinMode (GREEN_PIN, OUTPUT);
 pinMode (LED_PIN, OUTPUT);
 digitalWrite (ENABLE_PIN, LOW);
}

void loop()
{
 byte buf [20];
 
 byte received = recvMsg (fAvailable, fRead, buf, sizeof (buf) - 1);
 
 if (received)
   {
   digitalWrite (ERROR_PIN, LOW);
   if (buf [0] != SLAVE_NUMBER) {
     digitalWrite (GREEN_PIN, HIGH);
     return;  // not my device
   }
   digitalWrite (GREEN_PIN, LOW);
   digitalWrite (LED_PIN, buf[1]);  // set light level

   byte msg [] = {
      0,  // device 0 (master)
      3,  // turn light on command received
   };
   
   delay (1);  // give the master a moment to prepare to receive
   digitalWrite (ENABLE_PIN, HIGH);  // enable sending
   sendMsg (fWrite, msg, sizeof msg);
   
   while (!(UCSR0A & (1 << UDRE0)))  // Wait for empty transmit buffer
       UCSR0A |= 1 << TXC0;  // mark transmission not complete
   while (!(UCSR0A & (1 << TXC0)));   // Wait for the transmission to complete
   
   digitalWrite (ENABLE_PIN, LOW);  // disable sending
   
   
  }  else { // if nothing received
    digitalWrite (ERROR_PIN, HIGH);
  }  // end receive if
 
}  // end of loop


No Master, o LED fica sempre aceso (indicando erro na leitura), e no Slave, o LED de erro acende entre comandos bem sucedidos.

Alguma idéia?

bubulindo

De onde tiraste este código?

Eu posso estar errado, mas olhando assim de repente parece que envias 2 bytes e tentas ler 20...
Eu não sou o teu criado. Se respondo no fórum é para ajudar todos mediante a minha disponibilidade e disposição. Responder por mensagem pessoal iria contra o propósito do fórum e por isso evito-o.
Se realmente pretendes que eu te ajude por mensagem pessoal, então podemos chegar a um acordo e contrato onde me pagas pela ajuda que eu fornecer e poderás então definir os termos de confidencialidade do meu serviço. De forma contrária toda e qualquer ajuda que eu der tem de ser visível a todos os participantes do fórum (será boa ideia, veres o significado da palavra fórum).
Nota também que eu não me responsabilizo por parvoíces escritas neste espaço pelo que se vais seguir algo dito por mim, entende que o farás por tua conta e risco.

Dito isto, mensagens pessoais só se forem pessoais, ou seja, se já interagimos de alguma forma no passado ou se me pretendes convidar para uma churrascada com cerveja (paga por ti, obviamente).

LegendBR


De onde tiraste este código?

Eu posso estar errado, mas olhando assim de repente parece que envias 2 bytes e tentas ler 20...


Do mesmo site que peguei a biblioteca: http://www.gammon.com.au/forum/?id=11428

Você não está errado, mas não acredito que isso seja problema, pois o master também envia 2 bytes e o slave tenta ler 20 e pega os 2 bytes tranquilamente.

bubulindo

Pergunta idiota...

Estás a usar um Uno ou 2009?
Eu não sou o teu criado. Se respondo no fórum é para ajudar todos mediante a minha disponibilidade e disposição. Responder por mensagem pessoal iria contra o propósito do fórum e por isso evito-o.
Se realmente pretendes que eu te ajude por mensagem pessoal, então podemos chegar a um acordo e contrato onde me pagas pela ajuda que eu fornecer e poderás então definir os termos de confidencialidade do meu serviço. De forma contrária toda e qualquer ajuda que eu der tem de ser visível a todos os participantes do fórum (será boa ideia, veres o significado da palavra fórum).
Nota também que eu não me responsabilizo por parvoíces escritas neste espaço pelo que se vais seguir algo dito por mim, entende que o farás por tua conta e risco.

Dito isto, mensagens pessoais só se forem pessoais, ou seja, se já interagimos de alguma forma no passado ou se me pretendes convidar para uma churrascada com cerveja (paga por ti, obviamente).

LegendBR

Uno (master) e um ATMega328p na protoboard funcionando com os 8 MHz internos.

bubulindo

Um problema que eu vejo é que o Uno tem dois chips ligados aos pinos 0 e 1 (que suponho seja o que estás a usar).

É sempre uma possibilidade que o chip que faz a traducão entre USB e TTL esteja a estragar isto.

Experimenta com a NewSoftSerial, como o Gammon tem no seu site e vê o resultado. Se tiveres a oportunidade de usar dois chips em vez da placa do Arduino seria o ideal pois tiravas a limpo que não tinhas problemas de ligacão.

O hardware está de acordo com o que ele tem no site dele?
Eu não sou o teu criado. Se respondo no fórum é para ajudar todos mediante a minha disponibilidade e disposição. Responder por mensagem pessoal iria contra o propósito do fórum e por isso evito-o.
Se realmente pretendes que eu te ajude por mensagem pessoal, então podemos chegar a um acordo e contrato onde me pagas pela ajuda que eu fornecer e poderás então definir os termos de confidencialidade do meu serviço. De forma contrária toda e qualquer ajuda que eu der tem de ser visível a todos os participantes do fórum (será boa ideia, veres o significado da palavra fórum).
Nota também que eu não me responsabilizo por parvoíces escritas neste espaço pelo que se vais seguir algo dito por mim, entende que o farás por tua conta e risco.

Dito isto, mensagens pessoais só se forem pessoais, ou seja, se já interagimos de alguma forma no passado ou se me pretendes convidar para uma churrascada com cerveja (paga por ti, obviamente).

LegendBR

Hum... agora entendi o motivo do NewSoftSerial... alimentar o Uno pela porta DC ao invés do USB pode resolver?

De qualquer forma, vou tentar trocar de portas. Mas acho que o problema é de sincronização, algo assim.

Sobre o hardware, só não coloquei os resistores, mas como por enquanto está tudo na protoboard, está tranquilo.

bubulindo

Existe um motivo pelo qual as resistências estão lá...

Alimientar pela porta DC não ajuda porque o outro chip continua activo.
Eu não sou o teu criado. Se respondo no fórum é para ajudar todos mediante a minha disponibilidade e disposição. Responder por mensagem pessoal iria contra o propósito do fórum e por isso evito-o.
Se realmente pretendes que eu te ajude por mensagem pessoal, então podemos chegar a um acordo e contrato onde me pagas pela ajuda que eu fornecer e poderás então definir os termos de confidencialidade do meu serviço. De forma contrária toda e qualquer ajuda que eu der tem de ser visível a todos os participantes do fórum (será boa ideia, veres o significado da palavra fórum).
Nota também que eu não me responsabilizo por parvoíces escritas neste espaço pelo que se vais seguir algo dito por mim, entende que o farás por tua conta e risco.

Dito isto, mensagens pessoais só se forem pessoais, ou seja, se já interagimos de alguma forma no passado ou se me pretendes convidar para uma churrascada com cerveja (paga por ti, obviamente).

LegendBR

Existe, melhorar o sinal para longas distâncias, aumentando a diferença entre as linhas A e B. Mas na protoboard, não precisa, até onde eu li e entendi. Inclusive, no datasheet nem fala nessas resistências entre as linhas e  o ground/5v, apenas em uma resistência entre as linhas A e B.

tretas

Boas,

A ver o teu esquema sem ver o código, vejo que lhe faltam as 2 resistências fim de linha que normalmente são de 120 ohm.

E para mais RS485 não é nenhum protocolo "soft" mas sim hard

aqui te deixo alguns links que pesquisei em tempos para comunicar com uma carta de entrada/saídas via rs485 ( vê os meus antigos posts)

http://arduino-info.wikispaces.com/RS485-Brick

http://real2electronics.blogspot.fr/2009/09/buses-de-campo-para-arduino-rs485.html

Cumprimentos

Zé tretas
Arduino Mega 2560
Arduino Nano
Arduino UNO Rev3
Raspberry PI Model B
EasyPIC v4

bubulindo


Existe, melhorar o sinal para longas distâncias, aumentando a diferença entre as linhas A e B. Mas na protoboard, não precisa, até onde eu li e entendi. Inclusive, no datasheet nem fala nessas resistências entre as linhas e  o ground/5v, apenas em uma resistência entre as linhas A e B.


Ok... tu obviamente sabes o que está errado no sistema logo não me parece que te consiga ajudar muito mais.
Eu não sou o teu criado. Se respondo no fórum é para ajudar todos mediante a minha disponibilidade e disposição. Responder por mensagem pessoal iria contra o propósito do fórum e por isso evito-o.
Se realmente pretendes que eu te ajude por mensagem pessoal, então podemos chegar a um acordo e contrato onde me pagas pela ajuda que eu fornecer e poderás então definir os termos de confidencialidade do meu serviço. De forma contrária toda e qualquer ajuda que eu der tem de ser visível a todos os participantes do fórum (será boa ideia, veres o significado da palavra fórum).
Nota também que eu não me responsabilizo por parvoíces escritas neste espaço pelo que se vais seguir algo dito por mim, entende que o farás por tua conta e risco.

Dito isto, mensagens pessoais só se forem pessoais, ou seja, se já interagimos de alguma forma no passado ou se me pretendes convidar para uma churrascada com cerveja (paga por ti, obviamente).

LegendBR

É, acho que era algum problema de timing... enfim, acabei deixando a biblioteca do Nick Gammon de lado e desenvolvi a minha própria, com base no protocolo que encontrei neste link.

Depois de alguns ajustes, já estou conseguindo comunicar os arduinos pelo RS495, com uma comunicação bem robusta (com o protocolo tenho acesso a MUITOS comandos, agora só preciso definir os comandos de acordo com o design da minha rede), utilização relativamente simples, e rápida o suficiente para minha necessidade, sem precisar fazer delay para não ter problema de sincronia (estou conseguindo enviar um comando após o outro, sem delay entre eles, e todos os comandos estão sendo entendidos).

Ah, e não estou com resistores entre as pernas A e B dos MAX485. Como falei, uma vez que eles estão no protoboard, não precisam desse artifício. Pelo o que eu entendi, esses resistores ajudam a melhorar o sinal para longas distâncias, para aumentar a diferença entre a linha A e B, melhorando assim o sinal (pelo menos foi assim que eu entendi, depois testo em um sistema real, com maiores distâncias, onde o sinal pode sofrer interferências).

HugoPT

#12
Apr 29, 2013, 10:26 am Last Edit: Apr 29, 2013, 10:32 am by HugoPT Reason: 1
Ola a uns tempos também andei a brincar com o RS485 e desenvolvi uma pequena lib para o que eu queria. Nao está terminada e deve ter coisas menos correctas mas funciona para o meu fim.Tem coisas que podem ser melhor optimizadas, nao estou a implementar ACK dos slaves inda ,nem tempos de timeout de resposta dos slaves ...
Digamos que a deixei ficar assim por falta de tempo e ter o projecto na gaveta à espera de ser sacado fora.
No entanto pode te dar uma visão do que fiz e fazer melhor do que fiz.
Também falta me depois colocar isso tudo dentro de uma class c++ para ser possível instanciar um objecto

Debian,Mint,Ubuntu
Arduino Mega 2560
Arduino Nano
Arduino Duemilanove
MAC OS Montain Lion
Raspberry PI Model B

LegendBR


Ola a uns tempos também andei a brincar com o RS485 e desenvolvi uma pequena lib para o que eu queria. Nao está terminada e deve ter coisas menos correctas mas funciona para o meu fim.Tem coisas que podem ser melhor optimizadas, nao estou a implementar ACK dos slaves inda ,nem tempos de timeout de resposta dos slaves ...
Digamos que a deixei ficar assim por falta de tempo e ter o projecto na gaveta à espera de ser sacado fora.
No entanto pode te dar uma visão do que fiz e fazer melhor do que fiz.
Também falta me depois colocar isso tudo dentro de uma class c++ para ser possível instanciar um objecto




Então, fiz como você, mas já implementei o ACK dos slaves e coloquei dentro de um classe. Uma diferença que percebi pelo o .h que você passou é que utilizo um protocolo fechado, onde cada comando tem 15 bytes, e me parece que sua biblioteca deixa isso aberto.

A noite envio minha lib para vocês darem uma olhada.

LegendBR

Demorou, mas segue minha biblioteca para comunição RS485.

Como dito anteriormente, o protocolo utilizado é o descrito neste link.

No construtor é informado o id do dispositivo, um pointer para o Stream (&Serial, ou um SoftwareSerial) e o pino de controle envio/leitura do RS485.

Depois é só enviar a mensagem pelos métodos sendENQ, sendACK e sendNAK, de acordo com o que se deseja. Para receber a mensagem, deve-se ficar aguardando a mensagem (waitForMessage(long)), e depois verificar se houve atualização na mensagem (updated()). Só será recebida a mensagem se ela foi destinada ao dispositivo.

Via de regra, o master tem id 1 e os slaves quaisquer outros ids. O master envia comando para o slave, e aguarda resposta do mesmo, confirmando que a mensagem foi recebida (ACK). Os slaves sempre ficam aguardando comando, e quando recebem respondem dizendo que entenderam o comando (ACK) ou que não entenderam (NAK). Nessa resposta pode estar a informação desejada pelo master.

Go Up