Innholdsfortegnelse:

I2C -buss for ATtiny og ATmega: 8 trinn
I2C -buss for ATtiny og ATmega: 8 trinn

Video: I2C -buss for ATtiny og ATmega: 8 trinn

Video: I2C -buss for ATtiny og ATmega: 8 trinn
Video: I2C Bus Programming On AVR Microcontollers 2024, November
Anonim
I2C -buss for ATtiny og ATmega
I2C -buss for ATtiny og ATmega

Jeg elsker Atmel AVR mikrokontrollere! Siden jeg bygde Ghetto Development System beskrevet i denne instruksjonsboken, har jeg ikke hatt noen ende på moro med å eksperimentere med AVR ATtiny2313 og spesielt ATmega168. Jeg gikk til og med så langt som å skrive en instruks om bruk av brytere som innganger, og utvidet Ghetto Development System -konseptet til CPLDs. Under et nylig prosjekt trengte jeg flere brytere for å sette kontrollverdier. AVR -ene hadde ikke nok I/O -pinner, så jeg måtte tenke på noe. Jeg kunne ha prøvd et komplekst inngangssystem med tastatur og skjerm, men ATtiny2313 ville ha gått tom for ressurser. Heldigvis har Atmel gitt en løsning på dette problemet ved å inkludere et grensesnitt som kan koble til flere sjetonger (for eksempel minne eller I/O -porter) med et enkelt to -leder grensesnitt. Det er riktig, ved å bruke bare to I/O -pinner på en AVR kan vi få tilgang til mange flere I/O -pinner og andre ressurser også. Dette totrådsgrensesnittet er formelt kjent som den interintegrerte kretsbussen, eller bare I2C-bussen, og ble oppfunnet av NXP da den fremdeles var Philips Semiconductors. Hvis du leser denne Instructable, har du sannsynligvis hørt om I2C -bussen og kan til og med ha brukt den på en PIC eller annen mikrokontroller. Selv om det er konseptuelt veldig enkelt og støttet av maskinvareressurser på AVR -ene, er det fortsatt nødvendig med programvaredrivere for å bruke I2C -bussen. Atmel gir applikasjonsnotater (se ressursene senere i denne instruksjonsboken), men disse er ufullstendige og viser ingen eksempler utover kommunikasjon med en annen AVR -enhet. Det er ikke hensikten med denne instruksen å lære noen hvordan man lager I2C -drivere for AVR -er. Jeg vil heller tilby utvidede versjoner av Atmel -driverne for ATtiny2313 og ATmega168 -enheter, jeg skal forklare kravene og begrensningene som gjelder når du bruker disse, og jeg vil vise deg eksempler på bruk av I2C -enheter. Etter at du har jobbet med denne instruksjonsboken, vil du kunne bruke I2C -bussen vellykket i AVR -prosjektene dine. Tydeligvis kan du ignorere driverne for enten bittesmå eller MEGA hvis du bare er interessert i en av dem. For de som er interessert i å lære mer om I2C -bussen, gir jeg lenker til passende materiale.

Trinn 1: Hva er alt dette I2C -stoffet uansett?

Hva er alt dette I2C -stoffet uansett?
Hva er alt dette I2C -stoffet uansett?
Hva er alt dette I2C -stoffet uansett?
Hva er alt dette I2C -stoffet uansett?
Hva er alt dette I2C -stoffet uansett?
Hva er alt dette I2C -stoffet uansett?
Hva er alt dette I2C -stoffet uansett?
Hva er alt dette I2C -stoffet uansett?

I2C-bussen er en enkel totrådsforbindelse som kan koble flere enheter sammen og la dem utveksle data. I sin enkleste form er det en hovedenhet som kommuniserer til flere slaveenheter. Alle enheter er parallelt koblet til de to ledningene til I2C -bussen. De to ledningene er kjent som SCL og SDA. SCL er klokkelinjen og styres av hovedenheten. SDA er den toveis datalinjen. For å overføre data sender masteren ut en slave -adresse kombinert med et bit -lese/skrive -flagg. Hvis det er ønsket å skrive, vil masteren fortsette å sende data til den adresserte slaven. Hvis det blir bedt om en lesing, vil slaven svare med data. For å koordinere transaksjoner manipuleres SCL- og SDA -linjene av masteren og slaven for å signalisere flere forhold. Disse inkluderer START, STOP, ACK (bekreft) og NAK (ingen bekreftelse). Detaljene i disse forholdene håndteres av sjåførene. De sanne nørdene blant dere kan lære alle detaljene i koblingene på slutten av denne instruksjonsboken. De elektriske kravene er ganske enkle. Mesteren og slaver må bruke samme nivå for Vcc, grunnen må være tilkoblet, og SCL- og SDA -linjene må trekkes opp til Vcc. Verdien av opptrekkmotstandene bestemmes nøyaktig av en beregning basert på den totale kapasitansen på bussen, men kan praktisk talt være omtrent hvilken som helst verdi mellom 1,8K og 10K. Jeg starter med 5.1K og bruker lavere verdier til det fungerer. Dette er vanligvis ikke et problem med mindre du har mange enheter eller lange ledninger mellom enheter. Den nominelle datahastigheten på I2C -bussen er 100Kbits/sekund. Priser på 400Kbit/sekund, 1Mbit/sekund og utover er også mulig, men støttes ikke av driverne i denne instruksjonsboken. Alle I2C -enheter vil fungere med 100Kbits/sekund. ATtiny2313 og ATmega168 implementerer hver I2C -bussen annerledes. ATtiny2313 bruker maskinvaren Universal Serial Interface (USI) - som også kan brukes til SPI -bussen. ATmega168 har dedikert maskinvare for I2C -bussen kjent som Two Wire Interface (TWI). Når driverne er skrevet, er disse forskjellene stort sett gjennomsiktige for brukeren. En vesentlig forskjell er i programvaren: ATmega168 I2C -driveren er avbruddsdrevet, mens den for ATtiny2313 ikke er det. Dette betyr at et ATmega168 -program ikke trenger å vente på at I2C -dataoverføringer finner sted, men bare trenger å vente før en ny overføring påbegynnes, eller til data kommer fra en leseoperasjon. Eksemplene og diskusjonen som skal følges bør gjøre dette klart. I2C -adresser er 7 bits lange, så opptil 127 enheter kan være på bussen hvis hver har en unik adresse. Som vist på figuren, flyttes denne 7 -biters adressen til en bit til venstre, og den minst signifikante biten brukes til å markere en lese eller skrive av enheten på adressen. Dermed er den komplette slaveadressen en 8 bit byte. Den faktiske adressen er delvis bestemt internt til enheten og kan ikke endres (4 mest signifikante biter), og delvis bestemt av biter som kan kobles til enhetens pinner (3 minst signifikante biter) som kan bindes høyt eller lavt for å sette en bestemt adresse. Høres forvirrende ut, men et eksempel vil gjøre dette klart. PCA8574A -databladet viser at de fire viktigste bitene i I2C -adressen alltid vil være 0111. De neste tre bitene bestemmes av innstillingene på pinnene AD0, AD1 og AD2. Disse pinnene kan knyttes til bakken eller til den positive spenningsforsyningen (5 volt) for å representere henholdsvis 0 eller 1. Så området med mulige adresser er 38 til 3F heksadesimalt, som vist i den andre figuren fra PCA8574 -databladet. Så ved å endre adressebitinnstillingene, kan opptil 8 PCA8574As være på I2C -bussen samtidig. Hver vil svare på sin spesifikke slave -adresse. Hvis det trengs enda flere I/O -porter, kan PCA8574 brukes. Den eneste forskjellen mellom PCA8574 og PCA8574A er at I2C -slaveadresseområdet til PCA8574 er 20 til 27 heksadesimalt. Å bestemme adressen til en gitt enhet kan være forvirrende siden noen datablad anser lese-/skrivebiten som en del av adresse. Les databladet nøye, og husk at slaveadressen vil være 7 bits lang. Les/skriv -biten bør behandles separat. Igjen, et eksempel vil hjelpe. Dataarket for 24C16 EEPROM vi vil eksperimentere med sier at de første (mest signifikante) fire bitene i slaveadressen er 1010. De neste tre bitene kan bestemmes av A0, A1 og A2; men vær oppmerksom på at databladet også dekker 24C01 til 24C08 som er mindre EEPROM -er. Figuren fra databladet viser at innstillingene til disse adressebitene ignoreres når størrelsen øker og ignoreres fullstendig for 24C16. Det vil si at de tre siste bitene ikke spiller noen rolle, og 24C16 bruker virkelig alle I2C -slaveadressene 50 til 57 heksadesimale. Utvalget av slaveadresser vil faktisk adressere forskjellige seksjoner innenfor 24C16. De første 256 byte er på adressen 50h, de neste 256 på 51h, og så videre opp til de siste 256 bytes på 57h - totalt 2K byte. Siden adressen til PCF8570 RAM vi også eksperimenterer med er i dette området, kan ikke 24C16 og PCF8570 brukes sammen.

Trinn 2: Bestill noen I2C -enheter

Nå som du vet litt om I2C -bussen og vil bruke den, hvorfor ikke bestille noen I2C -enheter til å eksperimentere med nå, slik at de kan være på vei til deg mens du gjør programvaren klar? Egnede enheter inkluderer en I/ O Interface Expander (min favoritt), en statisk ram og en EEPROM. Det er mye mer, men disse er en god start. AVR -prosessorene vi skal bruke er ATtiny2313 og Atmega168 (brukt i Arduino). Hvis du er ny på disse, så ta en titt på denne flotte Instructable for å lære om dem og bygge ditt Ghetto Development System. Skjematikken til ATmega168 i den nåværende instruksjonsfilen viser hvordan man implementerer Ghetto Development System for denne prosessoren. Parallellportkabelen er den samme som den for ATtiny2313. (Jeg har ikke prøvd USB -versjonen av Ghetto Development System, så jeg er ikke sikker på hvordan I2C -bussen er tilgjengelig på den. Samme for Arduino.) Her er Digikey -delenumre. Port Expander: 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

Trinn 3: I2C -drivere

Her er beskrivelsene av driverfunksjonene for I2C -bussen. Disse ble utviklet ved hjelp av Atmel Apps Notes til å begynne med. Jeg kunne ikke ha gjort dette uten dem som en base å bygge på. Utviklingen ble gjort ved hjelp av WinAVR og gcc C -kompilatoren. Begrensninger for klokkefrekvens er beskrevet nedenfor for hver prosessor. Siden jeg ikke er i stand til å teste alle kombinasjonene av prosessorsmak / klokkefrekvens som er mulig, vil jeg bare holde meg til det jeg faktisk kan teste og prøve å angi begrensninger og begrensninger. Her er driverfunksjonene og hvordan jeg bruker dem. Vennligst se eksemplene for mer informasjon og for å se funksjonene som brukes i komplette programmer. For ATtiny2313: Klokkekrav: Driverne er designet for en klokkefrekvens på 1MHz (standardhastigheten) for ATtiny2313. Hvis du vil kjøre med andre hastigheter, må du justere konstanter i driverne. Send meg en e -post hvis du trenger hjelp til dette. Du kan også få noen hint fra notatene fra Atmel -appene i koblingene i Resources Step. USI_TWI_Master_Initialise () Denne funksjonen initialiserer USI -maskinvaren for drift i I2C -modus. Kall det en gang i starten av programmet. Den returnerer ugyldig og det er ingen argumenter. USI_TWI_Get_State_Info () Denne funksjonen returnerer I2C -feilinformasjon og brukes hvis det oppstod en feil under en I2C -transaksjon. Siden denne funksjonen bare returnerer en feilkode, bruker jeg funksjonen TWI_Act_On_Failure_In_Last_Transmission (TWIerrorMsg) til å blinke en feil -LED. Feilkodene er definert i USI_TWI_Master.h. Slik kaller du det: TWI_Act_On_Failure_In_Last_Transmission (USI_TWI_Get_State_Info ()) USI_TWI_Start_Read_Write () Denne funksjonen brukes til å lese og skrive enkeltbyte til I2C -enheter. Det brukes også til å skrive flere byte. Det er 6 trinn for å bruke denne funksjonen. unsigned char messageBuf (MESSAGEBUF_SIZE); 2) Sett slaveadressen som den første byten i bufferen. Flytt den en bit til venstre og ELLER i Les/skriv -biten. Legg merke til at Read/Write -biten vil være 1 for en Read og 0 for en Write. Dette eksemplet er for en Read. messageBuf (0) = (TWI_targetSlaveAddress << TWI_ADR_BITS) | (TRUE << TWI_READ_BIT); 3) Når du skriver, setter du byten som skal skrives til neste sted i bufferen. returnert verdi (temp i dette tilfellet) kan testes for å se om det oppstod en feil. I så fall håndteres det som diskutert ovenfor. Se eksempler i programmene. 6) Hvis det ble bedt om en lesing, vil byteavlesningen være på det andre stedet i bufferen. Hvis flere byte skal skrives (for eksempel til en minneenhet), kan den samme rutinen brukes. Å sette opp bufferen og ringe rutinen er litt annerledes. Den andre byten i bufferen vil være startminneadressen du vil skrive til. Dataene som skal skrives vil være i påfølgende byte. Meldingsstørrelsen vil være størrelsen inkludert alle gyldige data. Så hvis 6 byte skal skrives, vil meldingsstørrelsen være 8 (slaveadresse + minneadresse + 6 byte med data). USI_TWI_Start_Random_Read () Denne funksjonen brukes til å lese flere byte fra en I2C -enhet, vanligvis er det bare meningsfullt for et minne av noe slag. Å bruke denne rutinen ligner veldig på den forrige rutinen, med to unntak. Innstillingen av Read/Write -biten spiller ingen rolle. Hvis du kaller denne rutinen, vil det alltid føre til en leseoperasjon. Meldingen Størrelse skal være 2 pluss antall byte som skal leses. Hvis det ikke oppstår noen feil, vil dataene være i bufferen som begynner på det andre stedet. For ATmega168: Klokkekrav: drivere er designet for en klokkefrekvens på 4MHz for ATmega168. Eksempelkoden viser hvordan du stiller inn denne klokkefrekvensen. Hvis du vil kjøre med andre hastigheter, må du justere konstanter i driverne. Send meg en e -post hvis du trenger å gjøre dette. TWI_Master_Initialise () Denne funksjonen initialiserer TWI -maskinvaren for drift i I2C -modus. Kall det en gang i starten av programmet. Det returnerer ugyldig og det er ingen argumenter. Sørg for å aktivere avbrudd ved å ringe swi () etter initialisering. TWI_Get_State_Info () Denne funksjonen returnerer I2C -feilinformasjon og brukes hvis det oppstod en feil under en I2C -transaksjon. Siden denne funksjonen bare returnerer en feilkode, bruker jeg funksjonen TWI_Act_On_Failure_In_Last_Transmission (TWIerrorMsg) til å blinke en feil -LED. Feilkodene er definert i TWI_Master.h, men er modifisert for signalering på en feil -LED. Se eksempelkoden for detaljer. Slik kaller du det: TWI_Act_On_Failure_In_Last_Transmission (TWI_Get_State_Info ()) Merk at feilkontroll utføres ved å kontrollere at I2C -transaksjonen er fullført (funksjon beskrevet nedenfor) og deretter teste litt i det globale statusordet. TWI_Start_Read_Write () TWI_Start_R_ to funksjoner fungerer på samme måte som de tilsvarende funksjonene beskrevet ovenfor, men med noen få unntak. De returnerer ingen feilverdier. Data som leses overføres ikke til bufferen. Dette gjøres med funksjonen beskrevet neste. Når du ringer TWI_Start_Random_Read, skal meldingstørrelsen være antall databyte som er forespurt pluss en, ikke to. I2C -driveren for ATmega168 er avbruddsdrevet. Det vil si at I2C -transaksjonene startes og deretter utføres uavhengig mens hovedrutinen fortsetter å kjøre. Når hovedrutinen ønsker data fra en I2C -transaksjon som den startet, må den sjekke om dataene er tilgjengelige. Situasjonen er den samme for feilkontroll. Hovedrutinen må være sikker på at I2C -transaksjonen er fullført før du ser etter feil. De to neste funksjonene brukes til disse formålene. TWI_Transceiver_Busy () Ring denne funksjonen for å se om en I2C -transaksjon er fullført før du ser etter feil. Eksempelprogrammene viser hvordan du bruker dette. TWI_Read_Data_From_Buffer () Ring denne funksjonen for å overføre data fra I2C -driverens mottaksbuffer til meldingsbufferen. Denne funksjonen vil sikre at I2C -transaksjonen er fullført før dataene overføres. Selv om en verdi returneres av denne funksjonen, synes jeg det er mer pålitelig å sjekke feilbiten direkte. Slik kaller du det. Meldingsstørrelsen skal være en større enn ønsket antall databiter. Dataene vil være i messageBuf fra den andre plasseringen.temp = TWI_Read_Data_From_Buffer (messageBuf, messageSize);

Trinn 4: La oss bygge

La oss bygge!
La oss bygge!
La oss bygge!
La oss bygge!
La oss bygge!
La oss bygge!
La oss bygge!
La oss bygge!

Start med å laste ned filen I2C Schematics.zip. Det kan være lurt å opprette en I2C -mappe i arbeidsområdet for å inneholde skjemaene og eksempelfilene. Pakk ut skjemaene i denne katalogen. Du finner en mappe som heter I2C Schematics. Åpne filen kalt lille I2C.pdf. Denne skjemaet viser ATtiny2313 Ghetto Development System og PCA8574A I/O Port Expander (har den store stiplede boksen rundt seg). Port Expander -kretsen er bygget på et brødbrett. Ta en titt på bildene for å se hvordan disse kretsene ser ut. De er veldig enkle. ATtiny2313 -delen av skjemaet er bare Ghetto Development System med tre blinklys (LED1, 2 og 3, pluss R4, 5 og 6) og en trykknapp (S1) koblet til den, pluss en ytterligere detaljer. Denne detaljen er tillegg av hoppere (JP4, 5 og 6) som kan fjernes for å tillate tilkobling av I2C -buss SCL- og SDA -linjer. Hopperne må være på plass for programmering, deretter fjernet slik at SCL og SDA kan kobles til. Bildene viser hopperne på plass og fjernet. Plasseringen av disse hopperne er opp til deg, du må bare sette dem på Ghetto Development System hvis du vil bruke I2C -bussen. I2C -bussen må kobles fra og hopperne settes på plass for programmering. Vær oppmerksom på at du bare trenger å bekymre deg for JP4 og JP6 for I2C -bussen. Sett inn JP5 hvis du tror du noen gang vil bruke SPI -bussen. Det er veldig enkelt å brede PCA8574A I/O Port Expander. Gi Vcc (+5 volt) og Gnd (jord) tilkoblinger og koble AD0, 1 og 2 til jord (gjør I2C slave -adressen 38 hex). Koble deretter til 4 blinkenlights og 4 DIP -brytere. (Hvis du ikke har DIP-brytere, kan du bare bruke ledninger. Knyt til bakken eller la flyte for å signalisere henholdsvis på eller av.) Til slutt kobler du opptrekkmotstandene (R11 og 12) fra SDA og SCL til Vcc. Disse er vist som 3,3K, men en verdi fra 1,8K til 5,1K burde fungere (kanskje opptil 10K, men jeg har ikke prøvd det). Når du har programmert ATtiny2313 kan du fjerne hopperne og koble til SDA og SCL for testing. Nå for ATmega168. Den eneste rynken her er at du kanskje ikke har bygget et Ghetto Development System for denne prosessoren. Hvis det er tilfelle, viser skjematikken jeg gir (MEGA I2C.pdf) deg hvordan. Dette er bare en permutasjon av ATtiny2313 -versjonen. Hvis du planlegger på forhånd, kan du sørge for at programmeringskabelen passer til begge systemene. Hovedforskjellen er tilsetningen av C2 og C3. Se bildene for plassering av disse, de skal være veldig nær brikken; en av dem er faktisk under brikken. Disse hjelper spesielt med å holde støy utenfor den analoge til digitale omformeren. Du trenger ikke å sette i hopperne med mindre du planlegger å bruke SPI -bussen siden de ikke er nødvendige for I2C -bussen på denne brikken. Vær oppmerksom på at PCA8754A -brødbrettet blir uendret. Du vil bare koble til SDA og SCL og du går! Lett, hva?

Trinn 5: La oss kode og teste

La oss kode og teste!
La oss kode og teste!
La oss kode og teste!
La oss kode og teste!
La oss kode og teste!
La oss kode og teste!

Det er på tide å bygge driverne og eksempelprogrammene. Vi starter med ATtiny2313 og brødbrettet PCA8574A som vi nettopp har bygget. Last ned filen I2C.zip til I2C -arbeidskatalogen og pakk den ut. Du får en ny mappe som heter I2C. I den finner du USI I2C (for ATtiny2313) og TWI I2C (for ATmega168). I USI I2C finner du mappen I_O Port. Denne mappen inneholder koden for vårt første eksempelprogram og USI I2C -driverne. Bruk WinAVR til å kompilere og laste inn koden i ATtiny2313. Pust dypt og slå på strømmen. Her er hva du kan forvente: Når strømmen slås på, blinker LED 1 på port PD6 på ATtiny2313 to ganger. Ingenting annet vil skje før du trykker på knappen (S1). Hver gang du trykker på knappen, leses bryterne, og innstillingen vises på lysdiodene som er koblet til PCA8574A. Endre verdien på bryterne, trykk på knappen, og lysdiodene bør endres. Fortsett å gjøre dette til du kommer over spenningen ved å se at det fungerer. Hvis (Gud forby!) Ting ikke fungerer som forventet, må du kontrollere ledningene nøye. I2C -feil vil bli signalisert av blink på LED3 (PD4) og sannsynligvis bety at du må kontrollere at SDA og SCL er koblet til de riktige pinnene og er trukket opp riktig. Hvis ting fortsatt ikke fungerer, kan du lese resten av denne delen for å lære om feilsøking. Gå nå tilbake og la oss se på koden. Åpne filen USI_I2C_Port.c. Dette er koden for eksempelprogrammet. (USI_TWI_Master.c og USI_TWI_Master.h inneholder driverne - du kan ignorere dem med mindre du er nysgjerrig.) Bruk eksemplet til å veilede dine egne I2C -applikasjoner. Stort sett viser programmet deg hvordan du initialiserer og bruker I2C -driverne, inkludert innstilling opp slaveadressen og resten av meldingsbufferen, og få dataene ut av den. Du vil også se hvordan jeg fjerner knappen og konfigurerer mensløkken. Det er noen detaljer om programmet som er verdt å nevne. Vær oppmerksom på at dataene fra bryterne inverteres før de skrives til lysdiodene på Port Expander. Vær også oppmerksom på at inngangsportene på Port Expander må skrives som High for å få dem til å fungere skikkelig. Disse detaljene er beskrevet i PCA8574A -databladet. Les alltid databladene nøye! Av mer interesse er bruk av betinget feilsøking. Nær starten av programfilen er setningen // #define DEBUG og sprinklet gjennom koden er #ifdef DEBUG -setninger. Så lenge DEBUG ikke er definert (de to skråstrekkene gjør linjen til en kommentar og holder den fra å bli definert), vil ikke koden i #ifdef til #endif -setningene bli samlet. Men hvis ting ikke fungerer som du forventer, kan du kompilere og laste inn koden på nytt med #define DEBUG uten kommentarer. Du får mye mer blink på lysdiodene som du kan dekode for å følge utførelsen av programmet og hjelpe deg med å finne nøyaktig hvor ting går galt. Faktisk anbefaler jeg deg å prøve dette bare for å se hva som skjer. Det du ser er at LED 2 (på PD5) blinker etter hvert som utførelsen går gjennom programmet. Verdien som leses fra bryterne vil blinke på LED 1 (PD6) før den vises på Port Expander -lysdiodene. Du bør kunne spore programmet mens det kjører ved å bruke disse lysdiodene. Vi jobber med ATmega168 neste; hopp over denne delen hvis du bare er interessert i ATtiny2313. Fortsatt med meg? God. Flytt til mappen TWI_I2C, endre arbeidskatalogen til IO_Port, og kompiler og last inn TWI_I2C_Port.c i ATmega168. Koble SDA- og SCL -linjene fra ATtiny2313 og koble dem til ATmega168. Koble til strøm og jord, og slå på. Operasjonen skal være den samme! Spill til spenningen avtar, så la oss se på koden. Åpne TWI_I2C_Port.c. Koden er nesten identisk bortsett fra feilhåndtering og imøtekommende avbruddsdrevne drivere. Her er forskjellene: Vær oppmerksom på at klokken må settes til 4MHz for at I2C -bussen skal fungere skikkelig. Seien (); setning slår på avbrudd etter initialisering av I2C -driverne. For å se etter feil, testes en bestemt statusbit. Under en lesing må TWI_Read_Data_From_Buffer -funksjonen kalles for å overføre dataene som er lest til meldingsbufferen. Under en skriving, mens (TWI_Transceiver_Busy ()) må brukes for å være sikker på at overføringen er fullført før du ser etter feil. Disse to siste funksjonene er beskrevet ovenfor i beskrivelsen av driverne. Annet enn det, er koden stort sett den samme som for ATtiny2313. DEBUG fungerer det samme også hvis du vil eksperimentere med det.

Trinn 6: Bruke I2C -minne

Bruke I2C -minne
Bruke I2C -minne
Bruke I2C -minne
Bruke I2C -minne
Bruke I2C -minne
Bruke I2C -minne
Bruke I2C -minne
Bruke I2C -minne

Nå som vi har lært å bruke I2C -bussen til å lese og skrive en I/O -portutvidelse, la oss gå videre til å bruke I2C -minner, både RAM og EEPROM. Hovedforskjellen er at flere byte kan leses til eller skrives fra minner med en enkelt I2C -kommando. For å gjøre oss klare for disse eksperimentene, må vi modifisere maskinvaren litt og bygge et par nye kretser på brødbrettet. Behold Port Expander -kretsen siden vi bruker den til å vise noen minneverdier. Fjern DIP -bryterne fra PCA8574A og sett blinklys på disse pinnene. Hvis du ikke har nok blinklys, flytter du dem på P4 til og med P7 over til P0 til og med P3. (Verdiene som skal vises er små nok.) Se nå på skjematisk I2C Ram.pdf og koble til PCF8570 på brødbrettet. Ta en titt på bildet også. Sørg for å knytte pin 7 til Vcc. Kjør ledninger for SDA og SCL fra PCA8574A. Ingen ekstra pull-up motstander kreves. Hvis du også er interessert i EEPROM, kan du bygge den kretsen også ved hjelp av I2C EEPROM.pdf for 24C16, men vær advart om at eksemplet bruker ATmega168. Denne kretsen er veldig enkel. Som diskutert ovenfor, bør adressebitene ignoreres. Bare koble til strøm og jord. Ikke koble SDA og SCL ennå siden vi ikke har fullført eksperimentene med Ram. Vi starter våre minneeksperimenter med ATtiny2313 koblet til PCA8574A Port Expander og til PCF8570 Ram. Programmet vil skrive noen tall til Ram, deretter lese dem tilbake og vise dem på Port Expander. Endre arbeidskatalogen til RAM under USI I2C. Bruk make -filen til å kompilere og laste ned USI_I2C_RAM.c. Vær oppmerksom på at I2C -driverfilene er identiske med de vi brukte tidligere. Koble til strømmen, og du bør se et enkelt blink på LED 1 (PD6). Data blir skrevet til de første 4 byte av minne. Trykk på knappen og to byte leses tilbake og vises. Du bør se ett LED -lys på Port Expander (P0), en pause på to sekunder, deretter to LEDer (P0 og P1). Ytterligere to sekunders pause og lysdiodene skal slås av. Trykk på knappen igjen for å starte sekvensen på nytt. Debugging ligner metoden beskrevet ovenfor. La oss ta en titt på koden. Åpne USI_I2C_RAM.c. Det skal se ganske likt den forrige koden ut. De viktigste forskjellene er detaljene i lese- og skrivehukommelsen. Se på hvordan meldingsbufferen lastes inn før samtalen som faktisk skriver. Den første byten er slaveadressen med lese-/skrivebiten satt riktig. Men den neste byten er minneadressen for å begynne å skrive data. Deretter kommer de faktiske databyte som vil bli sekvensielt lastet inn i minnet fra adressen vi spesifiserte. Vi angir meldingsstørrelsen som 6. Så vi begynner å skrive på adressen 00 og skriver verdiene 01, 03, 02 og 06 inn i minnestedene 00 til 03. For å lese dataene tilbake fra minnet må vi bruke funksjonen USI_TWI_Start_Random_Read. Meldingsbufferen får slaveadressen i den første byten og startadressen i den andre byten. Deretter kaller du funksjonen med meldingsstørrelsen satt til antall byte som skal leses pluss 2. Legg merke til at lese-/skrivebiten ikke spiller noen rolle, siden en lesing vil bli utført uansett. Dataene som returneres starter på det andre stedet i meldingsbufferen. Når dataene er lest inn, blir de invertert for visning på Port Expander og skrevet en byte om gangen til den med en pause mellom verdiene. Til slutt er Port Expander -lysdiodene slått av. Skrivene til Port Expander er identiske med det som ble gjort i de foregående eksemplene. For moro skyld kan du kommentere #define DEBUG -setningen som ovenfor og se mange blinkende lysdioder. Skyllet av spenning etter nok et vellykket eksperiment, la oss gå til ATmega168 og en EEPROM. Endre arbeidskatalogen til EEPROM under TWI I2C. Bruk make -filen til å kompilere og laste ned TWI_I2C_EEPROM.c. Vær oppmerksom på at I2C -driverfilene er identiske med de vi brukte tidligere for PCA8574A. For å teste programmet, koble fra ATtiny2313 og koble til ATmega168. La I2C -bussen være tilkoblet Ram og slå på strømmen. Resultatene er forskjellige siden vi nå skriver og leser mer data. LED 1 på PD7 skal blinke ved initialisering. Trykk på knappen og data vil bli lest tilbake fra minnet og vist. Lysdiodene på PCA8574 skal blinke i følgende rekkefølge: P1, P0 og P2, (alle av), P0 & P1, P1 og P2. Til slutt skal alle LED -lampene slukke. Trykk på knappen igjen for å gjenta dette. Åh, men vent, sier du. Er ikke dette programmet for EEPROM? Siden vi får tilgang til en minneenhet på samme I2C -adresse, fungerer det samme programmet for både Ram og EEPROM. Slå av og flytt SDA og SCL fra Ram til EEPROM og kjør programmet igjen. Det skal fungere akkurat det samme. Vær oppmerksom på at EEPROM og Ram ikke kan kobles til I2C -bussen samtidig siden de deler samme adresse. (De smarte blant dere kan vurdere å endre de programmerbare adressebitene på Ram, men det vil fortsatt ikke fungere. 24C16 bruker hele adresseblokken som kan programmeres for Ram.) OK, la oss se på dette siste programmet. Åpne TWI_I2C_EEPROM.c. Det første jeg må legge merke til er at jeg har angitt hvordan jeg skal adressere hele 24C16 EEPROM. Den kan nås i 256 byte biter på 8 forskjellige I2C -slaveadresser. Se hvordan MEMORY_ADDR er definert som startadressen ved 50 heksadesimale; det var derfor Ram fungerte. Hvis du vil ha tilgang til andre blokker av 24C16, kan du bruke de andre adressene som jeg har angitt. Ta en titt på hvordan jeg konfigurerte meg for å skrive til minnet. Først settes slaveadressen med lese-/skrivebitsettet i bufferen, deretter startadressen til 00, deretter 16 byte med data. Funksjonen TWI_Start_Read_Write kalles til å skrive dataene (som før) med meldingsstørrelsen satt til 18. Når knappen trykkes, bruker vi TWI_Start_Random_Read og TWI_Read_Data_From_Buffer for å lese dataene tilbake. Hver tredje byte vises på Port Expander -lysdiodene. Til slutt slås lysdiodene av for å vente på neste knappetrykk. Du lurer kanskje på hvorfor jeg valgte å skrive 16 byte. Hvis du leser databladet nøye, ser du at 24C16 gjør en skrivesyklus hver gang den mottar 16 byte, selv om flere byte blir sendt. Så det virket som et fint tall å bruke. Hvis du velger å øke dette, må du endre størrelsen på MESSAGEBUF_SIZE. Du må også endre verdien TWI_BUFFER_SIZE i TWI_Master.h. Dette er fordi driveren kopierer dataene fra meldingsbufferen for bruk av avbruddstjenesterutinen. Gratulerer! Du er nå klar til å bruke I2C -bussen i dine egne prosjekter!

Trinn 7: Nettressurser

Her er koblingene til databladene for delene som ble brukt til eksperimentene. Du bør definitivt få disse hvis du ikke får noe annet. Port ExpanderRamEEPROM Å være skaperen av I2C, NXP (Philips) har massevis av flotte ting. (De liker å bruke firkantede parenteser i nettadressene sine, så jeg kan ikke inkludere dem ordentlig her. Beklager.] For å komme til I2C -området, velg Grensesnitt fra produktlisten. Du kommer til I2C -siden deres og tilgang til alle databladene og appnotatene de tilbyr. I2C -bussbeskrivelsen og tekniske detaljer spesielt er her. Få ATtiny2313 og ATmega168 datablad (databøker?) fra Atmel. Atmel applikasjonsnotater er her. Se på AVR310 og AVR315. Ta tak i koden. Se her for mange flere I2C -ting.

Trinn 8: Notater for Geeks

For den sanne nerd som vil vite detaljene, her er noen ting du må huske på hvis du ser på Atmel Apps Notes og driverkode:- Metoden for å adressere og kommandere en I2C-enhet er ikke en del av spesifikasjonen! Annet enn slaveadressen og lese/skrive -biten, er kommandoer, moduser osv. Ikke spesifisert og er spesifikke for en gitt enhet. For å gjøre dette veldig klart, vær oppmerksom på at opplegget som brukes i Atmel-eksemplet bare gjelder det eksemplet, og er ganske mye ikke-standard.- USI-implementeringen skiller seg fra TWI-implementeringen på noen få viktige måter. + Med USI tilbys klokkering av programvare; med TWI leveres den av en bithastighetsgenerator. + USI -metoden bruker ikke avbrudd; TWI gjør. Dette gir en viss mening, siden Mega -familien (ved bruk av TWI) kan gjøre mange andre ting og ikke bør bli hogged av I2C -overføringer. En avbruddsdrevet versjon for USI er absolutt mulig, den er bare ikke implementert i denne instruksjonsboken. + USI -maskinvaren er ikke optimalisert for I2C og kan bare håndtere 8 -biters overføringer. Dette betyr at to overføringer er nødvendig for å sende den niende biten (enten NACK eller ACK). TWI -maskinvaren håndterer dette automatisk. Dette gjør implementeringen av USI -driveren litt mer komplisert. + Feildeteksjon for TWI håndteres i maskinvare. USI krever håndtering i programvare som kompliserer ting noe. + TWI -maskinvaren styrer konfigurasjonen av porten direkte. USI -maskinvaren krever at portbitene konfigureres før porten kan brukes. Du vil se dette i Master_Initialize-rutinen for USI.-Atmel hevder at det er mulig å bruke AVR-port pull-ups for I2C buss pull-ups. Jeg har ikke funnet ut en måte å få den tilnærmingen til å fungere. Å bruke to eksterne motstander virker som en ganske enkel ordning, så jeg brukte ikke mye tid på dette.

Anbefalt: