Go Down

Topic: differenze prestazionali I2C e RS485 (Read 2789 times) previous topic - next topic

dab77

#15
May 04, 2012, 03:06 am Last Edit: May 04, 2012, 03:10 am by dab77 Reason: 1
se ti può essere utile un altro parere, io sto facendo un mio protocollino per far comunicare 4 Slave standalone Attiny85 con un Master 328P sempre standalone. Trovo l'RS485 geniale come idea (per la soluzione all'immunità ai disturbi, essendo differenziale.) un chip e passa la paura, metti quante unità vuoi (in realtà no, ma in pratica..) e per il protocollo ti puoi divertire.
qui: http://www.gammon.com.au/forum/?id=11428 trovi una soluzione. ce ne sono molte. io alla fine ho optato per fare un protocollo mio, dimensionato alle mie necessità. Cmq ho imparato un pò di cose in più, che non fa mai male...
Nel modo più semplice si tratta di mandare una serie di caratteri ascii, in cui c'è:
Inizio trasmissione
dato A
dato B
dato x..
Checksum (giusto per non andare allo sbaraglio)
Fine trasmissione.

il ricevente sa già quanti Byte deve leggere dopo aver riconosciuto l'inizio e se l'ultimo è Fine, e la somma combacia, leggi i Dati e li lavori come ti pare.

ah, dimenticavo.. trovi due modi per cablare l'SN75176. il più comodo per me è usare un solo pin di arduino per comandare sia il DE che l'RE. quando lo setti LOW Ricevi, sennò HIGH e trasmetti.
Poi (ma servono altri più ferrati per conferma) si dovrebbe aggiungere una resistenza tra A e B a "tappo" al termine di lunghe catene RS485.
Ciao, Davide.

leo72


ah, dimenticavo.. trovi due modi per cablare l'SN75176. il più comodo per me è usare un solo pin di arduino per comandare sia il DE che l'RE. quando lo setti LOW Ricevi, sennò HIGH e trasmetti.

Sì, questo è un modo comodo per risparmiare pin su dispositivi come il Tiny85.

Quote

Poi (ma servono altri più ferrati per conferma) si dovrebbe aggiungere una resistenza tra A e B a "tappo" al termine di lunghe catene RS485.

Serve una R tra A e B collegata il più vicino possibile ai pin sui 2 micro alle estremità della catena (normalmente 100 ohm).

z3us

@dab77

grazie! darò un 'occhiata a quel protocollo che hai postato! sembra ben documentato!
Il tuo cosa ha di differente? su che periferiche lo stai utilizzando?

uhm, devo provare a fare qualcosa, ordino un pò di questo chip!

un po di domotica ce l'ho in progetto da una vita! anche a scopo sistema di allarme!

dab77

#18
May 04, 2012, 07:07 pm Last Edit: May 21, 2012, 11:16 am by dab77 Reason: 1
Ti posto il mio codice volentieri, ma prendilo con le pinze perchè non sono per niente esperto (anzi ogni commento è ben accetto!)

Come detto altrove il mio setup consiste in 4 moduli con ATtiny85 che aspettano di essere interrogati dal Master (per ora un Arduino Mega, per debug) e rispondono con la lettura di 2 pin analogici. Gli ATtiny85 non hanno Seriale HW, quindi utilizzo la Newsoftserial modificata (Grazie Leo..).
Il Mega per ora legge soltanto i dati in arrivo controllandone la qualità.
Non ho avuto tempo di provarlo bene, sto aspettando di rientrare a casa, ma ad una prima prova funzionava.

Cmq, Master su Arduino Mega:
Code: [Select]
int EN_PIN = 4;
int LED_PIN = 13;
int ind = 0;
char buf[8];
int dati[4][2];

void setup() {
  pinMode(EN_PIN, OUTPUT);
  Serial.begin(9600);
  Serial1.begin(9600);
  Serial.println("iniziamo!");
  pinMode (LED_PIN, OUTPUT);
  digitalWrite(EN_PIN, LOW);
}

void loop() {
  // inviare req(address '1' to '4', richiesta '5' to '8')
  req('1','5');
  delay(100);
  req('2','5');
  delay(100);
  req('3','5');
  delay(100);
  req('4','5');
  delay(1000); 
}

void req(char addr, char reqType) {
 
  // Invia richiesta:
 
  digitalWrite(EN_PIN, HIGH);
  delay(10);
  Serial1.write(2);
  Serial1.write(addr);
  Serial1.write(reqType);
  Serial1.write(addr+reqType);
  Serial1.write(3);
  Serial.println("dati inviati..");
  digitalWrite(EN_PIN, LOW);
 
  // Lettura risposta:
 
  if (Serial1.available()>0) {
    Serial.println("La seriale c'e'..");
    if (Serial1.read()==2) {
      Serial.println("ricevuto 2");
      for (int i=0; i<8; i++) {
        buf[i] = Serial1.read();
      }
      ind = buf[0];
      if (ind == addr) {
        int sommaBytes = 0;
        for (int k=0;k<5;k++) {
          sommaBytes = sommaBytes + byte(buf[k]);
        }
        byte checksum = (buf[6] << 8 | buf[5]);           //////////// prima era: int checksum = (buf[6] << 8 | buf[5]);
                                                       //////////// ma se buf[6] inizia per 1 checksum diventa negativo, e la comparazione con sommaBytes ritorna False.

        if ((buf[7]==3)&&(sommaBytes==checksum)) {
          Serial.println("Checksum and ETX ok!");
          ind = ind-48;
          Serial.print("Indirizzo : ");
          Serial.println(ind);
          Serial.println("SUM ok!");
          Serial.println("ETX ok!");
          Serial.print("Motore : ");
          Serial.println(ind);
          dati[ind][0] = (byte(buf[2]) << 8 | byte(buf[1]));
          dati[ind][1] = (byte(buf[4]) << 8 | byte(buf[3]));
          Serial.print("  Cella1 : ");
          Serial.println(dati[ind][0]);
          Serial.print("  Cella2 : ");
          Serial.println(dati[ind][1]);
        }
      }
    }
  }
}

e Slave su ATtiny85:
Code: [Select]
#include <NewSoftSerial.h>
#include <icrmacros.h>

NewSoftSerial mySer (2, 0);

int EN_PIN = 1;
//int LED_PIN = 0;
int cella1 = 1012;
int cella2 = 1003;
char addr = '1';
int reqType;
char buf[4];

void setup() {
  pinMode(EN_PIN, OUTPUT);
  mySer.begin(9600);
  //pinMode (LED_PIN, OUTPUT);
  digitalWrite(EN_PIN, LOW);
}

void loop() {
  while (mySer.available()==0) {
  }
  delay(10);
  if (mySer.read()==2) {
    for (int i=0; i<4; i++) {
      buf[i] = mySer.read();
    }
    int ind = buf[0];
    if (ind == addr) {
      reqType = buf[1];
      if ((buf[3]==3)&&(buf[0]+buf[1]==buf[2])) {
        if (reqType == '5') {
          invia();
        }
      }
    }
  }
}

void invia() {
  digitalWrite(EN_PIN, HIGH);
  delay(1);
  mySer.write(2);
  mySer.write(addr);
  mySer.write(lowByte(cella1));
  mySer.write(highByte(cella1));
  mySer.write(lowByte(cella2));
  mySer.write(highByte(cella2));
  int checksum = (addr+lowByte(cella1)+highByte(cella1)+lowByte(cella2)+highByte(cella2));
  mySer.write(lowByte(checksum));
  mySer.write(highByte(checksum));
  mySer.write(3);
  digitalWrite(EN_PIN, LOW);
}



EDIT: lo scrivo solo se a qualcuno viene in mente di prendere spunto da questo codice, che c'è un piccolo errore nel Master. l'ho corretto e ho segnato il punto.
in più i delay sono da regolare a seconda della velocità di trasmissione. Quindi il codice così com'è non è affidabile al 100%.

Davide.

Go Up