Sommario:

Bus I2C per ATtiny e ATmega: 8 passaggi
Bus I2C per ATtiny e ATmega: 8 passaggi

Video: Bus I2C per ATtiny e ATmega: 8 passaggi

Video: Bus I2C per ATtiny e ATmega: 8 passaggi
Video: Amazing arduino project 2024, Luglio
Anonim
I2C Bus per ATtiny e ATmega
I2C Bus per ATtiny e ATmega

Adoro i microcontrollori Atmel AVR! Da quando ho costruito il Ghetto Development System descritto in questo Instructable, non mi sono mai divertito a sperimentare con l'AVR ATtiny2313 e l'ATmega168 in particolare. Sono persino arrivato al punto di scrivere un Instructable sull'uso degli interruttori come input e ho esteso il concetto di Ghetto Development System ai CPLD. Durante un progetto recente, avevo bisogno di diversi interruttori per impostare i valori di controllo. Gli AVR non avevano abbastanza pin I/O, quindi ho dovuto pensare a qualcosa. Avrei potuto provare un sistema di input complesso con tastiera e display, ma l'ATtiny2313 avrebbe esaurito le risorse. Fortunatamente, Atmel ha fornito un modo per aggirare questo problema includendo un'interfaccia che può collegarsi a chip aggiuntivi (come memoria o porte I/O) con una semplice interfaccia a due fili. Esatto, utilizzando solo due pin I/O su un AVR possiamo accedere a molti pin I/O aggiuntivi e anche ad altre risorse. Questa interfaccia a due fili è formalmente conosciuta come bus Inter-Integrated Circuit, o semplicemente bus I2C ed è stata inventata da NXP quando era ancora Philips Semiconductors. Se stai leggendo questo Instructable, probabilmente hai sentito parlare del bus I2C e potresti persino averlo usato su un PIC o un altro microcontrollore. Sebbene concettualmente molto semplici e supportati da risorse hardware sugli AVR, i driver software sono ancora necessari per utilizzare il bus I2C. Atmel fornisce note applicative (vedere le risorse più avanti in questo Instructable), ma questi sono incompleti e non mostrano alcun esempio oltre alla comunicazione con un altro dispositivo AVR. Non è scopo di questo Instructable insegnare a chiunque come creare driver I2C per il AVR. Piuttosto, fornirò versioni estese dei driver Atmel per i dispositivi ATtiny2313 e ATmega168, spiegherò i requisiti e le restrizioni che si applicano quando li usi e ti mostrerò esempi di dispositivi I2C funzionanti. Dopo aver elaborato questo Instructable, sarai in grado di utilizzare con successo il bus I2C nei tuoi progetti AVR. Ovviamente, puoi ignorare i driver per tiny o MEGA se sei interessato solo a uno di loro. Per coloro interessati a saperne di più sul bus I2C, fornirò collegamenti a materiale appropriato.

Passaggio 1: cos'è tutta questa roba I2C comunque?

Che cos'è tutta questa roba I2C comunque?
Che cos'è tutta questa roba I2C comunque?
Che cos'è tutta questa roba I2C comunque?
Che cos'è tutta questa roba I2C comunque?
Che cos'è tutta questa roba I2C comunque?
Che cos'è tutta questa roba I2C comunque?
Che cos'è tutta questa roba I2C comunque?
Che cos'è tutta questa roba I2C comunque?

Il bus I2C è una semplice connessione a due fili che può collegare più dispositivi insieme e consentire loro di scambiare dati. Nella sua forma più semplice c'è un dispositivo master che comunica con più dispositivi slave. Tutti i dispositivi sono collegati in parallelo ai due fili del bus I2C. I due fili sono noti come SCL e SDA. SCL è la linea di clock ed è controllata dal dispositivo master. SDA è la linea dati bidirezionale. Per trasferire i dati, il master invia un indirizzo slave combinato con un flag di lettura/scrittura di un bit. Se si desidera una scrittura, il master continuerà a inviare dati allo slave indirizzato. Se viene richiesta una lettura, lo slave risponderà con i dati. Per coordinare le transazioni, le linee SCL e SDA vengono manipolate dal master e dallo slave per segnalare diverse condizioni. Questi includono START, STOP, ACK (riconoscimento) e NAK (nessun riconoscimento). I dettagli di queste condizioni sono gestiti dai conducenti. I veri geek tra di voi possono imparare tutti i dettagli nei collegamenti forniti alla fine di questo Instructable. I requisiti elettrici sono piuttosto semplici. Il master e gli slave devono usare lo stesso livello per Vcc, le masse devono essere collegate e le linee SCL e SDA devono essere tirate fino a Vcc. Il valore dei resistori di pull-up è determinato con precisione da un calcolo basato sulla capacità totale sul bus, ma in pratica può essere praticamente qualsiasi valore compreso tra 1,8K e 10K. Comincio con 5.1K e uso valori più bassi finché non funziona. Questo di solito non è un problema a meno che non si disponga di molti dispositivi o di lunghi cavi tra i dispositivi. La velocità dati nominale sul bus I2C è di 100 Kbit/secondo. Sono possibili anche velocità di 400 Kbit/secondo, 1 Mbit/secondo e oltre, ma non sono supportate dai driver in questo Instructable. Tutti i dispositivi I2C funzioneranno a 100 Kbit/secondo. L'ATtiny2313 e l'ATmega168 implementano ciascuno il bus I2C in modo diverso. ATtiny2313 utilizza l'hardware Universal Serial Interface (USI), che può essere utilizzato anche per il bus SPI. ATmega168 dispone di hardware dedicato per il bus I2C noto come Two Wire Interface (TWI). Una volta scritti i driver, queste differenze sono per lo più trasparenti per l'utente. Una differenza significativa è nel software: il driver ATmega168 I2C è guidato da interrupt mentre quello per ATtiny2313 non lo è. Ciò significa che un programma ATmega168 non deve attendere che avvengano i trasferimenti di dati I2C, ma deve solo attendere prima di iniziare un altro trasferimento o finché i dati non arrivano da un'operazione di lettura. Gli esempi e la discussione da seguire dovrebbero chiarire questo punto. Gli indirizzi I2C sono lunghi 7 bit, quindi sul bus possono essere presenti fino a 127 dispositivi se ognuno ha un indirizzo univoco. Come mostrato in figura, questo indirizzo a 7 bit viene spostato a sinistra di un bit e il bit meno significativo viene utilizzato per contrassegnare una lettura o scrittura del dispositivo all'indirizzo. Quindi l'indirizzo completo dello slave è un byte di 8 bit. L'indirizzo effettivo è parzialmente determinato internamente al dispositivo e non può essere modificato (4 bit più significativi) e parzialmente determinato dai bit che possono essere collegati ai pin del dispositivo (3 bit meno significativi) che possono essere impostati in alto o in basso per impostare un indirizzo specifico. Sembra confuso, ma un esempio lo chiarirà. La scheda tecnica PCA8574A mostra che i quattro bit più significativi dell'indirizzo I2C saranno sempre 0111. I tre bit successivi sono determinati dalle impostazioni sui pin AD0, AD1 e AD2. Questi pin possono essere collegati a massa o all'alimentazione di tensione positiva (5 volt) per rappresentare rispettivamente 0 o 1. Quindi l'intervallo di indirizzi possibili va da 38 a 3F esadecimali, come mostrato nell'altra figura del foglio dati PCA8574. Quindi, modificando le impostazioni del bit di indirizzo, sul bus I2C possono essere contemporaneamente fino a 8 PCA8574A. Ciascuno risponderà solo al suo specifico indirizzo slave. Se sono necessarie ancora più porte I/O, è possibile utilizzare PCA8574. L'unica differenza tra il PCA8574 e il PCA8574A è che l'intervallo di indirizzi slave I2C del PCA8574 è compreso tra 20 e 27 esadecimali. La determinazione dell'indirizzo di un determinato dispositivo può creare confusione poiché alcuni data sheet considerano il bit di lettura/scrittura come parte del indirizzo. Leggere attentamente la scheda tecnica e tenere presente che l'indirizzo dello slave sarà lungo 7 bit. Il bit di lettura/scrittura deve essere trattato separatamente. Ancora una volta, un esempio aiuterà. Il datasheet della EEPROM 24C16 che sperimenteremo dice che i primi quattro bit (più significativi) dell'indirizzo slave sono 1010. I tre bit successivi possono essere determinati da A0, A1 e A2; ma si noti che la scheda tecnica copre anche da 24C01 a 24C08 che sono EEPROM di dimensioni più piccole. La figura della scheda tecnica mostra che le impostazioni di questi bit di indirizzo vengono ignorate all'aumentare della dimensione e vengono completamente ignorate per il 24C16. Cioè, gli ultimi tre bit non contano e il 24C16 usa davvero tutti gli indirizzi slave I2C da 50 a 57 esadecimali. L'intervallo di indirizzi slave indirizzerà effettivamente diverse sezioni all'interno del 24C16. I primi 256 byte sono all'indirizzo 50h, i successivi 256 alle 51h e così via fino agli ultimi 256 alle 57h, per un totale di 2K byte. Poiché l'indirizzo della RAM PCF8570 con cui sperimentiamo è compreso in questo intervallo, il 24C16 e il PCF8570 non possono essere utilizzati insieme.

Passaggio 2: ordina alcuni dispositivi I2C

Ora che conosci un po' il bus I2C e vuoi usarlo, perché non ordinare alcuni dispositivi I2C con cui sperimentare ora in modo che possano essere sulla strada per te mentre prepari il software? I dispositivi appropriati includono un I/ O Interface Expander (il mio preferito), una RAM statica e una EEPROM. C'è molto di più, ma questi sono un ottimo inizio. I processori AVR che utilizzeremo sono l'ATtiny2313 e l'Atmega168 (usato in Arduino). Se sei nuovo a questi, dai un'occhiata a questo fantastico Instructable per conoscerli e costruire il tuo sistema di sviluppo del ghetto. Lo schema dell'ATmega168 nel presente Instructable mostra come implementare il Ghetto Development System per questo processore. Il cavo della porta parallela è lo stesso di ATtiny2313. (Non ho provato la versione USB del Ghetto Development System, quindi non sono sicuro di come si accede al bus I2C su di esso. Lo stesso per Arduino.) Ecco i numeri di parte Digikey. Port Expander: IC I2C I/O EXPANDER 568-4236-5-NDRAM:IC SRAM 256X8 W/I2C 568-1071-5-NDEEPROM:IC EEPROM SERIALE 16K CAT24C16LI-G-ND

Passaggio 3: driver I2C

Ecco le descrizioni delle funzioni del driver per il bus I2C. Questi sono stati sviluppati utilizzando le note di Atmel Apps per i principianti. Non avrei potuto farlo senza di loro come base su cui costruire. Lo sviluppo è stato fatto utilizzando WinAVR e il compilatore C gcc. Di seguito sono descritte le limitazioni della frequenza di clock per ciascun processore. Dal momento che non sono in grado di testare tutte le combinazioni possibili di sapore del processore/frequenza di clock, mi limiterò a ciò che posso effettivamente testare e cercherò di indicare le restrizioni e le limitazioni. Ecco le funzioni del driver e come usarle. Si prega di guardare gli esempi per maggiori dettagli e per vedere le funzioni in uso nei programmi completi. Per ATtiny2313:Requisiti di clock:I driver sono progettati per una frequenza di clock di 1MHz (la frequenza predefinita) per ATtiny2313. Se vuoi correre ad altre velocità, dovrai regolare le costanti nei driver. Inviami un'e-mail se hai bisogno di aiuto per farlo. È inoltre possibile ottenere alcuni suggerimenti dalle note delle app Atmel nei collegamenti nella Fase delle risorse. USI_TWI_Master_Initialise() Questa funzione inizializza l'hardware USI per il funzionamento in modalità I2C. Chiamalo una volta all'inizio del tuo programma. Restituisce void e non ci sono argomenti. USI_TWI_Get_State_Info() Questa funzione restituisce informazioni sull'errore I2C e viene utilizzata se si è verificato un errore durante una transazione I2C. Poiché questa funzione restituisce solo un codice di errore, utilizzo la funzione TWI_Act_On_Failure_In_Last_Transmission(TWIerrorMsg) per far lampeggiare un LED di errore. I codici di errore sono definiti in USI_TWI_Master.h. Ecco come chiamarlo:TWI_Act_On_Failure_In_Last_Transmission(USI_TWI_Get_State_Info())USI_TWI_Start_Read_Write() Questa funzione viene utilizzata per leggere e scrivere singoli byte su dispositivi I2C. Viene anche utilizzato per scrivere più byte. Ci sono 6 passaggi per utilizzare questa funzione.1) Dichiarare un buffer di messaggi nel programma per contenere l'indirizzo dello slave e il byte di dati da inviare o ricevere. unsigned char messageBuf (MESSAGEBUF_SIZE);2)Inserisce l'indirizzo dello slave come primo byte nel buffer. Spostalo di un bit a sinistra e OR nel bit di lettura/scrittura. Notare che il bit di lettura/scrittura sarà 1 per una lettura e 0 per una scrittura. Questo esempio è per un Read. messageBuf(0) = (TWI_targetSlaveAddress<<TWI_ADR_BITS) | (TRUE<<TWI_READ_BIT); 3) Quando si esegue una scrittura, inserire il byte da scrivere nella posizione successiva nel buffer. 4) Richiamare la funzione USI_TWI_Start_Read_Write con il buffer del messaggio e la dimensione del messaggio come arguments.temp = USI_TWI_Start_Read_Write(messageBuf, 2);5)Il il valore restituito (temp in questo caso) può essere testato per vedere se si è verificato un errore. In tal caso, viene gestito come discusso sopra. Vedere esempi nei programmi.6)Se è stata richiesta una lettura, il byte letto sarà nella seconda posizione nel buffer. Se devono essere scritti più byte (ad esempio su un dispositivo di memoria), è possibile utilizzare questa stessa routine. L'impostazione del buffer e la chiamata della routine sono leggermente diverse. Il secondo byte nel buffer sarà l'indirizzo di memoria iniziale su cui scrivere. I dati da scrivere saranno nei byte successivi. La dimensione del messaggio sarà la dimensione che include tutti i dati validi. Quindi, se devono essere scritti 6 byte, la dimensione del messaggio sarà 8 (indirizzo slave + indirizzo di memoria + 6 byte di dati). USI_TWI_Start_Random_Read() Questa funzione viene utilizzata per leggere più byte da un dispositivo I2C, in genere è significativa solo per un ricordo di qualche tipo. L'utilizzo di questa routine è molto simile alla routine precedente, con due eccezioni. L'impostazione del bit di lettura/scrittura non ha importanza. La chiamata a questa routine causerà sempre un'operazione di lettura. La dimensione del messaggio dovrebbe essere 2 più il numero di byte da leggere. Se non si sono verificati errori, i dati saranno nel buffer a partire dalla seconda posizione. i driver sono progettati per una frequenza di clock di 4MHz per ATmega168. Il codice di esempio mostra come impostare questa frequenza di clock. Se vuoi correre ad altre velocità, dovrai regolare le costanti nei driver. Inviami un'e-mail se hai bisogno di farlo. TWI_Master_Initialise() Questa funzione inizializza l'hardware TWI per il funzionamento in modalità I2C. Chiamalo una volta all'inizio del tuo programma. Restituisce void e non ci sono argomenti. Assicurati di abilitare gli interrupt chiamando swi() dopo l'inizializzazione. TWI_Get_State_Info() Questa funzione restituisce informazioni sull'errore I2C e viene utilizzata se si è verificato un errore durante una transazione I2C. Poiché questa funzione restituisce solo un codice di errore, utilizzo la funzione TWI_Act_On_Failure_In_Last_Transmission(TWIerrorMsg) per far lampeggiare un LED di errore. I codici di errore sono definiti in TWI_Master.h, ma vengono modificati per la segnalazione su un LED di errore. Vedere il codice di esempio per i dettagli. Ecco come chiamarlo:TWI_Act_On_Failure_In_Last_Transmission(TWI_Get_State_Info())Si noti che il controllo degli errori viene eseguito assicurandosi che la transazione I2C sia completa (funzione descritta di seguito) e quindi testando un po' nella parola di stato globale. TWI_Start_Read_Write()TWI_Start_Thesendom_Read() due funzioni funzionano come le funzioni corrispondenti descritte sopra ma con alcune eccezioni. Non restituiscono alcun valore di errore. I dati letti non vengono trasferiti nel buffer. Fare questo sarà fatto con la funzione descritta di seguito. Quando si chiama TWI_Start_Random_Read, il messageSize dovrebbe essere il numero di byte di dati richiesti più uno, non due. Il driver I2C per l'ATmega168 è guidato da interrupt. Cioè, le transazioni I2C vengono avviate e quindi eseguite in modo indipendente mentre la routine principale continua a essere eseguita. Quando la routine principale richiede dati da una transazione I2C che ha avviato, deve verificare se i dati sono disponibili. La situazione è la stessa per il controllo degli errori. La routine principale deve assicurarsi che la transazione I2C sia completa prima di verificare la presenza di errori. Le prossime due funzioni vengono utilizzate per questi scopi. TWI_Transceiver_Busy() Chiama questa funzione per vedere se una transazione I2C è completa prima di controllare gli errori. I programmi di esempio mostrano come utilizzare this. TWI_Read_Data_From_Buffer() Chiama questa funzione per trasferire i dati dal buffer di ricezione del driver I2C nel buffer dei messaggi. Questa funzione assicurerà che la transazione I2C sia completa prima di trasferire i dati. Mentre un valore viene restituito da questa funzione, trovo che controllare direttamente il bit di errore sia più affidabile. Ecco come chiamarlo. La dimensione del messaggio deve essere uno maggiore del numero di bit di dati desiderati. I dati saranno in messageBuf a partire dalla seconda location.temp = TWI_Read_Data_From_Buffer(messageBuf, messageSize);

Passaggio 4: costruiamo

Costruiamo!
Costruiamo!
Costruiamo!
Costruiamo!
Costruiamo!
Costruiamo!
Costruiamo!
Costruiamo!

Inizia scaricando il file I2C Schematics.zip. Potresti voler creare una cartella I2C nella tua area di lavoro per contenere gli schemi e i file di programma di esempio. Decomprimi gli schemi in questa directory. Troverai una cartella chiamata Schemi I2C. Apri il file chiamato tiny I2C.pdf. Questo schema mostra il sistema di sviluppo del ghetto ATtiny2313 e l'espansione della porta I/O PCA8574A (ha il grande riquadro tratteggiato intorno). Il circuito Port Expander è costruito su una breadboard. Dai un'occhiata alle foto per vedere come sono questi circuiti. Sono davvero piuttosto semplici. La parte ATtiny2313 dello schema è solo il Ghetto Development System con tre lampeggianti (LED1, 2 e 3, più R4, 5 e 6) e un pulsante (S1) agganciato ad esso, più uno dettaglio aggiuntivo. Quel dettaglio è l'aggiunta di ponticelli (JP4, 5 e 6) che possono essere rimossi per consentire il collegamento delle linee SCL e SDA del bus I2C. I ponticelli devono essere in posizione per la programmazione, quindi rimossi in modo che SCL e SDA possano essere collegati. Le foto mostrano i ponticelli in posizione e rimossi. Il posizionamento di questi jumper dipende da te, devi solo metterli sul tuo Ghetto Development System se vuoi usare il bus I2C. Il bus I2C deve essere scollegato e devono essere inseriti i ponticelli per la programmazione. Nota che devi preoccuparti solo di JP4 e JP6 per il bus I2C. Inserisci JP5 se pensi di voler utilizzare il bus SPI. Il breadboarding del PCA8574A I/O Port Expander è molto semplice. Fornire connessioni Vcc (+5 volt) e Gnd (massa) e collegare AD0, 1 e 2 a terra (rende l'indirizzo slave I2C 38 esadecimale). Quindi collegare 4 lampeggianti e 4 interruttori DIP. (Se non si dispone di interruttori DIP, è possibile utilizzare semplicemente i cavi. Collegare a terra o lasciare flottante per attivare o disattivare rispettivamente il segnale.) Infine, collegare i resistori di pull-up (R11 e 12) da SDA e SCL a Vcc. Questi sono mostrati come 3.3K, ma qualsiasi valore da 1.8K a 5.1K dovrebbe funzionare (forse fino a 10K ma non l'ho provato). Una volta programmato l'ATtiny2313, è possibile rimuovere i ponticelli e collegare SDA e SCL per il test. Ora per l'ATmega168. L'unica pecca qui è che potresti non aver costruito un Ghetto Development System per questo processore. In tal caso, lo schema che fornisco (MEGA I2C.pdf) ti mostrerà come. Questa è solo una permutazione della versione ATtiny2313. Se pianifichi in anticipo, puoi assicurarti che il cavo di programmazione si adatti a entrambi i sistemi. La differenza principale è l'aggiunta di C2 e C3. Guarda le immagini per il posizionamento di questi, dovrebbero essere molto vicini al chip; uno di loro è in realtà sotto il chip. Questi aiutano a mantenere il rumore fuori dal convertitore analogico-digitale in particolare. Non è necessario inserire i ponticelli a meno che non si preveda di utilizzare il bus SPI poiché non sono necessari per il bus I2C su questo chip. Si noti che la breadboard PCA8754A rimarrà invariata. Collegherai solo SDA e SCL e via! Facile, eh?

Passaggio 5: codice e test

Codifichiamo e testiamo!
Codifichiamo e testiamo!
Codifichiamo e testiamo!
Codifichiamo e testiamo!
Codifichiamo e testiamo!
Codifichiamo e testiamo!

È il momento di creare i driver ei programmi di esempio. Inizieremo con l'ATtiny2313 e la breadboard PCA8574A che abbiamo appena costruito. Scarica il file I2C.zip nella directory di lavoro di I2C e decomprimilo. Avrai una nuova cartella chiamata I2C. In esso troverai USI I2C (per ATtiny2313) e TWI I2C (per ATmega168). In USI I2C troverai la cartella I_O Port. Quella cartella contiene il codice per il nostro primo programma di esempio e i driver USI I2C. Usando WinAVR, compila e carica il codice nell'ATtiny2313. Fai un respiro profondo e accendi la corrente. Ecco cosa aspettarsi: all'accensione, il LED 1 sulla porta PD6 dell'ATtiny2313 lampeggia due volte. Non succederà altro finché non si preme il pulsante (S1). Ogni volta che si preme il pulsante, gli interruttori vengono letti e la loro impostazione verrà visualizzata sui LED collegati al PCA8574A. Modificare il valore degli interruttori, premere il pulsante e i LED dovrebbero cambiare. Continua a farlo finché non superi l'emozione di vederlo funzionare. Se (Dio non voglia!) le cose non funzionano come previsto, controlla attentamente il cablaggio. Gli errori I2C saranno segnalati dai lampeggi del LED3 (PD4) e probabilmente significano che è necessario verificare che SDA e SCL siano collegati ai pin corretti e siano correttamente sollevati. Se le cose continuano a non funzionare, leggi il resto di questa sezione per informazioni sul debug. Ora torna indietro e diamo un'occhiata al codice. Apri il file USI_I2C_Port.c. Questo è il codice per il programma di esempio. (USI_TWI_Master.c e USI_TWI_Master.h contengono i driver - puoi ignorarli a meno che tu non sia curioso.) Usa l'esempio per guidare le tue applicazioni I2C. Principalmente, il programma mostra come inizializzare e utilizzare i driver I2C, inclusa l'impostazione l'indirizzo dello slave e il resto del buffer dei messaggi e ricavarne i dati. Vedrai anche come rimbalzare il pulsante e impostare il ciclo while. Ci sono alcuni dettagli del programma che vale la pena menzionare. Notare che i dati dagli switch vengono invertiti prima di essere scritti sui LED del Port Expander. Si noti inoltre che le porte di ingresso sul Port Expander devono essere scritte come High per farle funzionare correttamente. Questi dettagli sono descritti nella scheda tecnica PCA8574A. Leggere sempre attentamente le schede tecniche! Di maggiore interesse è l'uso del debug condizionale. Vicino all'inizio del file di programma c'è l'istruzione //#define DEBUG e sparse nel codice ci sono le istruzioni #ifdef DEBUG. Finché DEBUG non è definito (le due barre rendono la riga un commento e impediscono che venga definita), il codice all'interno delle istruzioni da #ifdef a #endif non verrà compilato. Ma se le cose non funzionano come previsto, ricompila e ricarica il codice con #define DEBUG senza commento. Otterrai molti più lampeggi sui LED che puoi decodificare per seguire l'esecuzione del tuo programma e aiutarti a trovare esattamente dove le cose vanno male. In effetti, ti consiglio di provare questo solo per vedere cosa succede. Quello che vedrai è che il LED 2 (su PD5) lampeggerà mentre l'esecuzione procede attraverso il programma. Il valore letto dagli switch lampeggerà sul LED 1 (PD6) prima di essere visualizzato sui LED del Port Expander. Dovresti essere in grado di monitorare il programma mentre viene eseguito utilizzando questi LED. Lavoreremo con l'ATmega168; salta questa sezione se sei interessato solo all'ATtiny2313. Ancora con me? Bene. Spostati nella cartella TWI_I2C, cambia la tua directory di lavoro in IO_Port e compila e carica TWI_I2C_Port.c in ATmega168. Scollegare le linee SDA e SCL dall'ATtiny2313 e collegarle all'ATmega168. Collega l'alimentazione e la messa a terra e accendi. L'operazione dovrebbe essere la stessa! Gioca finché il brivido non si placa, quindi diamo un'occhiata al codice. Apri TWI_I2C_Port.c. Il codice è quasi identico tranne che per la gestione degli errori e l'adattamento dei driver guidati dagli interrupt. Ecco le differenze: si noti che l'orologio deve essere impostato su 4 MHz affinché il bus I2C funzioni correttamente. Il se(); L'istruzione attiva gli interrupt dopo l'inizializzazione dei driver I2C. Per verificare la presenza di errori, viene testato un bit di stato specifico. Durante una lettura, è necessario richiamare la funzione TWI_Read_Data_From_Buffer per trasferire i dati letti nel buffer dei messaggi. Durante una scrittura, è necessario utilizzare while (TWI_Transceiver_Busy()) per assicurarsi che il trasferimento sia completo prima di verificare la presenza di errori. Queste ultime due funzioni sono descritte sopra nella descrizione dei driver. A parte questo, il codice è praticamente lo stesso di ATtiny2313. DEBUG funziona allo stesso modo anche se vuoi sperimentarlo.

Passaggio 6: utilizzo della memoria I2C

Utilizzo della memoria I2C
Utilizzo della memoria I2C
Utilizzo della memoria I2C
Utilizzo della memoria I2C
Utilizzo della memoria I2C
Utilizzo della memoria I2C
Utilizzo della memoria I2C
Utilizzo della memoria I2C

Ora che abbiamo imparato ad usare il bus I2C per leggere e scrivere un I/O Port Expander, passiamo all'utilizzo delle memorie I2C, sia RAM che EEPROM. La differenza principale è che più byte possono essere letti o scritti dalle memorie con un singolo comando I2C. Per prepararci a questi esperimenti, dobbiamo modificare leggermente l'hardware e costruire un paio di nuovi circuiti sulla breadboard. Mantieni il circuito Port Expander poiché lo useremo per visualizzare alcuni valori di memoria. Rimuovere gli interruttori DIP dal PCA8574A e mettere le luci lampeggianti su quei pin. Se non hai abbastanza luci lampeggianti, sposta quelle da P4 a P7 da P0 a P3. (I valori da visualizzare sono abbastanza piccoli.) Ora guarda lo schema I2C Ram.pdf e collega il PCF8570 alla breadboard. Dai un'occhiata anche alla foto. Assicurati di legare il pin 7 a Vcc. Eseguire i cavi per SDA e SCL dal PCA8574A. Non sono necessarie resistenze di pull-up aggiuntive. Se sei interessato anche alla EEPROM, costruisci quel circuito anche usando I2C EEPROM.pdf per il 24C16, ma tieni presente che l'esempio utilizza l'ATmega168. Questo circuito è davvero semplice. Come discusso in precedenza, i bit di indirizzo dovrebbero essere ignorati. Basta collegare l'alimentazione e la messa a terra. Non collegare ancora SDA e SCL poiché non abbiamo ancora finito di sperimentare con la Ram. Inizieremo i nostri esperimenti di memoria con l'ATtiny2313 collegato al Port Expander PCA8574A e al PCF8570 Ram. Il programma scriverà alcuni numeri sulla RAM, quindi li leggerà e li visualizzerà sul Port Expander. Cambia la tua directory di lavoro in RAM sotto USI I2C. Usa il file make per compilare e scaricare USI_I2C_RAM.c. Nota che i file del driver I2C sono identici a quelli che abbiamo usato in precedenza. Collega l'alimentazione e dovresti vedere un singolo lampeggio sul LED 1 (PD6). I dati verranno scritti nei primi 4 byte di memoria. Premere il pulsante e verranno riletti e visualizzati due byte. Dovresti vedere una luce LED sul Port Expander (P0), una pausa di due secondi, quindi due LED (P0 e P1). Altri due secondi di pausa e i LED dovrebbero spegnersi. Premere di nuovo il pulsante per ricominciare la sequenza. Il debug è simile al metodo descritto sopra. Diamo un'occhiata al codice. Apri USI_I2C_RAM.c. Dovrebbe essere abbastanza simile al codice precedente. Le principali differenze sono i dettagli di lettura e scrittura della memoria. Guarda come viene caricato il buffer dei messaggi prima della chiamata che esegue effettivamente la scrittura. Il primo byte è l'indirizzo dello slave con il bit di lettura/scrittura impostato in modo appropriato. Ma il byte successivo è l'indirizzo di memoria da cui iniziare a scrivere i dati. Quindi vengono i byte di dati effettivi che verranno caricati in sequenza in memoria a partire dall'indirizzo specificato. Specifichiamo la dimensione del messaggio come 6. Quindi iniziamo a scrivere all'indirizzo 00 e scriviamo i valori 01, 03, 02 e 06 nelle locazioni di memoria da 00 a 03. Per rileggere i dati dalla memoria dobbiamo usare la funzione USI_TWI_Start_Random_Read. Il buffer dei messaggi ottiene l'indirizzo slave nel primo byte e l'indirizzo iniziale nel secondo byte. Quindi chiamare la funzione con la dimensione del messaggio impostata sul numero di byte da leggere più 2. Si noti che il bit di lettura/scrittura non ha importanza poiché una lettura verrà eseguita a prescindere. I dati restituiti inizieranno nella seconda posizione nel buffer dei messaggi. Una volta che i dati sono stati letti, vengono invertiti per la visualizzazione sul Port Expander e scritti un byte alla volta con una pausa tra i valori. Infine, i LED di Port Expander sono spenti. Le scritture sul Port Expander sono identiche a quanto fatto negli esempi precedenti. Per divertimento, puoi decommentare l'istruzione #define DEBUG come sopra e vedere molti LED lampeggianti. Accesi dall'eccitazione dopo un altro esperimento riuscito, passiamo all'ATmega168 e a una EEPROM. Cambia la tua directory di lavoro in EEPROM sotto TWI I2C. Usa il file make per compilare e scaricare TWI_I2C_EEPROM.c. Si noti che i file del driver I2C sono identici a quelli utilizzati in precedenza per PCA8574A. Per testare il programma, scollegare l'ATtiny2313 e collegare l'ATmega168. Lascia il bus I2C agganciato alla Ram e accendi. I risultati sono diversi poiché ora stiamo scrivendo e leggendo più dati. Il LED 1 su PD7 dovrebbe lampeggiare all'inizializzazione. Premendo il pulsante i dati verranno riletti dalla memoria e visualizzati. I LED sul PCA8574 dovrebbero lampeggiare nella seguente sequenza: P1, P0 e P2, (tutti spenti), P0 e P1, P1 e P2. Alla fine i LED della porta dovrebbero spegnersi tutti. Premi di nuovo il pulsante per ripetere questo. Oh, ma aspetta, dici. Questo programma non è per la EEPROM? Poiché stiamo accedendo a un dispositivo di memoria allo stesso indirizzo I2C, lo stesso programma funziona sia per la Ram che per l'EEPROM. Spegnere e spostare SDA e SCL dalla Ram alla EEPROM ed eseguire nuovamente il programma. Dovrebbe funzionare esattamente lo stesso. Si noti che la EEPROM e la Ram non possono essere collegate contemporaneamente al bus I2C poiché condividono lo stesso indirizzo. (I più intelligenti tra di voi potrebbero considerare di cambiare i bit di indirizzo programmabili sulla Ram, ma ciò non funzionerà comunque. Il 24C16 utilizza l'intero blocco di indirizzi che possono essere programmati per la Ram.) OK, diamo un'occhiata a quest'ultimo programma. Apri TWI_I2C_EEPROM.c. La prima cosa da notare è che ho indicato come indirizzare l'intera EEPROM 24C16. È possibile accedervi in blocchi di 256 byte a 8 diversi indirizzi slave I2C. Guarda come MEMORY_ADDR è definito come indirizzo iniziale a 50 esadecimali; ecco perché il Ram ha funzionato. Se vuoi accedere ad altri blocchi del 24C16, usa gli altri indirizzi come ti ho indicato. Dai un'occhiata a come ho impostato per scrivere nella memoria. Prima viene inserito nel buffer l'indirizzo dello slave con il bit di lettura/scrittura impostato, quindi l'indirizzo iniziale di 00, quindi 16 byte di dati. Viene chiamata la funzione TWI_Start_Read_Write per scrivere i dati (come prima) con la dimensione del messaggio impostata su 18. Quando si preme il pulsante, si utilizzano TWI_Start_Random_Read e TWI_Read_Data_From_Buffer per rileggere i dati. Ogni terzo byte viene visualizzato sui LED di Port Expander. Infine, i LED si spengono in attesa della successiva pressione del pulsante. Potresti chiederti perché ho scelto di scrivere 16 byte. Se leggi attentamente la scheda tecnica, vedrai che il 24C16 esegue un ciclo di scrittura ogni volta che riceve 16 byte anche se ne vengono inviati più byte. Quindi sembrava un bel numero da usare. Se scegli di aumentarlo, dovrai modificare la dimensione di MESSAGEBUF_SIZE. Dovrai anche modificare il valore TWI_BUFFER_SIZE in TWI_Master.h. Ciò è dovuto al fatto che il driver copia i dati dal buffer dei messaggi per l'utilizzo da parte della routine del servizio di interrupt. Congratulazioni! Ora sei pronto per utilizzare il bus I2C nei tuoi progetti!

Passaggio 7: risorse Web

Di seguito i link alle schede tecniche delle parti utilizzate per gli esperimenti. Dovresti assolutamente prenderli se non ottieni nient'altro. Port ExpanderRamEEPROM Essendo il creatore di I2C, NXP (Philips) ha un sacco di cose fantastiche. (A loro piace usare le parentesi quadre nei loro URL, quindi non posso includerli correttamente qui. Mi dispiace.] Per accedere all'area I2C, seleziona Interfaccia dall'elenco Prodotti. Sarai in grado di accedere al loro sito I2C e accesso a tutte le schede tecniche e le note delle app che offrono. La descrizione del bus I2C e i dettagli tecnici in particolare sono qui. Ottieni le schede tecniche ATtiny2313 e ATmega168 (libri dati?) da Atmel. Le note applicative Atmel sono qui. Guarda AVR310 e AVR315. Prendi anche il codice. Dai un'occhiata qui per molte altre cose I2C.

Passaggio 8: note per geek

Per il vero geek che vuole conoscere i dettagli, ecco alcune cose da tenere a mente se guardi le note delle app Atmel e il codice del driver: - Il metodo di indirizzamento e comando di un dispositivo I2C non fa parte delle specifiche! Oltre all'indirizzo dello slave e al bit di lettura/scrittura, i comandi, le modalità, ecc. non sono specificati e sono specifici di un dato dispositivo. Per chiarire questo aspetto, si noti che lo schema utilizzato nell'esempio Atmel si applica solo a quell'esempio ed è praticamente non standard. L'implementazione USI differisce dall'implementazione TWI in alcuni importanti aspetti. + Con USI, il clock è fornito dal software; con TWI è fornito da un Bit Rate Generator. + Il metodo USI non utilizza gli interrupt; il TWI lo fa. Questo ha un certo senso poiché la famiglia Mega (usando TWI) potrebbe fare molte altre cose e non dovrebbe essere monopolizzata dai trasferimenti I2C. Una versione basata su interrupt per USI è certamente possibile, ma non è implementata in questo Instructable. + L'hardware USI non è ottimizzato per I2C e può gestire solo trasferimenti a 8 bit. Ciò significa che sono necessari due trasferimenti per inviare il nono bit (NACK o ACK). L'hardware TWI lo gestisce automaticamente. Questo rende l'implementazione del driver USI un po' più complicata. + Il rilevamento degli errori per TWI è gestito nell'hardware. L'USI richiede una gestione del software che complica un po' le cose. + L'hardware TWI controlla direttamente la configurazione della porta. L'hardware USI richiede che i bit della porta siano configurati prima che la porta possa essere utilizzata. Lo vedrai nella routine Master_Initialize per l'USI.- Atmel afferma che è possibile utilizzare i pull-up della porta AVR per i pull-up del bus I2C. Non ho trovato un modo per far funzionare questo approccio. L'uso di due resistori esterni sembra uno schema piuttosto semplice, quindi non ho dedicato molto tempo a questo.

Consigliato: