In questa pagina è mostrato come utilizzare MPLAB(c) Code Configurator per trasmettere e ricevere dati serialmente utilizzando il protocollo asincrono alla base degli standard RS-232 e RS485.
Alcune informazioni sulla struttura hardware sono disponibili alla pagina Trasmissione seriale asincrona.
La configurazione è, al solito, particolarmente semplice; si limita:
Il codice da scrivere per trasmettere un byte è altrettanto semplice e si basa sull'uso della funzione EUSART_Write(uint8_t txData) (nota 2), descritta nel file eusart.h automaticamente creato da MCC. Un esempio di semplice trasmissione di due byte:
EUSART_Write(0x08);
EUSART_Write(0x50);
Di seguito il segnale presente sul pin del PIC e la relativa decodifica:
Un paio di osservazioni sul codice:
[Approfondimento] L'ultima osservazione ha riflessi importanti quando siamo interessati a conoscere il tempo richiesto per la trasmissione di una serie di byte.
Consideriamo il seguente codice, costituito da un ciclo infinito contenente un ritardo di 2 ms e la trasmissione di un singolo byte a 9600 baud:
while (1) {
__delay_ms(2);
EUSART_Write(0x50);
}
Si noti che il ritardo di 2 ms inserito è sufficiente per la trasmissione del byte, pari a 1 / 9600 · (1 + 8 +1) = 1,04 ms
Il diagramma temporale corrispondente mostra la trasmissione di un byte ogni 2 ms circa, coerentemente con il fatto che la funzione EUSART_Write(0x50) utilizza per la sua esecuzione un tempo trascurabile e quindi il tempo di esecuzione complessivo del ciclo dipende praticamente solo dalla macro __delay_ms(2);:
Il seguente esempio apparentemente è simile: ritardo di 10 ms seguito dalla trasmissione di 8 byte, sempre a 9600 baud:
while (1) {
__delay_ms(10);
EUSART_Write(0x10);
EUSART_Write(0x20);
EUSART_Write(0x30);
EUSART_Write(0x40);
EUSART_Write(0x50);
EUSART_Write(0x60);
EUSART_Write(0x70);
EUSART_Write(0x80);
}
Anche in questo caso il tempo richiesto per la trasmissione (8,32 ms) è inferiore al ritardo prodotto dalla macro __delay_ms(10);
Il diagramma temporale mostra la trasmissione di 8 byte ogni 16 ms abbondanti. Vediamo di calcolare questo tempo:
La ricezione è altrettanto semplice ed utilizza una funzione ed una macro, dall'ovvio significato e documentate nel file eusart.h:
uint8_t EUSART_Read(void);
EUSART_DataReady
I byte ricevuti, fino ad un massimo di tre, sono accodati nel registro FIFO hardware di ricezione.
Il modo più semplice per verificare il funzionamento è la creazione di una connessione fisica tra il pin Tx ed il pin Rx del PIC (loopback): in questo modo quanto è trasmesso viene immediatamente ricevuto.
while (1) {
__delay_ms(10);
EUSART_Write(0xA0); // Write a byte to Tx FIFO
while (!EUSART_DataReady); // Wait until a byte is ready
myData = EUSART_Read(); // Read the byte from Rx FIFO
Nop();
Nop();
}
Alcune osservazioni:
L'uso delle interruzioni per la trasmissione seriale rende il codice non bloccante e permette la trasmissione e, soprattutto, la ricezione mentre il processore è in altre faccende affaccendato. In pratica vengono creati due buffer FIFO software, uno per la trasmissione ed uno per la ricezione, gestiti tramite interrupt.
Un tipico diagramma temporale è il seguente:
La configurazione con MCC è, al solito rapida:
Il main() è piuttosto convenzionale:
#include <string.h>
void main(void) {
char myData[]="hello World!";
int len;
SYSTEM_Initialize();
INTERRUPT_GlobalInterruptHighEnable();
INTERRUPT_GlobalInterruptLowEnable();
while (1) {
len = strlen(myData);
for (uint8_t i = 0; i < len; i++) // Send string
EUSART_Write (myData[i]);
for(int j=0; j<2000; j++) // Blink LED
LED_TEST_Toggle();
}
}
Si noti che in questo caso la funzione EUSART_Write() non scrive direttamente nel registro hardware di trasmissione, ma accoda il byte nel buffer FIFO software di trasmissione. Se i byte il buffer FIFO è sufficientemente grande quindi questa funzione ha un tempo di esecuzione molto breve.
Se viene attivato il flag Redirect STDIO to USART nella finestra di configurazione di MCC è possibile l'uso delle funzioni standard di I/O del C, in genere usate nelle applicazioni console. Per esempio è possibile sostituire il ciclo for() del precedente esempio con:
printf("%s", myData );
Se sono attivate le interruzioni, tutti i byte ricevuti sono accodati nel buffer FIFO software di ricezione
Il codice per leggere il buffer con i dati ricevuti richiede l'uso della macro EUSART_DataReady e della funzione EUSART_Read(). Per esempio, il codice seguente permette di verificare il funzionamento della lettura con l'uso di un semplice filo che collega il pin Tx con il pin Rx del PIC (loop-back):
len = strlen(dataWrite);
for (uint8_t i = 0; i <= len; i++) // Write a string to UART Tx FIFO
EUSART_Write(dataWrite[i]);
k=0;
while EUSART_DataReady { //
Any data in Rx FIFO?
dataRead[k] = EUSART_Read(); // Read back the string from UART
Rx FIFO
k++;
}
Questo codice di esempio è solo presentato per sommi capi e senza commenti nel codice in quanto oggetto degli esercizi.
L'obbiettivo è quello di scambiare dati tra un PIC18 ed un Raspberry Pi attraverso una comunicazione seriale:
Il collegamento è piuttosto ovvio:
Ovviamente la frequenza di clock deve essere la stessa (nell'esempio 115 200 baud)
Spesso i microcontrollori comunicano attraverso un segnale RS485.
Il diagramma temporale seguente mostra dall'alto:
L'aspetto delicato è legato alla disattivazione del trasmettitore RS485, da fare appena terminata la trasmissione del frame. In genere si preferisce non basarsi sul tempo di trasmissione, che dipende dall'eventuale presenza nel buffer di altri pacchetti, ma ascoltare la propria trasmissione e riconosce la fine.
Lo spezzone di codice seguente è quello che ha generato il diagramma temporale:
DE_SetHigh(); // Enable RS485 trasmitter
EUSART_Write(MAGIC); // Write 4 byte
EUSART_Write(0x33);
EUSART_Write(0x44);
EUSART_Write(0x55);
while (EUSART_DataReady < 4); // Wait until 4 byte are in Rx buffer
DE_SetLow(); // Disable transmitter
data[0] = EUSART_Read(); // Flush buffer
data[1] = EUSART_Read();
data[2] = EUSART_Read();
data[3] = EUSART_Read();
Quella mostrata non è una soluzione particolarmente robusta, ma è la base per costruire un rete RS485. Si veda a questo proposito il terzo esercizio
Data di creazione di questa pagina: giugno 2016
Ultima modifica: 29 marzo 2017
PIC18 in C - Versione 0.991 - luglio 2019
Copyright 2014-2019, Vincenzo Villa (https://www.vincenzov.net)
PIC18 in C di Vincenzo Villa è distribuito con Licenza Creative Commons Attribuzione 4.0 Internazionale