Innehållsförteckning:

I2C -buss för ATtiny och ATmega: 8 steg
I2C -buss för ATtiny och ATmega: 8 steg

Video: I2C -buss för ATtiny och ATmega: 8 steg

Video: I2C -buss för ATtiny och ATmega: 8 steg
Video: LDmicro 20: решен вопрос жидкокристаллического дисплея I2C (программирование ПЛК микроконтроллера с помощью LDmicro) 2024, November
Anonim
I2C -buss för ATtiny och ATmega
I2C -buss för ATtiny och ATmega

Jag älskar Atmel AVR -mikrokontroller! Sedan jag byggde det Ghetto -utvecklingssystem som beskrivs i denna instruktionsbok har jag inte haft något kul att experimentera med AVR ATtiny2313 och ATmega168 i synnerhet. Jag gick till och med så långt som att skriva en instruktionsbok om hur man använder switchar som ingångar och utökade Ghetto Development System -konceptet till CPLDs. Under ett nyligen genomfört projekt behövde jag flera switchar för att ställa in kontrollvärden. AVR: erna hade inte tillräckligt med I/O -stift, så jag var tvungen att tänka på något. Jag kunde ha provat ett komplext inmatningssystem med tangentbord och skärm, men ATtiny2313 skulle ha slut på resurser. Lyckligtvis har Atmel tillhandahållit en väg runt detta problem genom att inkludera ett gränssnitt som kan länka till ytterligare chips (t.ex. minne eller I/O -portar) med ett enkelt tvåtrådigt gränssnitt. Det stämmer, genom att använda bara två I/O -stift på en AVR kan vi komma åt många ytterligare I/O -stift och andra resurser också. Detta tvåtrådsgränssnitt är formellt känt som den interintegrerade kretsbussen, eller bara I2C-bussen och uppfanns av NXP när den fortfarande var Philips Semiconductors. Om du läser den här instruerbara har du förmodligen hört talas om I2C -bussen och kanske till och med har använt den på en PIC eller annan mikrokontroller. Även om de är konceptuellt mycket enkla och stöds av hårdvaruresurser på AVR: erna, är det fortfarande nödvändigt med drivrutiner för att använda I2C -bussen. Atmel tillhandahåller applikationsanteckningar (se resurserna senare i denna instruktionsbok), men dessa är ofullständiga och visar inga exempel utöver att kommunicera med en annan AVR -enhet. Det är inte syftet med denna instruktionsbok att lära någon hur man skapar I2C -drivrutiner för AVR. Jag kommer snarare att tillhandahålla utökade versioner av Atmel -drivrutinerna för ATtiny2313- och ATmega168 -enheter, jag ska förklara de krav och begränsningar som gäller vid användning av dessa, och jag visar dig exempel på I2C -enheter. När du har arbetat igenom denna instruerbara kommer du att kunna använda I2C -bussen framgångsrikt i dina AVR -projekt. Uppenbarligen kan du ignorera drivrutinerna för antingen små eller MEGA om du bara är intresserad av en av dem. För dem som är intresserade av att lära sig mer om I2C -bussen kommer jag att länka till lämpligt material.

Steg 1: Vad är allt detta I2C -saker i alla fall?

Vad är allt detta I2C -grejer i alla fall?
Vad är allt detta I2C -grejer i alla fall?
Vad är allt detta I2C -grejer i alla fall?
Vad är allt detta I2C -grejer i alla fall?
Vad är allt detta I2C -grejer i alla fall?
Vad är allt detta I2C -grejer i alla fall?
Vad är allt detta I2C -grejer i alla fall?
Vad är allt detta I2C -grejer i alla fall?

I2C-bussen är en enkel, tvåtrådig anslutning som kan koppla ihop flera enheter och låta dem utbyta data. I sin enklaste form finns det en huvudenhet som kommunicerar till flera slavenheter. Alla enheter är parallellt anslutna till I2C -bussens två ledningar. De två ledningarna är kända som SCL och SDA. SCL är klocklinjen och styrs av huvudenheten. SDA är den dubbelriktade datalinjen. För att överföra data skickar mastern ut en slavadress kombinerad med en bitars läs-/skrivflagga. Om en skrivning önskas fortsätter mastern att skicka data till den adresserade slaven. Om en läsning begärs svarar slaven med data. För att koordinera transaktioner manipuleras SCL- och SDA -linjerna av mastern och slaven för att signalera flera villkor. Dessa inkluderar START, STOP, ACK (kvittera) och NAK (ingen kvittering). Informationen om dessa villkor hanteras av förarna. De sanna nördarna bland er kan lära sig alla detaljer i länkarna i slutet av denna instruktionsbok. De elektriska kraven är ganska enkla. Mästaren och slavarna måste använda samma nivå för Vcc, grunderna måste vara anslutna och SCL- och SDA -linjerna måste dras upp till Vcc. Värdet på uppdragningsmotstånden bestäms exakt av en beräkning baserad på den totala kapacitansen på bussen, men kan praktiskt taget vara i stort sett vilket värde som helst mellan 1,8K och 10K. Jag börjar med 5.1K och använder lägre värden tills det fungerar. Detta är vanligtvis inte ett problem om du inte har många enheter eller långa kablar mellan enheterna. Den nominella datahastigheten på I2C -bussen är 100Kbit/sekund. Priser på 400Kbit/sekund, 1Mbit/sekund och därefter är också möjliga, men stöds inte av förarna i denna instruktionsbok. Alla I2C -enheter fungerar med 100 kbit/sekund. ATtiny2313 och ATmega168 implementerar var och en I2C -bussen olika. ATtiny2313 använder hårdvaran Universal Serial Interface (USI) - som också kan användas för SPI -bussen. ATmega168 har dedikerad hårdvara för I2C -bussen, känd som Two Wire Interface (TWI). När drivrutinerna väl skrivits är dessa skillnader oftast transparenta för användaren. En signifikant skillnad är i programvaran: ATmega168 I2C -drivrutinen drivs avbrott medan den för ATtiny2313 inte är det. Detta innebär att ett ATmega168 -program inte behöver vänta på att I2C -dataöverföringar ska ske, utan behöver bara vänta innan en annan överföring påbörjas, eller tills data kommer från en läsoperation. Exemplen och diskussionen som ska följas bör göra detta klart. I2C -adresser är 7 bitar långa, så upp till 127 enheter kan vara på bussen om var och en har en unik adress. Som visas i figuren flyttas denna 7 -bitars adress vänster en bit och den minst signifikanta biten används för att flagga en läsning eller skrivning av enheten vid adressen. Således är den fullständiga slavadressen en 8 bitars byte. Den faktiska adressen bestäms delvis internt till enheten och kan inte ändras (4 mest betydande bitar), och delvis bestäms av bitar som kan anslutas till enhetens stift (3 minst signifikanta bitar) som kan bindas högt eller lågt för att ställa in en specifik adress. Låter förvirrande, men ett exempel kommer att göra detta tydligt. PCA8574A -databladet visar att de fyra viktigaste bitarna i I2C -adressen alltid kommer att vara 0111. De tre nästa bitarna bestäms av inställningarna på stiften AD0, AD1 och AD2. Dessa stift kan knytas till jord eller till den positiva spänningsförsörjningen (5 volt) för att representera 0 respektive 1. Så intervallet av möjliga adresser är 38 till 3F hexadecimal, som visas i den andra figuren från PCA8574 -databladet. Så genom att ändra adressbitinställningarna kan upp till 8 PCA8574As finnas på I2C -bussen samtidigt. Var och en svarar bara på sin specifika slavadress. Om det behövs ännu fler I/O -portar kan PCA8574 användas. Den enda skillnaden mellan PCA8574 och PCA8574A är att I2C -slavadressintervallet för PCA8574 är 20 till 27 hexadecimalt. Att bestämma adressen för en given enhet kan vara förvirrande eftersom vissa datablad anser att läs-/skrivbiten är en del av adress. Läs databladet noggrant och tänk på att slavadressen kommer att vara 7 bitar lång. Läs/skrivbiten bör behandlas separat. Återigen, ett exempel hjälper. Databladet för 24C16 EEPROM som vi experimenterar med säger att de första (mest signifikanta) fyra bitarna i slavadressen är 1010. De tre nästa bitarna kan bestämmas av A0, A1 och A2; men notera att databladet också täcker 24C01 till 24C08 som är mindre EEPROM. Figuren från databladet visar att inställningarna för dessa adressbitar ignoreras när storleken ökar och ignoreras helt för 24C16. Det vill säga, de tre sista bitarna spelar ingen roll och 24C16 använder verkligen alla I2C -slavadresser 50 till 57 hexadecimala. Utbudet av slavadresser kommer faktiskt att adressera olika sektioner inom 24C16. De första 256 byten är vid adressen 50h, de nästa 256 vid 51h, och så vidare upp till de sista 256 bytesna vid 57h - totalt 2K byte. Eftersom adressen till PCF8570 -RAM -minnet som vi också experimenterar med ligger inom detta område kan 24C16 och PCF8570 inte användas tillsammans.

Steg 2: Beställ några I2C -enheter

Nu när du vet lite om I2C -bussen och vill använda den, varför inte beställa några I2C -enheter att experimentera med nu så att de kan vara på väg till dig medan du gör programvaran klar? Lämpliga enheter inkluderar en I/ O Interface Expander (min favorit), en statisk ram och en EEPROM. Det finns mycket mer, men det här är en bra start. AVR -processorerna vi använder är ATtiny2313 och Atmega168 (används i Arduino). Om du är ny på dessa, ta en titt på denna fantastiska instruktionsbok för att lära dig mer om dem och bygga ditt Ghetto -utvecklingssystem. Schemat över ATmega168 i den nuvarande instruktionsboken visar hur man implementerar Ghetto Development System för denna processor. Parallellportskabeln är densamma som den för ATtiny2313. (Jag har inte provat USB -versionen av Ghetto Development System, så jag är inte säker på hur I2C -bussen nås på den. Samma för Arduino.) Här är Digikey -artikelnummer. 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

Steg 3: I2C -drivrutiner

Här är beskrivningarna av drivrutinsfunktionerna för I2C -bussen. Dessa utvecklades med Atmel Apps Notes till att börja med. Jag hade inte kunnat göra detta utan dem som en bas att bygga på. Utvecklingen gjordes med WinAVR och gcc C -kompilatorn. Klockfrekvensbegränsningar beskrivs nedan för varje processor. Eftersom jag inte kan testa alla möjliga kombinationer av processorsmak / klockfrekvens, kommer jag bara att hålla mig till vad jag faktiskt kan testa och försöka ange begränsningar och begränsningar. Här är drivrutinsfunktionerna och hur jag använder dem. Titta på exemplen för mer information och för att se de funktioner som används i kompletta program. För ATtiny2313: Klockkrav: Drivrutinerna är utformade för en klockfrekvens på 1MHz (standardhastigheten) för ATtiny2313. Om du vill köra med andra hastigheter måste du justera konstanter i drivrutinerna. Maila mig om du behöver hjälp med detta. Du kan också få några tips från Atmel -appens anteckningar i länkarna i resurssteget. USI_TWI_Master_Initialise () Denna funktion initierar USI -maskinvaran för drift i I2C -läge. Kalla det en gång i början av ditt program. Den returnerar ogiltiga och det finns inga argument. USI_TWI_Get_State_Info () Denna funktion returnerar I2C -felinformation och används om ett fel uppstod under en I2C -transaktion. Eftersom denna funktion bara returnerar en felkod använder jag funktionen TWI_Act_On_Failure_In_Last_Transmission (TWIerrorMsg) för att blinka en fel -LED. Felkoderna definieras i USI_TWI_Master.h. Så här kallar du det: TWI_Act_On_Failure_In_Last_Transmission (USI_TWI_Get_State_Info ()) USI_TWI_Start_Read_Write () Denna funktion används för att läsa och skriva enstaka byte till I2C -enheter. Det används också för att skriva flera byte. Det finns 6 steg för att använda denna funktion. 1) Deklarera en meddelandebuffert i ditt program för att hålla slavadressen och databyten som ska skickas eller tas emot. osignerat char -meddelandeBuf (MESSAGEBUF_SIZE); 2) Sätt slavadressen som den första byten i bufferten. Flytta den en bit åt vänster och ELLER i Läs/skriv -biten. Observera att läs-/skrivbiten blir 1 för en läsning och 0 för en skrivning. Detta exempel är för en Läs. messageBuf (0) = (TWI_targetSlaveAddress << TWI_ADR_BITS) | (SANT << TWI_READ_BIT); 3) När du skriver skriver du den byte som ska skrivas till nästa plats i bufferten. 4) Ring funktionen USI_TWI_Start_Read_Write med meddelandebufferten och meddelandestorleken som argument.temp = USI_TWI_Start_Read_Write (messageBuf, 2); 5) The returnerat värde (temp i detta fall) kan testas för att se om ett fel uppstod. Om så är fallet hanteras det som diskuterats ovan. Se exempel i programmen. 6) Om en läsning begärdes kommer byteavläsningen att finnas på den andra platsen i bufferten. Om flera byte ska skrivas (t.ex. till en minnesenhet) kan samma rutin användas. Att ställa in bufferten och ringa rutinen är något annorlunda. Den andra byten i bufferten är startminnesadressen som ska skrivas till. Data som ska skrivas kommer att finnas i efterföljande byte. Meddelandestorleken är storleken inklusive all giltig data. Så om 6 byte ska skrivas, kommer meddelandestorleken att vara 8 (slavadress + minnesadress + 6 byte med data). USI_TWI_Start_Random_Read () Denna funktion används för att läsa flera byte från en I2C -enhet, vanligtvis är det bara meningsfullt för något minne. Att använda denna rutin är mycket lik den föregående rutinen, med två undantag. Inställningen av Läs/skriv -biten spelar ingen roll. Att kalla denna rutin kommer alltid att orsaka en läsoperation. Meddelandet Storlek ska vara 2 plus antalet byte som ska läsas. Om inga fel uppstår kommer data att finnas i bufferten som börjar på den andra platsen. För ATmega168: Klockkrav: drivrutiner är utformade för en klockfrekvens på 4MHz för ATmega168. Exempelkoden visar hur du ställer in denna klockfrekvens. Om du vill köra med andra hastigheter måste du justera konstanter i drivrutinerna. Maila mig om du behöver göra detta. TWI_Master_Initialise () Denna funktion initierar TWI -maskinvaran för drift i I2C -läge. Kalla det en gång i början av ditt program. Det returnerar ogiltiga och det finns inga argument. Var noga med att aktivera avbrott genom att ringa swi () efter initiering. TWI_Get_State_Info () Denna funktion returnerar I2C -felinformation och används om ett fel uppstod under en I2C -transaktion. Eftersom denna funktion bara returnerar en felkod använder jag funktionen TWI_Act_On_Failure_In_Last_Transmission (TWIerrorMsg) för att blinka en fel -LED. Felkoderna definieras i TWI_Master.h, men är modifierade för signalering på en fel -LED. Se exempelkoden för detaljer. Så här kallar du det: TWI_Act_On_Failure_In_Last_Transmission (TWI_Get_State_Info ()) Observera att felkontrollen görs genom att se till att I2C -transaktionen är klar (funktionen beskrivs nedan) och sedan testa lite i det globala statusordet. TWI_Start_Read_Write () TWI_Start_R två funktioner fungerar på samma sätt som motsvarande funktioner som beskrivs ovan men med några få undantag. De returnerar inga felvärden. Läst data överförs inte till bufferten. Detta görs med funktionen som beskrivs nästa gång. När du ringer TWI_Start_Random_Read ska meddelandet Storlek vara antalet begärda databyte plus en, inte två. I2C -drivrutinen för ATmega168 drivs avbrott. Det vill säga att I2C -transaktionerna startas och utförs sedan oberoende medan huvudrutinen fortsätter att köras. När huvudrutinen vill ha data från en I2C -transaktion som den startade måste den kontrollera om data är tillgänglig. Situationen är densamma för felkontroll. Huvudrutinen måste vara säker på att I2C -transaktionen är klar innan du letar efter fel. Nästa två funktioner används för dessa ändamål. TWI_Transceiver_Busy () Ring den här funktionen för att se om en I2C -transaktion är klar innan du kontrollerar om det finns fel. Exempelprogrammen visar hur du använder detta. TWI_Read_Data_From_Buffer () Anropa den här funktionen för att överföra data från I2C -drivrutins mottagningsbuffert till meddelandebufferten. Denna funktion kommer att se till att I2C -transaktionen är klar innan data överförs. Medan ett värde returneras av den här funktionen, tycker jag att det är mer pålitligt att kontrollera felbiten direkt. Så här kallar du det. Meddelandet Storlek bör vara en större än antalet önskade databitar. Data kommer att finnas i messageBuf från den andra platsen.temp = TWI_Read_Data_From_Buffer (messageBuf, messageSize);

Steg 4: Låt oss bygga

Låt oss bygga!
Låt oss bygga!
Låt oss bygga!
Låt oss bygga!
Låt oss bygga!
Låt oss bygga!
Låt oss bygga!
Låt oss bygga!

Börja med att ladda ner filen I2C Schematics.zip. Du kanske vill skapa en I2C -mapp i ditt arbetsområde för att hålla schemat och exempelprogramfilerna. Packa upp schemat i den här katalogen. Du hittar en mapp som heter I2C Schematics. Öppna filen med namnet tiny I2C.pdf. Denna schema visar ATtiny2313 Ghetto Development System och PCA8574A I/O Port Expander (har den stora streckade rutan runt den). Port Expander -kretsen är byggd på en brödbräda. Ta en titt på bilderna för att se hur dessa kretsar ser ut. De är verkligen ganska enkla. ATtiny2313 -delen av schemat är bara Ghetto Development System med tre blinkljus (LED1, 2 och 3, plus R4, 5 och 6) och en tryckknapp (S1) ansluten till den, plus en ytterligare detaljer. Den detaljen är tillägget av hoppare (JP4, 5 och 6) som kan tas bort för att möjliggöra anslutning av I2C -buss SCL- och SDA -linjer. Hopparna måste vara på plats för programmering och sedan tas bort så att SCL och SDA kan anslutas. Bilderna visar hopparna på plats och tagna bort. Placeringen av dessa hoppare är upp till dig, du måste bara sätta dem på ditt Ghetto Development System om du vill använda I2C -bussen. I2C -bussen måste kopplas bort och hopparna sättas på plats för programmering. Observera att du bara verkligen behöver oroa dig för JP4 och JP6 för I2C -bussen. Sätt i JP5 om du tror att du någonsin vill använda SPI -bussen. Det är väldigt enkelt att brädda PCA8574A I/O Port Expander. Ge Vcc (+5 volt) och Gnd (jord) anslutningar och anslut AD0, 1 och 2 till jord (gör I2C slavadress 38 hex). Anslut sedan 4 blinklampor och 4 DIP -omkopplare. (Om du inte har DIP-omkopplare kan du bara använda ledningar. Knyt till marken eller låt den flyta för att signalera respektive stänga av.) Anslut slutligen uppdragningsmotstånden (R11 och 12) från SDA och SCL till Vcc. Dessa visas som 3,3K, men alla värden från 1,8K till 5,1K borde fungera (kanske upp till 10K men jag har inte provat det). När du har programmerat ATtiny2313 kan du ta bort hopparna och ansluta SDA och SCL för testning. Nu för ATmega168. Den enda rynkan här är att du kanske inte har byggt ett Ghetto Development System för denna processor. Om så är fallet visar schemat som jag tillhandahåller (MEGA I2C.pdf) dig hur. Detta är bara en permutation av ATtiny2313 -versionen. Om du planerar i förväg kan du se till att din programmeringskabel passar båda systemen. Den största skillnaden är tillsatsen av C2 och C3. Se bilderna för placering av dessa, de ska vara mycket nära chipet; en av dem är faktiskt under chipet. Dessa hjälper till att hålla buller utanför den analoga till digitala omvandlaren i synnerhet. Du behöver inte sätta i hopparna om du inte planerar att använda SPI -bussen eftersom de inte behövs för I2C -bussen på detta chip. Observera att PCA8754A -brödbrädan kommer att vara oförändrad. Du kommer bara att ansluta SDA och SCL och iväg! Lätt, va?

Steg 5: Låt oss koda och testa

Låt oss koda och testa!
Låt oss koda och testa!
Låt oss koda och testa!
Låt oss koda och testa!
Låt oss koda och testa!
Låt oss koda och testa!

Det är dags att bygga drivrutinerna och exempelprogrammen. Vi börjar med ATtiny2313 och brödbrädan PCA8574A som vi just byggt. Ladda ner filen I2C.zip till din I2C -arbetskatalog och packa upp den. Du får en ny mapp som heter I2C. I den hittar du USI I2C (för ATtiny2313) och TWI I2C (för ATmega168). I USI I2C hittar du mappen I_O Port. Den mappen innehåller koden för vårt första exempelprogram och USI I2C -drivrutinerna. Använd WinAVR, kompilera och ladda in koden i ATtiny2313. Ta ett djupt andetag och slå på strömmen. Här är vad du kan förvänta dig: Vid påslagning blinkar LED 1 på port PD6 på ATtiny2313 två gånger. Inget annat händer innan du trycker på knappen (S1). Varje gång knappen trycks in läses omkopplarna och deras inställning visas på lysdioderna som är anslutna till PCA8574A. Ändra värdet på omkopplarna, tryck på knappen, så ska lysdioderna ändras. Fortsätt med det här tills du kommer över spänningen att se att det fungerar. Om (gud förbjuda!) Saker inte fungerar som förväntat, kontrollera noga dina kablar. I2C -fel indikeras av blinkningar på LED3 (PD4) och betyder förmodligen att du måste kontrollera att SDA och SCL är anslutna till rätt stift och dras upp korrekt. Om saker fortfarande inte fungerar, läs resten av det här avsnittet för att lära dig om felsökning. Gå nu tillbaka och låt oss titta på koden. Öppna filen USI_I2C_Port.c. Detta är koden för exempelprogrammet. (USI_TWI_Master.c och USI_TWI_Master.h innehåller drivrutinerna - du kan ignorera dem om du inte är nyfiken.) Använd exemplet för att vägleda dina egna I2C -applikationer. För det mesta visar programmet dig hur du initierar och använder I2C -drivrutiner, inklusive inställningar upp slavadressen och resten av meddelandebufferten och få ut data från den. Du kommer också att se hur jag tar bort knappen och ställer in medan loop. Det finns några detaljer om programmet värt att nämna. Observera att data från switcharna inverteras innan de skrivs till lysdioderna på Port Expander. Observera också att ingångsportarna på Port Expander måste skrivas som High för att de ska fungera korrekt. Dessa detaljer beskrivs i PCA8574A -databladet. Läs alltid databladen noga! Av mer intresse är användningen av villkorlig felsökning. Nära början av programfilen är satsen // #definiera DEBUG och sprids över hela koden #ifdef DEBUG -satser. Så länge DEBUG inte är definierat (de två snedstreckarna gör raden till en kommentar och hindrar den från att definieras) kommer koden inom #ifdef till #endif -satserna inte att sammanställas. Men om saker inte fungerar som du förväntar dig, kompilera om och ladda om koden med #define DEBUG okommenterad. Du får mycket fler blinkningar på lysdioderna som du kan avkoda för att följa genomförandet av ditt program och hjälpa dig att hitta exakt var saker går fel. Jag rekommenderar faktiskt att du provar det här bara för att se vad som händer. Vad du ser är att LED 2 (på PD5) kommer att blinka när körningen går igenom programmet. Värdet som läses från omkopplarna blinkar på LED 1 (PD6) innan det visas på Port Expander -lysdioderna. Du bör kunna spåra programmet när det körs med hjälp av dessa lysdioder. Vi kommer att arbeta med ATmega168 nästa; hoppa över det här avsnittet om du bara är intresserad av ATtiny2313. Fortfarande med mig? Bra. Flytta till mappen TWI_I2C, ändra din arbetskatalog till IO_Port och kompilera och ladda TWI_I2C_Port.c till ATmega168. Koppla bort SDA- och SCL -linjerna från ATtiny2313 och anslut dem till ATmega168. Anslut ström och jord, och slå på. Operationen ska vara densamma! Spela tills spänningen avtar, låt oss titta på koden. Öppna TWI_I2C_Port.c. Koden är nästan identisk förutom felhantering och tillmötesgående avbrottsdrivna drivrutiner. Här är skillnaderna: Observera att klockan måste ställas in på 4MHz för att I2C -bussen ska fungera korrekt. Seien (); sats aktiverar avbrott efter initiering av I2C -drivrutinerna. För att söka efter fel testas en specifik statusbit. Under en läsning måste TWI_Read_Data_From_Buffer -funktionen anropas för att överföra data som läses till meddelandebufferten. Under en skrivning, medan (TWI_Transceiver_Busy ()) måste användas för att vara säker på att överföringen är klar innan du letar efter fel. Dessa två sista funktioner beskrivs ovan i beskrivningen av drivrutinerna. Annat än det är koden ungefär densamma som för ATtiny2313. DEBUG fungerar på samma sätt också om du vill experimentera med det.

Steg 6: Använda I2C -minne

Använda I2C -minne
Använda I2C -minne
Använda I2C -minne
Använda I2C -minne
Använda I2C -minne
Använda I2C -minne
Använda I2C -minne
Använda I2C -minne

Nu när vi har lärt oss att använda I2C -bussen för att läsa och skriva en I/O -portutvidgare, låt oss gå vidare till att använda I2C -minnen, både RAM och EEPROM. Den största skillnaden är att flera byte kan läsas till eller skrivas från minnen med ett enda I2C -kommando. För att göra oss redo för dessa experiment måste vi modifiera hårdvaran något och bygga ett par nya kretsar på brödbrädan. Behåll Port Expander -kretsen eftersom vi kommer att använda den för att visa några minnesvärden. Ta bort DIP -omkopplarna från PCA8574A och sätt blinkers på dessa stift. Om du inte har tillräckligt med blinklampor, flytta dem på P4 till P7 över till P0 till och med P3. (Värden som ska visas är tillräckligt små.) Titta nu på den schematiska I2C Ram.pdf och koppla in PCF8570 på brödbrädan. Ta en titt på bilden också. Se till att knyta stift 7 till Vcc. Kör ledningar för SDA och SCL från PCA8574A. Inga ytterligare uppdragningsmotstånd krävs. Om du också är intresserad av EEPROM, bygg den kretsen också med I2C EEPROM.pdf för 24C16, men varnas för att exemplet använder ATmega168. Denna krets är verkligen enkel. Som diskuterats ovan bör adressbitarna ignoreras. Anslut bara ström och jord. Anslut inte SDA och SCL ännu eftersom vi inte har experimenterat färdigt med Ram. Vi börjar våra minnesexperiment med ATtiny2313 ansluten till PCA8574A Port Expander och till PCF8570 Ram. Programmet kommer att skriva några nummer till Ram, sedan läsa dem tillbaka och visa dem på Port Expander. Ändra din arbetskatalog till RAM under USI I2C. Använd make -filen för att kompilera och ladda ner USI_I2C_RAM.c. Observera att I2C -drivrutinsfilerna är identiska med dem vi använde tidigare. Anslut strömmen så ska du se en enda blinkning på LED 1 (PD6). Data kommer att skrivas till de första 4 byte av minne. Tryck på knappen och två byte kommer att läsas tillbaka och visas. Du bör se en LED -lampa på Port Expander (P0), en två sekunders paus och sedan två LED -lampor (P0 och P1). Ytterligare två sekunders paus och lysdioderna ska släckas. Tryck på knappen igen för att starta sekvensen igen. Felsökning liknar den metod som beskrivs ovan. Låt oss ta en titt på koden. Öppna USI_I2C_RAM.c. Det ska se ut ungefär som den tidigare koden. De största skillnaderna är detaljerna i läs- och skrivminne. Titta på hur meddelandebufferten laddas innan samtalet som faktiskt skriver. Den första byten är slavadressen med läs-/skrivbiten inställd på lämpligt sätt. Men nästa byte är minnesadressen för att börja skriva data. Därefter kommer de faktiska databyte som kommer att laddas i sekvens i minnet från den adress vi angav. Vi anger meddelandestorleken som 6. Så vi börjar skriva på adressen 00 och skriver värdena 01, 03, 02 och 06 i minnesplatserna 00 till 03. För att kunna läsa data från minnet måste vi använda funktionen USI_TWI_Start_Random_Read. Meddelandebufferten får slavadressen i den första byten och startadressen i den andra byten. Ring sedan funktionen med meddelandestorleken inställd på antalet byte som ska läsas plus 2. Observera att läs/skrivbiten inte spelar någon roll eftersom en läsning kommer att göras oavsett. Data som returneras startar på den andra platsen i meddelandebufferten. När data har lästs in, inverteras det för visning på Port Expander och skrivs en byte i taget till det med en paus mellan värdena. Slutligen är Port Expander -lysdioderna avstängda. Skrivningarna till Port Expander är identiska med vad som gjordes i de föregående exemplen. För skojs skull kan du kommentera #define DEBUG -uttalandet enligt ovan och se massor av blinkande lysdioder. Spolade av spänning efter ännu ett lyckat experiment, låt oss gå till ATmega168 och en EEPROM. Ändra din arbetskatalog till EEPROM under TWI I2C. Använd make -filen för att kompilera och ladda ner TWI_I2C_EEPROM.c. Observera att I2C -drivrutinsfilerna är identiska med dem vi använde tidigare för PCA8574A. För att testa programmet, koppla bort ATtiny2313 och anslut ATmega168. Lämna I2C -bussen ansluten till Ram och slå på. Resultaten är annorlunda eftersom vi nu skriver och läser mer data. Lysdiod 1 på PD7 ska blinka vid initialisering. Tryck på knappen så kommer data att läsas tillbaka från minnet och visas. Lysdioderna på PCA8574 ska blinka följande sekvens: P1, P0 & P2, (alla av), P0 & P1, P1 & P2. Slutligen bör port -lysdioderna slockna. Tryck på knappen igen för att upprepa detta. Åh, men vänta, säger du. Är inte detta program för EEPROM? Eftersom vi har åtkomst till en minnesenhet med samma I2C -adress fungerar samma program för både ram och EEPROM. Stäng av och flytta SDA och SCL från ram till EEPROM och kör programmet igen. Det borde fungera exakt likadant. Observera att EEPROM och Ram inte kan anslutas till I2C -bussen samtidigt eftersom de delar samma adress. (De smarta bland er kan överväga att ändra de programmerbara adressbitarna på Ram, men det fungerar fortfarande inte. 24C16 använder hela adressblocket som kan programmeras för Ram.) OK, låt oss titta på det sista programmet. Öppna TWI_I2C_EEPROM.c. Det första jag ska märka är att jag har angett hur jag ska hantera hela 24C16 EEPROM. Den kan nås i 256 byte bitar på 8 olika I2C -slavadresser. Se hur MEMORY_ADDR definieras som startadressen vid 50 hexadecimala; det var därför Ram arbetade. Om du vill komma åt andra block av 24C16, använd sedan de andra adresserna som jag har angett. Ta en titt på hur jag ställde upp för att skriva till minnet. Först läggs slavadressen med läs-/skrivbitsatsen i bufferten, sedan startadressen 00, sedan 16 byte data. Funktionen TWI_Start_Read_Write kallas för att skriva data (som tidigare) med meddelandestorleken inställd på 18. När knappen trycks in använder vi TWI_Start_Random_Read och TWI_Read_Data_From_Buffer för att läsa tillbaka data. Var tredje byte visas på Port Expander -lysdioderna. Slutligen släcks lysdioderna för att vänta på nästa knapptryckning. Du kanske undrar varför jag valde att skriva 16 byte. Om du läser databladet noggrant ser du att 24C16 gör en skrivcykel när den tar emot 16 byte även om fler byte skickas. Så det verkade vara ett trevligt nummer att använda. Om du väljer att öka detta måste du ändra storleken på MESSAGEBUF_SIZE. Du måste också ändra värdet TWI_BUFFER_SIZE i TWI_Master.h. Detta beror på att föraren kopierar data från meddelandebufferten för avbrottsrutinen. Grattis! Du är nu redo att använda I2C -bussen i dina egna projekt!

Steg 7: Webbresurser

Här är länkarna till databladen för de delar som används för experimenten. Du bör definitivt skaffa dessa om du inte får något annat. Port ExpanderRamEEPROM Genom att vara skaparen av I2C har NXP (Philips) massor av bra saker. (De gillar att använda hakparenteser i sina webbadresser, så jag kan inte inkludera dem ordentligt här. Tyvärr.] För att komma till I2C -området väljer du gränssnitt från produktlistan. Du kommer till deras I2C -webbplats och åtkomst till alla datablad och apparanteckningar de erbjuder. I2C -bussbeskrivningen och i synnerhet tekniska detaljer finns här. Hämta ATtiny2313- och ATmega168 -datablad (databöcker?) från Atmel. Atmel -applikationsanteckningarna finns här. Titta på AVR310 och AVR315. Ta koden också. Ta en titt här för mycket mer I2C -saker.

Steg 8: Anteckningar för nördar

För den sanna nörd som vill veta detaljerna, här är några saker att tänka på om du tittar på Atmel Apps Notes och förarkod:- Metoden för att adressera och styra en I2C-enhet är inte en del av specifikationen! Annat än slavadressen och läs-/skrivbiten är kommandon, lägen, etc. inte specificerade och är specifika för en given enhet. För att göra detta mycket tydligt, notera att schemat som används i Atmel-exemplet endast gäller det exemplet och är i stort sett icke-standard.- USI-implementeringen skiljer sig från TWI-implementeringen på några viktiga sätt. + Med USI tillhandahålls klockning av programvara; med TWI tillhandahålls den av en bithastighetsgenerator. + USI -metoden använder inte avbrott; TWI gör. Detta ger en viss mening, eftersom Mega -familjen (med TWI) kan göra många andra saker och inte bör tappas av I2C -överföringar. En avbrottsdriven version för USI är verkligen möjlig, den är helt enkelt inte implementerad i denna instruktionsbok. + USI -hårdvaran är inte optimerad för I2C och klarar bara 8 bitars överföringar. Detta innebär att två överföringar krävs för att skicka den nionde biten (antingen NACK eller ACK). TWI -hårdvaran hanterar detta automatiskt. Detta gör implementeringen av USI -drivrutinen lite mer komplicerad. + Felavkänning för TWI hanteras i hårdvara. USI kräver hantering i programvara som komplicerar saker och ting något. + TWI -hårdvaran styr portens konfiguration direkt. USI -hårdvaran kräver att portbitarna konfigureras innan porten kan användas. Du ser detta i Master_Initialize-rutinen för USI.-Atmel hävdar att det är möjligt att använda AVR-portuppdrag för I2C-bussuppdrag. Jag har inte kommit på ett sätt att få det tillvägagångssättet att fungera. Att använda två externa motstånd verkar vara ett ganska enkelt schema, så jag ägnade inte mycket tid åt detta.

Rekommenderad: