Domanda

Sto costruendo un piccolo dispositivo con una propria CPU (AVR Mega8) che dovrebbe connettersi a un PC. Supponendo che la connessione fisica e il passaggio dei byte siano stati raggiunti, quale sarebbe il miglior protocollo da utilizzare in cima a quei byte? Il computer deve essere in grado di impostare determinate tensioni sul dispositivo e rileggere alcune altre tensioni.

Al momento, sto pensando a un protocollo sincrono completamente gestito dall'host: richieste di invio computer, risposte CPU integrate. Altre idee?

È stato utile?

Soluzione

Modbus potrebbe essere quello che stai cercando. È stato progettato esattamente per il tipo di problema che hai. C'è un sacco di codice / strumenti là fuori e l'adesione a uno standard potrebbe significare un facile riutilizzo in seguito. Supporta anche ASCII leggibile dall'uomo, quindi è ancora facile da capire / testare.

Vedi FreeModBus per windows e sorgente incorporata.

Altri suggerimenti

C'è molto da dire sull'architettura client-server e sui protocolli sincroni. Semplicità e robustezza, per iniziare. Se la velocità non è un problema, potresti prendere in considerazione un protocollo compatto e leggibile per aiutare il debug. Sto pensando in base ai comandi AT del modem: un "wakeup" sequenza seguita da un comando set / get, seguito da un terminatore.

Host -->  [V02?]      // Request voltage #2
AVR  -->  [V02=2.34]  // Reply with voltage #2
Host -->  [V06=3.12]  // Set voltage #6
AVR  -->  [V06=3.15]  // Reply with voltage #6

Ogni lato potrebbe scadere se non vede la parentesi chiusa e si risincronizzerebbero sulla parentesi aperta successiva, che non può apparire all'interno del messaggio stesso.

A seconda dei requisiti di velocità e affidabilità, è possibile codificare i comandi in uno o due byte e aggiungere un checksum.

È sempre una buona idea rispondere con la tensione effettiva , piuttosto che semplicemente fare eco al comando, poiché salva una successiva operazione di lettura.

Utile anche per definire i messaggi di errore, nel caso sia necessario eseguire il debug.

Il mio voto è per la lettura umana.

Ma se diventi binario, prova a mettere un byte di intestazione all'inizio per contrassegnare l'inizio di un pacchetto. Ho sempre avuto sfortuna con i protocolli seriali non sincronizzati. Il byte dell'intestazione consente al sistema incorporato di risincronizzarsi con il PC. Inoltre, aggiungi un checksum alla fine.

Ho fatto cose del genere con un semplice formato binario

struct PacketHdr
{
  char syncByte1;
  char syncByte2;
  char packetType;
  char bytesToFollow;  //-or- totalPacketSize
};

struct VoltageSet
{ 
   struct PacketHdr;
   int16 channelId;
   int16 voltageLevel; 
   uint16 crc;
};

struct VoltageResponse
{
   struct PacketHdr;
   int16 data[N];  //Num channels are fixed
   uint16 crc;
}

I byte di sincronizzazione sono meno critici in un protocollo sincrono che in uno asincrono, ma aiutano ancora, specialmente quando il sistema incorporato si sta accendendo per la prima volta, e non sai se il primo byte che ottiene è al centro di un messaggio o no.

Il tipo dovrebbe essere un enum che spiega come interpretare il pacchetto. Le dimensioni potrebbero essere dedotte dal tipo, ma se lo si invia in modo esplicito, il ricevitore può gestire tipi sconosciuti senza soffocare. È possibile utilizzare "dimensione pacchetto totale" o "byte da seguire"; quest'ultimo può rendere il codice del ricevitore un po 'più pulito.

Il CRC alla fine aggiunge più sicurezza che tu abbia dati validi. A volte ho visto il CRC nell'intestazione, il che rende più semplice la dichiarazione delle strutture, ma metterlo alla fine ti consente di evitare un ulteriore passaggio sui dati durante l'invio del messaggio.

Il mittente e il destinatario devono avere entrambi i timeout a partire dal ricevimento del primo byte di un pacchetto, nel caso in cui un byte venga eliminato. Anche il lato PC ha bisogno di un timeout per gestire il case quando il sistema incorporato non è collegato e non c'è alcuna risposta.

Se si è certi che entrambe le piattaforme utilizzino i float IEEE-754 (lo fanno i PC) e abbiano la stessa endianness, è possibile utilizzare i float come tipo di dati. Altrimenti è più sicuro utilizzare numeri interi, bit grezzi A / D o una scala preimpostata (ovvero 1 bit = 0,001 V fornisce un intervallo di +/- 32,267 V)

Adam Liss fa molti ottimi punti. Semplicità e robustezza dovrebbero essere al centro. I trasferimenti ASCII leggibili dall'uomo aiutano MOLTO durante il debug. Ottimi suggerimenti.

Possono essere eccessivi per le tue esigenze, ma HDLC e / o PPP aggiungono il concetto di un livello di collegamento dati e tutti i vantaggi (e i costi) che derivano da un livello di collegamento dati. Gestione dei collegamenti, framing, checksum, numeri di sequenza, ritrasmissioni, ecc ... contribuiscono a garantire comunicazioni solide, ma aggiungono complessità, elaborazione e dimensioni del codice e potrebbero non essere necessari per la tua specifica applicazione.

USB bus risponderà a tutte le tue esigenze. Potrebbe essere un dispositivo USB molto semplice con solo la pipe di controllo per inviare una richiesta al tuo dispositivo oppure puoi aggiungere una pipe di interruzione che ti permetterà di avvisare l'host delle modifiche al tuo dispositivo. Esistono numerosi controller USB semplici che possono essere utilizzati, ad esempio Cypress o Microchip .

Il protocollo in cima al trasferimento riguarda davvero le tue esigenze. Dalla tua descrizione sembra che il semplice protocollo sincrono sia decisamente sufficiente. Cosa ti fa vagare e cercare un approccio aggiuntivo? Condividi i tuoi dubbi e cercheremo di aiutarti :).

Se non mi aspettavo di dover effettuare trasferimenti binari efficienti, sceglierei l'interfaccia in stile terminale già suggerita.

Se voglio fare un formato di pacchetto binario, tendo a usare qualcosa di vagamente basato sul formato HDLC byte-asnc PPP, che è estremamente semplice e facile da inviare ricevere, in sostanza:

I pacchetti iniziano e finiscono con 0x7e Esci da un carattere prefissandolo con 0x7d e alternando il bit 5 (cioè xor con 0x20) Quindi 0x7e diventa 0x7d 0x5e e 0x7d diventa 0x7d 0x5d

Ogni volta che vedi uno 0x7e, se hai dei dati memorizzati, puoi elaborarli.

Di solito faccio cose sincrone guidate dall'host a meno che non abbia un'ottima ragione per fare diversamente. È una tecnica che si estende dal semplice punto-punto RS232 al multidrop RS422 / 485 senza problemi - spesso un bonus.

Come avrai già determinato da tutte le risposte che non ti indirizzano direttamente a un protocollo, fai in modo che il tuo approccio sia la scelta migliore.

Quindi, questo mi ha fatto pensare e bene, ecco alcuni dei miei pensieri -

Dato che questo chip ha 6 canali ADC, molto probabilmente stai usando la comunicazione seriale Rs-232 (una supposizione dalla tua domanda), e ovviamente lo spazio di codice limitato, definire una semplice struttura di comando aiuterà, come sottolinea Adam - Potresti voler ridurre al minimo l'elaborazione dell'input sul chip, quindi il binario sembra attraente ma il compromesso è nella facilità di sviluppo E manutenzione (potresti dover risolvere un input morto tra 6 mesi) - hyperterminal è un potente strumento di debug, quindi mi ha fatto pensare a come implementare una struttura di comando semplice con una buona affidabilità.

Alcune considerazioni generali -

mantieni i comandi della stessa dimensione - semplifica la decodifica.

Inquadratura dei comandi e somma di controllo opzionale, come sottolinea Adam, possono essere facilmente racchiusi tra i tuoi comandi. (con piccoli comandi, un semplice checksum XOR / ADD è rapido e indolore)

Vorrei raccomandare un annuncio di avvio all'host con la versione del firmware al ripristino - ad es. " CIAO; Versione firmware 1.00z " - direbbe all'host che la destinazione è appena iniziata e che cosa è in esecuzione.

Se stai principalmente monitorando, potresti prendere in considerazione una "corsa libera" modalità in cui il bersaglio dovrebbe semplicemente scorrere tra le letture analogiche e digitali - ovviamente, questo non deve essere continuo, può essere spaziato a 1, 5, 10 secondi o semplicemente a comando. Il tuo micro è sempre in ascolto, quindi l'invio di un valore aggiornato è un'attività indipendente.

La chiusura di ogni riga di output con un CR (o altro carattere) rende semplice la sincronizzazione presso l'host.

per esempio il tuo micro potrebbe semplicemente emettere le stringhe;

  V0=3.20
  V1=3.21
  V2= ...
  D1=0
  D2=1
  D3=...
  and then start over -- 

Inoltre, i comandi potrebbero essere davvero semplici -

? - Leggi tutti i valori - non ce ne sono molti, quindi prendili tutti.

X = 12.34 - Per impostare un valore, il primo byte è la porta, quindi la tensione e io consiglierei di mantenere " = " e il ". " come frame per garantire un pacchetto valido se si rinuncia al checksum.

Un'altra possibilità, se le tue uscite rientrano in un intervallo prestabilito, potresti pre-venderle. Ad esempio, se l'output non deve essere esatto, è possibile inviare qualcosa di simile

5=0 
6=9
2=5  

che imposterebbe la porta 5 su off, la porta 6 su full on e la porta 2 su half value - Con questo approccio, i dati ascii e binari sono quasi sullo stesso piano per quanto riguarda il calcolo / decodifica delle risorse nel micro. O per maggiore precisione, rendere l'output di 2 byte, ad esempio 2 = 54 - OPPURE, aggiungere una tabella xrif e i valori non devono nemmeno essere lineari in cui il byte di dati è un indice in una tabella di ricerca. .

Come mi piace dire; semplice è di solito migliore, a meno che non lo sia.

Spero che questo aiuti un po '.


Ho avuto un altro pensiero durante la rilettura; aggiungendo un " * " il comando potrebbe richiedere i dati racchiusi nei tag html e ora l'app host potrebbe semplicemente reindirizzare l'output dal tuo micro a un browser e wala, browser pronto -

:)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top