Cuprins:

Autobuz I2C pentru ATtiny și ATmega: 8 pași
Autobuz I2C pentru ATtiny și ATmega: 8 pași

Video: Autobuz I2C pentru ATtiny și ATmega: 8 pași

Video: Autobuz I2C pentru ATtiny și ATmega: 8 pași
Video: LDmicro 14: I2C LCD & DS3231 Real-Time Clock (Microcontroller PLC Ladder Programming with LDmicro) 2024, Iulie
Anonim
Autobuz I2C pentru ATtiny și ATmega
Autobuz I2C pentru ATtiny și ATmega

Îmi plac microcontrolerele Atmel AVR! De când am construit sistemul de dezvoltare a ghetoului descris în acest instructabil, nu am avut sfârșit de distracție experimentând cu AVR ATtiny2313 și ATmega168 în special. Am mers chiar atât de departe încât am scris un Instructable privind utilizarea comutatoarelor ca intrări și am extins conceptul Ghetto Development System la CPLD-uri. În timpul unui proiect recent, aveam nevoie de mai multe comutatoare pentru setarea valorilor de control. AVR-urile nu aveau suficiente pini I / O, așa că a trebuit să mă gândesc la ceva. Aș fi putut încerca un sistem de intrare complex cu tastatură și afișaj, dar ATtiny2313 ar fi epuizat resursele. Din fericire, Atmel a oferit o cale de rezolvare a acestei probleme prin includerea unei interfețe care se poate conecta la cipuri suplimentare (cum ar fi porturi de memorie sau I / O) cu o interfață simplă cu două fire. Așa este, folosind doar doi pini I / O pe un AVR, putem accesa multe pini I / O suplimentare și, de asemenea, alte resurse. Această interfață cu două fire este cunoscută formal sub numele de magistrală de circuite inter-integrate sau doar magistrala I2C și a fost inventată de NXP când încă era Philips Semiconductors. Dacă citiți acest Instructable, probabil că ați auzit de autobuzul I2C și poate că l-ați folosit chiar și pe un PIC sau alt microcontroler. Deși din punct de vedere conceptual sunt foarte simple și sunt susținute de resurse hardware de pe AVR-uri, driverele software sunt încă necesare pentru a utiliza magistrala I2C. Atmel furnizează Note de aplicație (consultați Resursele mai târziu în acest Instructable), dar acestea sunt incomplete și nu prezintă exemple dincolo de comunicarea cu un alt dispozitiv AVR. AVR-uri. Mai degrabă, voi oferi versiuni extinse ale driverelor Atmel pentru dispozitivele ATtiny2313 și ATmega168, voi explica cerințele și restricțiile care se aplică atunci când le utilizați și vă voi arăta exemple de lucru ale dispozitivelor I2C. După ce veți trece prin acest Instructable, veți putea folosi autobuzul I2C cu succes în proiectele dvs. AVR. Evident, puteți ignora driverele pentru mici sau MEGA dacă sunteți interesat doar de unul dintre ele. Pentru cei interesați să afle mai multe despre autobuzul I2C, vă voi oferi linkuri către materialele adecvate.

Pasul 1: Ce este oricum toate aceste lucruri I2C?

Oricum, ce sunt toate aceste lucruri I2C?
Oricum, ce sunt toate aceste lucruri I2C?
Oricum, ce sunt toate aceste lucruri I2C?
Oricum, ce sunt toate aceste lucruri I2C?
Oricum, ce sunt toate aceste lucruri I2C?
Oricum, ce sunt toate aceste lucruri I2C?
Oricum, ce sunt toate aceste lucruri I2C?
Oricum, ce sunt toate aceste lucruri I2C?

Autobuzul I2C este o conexiune simplă, cu două fire, care poate lega mai multe dispozitive împreună și le permite să facă schimb de date. În forma sa cea mai simplă, există un dispozitiv master care comunică cu mai multe dispozitive slave. Toate dispozitivele sunt conectate în paralel cu cele două fire ale magistralei I2C. Cele două fire sunt cunoscute sub numele de SCL și SDA. SCL este linia de ceas și este controlată de dispozitivul master. SDA este linia de date bidirecțională. Pentru a transfera date, masterul trimite o adresă slave combinată cu un indicator de citire / scriere pe un bit. Dacă se dorește o scriere, masterul va continua să trimită date către sclavul adresat. Dacă se solicită o citire, sclavul va răspunde cu date. Pentru a coordona tranzacțiile, liniile SCL și SDA sunt manipulate de către comandant și sclav pentru a semnaliza mai multe condiții. Acestea includ START, STOP, ACK (confirmare) și NAK (fără confirmare). Detaliile acestor condiții sunt gestionate de șoferi. Adevărații geeks dintre voi pot afla toate detaliile în linkurile furnizate la sfârșitul acestui instructabil. Cerințele electrice sunt destul de simple. Maestrul și sclavii trebuie să utilizeze același nivel pentru Vcc, terenurile trebuie să fie conectate, iar liniile SCL și SDA trebuie să fie trase la Vcc. Valoarea rezistențelor de tracțiune este determinată cu precizie de un calcul bazat pe capacitatea totală pe autobuz, dar practic poate fi aproape orice valoare între 1,8K și 10K. Încep cu 5.1K și folosesc valori mai mici până când funcționează. De obicei, aceasta nu este o problemă, cu excepția cazului în care aveți o mulțime de dispozitive sau o lungime de cablu între dispozitive. Rata nominală de date pe magistrala I2C este de 100 KB / secundă. Tarifele de 400 KB / secundă, 1 Mb / secundă și mai mult sunt posibile, dar nu sunt acceptate de driverele din acest manual. Toate dispozitivele I2C vor funcționa la 100 Kbits / secundă. ATtiny2313 și ATmega168 implementează fiecare magistrala I2C diferit. ATtiny2313 utilizează hardware-ul Universal Serial Interface (USI) - care poate fi utilizat și pentru magistrala SPI. ATmega168 are hardware dedicat pentru magistrala I2C cunoscută sub numele de interfață cu două fire (TWI). Odată ce driverele sunt scrise, aceste diferențe sunt în mare parte transparente pentru utilizator. O diferență semnificativă este în software: Driverul ATmega168 I2C este întrerupt, în timp ce cel pentru ATtiny2313 nu este. Aceasta înseamnă că un program ATmega168 nu trebuie să aștepte ca transferurile de date I2C să aibă loc, ci trebuie să aștepte doar înainte de a iniția un alt transfer sau până când sosesc datele dintr-o operație de citire. Exemplele și discuțiile de urmat ar trebui să clarifice acest lucru: adresele I2C au o lungime de 7 biți, astfel încât până la 127 de dispozitive pot fi pe autobuz dacă fiecare are o adresă unică. Așa cum se arată în figură, această adresă de 7 biți este deplasată la stânga cu un bit, iar bitul cel mai puțin semnificativ este utilizat pentru a semnaliza o citire sau scriere a dispozitivului la adresă. Astfel, adresa slave completă este un octet de 8 biți. Adresa reală este parțial determinată intern la dispozitiv și nu poate fi modificată (4 biți cei mai semnificativi) și parțial determinată de biții care pot fi conectați la pinii dispozitivului (3 biți cel mai puțin semnificativi) care pot fi legați în sus sau în jos pentru a seta o adresă specifică. Sună confuz, dar un exemplu va clarifica acest lucru. Fișa de date PCA8574A arată că cei mai importanți patru biți ai adresei I2C vor fi întotdeauna 0111. Următorii trei biți sunt determinați de setările de pe pinii AD0, AD1 și AD2. Acești pini pot fi legați la masă sau la sursa de tensiune pozitivă (5 volți) pentru a reprezenta 0 sau respectiv 1. Deci, gama de adrese posibile este de 38 până la 3F hexazecimală, așa cum se arată în cealaltă figură din foaia de date PCA8574. Deci, modificând setările pentru bitul de adresă, până la 8 PCA8574A pot fi pe magistrala I2C în același timp. Fiecare va răspunde numai la adresa sa sclavă specifică. Dacă sunt necesare și mai multe porturi I / O, poate fi utilizat PCA8574. Singura diferență dintre PCA8574 și PCA8574A este că gama de adrese slave I2C a PCA8574 este de 20 până la 27 hexazecimală. Determinarea adresei unui dispozitiv dat poate fi confuză, deoarece unele foi de date consideră că bitul de citire / scriere face parte din abordare. Citiți cu atenție foaia de date și rețineți că adresa sclavului va avea 7 biți lungime. Bitul de citire / scriere ar trebui tratat separat. Din nou, un exemplu vă va ajuta. Fișa de date pentru EEPROM 24C16 cu care vom experimenta spune că primii (cei mai semnificativi) patru biți ai adresei slave sunt 1010. Următorii trei biți pot fi determinați de A0, A1 și A2; dar rețineți că fișa tehnică acoperă și 24C01 până la 24C08, care sunt EEPROM-uri de dimensiuni mai mici. Figura din foaia de date arată că setările acestor biți de adresă sunt ignorate pe măsură ce dimensiunea crește și sunt complet ignorate pentru 24C16. Adică, ultimii trei biți nu contează și 24C16 folosește cu adevărat toate adresele slave I2C de la 50 la 57 hexazecimale. Gama de adrese slave va aborda de fapt diferite secțiuni din 24C16. Primii 256 de octeți sunt la adresa 50h, următorii 256 la 51h și așa mai departe până la ultimii 256 la 57h - pentru un total de 2K octeți. Deoarece adresa RAM-ului PCF8570 cu care experimentăm este și în acest interval, 24C16 și PCF8570 nu pot fi utilizate împreună.

Pasul 2: Comandați câteva dispozitive I2C

Acum, că știți puțin despre autobuzul I2C și doriți să-l utilizați, de ce să nu comandați unele dispozitive I2C cu care să experimentați acum, astfel încât să poată fi pe drum în timp ce pregătiți software-ul? Dispozitivele adecvate includ un I / O Interface Expander (preferatul meu), un Ram static și o EEPROM. Mai sunt multe, dar acestea sunt un început minunat. Procesoarele AVR pe care le vom folosi sunt ATtiny2313 și Atmega168 (utilizate în Arduino). Dacă sunteți nou în acest domeniu, atunci aruncați o privire la acest instructabil minunat pentru a afla mai multe despre ele și pentru a vă construi sistemul de dezvoltare Ghetto. Schema ATmega168 din prezentul Instructable arată cum să implementăm Ghetto Development System pentru acest procesor. Cablul portului paralel este același cu cel pentru ATtiny2313. (Nu am încercat versiunea USB a Ghetto Development System, deci nu sunt sigur cum este accesat autobuzul I2C pe acesta. Același lucru pentru Arduino.) Iată numerele de piese Digikey. Extensor de port: IC I2C I / O EXPANDER 568-4236-5-NDRam: IC SRAM 256X8 W / I2C 568-1071-5-NDEEPROM: IC EEPROM SERIAL 16K CAT24C16LI-G-ND

Pasul 3: Drivere I2C

Iată descrierile funcțiilor driverului pentru magistrala I2C. Acestea au fost dezvoltate folosind Atmel Apps Notes pentru începători. Nu aș fi putut face acest lucru fără ele ca bază pe care să construiesc. Dezvoltarea a fost făcută folosind WinAVR și compilatorul gcc C. Restricțiile privind rata de ceas sunt descrise mai jos pentru fiecare procesor. Deoarece nu sunt capabil să testez toate combinațiile de arome ale procesorului / rata de ceas posibilă, voi rămâne doar la ceea ce pot testa de fapt și voi încerca să indic restricțiile și limitările. Iată funcțiile driverului și cum să le folosesc. Vă rugăm să consultați exemplele pentru mai multe detalii și pentru a vedea funcțiile utilizate în programele complete. Pentru ATtiny2313: Cerința ceasului: Driverele sunt proiectate pentru o rată de ceas de 1MHz (rata implicită) pentru ATtiny2313. Dacă doriți să rulați la alte rate, va trebui să ajustați constantele din drivere. Trimiteți-mi un e-mail dacă aveți nevoie de ajutor pentru a face acest lucru. De asemenea, puteți obține câteva sugestii din notele aplicațiilor Atmel din linkurile din Pasul Resurse. USI_TWI_Master_Initialise () Această funcție inițializează hardware-ul USI pentru funcționarea modului I2C. Sunați-l o dată la începutul programului. Se returnează nul și nu există argumente. Deoarece această funcție returnează doar un cod de eroare, folosesc funcția TWI_Act_On_Failure_In_Last_Transmission (TWIerrorMsg) pentru a aprinde un LED de eroare. Codurile de eroare sunt definite în USI_TWI_Master.h. Iată cum să-l numim: TWI_Act_On_Failure_In_Last_Transmission (USI_TWI_Get_State_Info ()) USI_TWI_Start_Read_Write () Această funcție este utilizată pentru citirea și scrierea de octeți singuri pe dispozitivele I2C. De asemenea, este folosit pentru a scrie mai mulți octeți. Există 6 pași pentru utilizarea acestei funcții. 1) Declarați un buffer de mesaje în programul dvs. pentru a păstra adresa slave și octetul de date care trebuie trimis sau primit. unsigned char messageBuf (MESSAGEBUF_SIZE); 2) Puneți adresa Slave ca primul octet în buffer. Deplasați-l cu un bit la stânga și SAU în bitul de citire / scriere. Rețineți că bitul de citire / scriere va fi 1 pentru o citire și 0 pentru o scriere. Acest exemplu este pentru o citire. messageBuf (0) = (TWI_targetSlaveAddress << TWI_ADR_BITS) | (ADEVĂRAT << TWI_READ_BIT); 3) Când efectuați o Scriere, puneți octetul care urmează să fie scris în următoarea locație din buffer. valoarea returnată (temp în acest caz) poate fi testată pentru a vedea dacă a apărut o eroare. Dacă da, se tratează așa cum s-a discutat mai sus. Vedeți exemple în programe. 6) Dacă a fost solicitată o citire, citirea octeților va fi în a doua locație din buffer. Dacă se vor scrie mai mulți octeți (cum ar fi pe un dispozitiv de memorie), poate fi utilizată aceeași rutină. Configurarea bufferului și apelarea rutinei sunt ușor diferite. Al doilea octet din buffer va fi adresa de memorie de pornire la care să scrieți. Datele care vor fi scrise vor fi în octeți ulteriori. Dimensiunea mesajului va fi dimensiunea, inclusiv toate datele valide. Deci, dacă se vor scrie 6 octeți, atunci dimensiunea mesajului va fi 8 (adresa slave + adresa memoriei + 6 octeți de date). Această funcție este utilizată pentru a citi mai mulți octeți de pe un dispozitiv I2C, de obicei este semnificativă o amintire de un fel. Utilizarea acestei rutine este foarte asemănătoare cu rutina anterioară, cu două excepții. Setarea bitului Citire / Scriere nu contează. Apelarea acestei rutine va provoca întotdeauna o operație de citire. Dimensiunea mesajului ar trebui să fie 2 plus numărul de octeți care trebuie citit. Dacă nu au apărut erori, datele vor fi în buffer începând din a doua locație. Pentru ATmega168: Cerința ceasului: driverele sunt proiectate pentru o rată de ceas de 4 MHz pentru ATmega168. Exemplul de cod arată cum să setați această rată de ceas. Dacă doriți să rulați la alte rate, va trebui să ajustați constantele din drivere. Trimiteți-mi un e-mail dacă trebuie să faceți acest lucru. TWI_Master_Initialise () Această funcție inițializează hardware-ul TWI pentru funcționarea în modul I2C. Sunați-l o dată la începutul programului. Revine nul și nu există argumente. Asigurați-vă că activați întreruperile apelând swi () după inițializare. TWI_Get_State_Info () Această funcție returnează informații de eroare I2C și este utilizată dacă a apărut o eroare în timpul unei tranzacții I2C. Deoarece această funcție returnează doar un cod de eroare, folosesc funcția TWI_Act_On_Failure_In_Last_Transmission (TWIerrorMsg) pentru a aprinde un LED de eroare. Codurile de eroare sunt definite în TWI_Master.h, dar sunt modificate pentru semnalizarea pe un LED de eroare. Consultați exemplul de cod pentru detalii. Iată cum să-l numim: TWI_Act_On_Failure_In_Last_Transmission (TWI_Get_State_Info ()) Rețineți că verificarea erorilor se face asigurându-vă că tranzacția I2C este completă (funcția descrisă mai jos) și apoi testând un bit în cuvântul de stare global. TWI_Start_Read_Write () TWI_Read_Rand () două funcții funcționează la fel ca funcțiile corespunzătoare descrise mai sus, dar cu câteva excepții. Nu returnează nici o valoare de eroare. Citirea datelor nu este transferată în buffer. Făcând acest lucru se va face cu funcția descrisă în continuare. Când apelați TWI_Start_Random_Read, mesajul Size trebuie să fie numărul de octeți de date solicitați plus unu, nu doi. Driverul I2C pentru ATmega168 este întrerupt. Adică, tranzacțiile I2C sunt pornite și apoi executate independent, în timp ce rutina principală continuă să ruleze. Când rutina principală dorește ca datele de la o tranzacție I2C să fie pornite, trebuie să verifice dacă datele sunt disponibile. Situația este aceeași pentru verificarea erorilor. Rutina principală trebuie să fie sigură că tranzacția I2C este completă înainte de a verifica erorile. Următoarele două funcții sunt utilizate în aceste scopuri. Programele de exemplu arată cum se folosește acest lucru. Această funcție se va asigura că tranzacția I2C este finalizată înainte de a transfera datele. În timp ce o valoare este returnată de această funcție, găsesc verificarea bitului de eroare direct pentru a fi mai fiabilă. Iată cum să-l numim. Dimensiunea mesajului trebuie să fie cu una mai mare decât numărul de biți de date dorit. Datele vor fi în mesajBuf începând cu a doua locație.temp = TWI_Read_Data_From_Buffer (messageBuf, messageSize);

Pasul 4: Să construim

Să construim!
Să construim!
Să construim!
Să construim!
Să construim!
Să construim!
Să construim!
Să construim!

Începeți prin descărcarea fișierului I2C Schematics.zip. Poate doriți să creați un folder I2C în zona dvs. de lucru pentru a conține schemele și exemplele de fișiere ale programului. Dezarhivați schemele în acest director. Veți găsi un folder numit I2C Schematics. Deschideți fișierul numit minuscul I2C.pdf. Această schemă arată ATtiny2313 Ghetto Development System și PCA8574A I / O Port Expander (are cutia mare întreruptă în jurul său). Circuitul Port Expander este construit pe o placă de calcul. Aruncați o privire la fotografii pentru a vedea cum arată aceste circuite. Sunt într-adevăr destul de simple. Porțiunea ATtiny2313 a schemei este doar sistemul de dezvoltare Ghetto cu trei lumini intermitente (LED1, 2 și 3, plus R4, 5 și 6) și un buton (S1) conectat la acesta, plus unul detalii suplimentare. Acest detaliu este adăugarea de jumperi (JP4, 5 și 6) care pot fi înlăturate pentru a permite conectarea liniilor SC2 și SDA ale magistralei I2C. Jumperii trebuie să fie la locul lor pentru programare, apoi eliminați, astfel încât SCL și SDA să poată fi conectate. Fotografiile arată jumperii la locul lor și eliminați. Plasarea acestor jumperi depinde de dvs., trebuie doar să le puneți pe sistemul de dezvoltare Ghetto dacă doriți să utilizați autobuzul I2C. Autobuzul I2C trebuie să fie deconectat și jumperii să fie stabiliți pentru programare. Rețineți că trebuie să fiți preocupați doar de JP4 și JP6 pentru magistrala I2C. Introduceți JP5 dacă credeți că veți dori vreodată să utilizați autobuzul SPI. Plăcerea cu portul I / O Port Expander PCA8574A este foarte simplă. Furnizați conexiuni Vcc (+5 volți) și Gnd (masă) și conectați AD0, 1 și 2 la masă (face ca adresa slave I2C să fie 38 hex). Apoi conectați 4 lumini intermitente și 4 comutatoare DIP. (Dacă nu aveți comutatoare DIP, puteți utiliza doar fire. Cravată la masă sau lăsați plutitoare pentru a semnaliza sau dezactiva respectiv.) În cele din urmă, conectați rezistențele de tragere (R11 și 12) de la SDA și SCL la Vcc. Acestea sunt afișate ca 3.3K, dar orice valoare de la 1.8K la 5.1K ar trebui să funcționeze (poate până la 10K, dar nu am încercat asta). După ce ați programat ATtiny2313, puteți elimina jumperii și puteți conecta SDA și SCL pentru testare. Acum pentru ATmega168. Singurul rid de aici este că este posibil să nu fi construit un Ghetto Development System pentru acest procesor. Dacă acesta este cazul, atunci schema pe care o furnizez (MEGA I2C.pdf) vă va arăta cum. Aceasta este doar o permutare a versiunii ATtiny2313. Dacă planificați în avans, vă puteți asigura că cablul de programare se potrivește ambelor sisteme. Principala diferență este adăugarea de C2 și C3. Vedeți imaginile pentru amplasarea acestora, acestea ar trebui să fie foarte aproape de cip; unul dintre ei este de fapt sub cip. Acestea ajută la menținerea zgomotului în special de la convertorul analogic la cel digital. Nu trebuie să introduceți jumperii decât dacă intenționați să utilizați autobuzul SPI, deoarece acestea nu sunt necesare pentru autobuzul I2C pe acest cip. Rețineți că placa de calcul PCA8754A va rămâne neschimbată. Veți conecta SDA și SCL și plecați! Ușor, nu?

Pasul 5: Să codăm și să testăm

Să codăm și să testăm!
Să codăm și să testăm!
Să codăm și să testăm!
Să codăm și să testăm!
Să codăm și să testăm!
Să codăm și să testăm!

Este timpul să construiți driverele și programele de exemplu. Vom începe cu ATtiny2313 și cu placa de computer PCA8574A pe care tocmai le-am construit. Descărcați fișierul I2C.zip în directorul de lucru I2C și dezarhivați-l. Veți avea un nou folder numit I2C. În el veți găsi USI I2C (pentru ATtiny2313) și TWI I2C (pentru ATmega168). În USI I2C, veți găsi folderul I_O Port. Acest folder conține codul pentru primul nostru exemplu de program și driverele USI I2C. Folosind WinAVR, compilați și încărcați codul în ATtiny2313. Respirați adânc și porniți puterea. Iată la ce să vă așteptați: la pornire, LED-ul 1 de pe portul PD6 al ATtiny2313 clipește de două ori. Nimic altceva nu se va întâmpla până când nu apăsați butonul (S1). De fiecare dată când butonul este apăsat, comutatoarele sunt citite și setarea lor va fi afișată pe LED-urile conectate la PCA8574A. Schimbați valoarea comutatoarelor, apăsați butonul și LED-urile ar trebui să se schimbe. Continuați să faceți acest lucru până când treceți peste fiorul de a vedea cum funcționează. Dacă (Doamne ferește!) Lucrurile nu funcționează conform așteptărilor, verificați cu atenție cablurile. Erorile I2C vor fi semnalate prin clipiri pe LED3 (PD4) și probabil înseamnă că trebuie să verificați dacă SDA și SCL sunt conectate la pinii corecți și sunt trase în sus corect. Dacă lucrurile încă nu funcționează, citiți restul acestei secțiuni pentru a afla despre depanare. Acum reveniți și să aruncăm o privire asupra codului. Deschideți fișierul USI_I2C_Port.c. Acesta este codul pentru exemplul de program. (USI_TWI_Master.c și USI_TWI_Master.h conțin driverele - le puteți ignora dacă nu sunteți curios.) Utilizați exemplul pentru a vă ghida propriile aplicații I2C. creșteți adresa sclavului și restul memoriei tampon de mesaje și scoateți datele din ea. Veți vedea, de asemenea, cum dezamăgesc butonul și configurez bucla while. Există câteva detalii despre program care merită menționate. Rețineți că datele de la comutatoare sunt inversate înainte de a fi scrise pe LED-urile de pe Port Expander. De asemenea, rețineți că porturile de intrare de pe Port Expander trebuie să fie scrise ca High pentru a le face să funcționeze corect. Aceste detalii sunt descrise în fișa tehnică PCA8574A. Citiți întotdeauna foile de date cu atenție! Un interes mai important este utilizarea depanării condiționate. Aproape de începutul fișierului program se află declarația // # define DEBUG și stropite în tot codul sunt instrucțiunile #ifdef DEBUG. Atâta timp cât DEBUG nu este definit (cele două bare fac linia un comentariu și o împiedică să fie definită), codul din instrucțiunile #ifdef to #endif nu va fi compilat. Dar dacă lucrurile nu funcționează așa cum vă așteptați, recompilați și reîncărcați codul cu #define DEBUG necomentat. Veți primi mult mai multe clipiri pe LED-uri, pe care le puteți decoda pentru a urmări executarea programului și pentru a vă ajuta să găsiți exact unde lucrurile merg prost. De fapt, vă recomand să încercați acest lucru doar pentru a vedea ce se întâmplă. Ceea ce veți vedea este că LED-ul 2 (pe PD5) va clipi pe măsură ce executarea progresează prin program. Valoarea citită de pe comutatoare va clipi pe LED-ul 1 (PD6) înainte de a fi afișată pe LED-urile Port Expander. Ar trebui să puteți urmări programul pe măsură ce rulează utilizând aceste LED-uri. Vom lucra cu ATmega168 în continuare; săriți peste această secțiune dacă sunteți interesat doar de ATtiny2313. Încă cu mine? Bun. Mutați-vă în folderul TWI_I2C, schimbați-vă directorul de lucru în IO_Port și compilați și încărcați TWI_I2C_Port.c în ATmega168. Deconectați liniile SDA și SCL de la ATtiny2313 și conectați-le la ATmega168. Conectați puterea și împământarea și alimentați. Operația ar trebui să fie aceeași! Jucați până când fiorul dispare, apoi să ne uităm la cod. Deschideți TWI_I2C_Port.c. Codul este aproape identic, cu excepția gestionării erorilor și a adaptării șoferilor conduși la întreruperi. Iată diferențele: Rețineți că ceasul trebuie setat la 4 MHz pentru ca magistrala I2C să funcționeze corect. The sei (); declarația activează întreruperile după inițializarea driverelor I2C. Pentru a verifica erorile, este testat un bit de stare specific. În timpul unei citiri, funcția TWI_Read_Data_From_Buffer trebuie apelată pentru a transfera datele citite în memoria tampon de mesaje. În timpul unei scrieri, trebuie folosit [TWI_Transceiver_Busy ()] pentru a vă asigura că transferul este finalizat înainte de a verifica erorile. Aceste ultime două funcții sunt descrise mai sus în descrierea driverelor. În afară de asta, codul este aproape la fel ca pentru ATtiny2313. DEBUG funcționează la fel și dacă doriți să experimentați cu asta.

Pasul 6: Utilizarea memoriei I2C

Utilizarea memoriei I2C
Utilizarea memoriei I2C
Utilizarea memoriei I2C
Utilizarea memoriei I2C
Utilizarea memoriei I2C
Utilizarea memoriei I2C
Utilizarea memoriei I2C
Utilizarea memoriei I2C

Acum, că am învățat să folosim autobuzul I2C pentru a citi și scrie un I / O Port Expander, să trecem la utilizarea memoriilor I2C, atât RAM, cât și EEPROM. Diferența principală este că mai mulți octeți pot fi citiți sau scrisați din amintiri cu o singură comandă I2C. Pentru a ne pregăti pentru aceste experimente, trebuie să modificăm ușor hardware-ul și să construim câteva circuite noi pe panou. Păstrați circuitul Port Expander, deoarece îl vom folosi pentru a afișa câteva valori de memorie. Scoateți comutatoarele DIP de pe PCA8574A și puneți lumini intermitente pe acei pini. Dacă nu aveți suficiente lumini intermitente, mutați cele de pe P4 până la P7 la P0 până la P3. (Valorile care urmează să fie afișate sunt suficient de mici.) Uită-te acum la schema I2C Ram.pdf și conectează PCF8570 la panoul de verificare. Uitați-vă și la imagine. Asigurați-vă că legați pinul 7 de Vcc. Rulați fire pentru SDA și SCL de pe PCA8574A. Nu sunt necesare rezistențe suplimentare de tragere. Dacă sunteți interesat și de EEPROM, construiți acel circuit folosind și I2C EEPROM.pdf pentru 24C16, dar fiți avertizat că exemplul folosește ATmega168. Acest circuit este foarte simplu. După cum sa discutat mai sus, biții de adresă ar trebui să fie ignorați. Cuplați doar puterea și solul. Nu conectați încă SDA și SCL, deoarece nu am terminat experimentarea cu RAM. Vom începe experimentele noastre de memorie cu ATtiny2313 conectat la PCA8574A Port Expander și la PCF8570 Ram. Programul va scrie câteva numere pe Ram, apoi le va citi înapoi și le va afișa pe Port Expander. Schimbați directorul de lucru în RAM sub USI I2C. Utilizați fișierul make pentru a compila și descărca USI_I2C_RAM.c. Rețineți că fișierele driverului I2C sunt identice cu cele utilizate anterior. Conectați alimentarea și ar trebui să vedeți o singură clipire pe LED-ul 1 (PD6). Datele vor fi scrise pe primii 4 octeți de memorie. Apăsați butonul și doi octeți vor fi cititi și afișați. Ar trebui să vedeți o lumină LED pe Port Expander (P0), o pauză de două secunde, apoi două LED-uri luminoase (P0 și P1). O altă pauză de două secunde și LED-urile ar trebui să se stingă. Apăsați din nou butonul pentru a porni secvența. Depanarea este similară cu metoda descrisă mai sus. Să aruncăm o privire asupra codului. Deschideți USI_I2C_RAM.c. Ar trebui să arate destul de similar cu codul anterior. Principalele diferențe sunt detaliile citirii și scrierii memoriei. Uitați-vă la modul în care este încărcat bufferul de mesaje înainte de apelul care efectiv scrie. Primul octet este adresa slave cu bitul de citire / scriere setat corespunzător. Dar următorul octet este adresa de memorie la care să începeți să scrieți date. Apoi vin octeții de date care vor fi încărcați secvențial în memorie începând cu adresa specificată de noi. Specificăm dimensiunea mesajului ca 6. Deci începem să scriem la adresa 00 și să scriem valorile 01, 03, 02 și 06 în locațiile de memorie 00 până la 03. Pentru a citi datele din memorie trebuie să folosim funcția USI_TWI_Start_Random_Read. Memoria tampon primește adresa slave în primul octet și adresa de pornire în al doilea octet. Apelați apoi funcția cu dimensiunea mesajului setată la numărul de octeți de citit plus 2. Rețineți că bitul de citire / scriere nu contează, deoarece o citire se va face indiferent. Datele returnate vor începe în a doua locație din bufferul de mesaje. Odată ce datele sunt citite, sunt inversate pentru afișare pe Port Expander și scrise câte un octet pe rând cu o pauză între valori. În cele din urmă, LED-urile Port Expander sunt stinse. Scrierile către Port Expander sunt identice cu ceea ce s-a făcut în exemplele anterioare. Pentru distracție, puteți descomenta declarația #define DEBUG ca mai sus și puteți vedea o mulțime de LED-uri care clipesc. Plini de emoție după un alt experiment de succes, să trecem la ATmega168 și la o EEPROM. Schimbați directorul de lucru în EEPROM sub TWI I2C. Utilizați fișierul make pentru a compila și descărca TWI_I2C_EEPROM.c. Rețineți că fișierele driverului I2C sunt identice cu cele pe care le-am folosit anterior pentru PCA8574A. Pentru a testa programul, deconectați ATtiny2313 și conectați ATmega168. Lăsați autobuzul I2C conectat la RAM și porniți-l. Rezultatele sunt diferite, deoarece acum scriem și citim mai multe date. LED-ul 1 de pe PD7 ar trebui să clipească la inițializare. Apăsați butonul și datele vor fi citite din memorie și afișate. LED-urile de pe PCA8574 ar trebui să clipească următoarea secvență: P1, P0 și P2, (toate oprite), P0 și P1, P1 și P2. În cele din urmă, LED-urile de port ar trebui să se stingă. Apăsați butonul din nou pentru a repeta acest lucru. O, dar așteptați, spuneți. Nu este acest program pentru EEPROM? Deoarece accesăm un dispozitiv de memorie la aceeași adresă I2C, același program funcționează atât pentru Ram, cât și pentru EEPROM. Opriți și mutați SDA și SCL de pe RAM la EEPROM și rulați din nou programul. Ar trebui să funcționeze exact la fel. Rețineți că EEPROM și RAM nu pot fi conectate la magistrala I2C în același timp, deoarece au aceeași adresă. (Cei mai inteligenți dintre voi ar putea lua în considerare schimbarea biților de adresă programabili de pe RAM, dar asta încă nu va funcționa. 24C16 folosește întregul bloc de adrese care poate fi programat pentru Ram.) OK, să ne uităm la acest ultim program. Deschideți TWI_I2C_EEPROM.c. Primul lucru de observat este că am indicat cum să abordez EEPROM 24C16 complet. Poate fi accesat în bucăți de 256 de octeți la 8 adrese slave I2C diferite. Vedeți cum MEMORY_ADDR este definit ca adresa de pornire la 50 hexazecimale; de aceea a funcționat Berbecul. Dacă doriți să accesați alte blocuri ale modelului 24C16, atunci utilizați celelalte adrese așa cum am indicat. Uitați-vă la modul în care am configurat să scriu în memorie. Mai întâi adresa slave cu setul de biți de citire / scriere este introdusă în buffer, apoi adresa de pornire 00, apoi 16 octeți de date. Funcția TWI_Start_Read_Write este apelată pentru a scrie datele (ca înainte) cu dimensiunea mesajului setată la 18. Când se apasă butonul, folosim TWI_Start_Random_Read și TWI_Read_Data_From_Buffer pentru a citi datele înapoi. Fiecare al treilea octet este afișat pe LED-urile Port Expander. În cele din urmă, LED-urile sunt oprite pentru a aștepta următoarea apăsare a butonului. S-ar putea să vă întrebați de ce am ales să scriu 16 octeți. Dacă citiți cu atenție foaia de date, veți vedea că 24C16 face un ciclu de scriere ori de câte ori primește 16 octeți, chiar dacă sunt expediați mai mulți octeți. Așa că mi s-a părut un număr frumos de folosit. Dacă alegeți să măriți acest lucru, va trebui să modificați dimensiunea MESSAGEBUF_SIZE. De asemenea, va trebui să modificați valoarea TWI_BUFFER_SIZE în TWI_Master.h. Acest lucru se datorează faptului că driverul copiază datele din memoria tampon pentru mesaje pentru a fi utilizate de rutina serviciului de întrerupere. Felicitări! Acum sunteți gata să utilizați autobuzul I2C în propriile dvs. proiecte!

Pasul 7: Resurse web

Iată linkurile către fișele tehnice pentru piesele utilizate pentru experimente. Cu siguranță ar trebui să le obțineți dacă nu obțineți altceva. Port ExpanderRamEEPROM Fiind creatorul I2C, NXP (Philips) are o mulțime de lucruri grozave. (Le place să utilizeze paranteze pătrate în adresele URL, așa că nu le pot include corect aici. Ne pare rău.) Pentru a ajunge la zona I2C, selectați Interfață din lista Produse. Veți putea accesa site-ul lor I2C și acces la toate fișele tehnice și notele de aplicații pe care le oferă. Descrierea autobuzului I2C și detaliile tehnice în special sunt aici. Obțineți fișele tehnice ATtiny2313 și ATmega168 (cărți de date?) de la Atmel. Notele aplicației Atmel sunt aici. Uitați-vă la AVR310 și AVR315. Prindeți și codul. Aruncați o privire aici pentru mai multe lucruri I2C.

Pasul 8: Note pentru Geeks

Pentru adevăratul geek care dorește să cunoască detaliile, iată câteva lucruri de care să ții cont dacă te uiți la Atmel Apps Notes și la codul driverului: - Metoda de adresare și comandare a unui dispozitiv I2C nu face parte din specificații! În afară de adresa slave și bitul de citire / scriere, comenzile, modurile etc. nu sunt specificate și sunt specifice unui anumit dispozitiv. Pentru a face acest lucru foarte clar, rețineți că schema utilizată în exemplul Atmel se aplică doar exemplului respectiv și este aproape nestandard. - Implementarea USI diferă de implementarea TWI în câteva moduri importante. + Cu USI, ceasul este asigurat de software; cu TWI este furnizat de un Bit Rate Generator. + Metoda USI nu folosește întreruperi; TWI o face. Acest lucru are un anumit sens, deoarece familia Mega (folosind TWI) ar putea face multe alte lucruri și nu ar trebui să fie învinsă de transferurile I2C. O versiune cu întrerupere pentru USI este cu siguranță posibilă, pur și simplu nu este implementată în acest instructabil. + Hardware-ul USI nu este optimizat pentru I2C și poate gestiona doar transferuri de 8 biți. Aceasta înseamnă că sunt necesare două transferuri pentru a trimite cel de-al nouălea bit (fie NACK, fie ACK). Hardware-ul TWI gestionează automat acest lucru. Acest lucru face ca implementarea driverului USI să fie un pic mai complicată. + Detectarea erorilor pentru TWI este tratată în hardware. USI necesită manipulare în software care complică oarecum lucrurile. + Hardware-ul TWI controlează direct configurația portului. Hardware-ul USI necesită configurarea biților de port înainte ca portul să poată fi utilizat. Veți vedea acest lucru în rutina Master_Initialize pentru USI.- Atmel susține că este posibil să utilizați extrageri de port AVR pentru extrageri de autobuz I2C. Nu am găsit o modalitate de a face ca această abordare să funcționeze. Folosirea a două rezistențe externe pare o schemă destul de simplă, așa că nu am petrecut mult timp în acest sens.

Recomandat: