Pages: [1]   Go Down
Author Topic: Protocollo trasmissione dati  (Read 993 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Faraday Member
**
Karma: 23
Posts: 2792
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Devo fare comunicare due atmega via seriale, uno si trova in una scheda con display, tastiera e RTC software. L'altro comanda triac e rele ed è collegato a dei sensori. La scheda con display ecc la chiamo "comando/interfaccia" (interfaccia utente), quella con triac ecc la chiamo scheda "potenza/controllo".

La scheda "comando/interfaccia" permette all'utente di selezionare una descrizione di un programma, tra i 15 presenti. Il programma però risiede nella scheda "potenza/controllo". Quando l'utente preme il tasto avvio il programma selezionato (es 10) deve avviarsi.

Quindi serve inviare un comando start seguito da numero programma. Il programma in corso di esecuzione può essere annullato e posto in pausa.

Quindi mi serve:
Start + numero programma
pausa
annulla programma in corso.

Semplice, si ma una volta ricevuto il comando cosa deve fare la scheda "potenza/controllo" inviare la conferma di avvio programma o non serve.

Un programma è composto da più fasi che devono essere visualizzate nel display, ci sono altri dati che devono essere visualizzati nel display sotto richiesta dell'utente, es il tempo trascorso dall'inizio programma ecc, alcuni dati sono acquisiti dalla scheda "potenza/controllo", come ad esempio la temperatura, il numero di giri motore, altri invece sono da considerare dati da considerare prioritari.

Un esempio di dati di prioritario:
Impossibile eseguire programma ed il perchè:
manca l'acqua
L'acqua non si riscalda.
ecc.

Avete qualche consiglio?
Non mi lasciate in Asso.

Ciao.
« Last Edit: December 12, 2011, 11:42:36 pm by MauroTec » Logged

AvrDudeQui front end per avrdude https://gitorious.org/avrdudequi/pages/Home

Riva del Garda, TN / Forlì
Offline Offline
Edison Member
*
Karma: 7
Posts: 2247
Il piu' modesto al mondo
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

scusa ma non ho capito..

avresti un diagramma?

tu vuoi una comunicazione a 2 vie insomma.

una volta avviata la riproduzione che tipo di dati devono tornare che non ho capito? e poi non puoi fare tutto con un solo atmega?
Logged

Il nuovo forum italiano sull'elettronica: http://www.electroit.tk/ <--- Nuovamente online!

Global Moderator
Italy
Online Online
Brattain Member
*****
Karma: 313
Posts: 21616
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

La conferma la puoi chiedere direttamente all'utente:
"Avvio il programma xx?"

a conferma, spedisci il comando alla seconda scheda.

La trasmissione è composta dalla solita sequenza di byte:
1) byte di inizio trasmissione
2) byte relativo al comando da eseguire
3) eventuali dati aggiuntivi
4) fine delle trasmissioni

Il comando potrebbe essere:
- programma da eseguire
- pausa programma
- riavvia programma
- annulla programma

Nel caso di programma da eseguire, a tale byte farai seguire un altro byte indicante il programma da eseguire.
Negli altri 3 casi la logica è ovvia: un solo byte.
Logged


0
Offline Offline
Faraday Member
**
Karma: 23
Posts: 2792
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
scusa ma non ho capito..

avresti un diagramma?

tu vuoi una comunicazione a 2 vie insomma.

una volta avviata la riproduzione che tipo di dati devono tornare che non ho capito? e poi non puoi fare tutto con un solo atmega?
No niente diagramma, ancora da fare.
Ho modificato il post iniziale.
Sapere che si tratta di una lavatrice ti aiuta?

Le due schede sono distanti le una dall'altra di circa 100cm, la linea seriale quindi si trova soggetta agli spike dovuti al triac ed al motore a spazzole tipo eccitazione serie. Quindi deve essere sicura, si deve evitare che la macchina si metta in moto da sola, ma anche che salti da un programma all'altro o si resetti ecc.

Sto pensando anche alla possibilità di usare un triac per controllare la resistenza vasca, questo mi darebbe la possibilità di riscaldare l'acqua impiegando solo 600W (anziche 1200-1800) dal contatore, ma questo allunghera i tempi di lavaggio, ma mi permette di sfruttare al meglio il contatore. Non è da escludere la possibilità di connettere alla scheda "potenza/controllo" una scheda wireless su ISP.

Quote
La conferma la puoi chiedere direttamente all'utente:
"Avvio il programma xx?"
Si, è l'utente che con i tasti visualizza il numero di programma nel display, premendo start per 1 secondo deve essere inviato il comando Start-numero_programma.

Ok chiamiamo le schede "potenza/controllo" e "comando/interfaccia", rispettimavente "backend" e "frontend" così e più semplice.

Quote
a conferma, spedisci il comando alla seconda scheda.
Cioè, quando il backend riceve il comando di start, fa i controlli del caso, avvia il programma e invia la conferma che il programma è stato avviato. Si ok credo sia necessario perchè il frontend deve permettere la messa in pausa e l'annullamento ed a display deve segnalare in qualche modo che il programma selezionato è stato avviato.

Quote
Nel caso di programma da eseguire, a tale byte farai seguire un altro byte indicante il programma da eseguire.
Negli altri 3 casi la logica è ovvia: un solo byte.

Quindi il frame è composto da due byte, di cui il secondo può essere nullo, però un byte dati potrebbe essere poco, vediamo scrivo un documento dove descrivo il protocollo e se sorge qualche problema posto qui.

Mi viene in mente una suddivisione ancora non chiara dei vari tipi di dialogo. Cioè un comando è diverso da una comunuicazione di stato/fase, che è diverso da una segnalazione anomalia/impossibilità di eseguire/continuare il programma.

Altri dati consultabili dall'utente possono essere considerati dati di servizio, inviati ogni secondo dal backend verso il frontend. Oppure questi dati consultabili sono composti da comando-codice-servizio. Es frontend invia SC5, cioè service command 5 che serve ad esempio per richiede la temperatura attuale dell'acqua, che il backend invia ed il frontend visualizza.

Ciao.
Logged

AvrDudeQui front end per avrdude https://gitorious.org/avrdudequi/pages/Home

Global Moderator
Italy
Online Online
Brattain Member
*****
Karma: 313
Posts: 21616
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Ok chiamiamo le schede "potenza/controllo" e "comando/interfaccia", rispettimavente "backend" e "frontend" così e più semplice.
Io le chiamo master e slave, sono nomi più intuitivi: capisco subito qual'è quella che spedisce il comando e quella che lo riceve e deve eseguire.

Quote
Cioè, quando il backend riceve il comando di start, fa i controlli del caso, avvia il programma e invia la conferma che il programma è stato avviato. Si ok credo sia necessario perchè il frontend deve permettere la messa in pausa e l'annullamento ed a display deve segnalare in qualche modo che il programma selezionato è stato avviato.
Se vuoi un feedback dalla slave, devi allora fare un protocollo bidirezionale, dove la scheda master invia il comando e poi attende risposta dalla scheda slave. Ma qui sono scelte personali, non vedo una reale necessità, a meno che tu non voglia la certezza che il comando sia arrivato correttamente e sia stato interpretato altrettanto correttamente.

Quote
Quindi il frame è composto da due byte, di cui il secondo può essere nullo, però un byte dati potrebbe essere poco, vediamo scrivo un documento dove descrivo il protocollo e se sorge qualche problema posto qui.
1 byte non mi pare poco per indicare un comando. Sono ben 256 comandi differenti.
E non è detto che i dati aggiuntivi siano composti da 1 solo byte. I dati aggiuntivi cambiano in base al comando. Ad esempio, se devi impostare la temperatura, potresti aver bisogno di 1 solo byte (25 per 25°C, ad esempio). Ma se devi impostare il livello di una fotoresistenza, avresti bisogno di 2 byte, perché un int (che può contenere i valori da 0 a 1023 di un pin analogico) è composto da 2 byte. Insomma, devi vedere caso per caso.

Quote
Altri dati consultabili dall'utente possono essere considerati dati di servizio, inviati ogni secondo dal backend verso il frontend. Oppure questi dati consultabili sono composti da comando-codice-servizio. Es frontend invia SC5, cioè service command 5 che serve ad esempio per richiede la temperatura attuale dell'acqua, che il backend invia ed il frontend visualizza.
SC5 non è pratico: dovresti inviare S-C-5, quindi 3 byte. SC lo sostituisci con un byte, 5 con un altro byte. Quindi hai da interpretare 2 byte invece che 3.
Per "comando" io intendo un codice inviato allo slave che esegue una operazione o richiede dei dati.

Ti allego una porzione di codice del firmware che su un Tiny84 gestisce l'LCD sulla mia stazioncina meteo, per capire cosa intendo per protocollo di comunicazione. Ci sono diversi comandi, alcuni (come il clear dello schermo) non necessitano di parametri addizionali, altri di 1 solo parametri (es. la visualizzazione dell'alimentazione) altri di 2 parametri (le coordinate X,Y dove posizionare il cursore) altri di un flusso di dati non stabilibile all'inizio (la ricezione di una stringa testuale):
Code:
//loop principale
void loop() {
    byte dato, i, comando;
    boolean esci;
   
    //spengi il video
    lcd.clear();
    lcd.noDisplay();
    letargo(); //si mette subito in letargo il micro
    /*controlla se è in arrivo qualcosa sul bus I2C
    grazie all'indirizzo univoco, la lib "legge" sul bus
    solo i comandi destinati all'LCD */
    lcd.display();
    esci=false;
    do {
        if (TinyWireS.available()) { // ho trovato qualcosa!
            //leggiamo il primo byte per capire il comando
            comando=TinyWireS.receive();
            switch (comando) {
                case 0x00: //pulisci il display
                    lcd.clear();
                    x=0;
                    y=0;
                    break;
                case 0x01: //comando di posizionamento del cursore: devo leggere altri 2 byte
                    x=TinyWireS.receive();
                    y=TinyWireS.receive();
                    if (x>=0 && x<MAX_X) {
                        if (y>=0 && y<MAX_Y) {
                            lcd.setCursor(x, y);
                        }
                    }
                    break;
                case 0x02: //scrive una stringa sul display
                    dato=0;
                    do {
                        dato = TinyWireS.receive();
                        if (dato != 0xFF) { //carattere terminatore
                            //lcd.setCursor(x, y);
                            lcd.print(char(dato));
                            x++;
                        } else {
                            break;
                        }
                    } while ((TinyWireS.available()) && (x<MAX_X)); // scrive finché ci sono dati o finché non si arriva a fine riga
                    break;
                case 0x03: //mette in standby/riaccende il display (conserva il testo)
                    dato=TinyWireS.receive();
                    if (dato==0x00) { //OFF
                        lcd.noDisplay();
                    } else if (dato==0x01) { //ON
                        lcd.display();
                    }
                    break;
                case 0x04: //spenge/riaccende il display (toglie l'alimentazione)
                    dato=TinyWireS.receive();
                    if (dato==0x00) { //OFF
                        digitalWrite(PIN_ALIMENTAZIONE_LCD, LOW);
                    } else if (dato==0x01) { //ON
                        digitalWrite(PIN_ALIMENTAZIONE_LCD, HIGH);
                    }
                    delay(10);
                    break;
                case 0x05: //spengi il display ed esci
                    lcd.clear();
                    esci=true;
                    break;
                case 0x06: //visualizza lo stato della stazione (1 byte)
                    dato=TinyWireS.receive();
                    if (dato>4) { //dato sconosciuto
                        lcd.print("X");
                    } else {
                        lcd.write(dato);
                    }
                    break;
                case 0x07: //cursore on/off (1 byte)
                    dato=TinyWireS.receive();
                    if (dato!=0) { //attivo cursore
                        lcd.cursor();
                    } else { //disattivo cursore
                        lcd.noCursor();
                    }
                    break;
                case 0x08: //invia il firmware
                    lcd.print(FIRMWARE);
                    break;
            }
        }
    } while (!esci);
    digitalWrite(PIN_ALIMENTAZIONE_LCD, LOW);
    delay(250);
}
Logged


0
Offline Offline
Faraday Member
**
Karma: 23
Posts: 2792
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Io le chiamo master e slave, sono nomi più intuitivi: capisco subito qual'è quella che spedisce il comando e quella che lo riceve e deve eseguire.
Ok, non le ho chiamate così, perchè in effetti ognuna è indipendente, es la slave comanda il motore, sa a che velocità farlo girare, sa la temperatura dell'acqua quale deve essere. Insomma una volta avviato il programma non ha più necessità della scheda master che servirà solo all'utente per vedere a che punto è il lavaggio. Quindi ok master e slave.

Quote
Se vuoi un feedback dalla slave, devi allora fare un protocollo bidirezionale, dove la scheda master invia il comando e poi attende risposta dalla scheda slave. Ma qui sono scelte personali, non vedo una reale necessità, a meno che tu non voglia la certezza che il comando sia arrivato correttamente e sia stato interpretato altrettanto correttamente.

Si il feedback è necessario, quindi prevedo una risposta sempre e comunque.

Quote
1 byte non mi pare poco per indicare un comando. Sono ben 256 comandi differenti.
E non è detto che i dati aggiuntivi siano composti da 1 solo byte. I dati aggiuntivi cambiano in base al comando. Ad esempio, se devi impostare la temperatura, potresti aver bisogno di 1 solo byte (25 per 25°C, ad esempio). Ma se devi impostare il livello di una fotoresistenza, avresti bisogno di 2 byte, perché un int (che può contenere i valori da 0 a 1023 di un pin analogico) è composto da 2 byte. Insomma, devi vedere caso per caso.

Ok, non è poco 1 byte, è poco perchè 0x0 può diventare facilmente 0x1 o 0x2 ecc. a causa dei disturbi derivati dal triac ed dalle spazole motore. Il rischio di con due byte sarebbe minore o no?

Quote
SC5 non è pratico: dovresti inviare S-C-5, quindi 3 byte. SC lo sostituisci con un byte, 5 con un altro byte. Quindi hai da interpretare 2 byte invece che 3.
Per "comando" io intendo un codice inviato allo slave che esegue una operazione o richiede dei dati.

Si, solo che il comando è composto da tipo di comando di due byte seguito da dato di x byte. Es tutti i comandi di un certo tipo, esempio segnalazione anomalie iniziano con un comando ES (error status) condice numerico un byte. Mentre i comandi che sono di interrogazione QC (query command) codice numerico 1 byte.

PS: non c'è necessità di comunicazione veloce tra le due schede, quindi mi posso sbizzarrire per renderlo sicuro, ma qual'è la strada giusta?

Ho visto il codice, tu usi la trappola case ed hai un frame variabile, io invece pensavo ad un frame fisso, legge e invia un numero massimo di byte a comando, anche se uno di questi vale 0. Come lo hai fatto tu e semplice ma mi chiedo è sicuro, conviene complicare il codice per evitare problemi legati alle interferenze.

Se metti la sonda dell'oscilloscopio (anche caricata con 10k) quando il motore va in centrifuga vedi che frequneze circolano nei dintorni. Il segnale spurio si riduce di molto spostando la sonda verso l'alto, lontano dal motore circa 50cm.

Grazie per il tuo intervento ho un pò le idee più chiare.

Ciao.






Logged

AvrDudeQui front end per avrdude https://gitorious.org/avrdudequi/pages/Home

Global Moderator
Italy
Online Online
Brattain Member
*****
Karma: 313
Posts: 21616
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Spedire 2 byte al posto di 1 solo non ti mette al riparo da interferenze. Se anche 1 solo dei 1 byte arriva corrotto, hai lo stesso risultato di 1 solo byte spedito ed arrivato male. Quindi, visto che il numero di byte non influisce sulla stabilità del dato spedito (per assurdo, forse, più byte spedisci e più probabilità hai di ritrovartene qualcuno corrotto), io tendo a semplificare usando meno risorse possibili.

Nel tuo caso, un ambiente ricco di interferenze, un CRC finale è sicuramente indicato per evitare problemi.

Logged


Offline Offline
Jr. Member
**
Karma: 0
Posts: 86
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Il programma principale (Master) deve essere come una macchina a stati finiti, cioe' se arriva un comando, in base allo stato attuale passa al nuovo stato richiesto, ammessa la compatibilita'.
Per cui devi per prima usare una variabile S, anche intera che contiene l'informazione sullo stato.
Quando arriva un nuovo comando via seriale lo memorizzi nella variabile intera C, in funzione dei loro valori, se compatibili, fai eseguire l'apposita routine.

Il micro che legge i tasti (Slave) ha una semplice routine che letto il nuovo comando lo invia, tramite seriale, al programma principale di cui sopra.
Questa routine deve pero' visualizzare correttamente il display. Pertanto dopo che il comando C e' stato inviato al Master (principale) quest'ultimo deve rispondere se tale comando, in base allo stato attuale S, e' eseguibile o no (incompatibile) ed informare di cio' lo Slave che ne terra conto per la visualizzazione.
La decisione sulla compatibilita' tra stato e comando la farei eseguire al Master che in seriale informa lo Slave.

Per cui la comunicazione deve essere bidirezionale: lettura e scrittura per entrambi.
Per esempio:
1_ Byte di istruzione (serve per riconoscere che dato stai inviando)
2_ Dati
3_ CRC

Dall'altra parte viene ricalcolato il CRC con i dati ricevuti e quindi, se corrispondono, risponde con una apposita istruzione di "ricezione OK" ripetuta 3 volte, in modo da superare l'eventuale disturbo sulla trasmissione.

Il tutto e' abbastanza teorico ma mette dei paletti fissi da rispettare e sui quali sviluppare il codice.
ciao Giorgio

Logged

0
Offline Offline
Faraday Member
**
Karma: 23
Posts: 2792
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Il programma principale (Master) deve essere come una macchina a stati finiti, cioe' se arriva un comando, in base allo stato attuale passa al nuovo stato richiesto, ammessa la compatibilita'.

Ok, allora sono due programmi che implementano la macchina a stati finiti, anche per questo non li ho chiamati Master e slave.

La scheda display/tastiera è una macchina a stati, uno volta inviato lo start è ricevuto conferma di avvio, si pone in SGO (Global Operative Status), in questo stato si può solo aspettare dei comandi operatore tramite tastiera, o dei dati comunicazione/errore di ERRORE, nessun comando operativo sarà possibile, perchè già in essere.

La scheda di potenza è indipendente ed anche essa è una macchina a stati. Una volta avviato un programma entra in stato operativo. Essa sa come portare avanti un programma perchè ha i dati che descrivono le fasi di lavaggio sul micro, e legge tutti i sensori e comanda il motore e le elettrovalvole. In questo stato si aspetta solo comandi operativi Pausa, Annulla lavaggio. 

Quote
Il micro che legge i tasti (Slave) ha una semplice routine che letto il nuovo comando lo invia, tramite seriale, al programma principale di cui sopra.
Questa routine deve pero' visualizzare correttamente il display. Pertanto dopo che il comando C e' stato inviato al Master (principale) quest'ultimo deve rispondere se tale comando, in base allo stato attuale S, e' eseguibile o no (incompatibile) ed informare di cio' lo Slave che ne terra conto per la visualizzazione.
La decisione sulla compatibilita' tra stato e comando la farei eseguire al Master che in seriale informa lo Slave.

Questa non l'ho capita forse perchè i tasti risiedono nel pannello operatore insieme al display, oddio pannello operatore sembra stia parlando di una macchina a controllo numerico. Anche per questo mi sono inventato la definizione "comando/interfaccia".

C'è necessità tra le due di comunicarsi chi sono, cioè il master chiede chi sei, lo slave risponde tipo-versione, se questa risposta sta bene il master acconsente al dialogo successivo, altrimenti segnala all'utente il problema, e non permette nessun comando operativo.
Questo potrebbe essere lo stato di Identificazione Slave.

Grazie per il tuo intervento è stato molto utile.

Ciao.
Logged

AvrDudeQui front end per avrdude https://gitorious.org/avrdudequi/pages/Home

0
Offline Offline
Faraday Member
**
Karma: 23
Posts: 2792
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Finalmente il display 20x4 è arrivato, lo sto usando in modo Nible.
La tastiera dieci tasti su analog0 funziona.

Con il protocollo ho mosso i primi passi.
Le due schede vengono alimentate insieme.
All'accensione le due schede iniziano l'identificazione, comunicando su seriale:
Slave si mette nello stato Startup ed avvia la macchina a stati
Master si mette nello stato Startup ed avvia la macchina a stati.

Master invia solo dati/comandi numerici pari e slave solo dispari, così ho già una discriminazione, in quanto se lo slave riceve un comando dispari neanche lo prende in considerazione. Stessa cosa per il master.

In startup lo slave si mette in ascolto ed aspetta dati dal Master.
In startup il master invia un dato/comando di un byte (MASTER_ID_REQUEST), ascolta per 10 cilci cpu e se non riceve risposta ricompie la stessa operazione x volte. Se riceve risposta (response), Master cerca nell'array "compatibilty_id", se "response" è presente. Se presente la compatibilità tra versioni è garantita, ed esce dallo stato Startup per entrare nello stato successivo che ancora non so quale sarà. 

Se il dialogo non va a buon fine la macchina a stati del master viene messa in CRITICAL_ERROR, e la tastiere disabilitata ed il display mostra l'errore.

Io la macchina a stati non l'ho mai studiata, se avete link da consigliarmi che parlano della macchina a stati e di come implementarla, siete pregati di postare qui.

Ciao.

Logged

AvrDudeQui front end per avrdude https://gitorious.org/avrdudequi/pages/Home

Pages: [1]   Go Up
Jump to: