
In una lezione precedente abbiamo visto come si utilizza la periferica USART, utile per comunicazioni seriali asincrone di tipo full-duplex tra solo due dispositivi. Abbiamo inoltre visto come la periferica USART viene interfacciata con le comunicazioni RS232 tramite opportuni traslatori di livello per adattare il livello logico TTL al livello logico EIA232.
In questa lezione ci occuperemo della periferica MSSP (Master Synchronous Serial Port). Anche in questo caso si tratta di una periferica in grado di effettuare una comunicazione seriale. Tale periferica, però, si occupa unicamente di trasmissioni seriali sincrone (ovvero abbiamo in aggiunta una linea che fornisce il clock) secondo i protocolli I2C ed SPI.
Il protocollo I2C è un protocollo di comunicazione seriale sincrona half-duplex (vi è una sola linea di comunicazione, oltre al clock, sulla quale possono inviare i dati un dispositivo alla volta), l’SPI è invece full-duplex (due dispositivi possono inviare dati contemporaneamente in quanto, oltre al clock, vi sono due linee di comunicazione). Tali protocolli sono utilizzati da svariati tipi di dispositivi e permettono la comunicazione anche tra più dispositivi sullo stesso bus: nei due protocolli menzionati, difatti, ci sono diversi sistemi di indirizzamento che permettono di selezionare solo il dispositivo al quale sono destinate le informazioni: tutti gli altri dispositivi presenti sulla linea, quindi, ignoreranno l’informazione. Questa cosa abbiamo visto che non è possibile con la comunicazione secondo lo standard RS232.

Estratto dallo schema della Freedom II di Mauro Laurenti. Vediamo come due dispositivi I2C (una eeprom serie24 e un Orologio Realtime PCF8563) sono connessi in parallelo sulla stessa linea di comunicazione

Sensore ad ultrasuoni SRF10 della Devantech. Comunica in I2C e fornisce una misura di distanza dagli oggetti.
Sui picmicro vi sono alcuni registri che permettono di impostare la periferica MSSP per il funzionamento in modalità I2C o SPI. In questo articolo ci occuperemo del funzionamento in I2C, che è forse il più diffuso e permette l’interfacciamento con numerosi dispositivi di uso comune (eeprom esterne della serie 24, orologi real clock come il DS1307, bussole, sonar e tanto altro ancora).
Prima di continuare, però, dovete necessariamente leggere l’ottimo tutorial di Mauro Laurenti sull’ I2C, in maniera tale che io possa evitare di dire cose già dette (e tra l’altro dette anche molto bene ed in maniera semplice ed esaustiva), per cui proseguirò supponendo che sappiate già com’è strutturata una comunicazione I2C, anche se per forza di cose ogni tanto dovrò comunque ripetere dei concetti.
Sappiamo quindi che in una comunicazione I2C c’è un dispositivo identificato come Master che gestisce la comunicazione (ovvero: fornisce il segnale di clock, avvia e termina le comunicazioni) e uno o più dispositivi identificati come Slave che rispondono ai comandi impartiti dal dispositivo Master. Il modulo MSSP può implementare il protocollo I2C in varie modalità: Master, Multi-Master e Slave. In questo articolo mi occuperò unicamente della modalità Master, che è forse quella più usata.
Non mi occuperò in questa sede del modulo SSP (presente ad esempio nei pic16F88, pic16F819 ecc), che ha sempre e comunque la funzione di gestire le comunicazioni I2C e SPI. Nei pic con modulo SSP, però, la modalità master non è supportata appieno e molte cose vanno implementate via software. Non per niente nel modulo MSSP la “M” sta appunto per Master e nelle caratteristiche viene appunto dichiarato “Full Master” e vi assicuro che quel full fa molta differenza!
La modalità I2C prevede l’utilizzo di soli due pin: quello indicato come SCL (Serial CLock), che ha il compito di fornire il segnale di clock necessario per la comunicazione sincrona e il pin SDA (Serial DAta) sul quale transitano i dati ed è usata sia da chi trasmette che da chi riceve (half-duplex). Sul 16F877A questi due pin si trovano rispettivamente su RC3 e RC4, fate riferimento al datasheet del picmicro in vostro possesso per identificare quali pin sono usati per la comunicazione I2C.
La modalità I2C prevede l’impostazione e l’utilizzo di 5 registri:
SSPCON – Primo registro di controllo del modulo MSSP
Su alcuni picmicro tale registro potrebbe essere identificato come SSPCON1, in altri le due definizioni sono equivalenti, tutto dipende dal file header del pic utilizzato.
SSPCON2 – Secondo registro di controllo (e stato) del modulo MSSP
SSPSTAT – Registro di stato (e controllo)
SSPBUF – Buffer di ricetrasmissione
SSPADD – Registro di indirizzamento (solo in modalità slave) / Impostazione velocità di trasmissione (meglio noto come Baud Rate Generator, solo in modalità master)
I pic con modulo SSP anzichè MSSP, ad esempio, non hanno il registro SSPCON2 che invece noi qui andremo a sfruttare appieno per realizzare una comunicazione full master interamente gestita in hardware.
In aggiunta c’è un sesto registro non accessibile, SSPSR, che funziona da shift register per il registro SSPBUF: quando un dispositivo riceve, i dati vengono caricati prima in SSPSR e quindi spostati in SSPBUF creando quindi un doppio buffer di ricezione. In trasmissione invece il registro SSPBUF viene caricato direttamente.
Alcuni pic16 (ma non solo), appartenenti alla serie Enanched (ovvero PIC16Fxxxx cioè con quattro cifre nella parte finale della sigla), hanno 2 registri aggiuntivi: SSPCON3 e SSPMSK che servono per impostare caratteristiche avanzate, che qui non andremo ad utilizzare e non sono strettamente necessarie per una comunicazione I2C di base. Altri pic, sempre appartenenti alla serie Enanched (prendo ad esempio il PIC16F1827) hanno ben due moduli MSSP (MSSP1 e MSSP2), indipendenti tra loro e configurabili individualmente, che permettono, ad esempio, di implementare su un unico picmicro sia la comunicazione I2C che quella SPI (o anche due comunicazioni I2C nel caso che su una abbiamo raggiunto il limite massimo di periferiche ammissibili e abbiamo necessità di inserirne ancora), cosa che, avendo un unico modulo, normalmente non è possibile a meno di non implementarle via software e non via hardware come stiamo facendo adesso. In questi picmicro tutti i registri associati ai moduli MSSP avranno in aggiunta il numero 1 o il 2 per indicare se appartengono al primo o al secondo modulo. Avremo quindi un SSP1CON e un SSP2CON, un SSP1STAT e un SSP2STAT e così via. Fate riferimento al datasheet del pic in vostro possesso e al file H dell’Hitec-C relativo al vostro picmicro. Inoltre su tali pic i nomi dei bit potrebbero avere un nome leggermente differente, come ad esempio il bit RW che è stato cambiato in R_nW.
Inizializzazione del modulo MSSP in modalità I2C master
Prima di tutto è necessario porre in stato di alta impedenza (ovvero: impostare come ingressi) i due pin destinati alla comunicazione I2C, ovvero RC3 e RC4 nel caso del 16F877A:
TRISC3=1; TRISC4=1;
oppure
TRISC=0bxxx11xxx; // sostituire le x
Inutile ripetere che su altri picmicro, specie su quelli con doppio modulo, i due pin si possono trovare in posizioni differenti.
Ponendo i due I/O in stato di alta impedenza dovremo quindi provvedere delle resistenze di pull-up sulle 2 linee di comunicazione per consentire le operazioni di transito dei dati; il valore delle resistenze varia in funzione della velocità di trasmissione e dell’impedenza della linea, abbiamo già letto nel tutorial di Mauro quali valori scegliere in base alle nostre esigenze.
I principali bit di inizializzazione si trovano nel registro SSPCON, ed in particolare:
SSPEN (bit 5): Synchronous Serial Port Enable. Impostato ad 1 abilita la porta seriale e configura i pin indicati SCL e SDA come linee di comunicazione per il modulo I2C. Questa impostazione prevede che abbiamo già settato il registro tristato per impostare tali pin come ingressi.
SSPM3:SSPM0 (bit 3:0): Synchronous Serial Port Mode. L’impostazione di tali bit permette di selezionare la modalità di funzionamento del modulo I2C, in questo caso, dovendo utilizzare il modulo I2C in modalità Master, tali bit andranno posti al valore 0b1000.

Impostazione dei bit SSPM sul pic16F877A. Sui pic con modulo SSP, l'impostazione ob1000 non è presente e l'unico modo per implementare una comunicazione I2C master è l'impostazione 0b1011, ovvero Master controllato via firmware...
Essendo il master il dispositivo che decide la frequenza del clock, tale impostazione prevede anche che il clock del modulo I2C, il quale determina la velocità di comunicazione sul bus, sia calcolato con la formula:
![]()
dove SSPADD è appunto il valore che andremo a dare al registro di indirizzamento (che nel caso della modalità master è detto Baud Rate Generator) in maniera tale da ottenere la frequenza di clock desiderata.
Nel nostro caso quindi l’impostazione da dare al registro SSPCON (o SSPCON1) sarà:
SSPCON=0b00101000; // 0x28
Dobbiamo quindi impostare la velocità di comunicazione. Come abbiamo visto, lavorando in modalità master, il nostro picmicro genererà il clock secondo la formula vista poc’anzi. Dobbiamo quindi impostare il registro SSPADD per poter scegliere la velocità di comunicazione. Tutti i dispositivi I2C possono lavorare alla velocità standard (standard mode), che prevede una frequenza di 100KHz, altri possono lavorare anche in modalità alta velocità (400KHz – Fast Speed). Dalla formula vista prima possiamo ricavare il valore da dare al registro SSPADD:
![]()
Lavorando con un quarzo da 20MHz e volendo impostare il clock del modulo I2C a 100KHz abbiamo che:
![]()
Per completare il settaggio del modulo I2C dovremo ancora impostare qualche altro bit, questa volta nel registro SSPSTAT:
SMP (bit 7): Slewrate control. Tale bit va impostato ad 1 per disabilitare il controllo dello slew rate e lavorare a 100KHz. Se vogliamo invece lavorare a 400KHz tale bit va posto a zero.
Il bit SMP va posto ad 1 anche nel caso che la frequenza di lavoro sia di 1MHz, che è ad esempio supportata dalle EEProm esterne di tipo 24FC. Inutile dire che se su un unico bus ci sono più dispositivi, per semplificarci le cose bisognerebbe fare in modo che tutti comunichino alla stessa velocità e cioè quella del dispositivo con velocità più bassa, a meno di non fare delle piccole “acrobazie” via software. Oppure ancora possiamo scegliere periferiche I2C che abbiano le più alte velocità possibili: il mercato è molto vasto.
CKE (bit 6): SMBus select. Tale bit serve per indicare al picmicro se vogliamo lavorare in modalità compatibile SMBus. L’SMBus è un protocollo, poco usato, praticamente uguale all’I2C nel quale però la frequenza di clock non va oltre 100KHz e i livelli di tensione sono più bassi. Va posto a zero per lavorare con lo standard I2C.
Infine, anche se non è strettamente necessario in quanto assume già valore zero all’accensione, azzeriamo il flag di interrupt associato alla comunicazione seriale del modulo MSSP:
SSPIF (bit 3 del registro PIR1) – Synchronous Serial Port Interrupt Flag
Tale flag verrà difatti monitorato per gestire correttamente la comunicazione.
Funzionamento di una comunicazione I2C in un picmicro
Abbiamo quindi visto i passaggi necessari per impostare il nostro modulo MSSP per funzionare in modalità I2C master. Vediamo ora come è strutturata la comunicazione.
Quando il picmicro deve iniziare una trasmissione, terminarla o inviare dei dati, deve attendere che il bus si trovi in condizione idle, ovvero non occupato da altre trasmissioni in corso.
Il bus è in stato idle quando SDA e SCL si trovano a livello logico alto
Tale condizione viene determinata eseguendo un OR tra il bit 2 (RW – ricordo che nei pic enanched è indicato come R_nW) del registro SSPSTAT e i bit [4:0] (ACKEN, RCEN, PEN, RSEN, SEN) del registro SSPCON2 : fino a che l’una o l’altra condizione non si verifica, il pic deve rimanere in attesa.
Quindi si capisce che non possiamo fare questa operazione su un modulo SSP in quanto tale registro non c’è
In particolare il bit RW, quando si trova a zero, indica che non vi sono trasmissioni in corso, i bit [4:0] di SSPCON2 quando posti ad 1 indicano che in qualche modo la linea è ancora occupata. Quindi in C, per far rimanere il pic in attesa nel frattempo che il bus si liberi, andremo a controllare queste condizioni nel modo seguente:
while ((SSPCON2 & 0x1F) | RW) { continue; }
Una volta che il bus è libero, il pic lo deve occupare per poter segnalare che ha intenzione di iniziare a trasmettere e viene quindi inviata la sequenza di start: questo si fa ponendo ad 1 il bit 0 (SEN – Start Condition Enabled) del registro SSPCON2 (azzeriamo, per sicurezza, anche il flag di interrupt – SSPIF). Nella sequenza di start la linea SDA viene portata a livello logico basso mentre SCL è a livello alto. In questa condizione il bus risulta occupato. Il nostro pic comincia quindi a generare il clock per permettere alle periferiche di sincronizzarsi e quindi prepararsi a ricevere le eventuali richieste da parte del master.
Il microcontrollore deve quindi, per prima cosa, segnalare con chi ha intenzione di comunicare, per cui viene inviato sulla linea l’indirizzo della periferica di destinazione, generalmente l’indirizzo delle periferiche è a 7 bit, un’ottavo bit viene inviato in coda per segnalare se si vuole ricevere un dato dalla periferica in questione (bit posto a 1) o si vuole scrivere un dato sulla periferica (bit posto a 0). L’indirizzo della periferica, così come i dati, viene trasmesso caricandolo nel registro SSPBUF. I dati vengono inoltre inviati a partire dal bit più significativo a quello meno significativo.
Si capisce quindi che sul bus I2C non possono esistere due dispositivi con lo stesso indirizzo: difatti molti dispositivi I2C (ad esempio le memorie, come vedremo nella seconda parte della lezione) hanno una parte di indirizzo fissa e un’altra parte modificabile dall’utente mettendo alcuni pin del dispositivo a massa o a Vdd. L’indirizzo delle periferiche I2C e le modalità con cui può essere variato è sempre chiaramente indicato sul loro datasheet ed è un dato assolutamente essenziale.
Altri dispositivi hanno invece un indirizzo a 10bit, per cui l’indirizzo con cui comunicare verrà inviato in due parti successive da 8 bit (essendo due byte composti da 16 bit, 5 bit avranno sempre un valore fisso indipendentemente dal dispositivo e l’ultimo bit restante è quello che decide la lettura/scrittura, sul tutorial di Mauro questo argomento è esposto in maniera molto chiara).
Nel caso di invio di dati a più di 8 bit, i bytes vengono sempre inviati in ordine dal più alto verso il più basso.
Dopo che il master ha inviato l’indirizzo della periferica con cui comunicare, si aspetta che qualcuno risponda: in pratica la periferica che ha riconosciuto il suo indirizzo invierà un segnale di Acknowledge (conferma) sulla linea. Tale segnale di conferma è possibile verificarlo controllando lo stato del bit 6 (ACKSTAT – Acknowledge Status) del registro SSPCON2. Quando tale bit è posto a zero, vuol dire che si è ricevuta una conferma e possiamo continuare la comunicazione.
Quindi fate molta attenzione: la logica di risposta è in un certo senso invertita: c’è il consenso quando tale bit è a zero, il mancato consenso quando tale bit è a 1. Nella libreria in fondo all’articolo, però, il consenso viene restituito con un 1 perchè mi sembrava più logico.
E’ comunque pratica comune non controllare tale condizione includendo un ritardo e continuare la trasmissione.
Vengono quindi inviati i dati in sequenza:
- nel caso che stiamo comunicando in scrittura (ovvero: vogliamo impostare un registro della periferica su un determinato valore), invieremo prima l’indirizzo del registro in cui si vuole scrivere e quindi in seguito il valore da scrivere. Si eseguiranno quindi le operazioni:
- Sequenza di Start
- Invio indirizzo periferica in scrittura
- Invio indirizzo del registro in cui scrivere
- Invio del valore da scrivere nel registro
- Sequenza di stop

Esempio di scrittura di un dato in una eeprom di tipo 24. Il "Control Byte" è l'indirizzo dell'EEProm (7 bit+bit di lettura/scrittura, vale 0 dato che vogliamo scrivere). Dopo l'indirizzo viene inviato l'indirizzo della cella in cui scrivere (indirizzo a 16 bit, quindi inviato in 2 byte successivi), infine viene inviato il dato ad 8 bit da scrivere nella cella. Tra l'invio di un byte e il successivo c'è l'acknowledge
- nel caso che stiamo comunicando in lettura (ovvero: vogliamo che la periferica ci restituisca un valore), viene inviato l’indirizzo del registro della periferica che si vuole leggere. In pratica se vogliamo leggere un registro dalla periferica si eseguiranno le seguenti operazioni:
- Sequenza di Start
- Invio indirizzo periferica in scrittura
- Invio indirizzo registro da cui prelevare il dato
- Sequenza di start ripetuto (verrà spiegato più in basso cosa significa)
- Invio indirizzo periferica in lettura
- Lettura del valore (il valore sarà contenuto nel registro SSPBUF)
- Sequenza di stop

Esempio di lettura eeprom. Lo start inviato dopo l'indirizzo è in realtà uno start ripetuto.
Le periferiche I2C, quindi, hanno più registri dai quali possiamo prelevare i dati o scrivere informazioni. L’indirizzo dei registri e la loro funzione è sempre indicata sui datasheet.
Tutti i dati (valori, registri) come già detto vanno caricati nel registro SSPBUF: appena caricati vengono trasmessi in automatico. I dati vengono sempre inviati/ricevuti in pacchetti da 8 bit e dopo ogni pacchetto si attende il segnale di acknowledge per poter continuare.
Tra un invio e il successivo bisogna sempre controllare il flag di interrupt SSPIF per evitare di generare conflitti di trasmissione e quindi inficiare la trasmissione dei dati: quando tale bit è posto ad uno vuol dire che la trasmissione è terminata, quindi lo azzeriamo e riprendiamo a trasmettere.
Viene quindi terminata la trasmissione inviando la sequenza di stop: si pone a 1 il bit 2 (PEN – Stop Condition Enable) di SSPCON2 e si da l’acknowledge (anche il master deve dare l’acknowledge!) ponendo a 1 il bit 4 (ACKEN – Acknowledge Sequence Enable) di SSPCON2. In questa condizione il bus si libera e si mette quindi in stato idle.
La trasmissione può anche essere interrotta e ripresa subito inviando la cosiddetta sequenza di start ripetuto: è simile alla sequenza di start ma serve a terminare la comunicazione e riprenderne un’altra senza inviare la sequenza di stop che farebbe perdere al Master il diritto di comunicazione costringendo ad aspettare altro tempo prima che il bus si liberi. La sequenza di start ripetuto viene effettuata poneno ad 1 il bit 1 di SSPCON2 (RSEN – Repeated Start Condition Enable). Questa funzione è molto sfruttata, e richiesta, quando si devono ad esempio trasferire dati in lettura.
Downloads
Ai miei fedeli lettori lascio qui due librerie, quella originale l’ho trovata con Google e dal momento che mi è sembrata fatta molto bene, ho deciso di utilizzarla. Ho apportato delle modifiche alla libreria per renderla più snella, in particolare sulla selezione della frequenza di funzionamento, del quarzo e dei pin da utilizzare, che andrà fatta nel file header (i2c.h) – penso non siano necessarie molte spiegazioni:
// Impostare la frequenza del clock del modulo MSSP espressa in KHz #define CLOCK 100 // (100, 400 o 1000) // Impostare la frequenza del quarzo espressa in Hertz, lasciare la L dopo il valore #define FOSC 20000000L // Impostare i pin usati per la comunicazione I2C #define SCL_PIN TRISC3 #define SDA_PIN TRISC4 /* PIC SCL SDA PIC16F877A TRISC3 TRISC4 PIC16F887 "" "" PIC16F1939 "" "" PIC16F1827 (mssp1) TRISB1 TRISB4 */
In aggiunta ho modificato la libreria i2c.c per poterla adattare ai pic serie enanched con doppio modulo MSSP (file i2c_mssp1.c). In particolare la libreria per doppio modulo è pensata per utilizzare unicamente il modulo MSSP1, se avete la necessità di utilizzare il modulo MSSP2, con le informazioni che ho dato nell’articolo dovreste essere in grado di riuscire a modificarla da soli (basta sostituire gli 1 dei registri con il 2: SSP1CON1 diventerà SSP2CON1 e così via).
Chi è abituato a lavorare con i pic di fascia base, troverà delle stranezze nel codice i2c_mssp1.c in quanto i singoli bit vengono indicati facendo uso di strutture, ad esempio il bit SEN verrà indicato come:
SSP1CON2bits.SEN
In pratica abbiamo il nome del registro a sinistra, un punto, e il nome del bit a destra. Questo modo di indicare i bit è usato anche nei pic di fascia superiore alla 16 e a mio avviso è un sistema migliore in quanto non fa perdere di vista il registro su cui si sta lavorando e permette di utilizzare lo stesso nome dei bit nel caso ci fossero due registri con funzioni uguali, come appunto nei moduli MSSP doppi: ci sono due registri SSPCON2 (il SSP1CON2 e il SSP2CON2), entrambi hanno dei bit con lo stesso nome, non facendo uso di strutture avremmo dovuto trovare un altro nome per il secondo bit SEN, e questo avrebbe reso molto difficile il districarsi in questi concetti che tra l’altro possono risultare già molto complicati di per sè.
A seconda del pic che utilizzate quindi includerete l’una o l’altra libreria.
Alcune funzioni verranno descritte in un prossimo articolo, anche se leggendo il codice penso non ci sia poi molto da chiarire. In particolare la libreria supporta sia la modalità master che la slave, per cui ci saranno funzioni di lettura e scrittura sia per la modalià master che per la modalità slave.
Ringrazio Luca Gallucci per avermi aiutato a testare questa libreria sul PIC16F1827.
Le nuove librerie sono scaricabili da questa pagina. In particolare la nuova versione (1.0) permette con un unico file di essere utilizzata sia sui picmicro vecchi che non utilizzano la numerazione del modulo MSSP, sia da quelli nuovi che la utilizzano.
Il vecchio download rimane qui per ragioni storiche ma non se ne consiglia l’utilizzo:
![]()
Librerie I2C Hardware per moduli MSSP (6.3 KB - 291 downloads)
Ricordo ancora una volta che queste librerie non possono essere usate nei pic che hanno il modulo SSP al posto dell’MSSP.
Approfondimenti
- Le specifiche ufficiali del Bus I2C, versione 2.1 (NXP, ex Philips)
- Application Note della NXP sull’utilizzo del bus I2C
- Tutorial di Mauro Laurenti sul bus I2C
- Application Note 735 Microchip: Using the picmicro MSSP module for I2C communications
- Application Note 734 Microchip : Using the PIC Devices’ SSP and MSSP Modules for Slave I2C Communication
- Presentazione Microchip sull’utilizzo del modulo MSSP in modalità I2C master
Articoli che potrebbero interessarti
Se desiderate che settorezero continui a rimanere gratuito e fruibile da tutti, non copiate il nostro materiale e segnalateci se qualcuno lo fa

Questo sito e tutto il suo contenuto sono distribuiti sotto la licenza








#1 da Peppazzz91 il 12 agosto 2010
Non vedo l’ora che arrivino le altre 2 parti :p
#2 da antomato il 1 ottobre 2010
Salve, volevo ringraziarti perchè grazie a te sto muovendo i primi passi con i microcontrollori PIC. volevo farti una domanda! Guardando le funzioni all’inteno di i2c.c ho notato che nella funzione I2cWriteMaster non viene resettato il Flag SSPIF; quindi dopo aver caricato il dato nel registro SSPBUF viene richiamata la funzione I2cWait dando per scontato che tale flag fosse a 0. La domanda è questa: Appena carico il dato nel registro SSPBUF il flag SSPIF viene resetteto in automatico?
Saluti Antonio
#3 da Giovanni Bernardo il 1 ottobre 2010
Nella libreria, il flag viene sempre resettato all’inizializzazione della periferica e quindi al termine delle operazioni di scrittura e all’inizio dell’operazione di lettura… Non vedo perchè dovrei aggiungere un’altro reset del flag? Che giovamento ne posso trarre? Quando vado a scrivere carico il dato in SSPBUF, quando il dato viene trasmesso il flag viene posto a 1 e quindi lo resetto e questo lo fa la funzione wait, che serve a mettere in attesa per evitare di eseguire operazioni successive fino a che il buffer non si svuota.
#4 da fra83 il 21 ottobre 2010
Ciao a tutti, ho un problema, questo è quello che ho iniziato a fare, voglio far dialogare il 16f877 con un pcf8583, in debug entra nella routine di start ed è sempre fermo in attesa del SSPIF che non và mai ad 1. Qualcuno può dirmi dove sbaglio?
Grazie
Francesco
#include
#include “Delay.c”
#include “i2c.c”
#include “lcd.c”
#define addr_rtc 0xA0 // Indirizzo Device PCF8583 (pin A0 -> Ground)
void main (void)
{
int a;
TRISB=0×00;
TRISD=0×00;
LCD_INIT(); // serve ad inizializzare l’LCD
DelayMs(250); // piccolo ritardo per completare l’inizializzazione LCD_CLEAR(); // Cancella il display
DelayUs(200); // pausa
LCD_CMD(LCD_line1); // primo rigo
LCD_PUTS(” Comunicazione i2c “);
I2cInitMaster(); // Init MSSP in Master mode
I2cStart(); // Sequenza di start
I2cWriteMaster(addr_rtc);
I2cWriteMaster(0×00);
I2cWriteMaster(0×02);
I2cStop();// Sequenza di stop
}
#5 da Giovanni Bernardo il 21 ottobre 2010
quei due comandi che invii dopo l’indirizzo (0×00 e 0×02) a cosa servono? In quale riga il programma si blocca?
#6 da fra83 il 21 ottobre 2010
Il programma si blocca nella routine I2cStart() precisamente quando entra in questa routine qui’ sotto:
void I2cWait()
{
while(!SSPIF)
{
continue;
}
SSPIF=0;
}
#7 da fra83 il 21 ottobre 2010
I comandi I2cWriteMaster(0×00); e I2cWriteMaster(0×02); mi servivano a scrivere nella posizione 0×00 del pcf8583 il dato 0×02 ….o almeno quella era la mia intenzione
#8 da Giovanni Bernardo il 21 ottobre 2010
Sei proprio sicuro di aver collegato bene l’orologio? Le resistenze di pullup ci sono? Funzionano correttamente? Queste librerie sono state provate con memorie eeprom e con il DS1307 per cui, personalmente, ritengo che funzionano. Il PCF8583 non ha niente di particolare e dovrebbe funzionare pure lui.
E’ ovvio che l’I2C start lo devi dare con le linee “in ordine” ovvero resistenze di pullup e almeno un dispositivo I2C collegato a tali linee
#9 da fra83 il 21 ottobre 2010
Non metto in dubbio che le librerie funzionino. I pull up ci sono da 2,2kohm e il dispositivo è collegato bene. Se puoi potresti mandarmi il progetto con il ds1307? Io compilo con hi tech e poi mi preparo il circuito su proteus.
Magari con un programma funzionante riesco a capire cosa non và e in seguito provo anche qualche memoria.
Anticipatamente ti ringrazio
#10 da vezzo il 22 ottobre 2010
Ciao ottimo lavoro!!;
c’é però una cosa che non capisco nella function I2cReadMaster…mettendo a 1 il flag ack decido se mandare oppure no l’Acknowledge sequence a fine lettura giusto? Se cosi fosse potresti spiegarmi la funzione del bit ACKDT??
Da quello che ho capito sta ad indicare la fine della ricezione e l’inizio di una sequenza di Acknowledge….
Grazie Ciao Ciao
#11 da fra83 il 22 ottobre 2010
Sono riuscito a far parlare il micro con il pcf8583, ho un altro problema ora, ho impostatosec, min, ore, giorno e mese ma l’anno non riesco.
il registro con indirizzo 0×05 è composto così AADDDDDD dove A= anno e D= data( cioè giorno in BCD.)La mia domanda è come faccio su 2 bit a rappresentare un numero in decimale che varia da 01 a 99?
Qualcuno sà rispondere?
Grazie
#12 da Giovanni Bernardo il 22 ottobre 2010
Con 2 bit esistono solo 4 possibili combinazioni, per cui è ovvio che con 2 bit non puoi codificare 99 numeri ma massimo 4. E fin qui non ci piove.
Mi sono letto il datasheet, da quello che ho potuto capire è l’anno che viene codificato con soli 2 bit, per cui puo assumere solo i valori 0,1,2 e 3… cioè 4 valori che servono solo per tenere memoria dell’anno bisestile. L’anno bisestile viene identificato da 0, questo si capisce dalla tabella 4 (cycle length of the time counters). Come vedi quando l’anno è uguale a zero il mese 2 (febbraio) conta fino a 29 giorni, quando l’anno è uguale a 1,2 e 3 febbraio conta fino a 28 giorni.
Quindi il PCF8583 non memorizza l’anno come fa il DS1307 ma sei tu che via software devi farti dei conti. Difatti il PCF8583 non ha nemmeno il backup: se manca la corrente la data la perdi per cui è implicito che la visualizzazione completa dell’anno la devi fare tu via software, mentre il DS1307 ha pure il backup: se manca la corrente e hai messo la batteria tampone, continua a tenere la data giusta.
#13 da fra83 il 24 ottobre 2010
Grazie! Mi era proprio sfuggito!
Ora sistemo il tutto!
#14 da odessos il 26 febbraio 2011
Salve a tutti.
All’inizio della sessione I2C si parla dei vari registri da settare per abilitare il modulo MSSP, quello che però non capisco è che tale protocollo fa uso del flag SSPIF nel registro PIR1 che riconosce se è avvenuto un interrupt da parte di questo modulo, ma per utilizzare questo controllo non bisogna anche settare i registri INTCON e PIE1 ?
#15 da Giovanni Bernardo il 26 febbraio 2011
Il flag di interrupt viene settato anche se in quei due registri è disattivato, l’unica cosa è che non “scatta” l’interrupt, ma se lo controlli in polling lo puoi verificare.
#16 da Valentino il 27 febbraio 2011
Buongiorno Giovanni, mi presento sono Valentino e mi sono iscritto oggi. In verità, è un paio di mesi che leggo le sue lezioni di programmazione sul PIC e non passa giorno che non apra il suo sito almeno una volta. Mi complimento per il lavoro che svolge e mi sento di farle una preghiera: Non smetta proprio adesso!!! Avrò sicuramente bisogno di lei in particolar modo per questa lezione sull’ I2C che mi si preannuncia ostica.
Spero di non disturbarla spesso, ma non posso prometterlo!
Grazie per ciò che fa.
Saluti
Valentino
#17 da odessos il 28 febbraio 2011
Sono riuscito a collegare un display 20×4 che comunica in seriale I2C. riesco ad inviare singoli caratteri ma non riesco ad usare la funzione printf(“stringa”), con questa funzione in compilatore mi rimanda un errore
“Error [499] ; 0. undefined symbol:
_putch(main.obj)
********** Build failed! **********
non capisco cosa non và nell’utilizzo della funzione printf
ho incluso naturalmente la libreria
#18 da Giovanni Bernardo il 28 febbraio 2011
Il compilatore dice che non trova la funzione putch. Adesso non so come è strutturata la libreria che sta usando. In genere includendo si ha disponibile la funzione printf che a sua volta utilizza la funzione putch. Normalmente queste due funzioni operano sul dispositivo di output più comune e cioè la uart.
Nel suo caso la funzione printf deve invece operare sul display e ha quindi bisogno di una funzione putch che invia i caratteri sul display. Se è riuscito a inviare singoli caratteri, con quale funzione li ha inviati? Le librerie le ha scritte lei?
#19 da Stefano il 28 febbraio 2011
La librerie che ho utilizzato sono quelle del bus I2C e la libreria stdio.h
I caratteri li ho inviati tramite le funzioni della libreria I2C.c come caratteri ASCII
Forse la funzione in C printf() fà riferimento a il solo output su seriale uart?
#20 da Giovanni Bernardo il 28 febbraio 2011
La funzione printf di default dirige l’output sulla seriale, ma lo fa perchè è putch che lo invia li, basterebbe riscrivere la putch. Ma ora nel suo caso specifico non ho idea di cosa ha fatto.
#21 da marcorn80 il 1 marzo 2011
Ciao mi chiamo Marco, anche io stò seguendo da parecchio le tue lezioni sul PIC in C e sono arrivato alla gestione della I2C
hai fatto un ottimo lavoro con queste librerie, sono molto chiare, le ho anche modificate e adesso riesco a gestire 8 sensori di temperatura TCN75 e un I2C extender PCF8574!
Ogni tanto però il programma all’avvio mi va in loop sulla sub I2Cwait e piu precisamente alla riga
while (!SSPIF)
come se lo slave non rispondesse, inoltre rimanendo in loop quà mi blocca anche tutto il resto del programma.
Questa cosa me la fà all’avvio del programma e non durante il funzionamento, poi con l’ICD resetto e riparto 3-4 volte e tutto riparte per magia…
non esiste un bit che mi permette di capire se lo slave non risponde e passo al successivo?
#22 da Giovanni Bernardo il 1 marzo 2011
Questa cosa è strana… la dovrei verificare
#23 da marcorn80 il 2 marzo 2011
Guardando quà e là su internet ho trovato questo:
SSPIF is set if the start condition actually happens. The most likely cause of this is your bus is being driven low by another device
potrebbe essere che fermando precedentemente l’ICD mentre un dispositivo I2C stà ritrasmettendo verso il master si potrebbe fermare in una condizione strana, e poi alla ripartenza il dipositivo continua a tenere impegnato il bus, non permettendo al master di trasmettere il bit di start ma portando il programma alla subroutine I2Cwait come se lo avesse tasmesso.
La cosa strana è che non dovrebbe accorgersi la routine di idle che il bus è occupato prima di trasmettere?
intanto stò pensando di mettere qualcosa all’interno del while della routine I2C per svincolarlo ed eventualmente ritrasmettere i bit di start fino a quando sto benedetto SSPIF non và a 1
#24 da valerio il 20 marzo 2011
Ciao mi chiamo valerio, grazie a questo corso di programmazione sono riuscito a capire come si utilizza il modulo MSSP dei PIC, grazie e complimenti per il sito.
#25 da odessos il 1 novembre 2011
Sto provando a collegare due processori in I2C, uno dei quali è il master 16F887 e l’altro lo slave 16F877A.
Utilizzo la libbreria che hai suggerito dove il master lo inizializzo con l’apposita funzione I2cInitMaster() e lo slave con I2cInitSlave(0xE2), 0xE2 è l’indirizzo della slave.
sul master invio un dato nel seguente modo:
I2cStart();
I2cWriteMaster(0xE2);
I2cWriteMaster(valore);
I2cStop();
mentre sullo slave cerco di ricevere nel seguente modo:
I2cWait();
numero=I2cReadSlave();
la variabile numero poi la visualizzo su un display ma quello che visualizzo è il valire “226″ che corrisponde al dato indirizzo inviato dal master subito dopo lo start 0xE2 e niente altro.
dove sbaglio?
buon tutto a tutti.
#26 da Giovanni Bernardo il 1 novembre 2011
L’indirizzo dello slave nell’inizializzazione lo devi fornire a 7 bit, quindi quando vai a leggere/scrivere ti devi ricordare di mettere il bit a 0/1
#27 da odessos il 1 novembre 2011
un’altra domanda: nel mio caso che collego due processori è necessario usare comunque le resistenze di pull-up, visto e considerato che entrambe le porte RC3 RC4 non sono open collector?
#28 da Giovanni Bernardo il 1 novembre 2011
Quando setti il modulo per la comunicazione I2C automaticamente i pin destinati all’I2C vanno in alta impedenza, ergo le resistenze vanno sempre messe.
#29 da odessos il 2 novembre 2011
Ok. ma il registro SSPADD è un registro a 8 bit non a 7, se il master invia un dato di 8 bit (compreso il bit 0 R/W)
lo slave compara i bit da 1 a 7 inviati dal master con i bit da 1 a 7 del registro SSPADD non da 0 a 7, se inserisco come parametro address sullo slave un valore a 7 bit il valore stesso cambia radicalmente, cioè da E2 come avevo impostato diventa 71.
Facendo così non c’è alcuna risposta da parte dello slave perchè non riconosce l’indirizzo inviato dal master.
Il mio problema è che lo slave riconosce l’indirizzo inviato dal master ma invece di visualizzare il dato visualizza il valore dell’indirizzo stesso. Ho scoperto che si verifica in pratica un overflow perchè viene settato il registro SSPOV.
Non riesco a capire, capisco solo che gestire un protocollo in slave è più difficile di quello che pensavo.
#30 da odessos il 22 gennaio 2012
Saluti a tutti e buon anno.
Maledeto sito della microchip… è un labirinto!
qualcuno sa dirmi dove trovare una pagina con le librerie da scaricare?
#31 da Giovanni Bernardo il 23 gennaio 2012
Di quali librerie parli?
#32 da djlorenz il 24 gennaio 2012
il sito microchip è un labirinto ma generlamente è facile accedere a tutto, di solito quello che cerchi lo trovi scrivendo microchip.com/quellochevuoicercare
oppure è sempre nel top delle pagine di google, quindi basta una ricerca ;)
ciao!