Inhoudsopgave:

I2C-bus voor ATtiny en ATmega - Ajarnpa
I2C-bus voor ATtiny en ATmega - Ajarnpa

Video: I2C-bus voor ATtiny en ATmega - Ajarnpa

Video: I2C-bus voor ATtiny en ATmega - Ajarnpa
Video: AVR 47# Программный I2C 2024, Juli-
Anonim
I2C-bus voor ATtiny en ATmega
I2C-bus voor ATtiny en ATmega

Ik ben dol op de Atmel AVR-microcontrollers! Sinds ik het Ghetto Development System heb gebouwd dat in deze Instructable wordt beschreven, heb ik eindeloos veel plezier gehad met het experimenteren met de AVR ATtiny2313 en de ATmega168 in het bijzonder. Ik ging zelfs zo ver dat ik een Instructable schreef over het gebruik van schakelaars als invoer, en breidde het Ghetto Development System-concept uit naar CPLD's. Tijdens een recent project had ik verschillende schakelaars nodig voor het instellen van controlewaarden. De AVR's hadden niet genoeg I/O-pinnen, dus ik moest iets bedenken. Ik had een complex invoersysteem met een toetsenbord en display kunnen proberen, maar de ATtiny2313 zou geen middelen meer hebben. Gelukkig heeft Atmel dit probleem opgelost door een interface op te nemen die kan worden gekoppeld aan extra chips (zoals geheugen of I/O-poorten) met een eenvoudige tweedraads interface. Dat klopt, door slechts twee I/O-pinnen op een AVR te gebruiken, hebben we toegang tot veel extra I/O-pinnen en ook andere bronnen. Deze tweedraadsinterface staat formeel bekend als de Inter-Integrated Circuit-bus, of gewoon de I2C-bus en werd uitgevonden door NXP toen het nog Philips Semiconductors was. Als je deze Instructable leest, heb je waarschijnlijk gehoord van de I2C-bus en heb je deze misschien zelfs op een PIC of andere microcontroller gebruikt. Hoewel conceptueel heel eenvoudig en ondersteund door hardwarebronnen op de AVR's, zijn er nog steeds softwarestuurprogramma's nodig om de I2C-bus te gebruiken. Atmel biedt Application Notes (zie de bronnen verderop in deze Instructable), maar deze zijn onvolledig en tonen geen andere voorbeelden dan communicatie met een ander AVR-apparaat. Het is niet de bedoeling van deze Instructable om iemand te leren hoe I2C-stuurprogramma's voor de AVR's. In plaats daarvan zal ik uitgebreide versies van de Atmel-stuurprogramma's voor ATtiny2313- en ATmega168-apparaten leveren, ik zal de vereisten en beperkingen uitleggen die van toepassing zijn bij het gebruik ervan, en ik zal u werkende voorbeelden van I2C-apparaten laten zien. Nadat je deze Instructable hebt doorlopen, kun je de I2C-bus met succes gebruiken in je AVR-projecten. Het is duidelijk dat je de stuurprogramma's voor tiny of MEGA kunt negeren als je maar in een van hen geïnteresseerd bent. Voor degenen die meer willen weten over de I2C-bus, geef ik links naar geschikt materiaal.

Stap 1: Wat is dit allemaal voor I2C-dingen eigenlijk?

Wat is al dit I2C-dingen eigenlijk?
Wat is al dit I2C-dingen eigenlijk?
Wat is al dit I2C-gedoe eigenlijk?
Wat is al dit I2C-gedoe eigenlijk?
Wat is al dit I2C-gedoe eigenlijk?
Wat is al dit I2C-gedoe eigenlijk?
Wat is al dit I2C-dingen eigenlijk?
Wat is al dit I2C-dingen eigenlijk?

De I2C-bus is een eenvoudige, tweedraads verbinding die meerdere apparaten aan elkaar kan koppelen en gegevens kan uitwisselen. In zijn eenvoudigste vorm is er één master-apparaat dat communiceert met meerdere slave-apparaten. Alle apparaten zijn parallel aangesloten op de twee draden van de I2C-bus. De twee draden staan bekend als SCL en SDA. SCL is de kloklijn en wordt bestuurd door het hoofdapparaat. SDA is de bidirectionele datalijn. Om gegevens over te dragen, stuurt de master een slave-adres in combinatie met een lees-/schrijfvlag van één bit. Als schrijven gewenst is, blijft de master data naar de geadresseerde slave sturen. Als een read wordt gevraagd, zal de slave antwoorden met data. Om transacties te coördineren, worden de SCL- en SDA-lijnen door de master en de slave gemanipuleerd om verschillende voorwaarden te signaleren. Deze omvatten START, STOP, ACK (bevestigen) en NAK (geen bevestiging). De details van deze voorwaarden worden afgehandeld door de chauffeurs. De echte geeks onder jullie kunnen alle details leren in de links aan het einde van deze Instructable. De elektrische vereisten zijn vrij eenvoudig. De master en de slaves moeten hetzelfde niveau gebruiken voor Vcc, de aarde moet zijn aangesloten en de SCL- en SDA-lijnen moeten naar Vcc worden getrokken. De waarde van de pull-up weerstanden wordt nauwkeurig bepaald door een berekening op basis van de totale capaciteit op de bus, maar kan praktisch elke waarde tussen 1,8K en 10K zijn. Ik begin met 5.1K en gebruik lagere waarden totdat het werkt. Dit is meestal geen probleem, tenzij je veel apparaten hebt of lange draden tussen apparaten. De nominale gegevenssnelheid op de I2C-bus is 100 Kbits/seconde. Tarieven van 400Kbits/seconde, 1Mbits/seconde en meer zijn ook mogelijk, maar worden niet ondersteund door de stuurprogramma's in deze Instructable. Alle I2C-apparaten werken met 100Kbits/seconde. De ATtiny2313 en de ATmega168 implementeren de I2C-bus elk anders. ATtiny2313 gebruikt de Universal Serial Interface (USI) hardware - die ook kan worden gebruikt voor de SPI-bus. ATmega168 heeft speciale hardware voor de I2C-bus die bekend staat als de Two Wire Interface (TWI). Zodra de stuurprogramma's zijn geschreven, zijn deze verschillen meestal transparant voor de gebruiker. Een belangrijk verschil zit in de software: de ATmega168 I2C-driver is interrupt-gedreven, terwijl die voor de ATtiny2313 dat niet is. Dit betekent dat een ATmega168-programma niet hoeft te wachten tot I2C-gegevensoverdrachten plaatsvinden, maar alleen hoeft te wachten voordat een nieuwe overdracht wordt gestart, of totdat er gegevens binnenkomen van een leesbewerking. De voorbeelden en discussie die volgen, zouden dit duidelijk moeten maken. I2C-adressen zijn 7 bits lang, dus er kunnen tot 127 apparaten op de bus zitten als elk een uniek adres heeft. Zoals weergegeven in de afbeelding, wordt dit 7-bits adres één bit naar links verschoven en wordt het minst significante bit gebruikt om een lees- of schrijfbewerking van het apparaat op het adres te markeren. Het volledige slave-adres is dus een 8-bits byte. Het werkelijke adres wordt gedeeltelijk intern aan het apparaat bepaald en kan niet worden gewijzigd (4 meest significante bits) en gedeeltelijk bepaald door bits die kunnen worden verbonden met apparaatpinnen (3 minst significante bits) die hoog of laag kunnen worden ingesteld om in te stellen een specifiek adres. Klinkt verwarrend, maar een voorbeeld zal dit duidelijk maken. De PCA8574A datasheet laat zien dat de vier meest significante bits van het I2C adres altijd 0111 zullen zijn. De volgende drie bits worden bepaald door de instellingen op pinnen AD0, AD1 en AD2. Deze pinnen kunnen worden verbonden met aarde of met de positieve voedingsspanning (5 volt) om respectievelijk 0 of 1 weer te geven. Het bereik van mogelijke adressen is dus 38 tot 3F hexadecimaal, zoals weergegeven in de andere afbeelding van het PCA8574-gegevensblad. Dus door de adresbitinstellingen te wijzigen, kunnen er maximaal 8 PCA8574A's tegelijkertijd op de I2C-bus zijn. Elk zal alleen reageren op zijn specifieke slave-adres. Als er nog meer I/O-poorten nodig zijn, kan de PCA8574 worden gebruikt. Het enige verschil tussen de PCA8574 en de PCA8574A is dat het I2C-slave-adresbereik van de PCA8574 20 tot 27 hexadecimaal is. adres. Lees het gegevensblad aandachtig en houd er rekening mee dat het slave-adres 7 bits lang zal zijn. Het lees-/schrijfbit moet apart worden behandeld. Nogmaals, een voorbeeld zal helpen. Het datablad voor de 24C16 EEPROM waarmee we zullen experimenteren zegt dat de eerste (meest significante) vier bits van het slave-adres 1010 zijn. De volgende drie bits kunnen worden bepaald door A0, A1 en A2; maar merk op dat het gegevensblad ook 24C01 tot en met 24C08 omvat, wat kleinere EEPROM's zijn. De figuur uit het datablad laat zien dat de instellingen van deze adresbits worden genegeerd naarmate de grootte toeneemt en volledig worden genegeerd voor de 24C16. Dat wil zeggen, de laatste drie bits doen er niet toe en de 24C16 gebruikt echt alle I2C-slave-adressen 50 tot en met 57 hexadecimaal. Het bereik van slave-adressen zal in feite verschillende secties binnen de 24C16 adresseren. De eerste 256 bytes zijn op adres 50h, de volgende 256 op 51h, enzovoort tot de laatste 256 op 57h - voor een totaal van 2K bytes. Aangezien het adres van de PCF8570 RAM waarmee we ook experimenteren binnen dit bereik ligt, kunnen de 24C16 en de PCF8570 niet samen worden gebruikt.

Stap 2: Bestel enkele I2C-apparaten

Nu u een beetje weet over de I2C-bus en deze wilt gebruiken, waarom bestelt u dan niet wat I2C-apparaten om mee te experimenteren, zodat ze onderweg naar u kunnen zijn terwijl u de software voorbereidt? Passende apparaten zijn onder meer een I/ O Interface Expander (mijn favoriet), een Static Ram en een EEPROM. Er is nog veel meer, maar dit is een goed begin. De AVR-processors die we zullen gebruiken zijn de ATtiny2313 en de Atmega168 (gebruikt in Arduino). Als je nieuw bent bij deze, kijk dan eens naar deze geweldige Instructable om er meer over te leren en je Ghetto Development System te bouwen. Het schema van de ATmega168 in de huidige Instructable laat zien hoe het Ghetto Development System voor deze processor kan worden geïmplementeerd. De parallelle poortkabel is dezelfde als die voor de ATtiny2313. (Ik heb de USB-versie van het Ghetto Development System niet geprobeerd, dus ik weet niet zeker hoe de I2C-bus erop wordt gebruikt. Hetzelfde geldt voor de Arduino.) Hier zijn de Digikey-onderdeelnummers. Poortexpander:IC I2C I/O UITBREIDING 568-4236-5-NDRAm:IC SRAM 256X8 W/I2C 568-1071-5-NDEEPROM:IC EEPROM SERIEEL 16K CAT24C16LI-G-ND

Stap 3: I2C-stuurprogramma's

Hier zijn de beschrijvingen van de driverfuncties voor de I2C-bus. Deze zijn ontwikkeld met behulp van de Atmel Apps Notes voor starters. Ik had dit niet kunnen doen zonder hen als basis om op voort te bouwen. De ontwikkeling is gedaan met behulp van WinAVR en de gcc C-compiler. De kloksnelheidsbeperkingen worden hieronder voor elke processor beschreven. Aangezien ik niet alle mogelijke combinaties van processorsmaak en kloksnelheid kan testen, blijf ik bij wat ik echt kan testen en probeer de beperkingen en beperkingen aan te geven. Hier zijn de stuurprogrammafuncties en hoe ze te gebruiken. Bekijk de voorbeelden voor meer details en om de functies te zien die in gebruik zijn in volledige programma's. Voor de ATtiny2313:Clock Vereiste:De drivers zijn ontworpen voor een kloksnelheid van 1MHz (de standaardsnelheid) voor ATtiny2313. Als u met andere snelheden wilt rijden, moet u constanten in de stuurprogramma's aanpassen. E-mail me als je hulp nodig hebt om dit te doen. U kunt ook enkele hints krijgen van de Atmel-app-notities in de links in de bronnen Step. USI_TWI_Master_Initialise()Deze functie initialiseert de USI-hardware voor I2C-modus. Roep het een keer aan het begin van je programma. Het retourneert ongeldig en er zijn geen argumenten. USI_TWI_Get_State_Info()Deze functie retourneert I2C-foutinformatie en wordt gebruikt als er een fout is opgetreden tijdens een I2C-transactie. Aangezien deze functie alleen een foutcode retourneert, gebruik ik de functie TWI_Act_On_Failure_In_Last_Transmission(TWIerrorMsg) om een fout-LED te laten knipperen. De foutcodes zijn gedefinieerd in USI_TWI_Master.h. Zo roept u het op: TWI_Act_On_Failure_In_Last_Transmission(USI_TWI_Get_State_Info())USI_TWI_Start_Read_Write()Deze functie wordt gebruikt om enkele bytes naar I2C-apparaten te lezen en te schrijven. Het wordt ook gebruikt om meerdere bytes te schrijven. Er zijn 6 stappen om deze functie te gebruiken.1) Declareer een berichtenbuffer in uw programma om het slave-adres en de te verzenden of ontvangen databyte te bevatten. unsigned char messageBuf (MESSAGEBUF_SIZE);2) Zet het slave-adres als de eerste byte in de buffer. Schuif het een bit naar links en OR in het Read/Write-bit. Merk op dat het lees-/schrijfbit 1 is voor lezen en 0 voor schrijven. Dit voorbeeld is voor een Read. messageBuf(0) = (TWI_targetSlaveAddress<<TWI_ADR_BITS) | (TRUE<<TWI_READ_BIT); 3) Wanneer u een Write uitvoert, plaatst u de byte die moet worden geschreven op de volgende locatie in de buffer.4) Roep de functie USI_TWI_Start_Read_Write aan met de berichtenbuffer en de berichtgrootte als argumenten.temp = USI_TWI_Start_Read_Write(messageBuf, 2);5)De geretourneerde waarde (temp in dit geval) kan worden getest om te zien of er een fout is opgetreden. Als dat zo is, wordt het behandeld zoals hierboven besproken. Zie voorbeelden in de programma's.6) Als een Read is aangevraagd, zal de byte read op de tweede locatie in de buffer staan. Als er meerdere bytes moeten worden geschreven (zoals naar een geheugenapparaat), kan dezelfde routine worden gebruikt. Het instellen van de buffer en het aanroepen van de routine zijn iets anders. De tweede byte in de buffer is het startgeheugenadres waarnaar moet worden geschreven. De te schrijven gegevens bevinden zich in de volgende bytes. De berichtgrootte is de grootte inclusief alle geldige gegevens. Dus als er 6 bytes moeten worden geschreven, dan is de berichtgrootte 8 (slave-adres + geheugenadres + 6 bytes aan gegevens). USI_TWI_Start_Random_Read()Deze functie wordt gebruikt om meerdere bytes van een I2C-apparaat te lezen. een soort herinnering. Het gebruik van deze routine lijkt erg op de vorige routine, met twee uitzonderingen. De instelling van de Read/Write-bit maakt niet uit. Het aanroepen van deze routine zal altijd een leesbewerking veroorzaken. De messageSize moet 2 zijn plus het aantal te lezen bytes. Als er geen fouten zijn opgetreden, bevinden de gegevens zich in de buffer vanaf de tweede locatie. Voor de ATmega168:Clock Requirement:The drivers zijn ontworpen voor een kloksnelheid van 4MHz voor ATmega168. De voorbeeldcode laat zien hoe u deze kloksnelheid instelt. Als u met andere snelheden wilt rijden, moet u constanten in de stuurprogramma's aanpassen. E-mail me als je dit moet doen. TWI_Master_Initialise()Deze functie initialiseert de TWI-hardware voor I2C-modus. Roep het een keer aan het begin van je programma. Het retourneert ongeldig en er zijn geen argumenten. Zorg ervoor dat u interrupts inschakelt door swi() aan te roepen na het initialiseren. TWI_Get_State_Info()Deze functie retourneert I2C-foutinformatie en wordt gebruikt als er een fout is opgetreden tijdens een I2C-transactie. Aangezien deze functie alleen een foutcode retourneert, gebruik ik de functie TWI_Act_On_Failure_In_Last_Transmission(TWIerrorMsg) om een fout-LED te laten knipperen. De foutcodes zijn gedefinieerd in TWI_Master.h, maar zijn aangepast voor signalering op een fout-LED. Zie de voorbeeldcode voor details. Zo roept u het op: TWI_Act_On_Failure_In_Last_Transmission(TWI_Get_State_Info()) Merk op dat foutcontrole wordt gedaan door ervoor te zorgen dat de I2C-transactie is voltooid (functie hieronder beschreven) en vervolgens een beetje te testen in het algemene statuswoord. twee functies werken hetzelfde als de corresponderende functies die hierboven zijn beschreven, maar met een paar uitzonderingen. Ze retourneren geen foutwaarden. De gelezen gegevens worden niet naar de buffer overgebracht. Dit wordt gedaan met de functie die hierna wordt beschreven. Wanneer u TWI_Start_Random_Read aanroept, moet de messageSize het aantal gevraagde databytes zijn plus één, niet twee. De I2C-driver voor de ATmega168 wordt door een interrupt gestuurd. Dat wil zeggen, de I2C-transacties worden gestart en vervolgens onafhankelijk uitgevoerd terwijl de hoofdroutine blijft lopen. Wanneer de hoofdroutine gegevens wil van een I2C-transactie die hij heeft gestart, moet hij controleren of de gegevens beschikbaar zijn. De situatie is hetzelfde voor foutcontrole. De hoofdroutine moet er zeker van zijn dat de I2C-transactie is voltooid voordat wordt gecontroleerd op fouten. De volgende twee functies worden voor deze doeleinden gebruikt. TWI_Transceiver_Busy() Roep deze functie aan om te zien of een I2C-transactie is voltooid voordat u op fouten controleert. De voorbeeldprogramma's laten zien hoe u dit kunt gebruiken. TWI_Read_Data_From_Buffer()Bel deze functie om gegevens van de ontvangstbuffer van het I2C-stuurprogramma over te brengen naar de berichtenbuffer. Deze functie zorgt ervoor dat de I2C-transactie is voltooid voordat de gegevens worden overgedragen. Hoewel deze functie een waarde retourneert, vind ik het rechtstreeks controleren van de foutbit betrouwbaarder. Hier is hoe het te noemen. De grootte van het bericht moet één groter zijn dan het gewenste aantal databits. De gegevens bevinden zich in messageBuf vanaf de tweede locatie.temp = TWI_Read_Data_From_Buffer (messageBuf, messageSize);

Stap 4: Laten we bouwen

Laten we bouwen!
Laten we bouwen!
Laten we bouwen!
Laten we bouwen!
Laten we bouwen!
Laten we bouwen!
Laten we bouwen!
Laten we bouwen!

Begin met het downloaden van het bestand I2C Schematics.zip. Misschien wilt u een I2C-map in uw werkgebied maken om de schema's en de voorbeeldprogrammabestanden te bewaren. Pak de schema's uit in deze map. U vindt een map met de naam I2C Schematics. Open het bestand met de naam tiny I2C.pdf. Dit schema toont het ATtiny2313 Ghetto Development System en de PCA8574A I/O Port Expander (met de grote gestippelde doos eromheen). Het Port Expander-circuit is gebouwd op een breadboard. Bekijk de foto's om te zien hoe deze circuits eruit zien. Ze zijn echt vrij eenvoudig. Het ATtiny2313-gedeelte van het schema is gewoon het Ghetto-ontwikkelingssysteem met drie knipperlichten (LED1, 2 en 3, plus R4, 5 en 6) en een drukknop (S1) eraan vastgemaakt, plus één extra detail. Dat detail is de toevoeging van jumpers (JP4, 5 en 6) die kunnen worden verwijderd om verbinding te maken met de I2C-bus SCL- en SDA-lijnen. De jumpers moeten op hun plaats zitten voor het programmeren, en dan verwijderd moeten worden zodat SCL en SDA kunnen worden aangesloten. De foto's tonen de jumpers op hun plaats en verwijderd. Het plaatsen van deze jumpers is aan jou, je hoeft ze alleen maar op je Ghetto Development System te zetten als je de I2C-bus wilt gebruiken. De I2C-bus moet worden losgekoppeld en de jumpers moeten worden geplaatst voor het programmeren. Merk op dat je je alleen echt zorgen hoeft te maken over JP4 en JP6 voor de I2C-bus. Zet JP5 in als je denkt ooit de SPI-bus te willen gebruiken. Breadboarden van de PCA8574A I/O Port Expander is heel eenvoudig. Zorg voor Vcc (+5 volt) en Gnd (aarde) aansluitingen en sluit AD0, 1 en 2 aan op aarde (maakt het I2C-slave-adres 38 hex). Sluit vervolgens 4 knipperlichten en 4 DIP-schakelaars aan. (Als je geen DIP-schakelaars hebt, kun je gewoon draden gebruiken. Bind aan aarde of laat zwevend staan om respectievelijk het signaal aan of uit te zetten.) Sluit tot slot de pull-up-weerstanden (R11 en 12) van SDA en SCL aan op Vcc. Deze worden weergegeven als 3,3K, maar elke waarde van 1,8K tot 5,1K zou moeten werken (misschien tot 10K, maar dat heb ik niet geprobeerd). Zodra je de ATtiny2313 hebt geprogrammeerd, kun je de jumpers verwijderen en SDA en SCL aansluiten om te testen. Nu voor de ATmega168. De enige rimpel hier is dat je misschien geen Ghetto Development System voor deze processor hebt gebouwd. Als dat het geval is, laat het schema dat ik geef (MEGA I2C.pdf) zien hoe. Dit is slechts een permutatie van de ATtiny2313-versie. Als u vooruit plant, kunt u ervoor zorgen dat uw programmeerkabel op beide systemen past. Het belangrijkste verschil is de toevoeging van C2 en C3. Zie de foto's voor plaatsing hiervan, deze moeten zeer dicht bij de chip zitten; een van hen zit eigenlijk onder de chip. Deze helpen met name om ruis uit de analoog-naar-digitaal-omzetter te houden. U hoeft geen jumpers te plaatsen, tenzij u van plan bent de SPI-bus te gebruiken, aangezien deze niet nodig zijn voor de I2C-bus op deze chip. Merk op dat het breadboard PCA8754A ongewijzigd blijft. Je sluit gewoon SDA en SCL aan en je bent vertrokken! Makkelijk, hè?

Stap 5: Laten we coderen en testen

Laten we coderen en testen!
Laten we coderen en testen!
Laten we coderen en testen!
Laten we coderen en testen!
Laten we coderen en testen!
Laten we coderen en testen!

Het is tijd om de stuurprogramma's en de voorbeeldprogramma's te bouwen. We beginnen met de ATtiny2313 en het PCA8574A breadboard die we zojuist hebben gebouwd. Download het bestand I2C.zip in uw I2C-werkmap en pak het uit. Je hebt een nieuwe map met de naam I2C. Daarin vind je USI I2C (voor ATtiny2313) en TWI I2C (voor ATmega168). In USI I2C vindt u de map I_O Port. Die map bevat de code voor ons eerste voorbeeldprogramma en de USI I2C-stuurprogramma's. Gebruik WinAVR om de code te compileren en in de ATtiny2313 te laden. Haal diep adem en zet de stroom aan. Dit is wat u kunt verwachten: Bij het inschakelen knippert LED 1 op poort PD6 van de ATtiny2313 twee keer. Er gebeurt niets anders totdat u op de knop drukt (S1). Elke keer dat de knop wordt ingedrukt, worden de schakelaars gelezen en wordt hun instelling weergegeven op de LED's die zijn aangesloten op de PCA8574A. Verander de waarde van de schakelaars, druk op de knop en de LED's zouden moeten veranderen. Blijf dit doen totdat je over de spanning heen bent om het te zien werken. Als (God verhoede!) dingen niet werken zoals verwacht, controleer dan zorgvuldig je bedrading. I2C-fouten worden gesignaleerd door knipperen op LED3 (PD4) en betekenen waarschijnlijk dat u moet controleren of SDA en SCL op de juiste pinnen zijn aangesloten en correct omhoog zijn getrokken. Als dingen nog steeds niet werken, lees dan de rest van dit gedeelte om meer te weten te komen over foutopsporing. Ga nu terug en laten we de code eens bekijken. Open het bestand USI_I2C_Port.c. Dit is de code voor het voorbeeldprogramma. (USI_TWI_Master.c en USI_TWI_Master.h bevatten de stuurprogramma's - u kunt ze negeren tenzij u nieuwsgierig bent.) Gebruik het voorbeeld om uw eigen I2C-toepassingen te begeleiden. Meestal laat het programma u zien hoe u de I2C-stuurprogramma's initialiseert en gebruikt, inclusief instellingen het slave-adres en de rest van de berichtenbuffer op, en de gegevens eruit halen. Je zult ook zien hoe ik de knop debounce en de while-lus instel. Er zijn een paar details van het programma die het vermelden waard zijn. Merk op dat de gegevens van de switches worden geïnverteerd voordat ze naar de LED's op de Port Expander worden geschreven. Houd er ook rekening mee dat de invoerpoorten op de Port Expander als Hoog moeten worden geschreven om ze correct te laten werken. Die details worden beschreven in het PCA8574A-gegevensblad. Lees de datasheets altijd goed door! Interessanter is het gebruik van conditionele debugging. Nabij het begin van het programmabestand staat de instructie //#define DEBUG en door de hele code heen zijn #ifdef DEBUG-instructies. Zolang DEBUG niet is gedefinieerd (de twee schuine strepen maken van de regel een opmerking en voorkomen dat deze wordt gedefinieerd), wordt de code binnen de #ifdef tot #endif-instructies niet gecompileerd. Maar als de dingen niet werken zoals je verwacht, hercompileer en laad de code dan opnieuw met #define DEBUG zonder commentaar. Je krijgt veel meer knipperingen op de LED's die je kunt decoderen om de uitvoering van je programma te volgen en je te helpen precies te vinden waar het mis gaat. Ik raad je zelfs aan om dit te proberen om te zien wat er gebeurt. Wat u zult zien is dat LED 2 (op PD5) knippert terwijl de uitvoering door het programma gaat. De waarde die van de schakelaars wordt afgelezen, knippert op LED 1 (PD6) voordat deze wordt weergegeven op de LED's van de poortuitbreiding. Je zou het programma moeten kunnen volgen terwijl het draait door deze LED's te gebruiken. We zullen hierna met de ATmega168 werken; sla deze sectie over als u alleen geïnteresseerd bent in de ATtiny2313. Nog steeds bij me? Mooi zo. Ga naar de map TWI_I2C, wijzig uw werkmap in IO_Port en compileer en laad TWI_I2C_Port.c in de ATmega168. Koppel de SDA- en SCL-lijnen los van de ATtiny2313 en sluit ze aan op ATmega168. Sluit stroom en aarde aan en zet aan. De werking zou hetzelfde moeten zijn! Speel totdat de spanning afneemt, laten we dan naar de code kijken. Open TWI_I2C_Port.c. De code is bijna identiek, met uitzondering van foutafhandeling en accommoderende interrupt-gestuurde stuurprogramma's. Dit zijn de verschillen: Merk op dat de klok moet worden ingesteld op 4 MHz om de I2C-bus goed te laten werken. De sei(); statement schakelt interrupts in na initialisatie van de I2C-stuurprogramma's. Om op fouten te controleren, wordt een specifiek statusbit getest. Tijdens het lezen moet de functie TWI_Read_Data_From_Buffer worden aangeroepen om de gelezen gegevens over te dragen naar de berichtenbuffer. Tijdens het schrijven moet while (TWI_Transceiver_Busy()) worden gebruikt om er zeker van te zijn dat de overdracht is voltooid voordat wordt gecontroleerd op fouten. Deze laatste twee functies zijn hierboven beschreven in de beschrijving van de stuurprogramma's. Afgezien daarvan is de code vrijwel hetzelfde als voor de ATtiny2313. DEBUG werkt hetzelfde ook als je daarmee wilt experimenteren.

Stap 6: I2C-geheugen gebruiken

I2C-geheugen gebruiken
I2C-geheugen gebruiken
I2C-geheugen gebruiken
I2C-geheugen gebruiken
I2C-geheugen gebruiken
I2C-geheugen gebruiken
I2C-geheugen gebruiken
I2C-geheugen gebruiken

Nu we hebben geleerd om de I2C-bus te gebruiken om een I/O-poortexpander te lezen en te schrijven, gaan we verder met het gebruik van I2C-geheugens, zowel RAM als EEPROM. Het belangrijkste verschil is dat meerdere bytes kunnen worden gelezen naar of geschreven uit geheugens met een enkele I2C-opdracht. Om ons voor te bereiden op deze experimenten, moeten we de hardware enigszins aanpassen en een paar nieuwe circuits op het breadboard bouwen. Bewaar het Port Expander-circuit omdat we het zullen gebruiken om enkele geheugenwaarden weer te geven. Verwijder de DIP-switches van de PCA8574A en plaats knipperlichten op die pinnen. Als je niet genoeg knipperlichten hebt, verplaats die dan op P4 t/m P7 naar P0 t/m P3. (De weer te geven waarden zijn klein genoeg.) Kijk nu naar het schematische I2C Ram.pdf en sluit de PCF8570 aan op het breadboard. Kijk ook eens naar de foto. Zorg ervoor dat u pin 7 vastmaakt aan Vcc. Leid draden voor SDA en SCL vanaf de PCA8574A. Er zijn geen extra pull-up-weerstanden nodig. Als je ook geïnteresseerd bent in de EEPROM, bouw dan dat circuit ook met I2C EEPROM.pdf voor de 24C16, maar wees gewaarschuwd dat het voorbeeld de ATmega168 gebruikt. Deze schakeling is heel eenvoudig. Zoals hierboven besproken, moeten de adresbits worden genegeerd. Sluit gewoon stroom en aarde aan. Sluit SDA en SCL nog niet aan omdat we nog niet klaar zijn met experimenteren met de Ram. We beginnen onze geheugenexperimenten met de ATtiny2313 aangesloten op de PCA8574A Port Expander en op de PCF8570 Ram. Het programma schrijft een aantal nummers naar de Ram, leest ze terug en geeft ze weer op de Port Expander. Verander je werkmap naar RAM onder USI I2C. Gebruik het make-bestand om USI_I2C_RAM.c te compileren en te downloaden. Merk op dat de I2C-stuurprogrammabestanden identiek zijn aan de bestanden die we eerder gebruikten. Sluit de stroom aan en je zou een enkele knippering moeten zien op LED 1 (PD6). De gegevens worden naar de eerste 4 bytes van het geheugen geschreven. Druk op de knop en twee bytes worden teruggelezen en weergegeven. U zou één LED-lampje op de Port Expander (P0) moeten zien, een pauze van twee seconden en vervolgens twee LED's (P0 en P1). Nog een pauze van twee seconden en de LED's moeten uitgaan. Druk nogmaals op de knop om de reeks opnieuw te beginnen. Debuggen is vergelijkbaar met de hierboven beschreven methode. Laten we de code eens bekijken. Open USI_I2C_RAM.c. Het moet er ongeveer hetzelfde uitzien als de vorige code. De belangrijkste verschillen zijn de details van het lees- en schrijfgeheugen. Kijk naar de manier waarop de berichtenbuffer wordt geladen vóór de aanroep die daadwerkelijk schrijft. De eerste byte is het slave-adres met de juiste lees-/schrijfbit. Maar de volgende byte is het geheugenadres waarop gegevens moeten worden geschreven. Dan komen de eigenlijke databytes die achtereenvolgens in het geheugen worden geladen vanaf het adres dat we hebben opgegeven. We specificeren de berichtgrootte als 6. We beginnen dus te schrijven op adres 00 en schrijven de waarden 01, 03, 02 en 06 in de geheugenlocaties 00 tot 03. Om de gegevens uit het geheugen terug te lezen, moeten we de functie USI_TWI_Start_Random_Read gebruiken. De berichtenbuffer krijgt het slave-adres in de eerste byte en het startadres in de tweede byte. Roep vervolgens de functie aan met de berichtgrootte ingesteld op het aantal bytes dat moet worden gelezen plus 2. Merk op dat het lees-/schrijfbit er niet toe doet, aangezien het lezen hoe dan ook wordt uitgevoerd. De geretourneerde gegevens beginnen op de tweede locatie in de berichtenbuffer. Zodra de gegevens zijn ingelezen, worden ze omgekeerd voor weergave op de Port Expander en er één byte per keer naartoe geschreven met een pauze tussen de waarden. Ten slotte zijn de Port Expander-LED's uitgeschakeld. De schrijfbewerkingen naar de Port Expander zijn identiek aan wat in de vorige voorbeelden is gedaan. Voor de lol kun je de opmerking #define DEBUG verwijderen zoals hierboven en veel knipperende LED's zien. Overspoeld met opwinding na weer een succesvol experiment, gaan we naar de ATmega168 en een EEPROM. Wijzig uw werkmap naar EEPROM onder TWI I2C. Gebruik het make-bestand om TWI_I2C_EEPROM.c te compileren en te downloaden. Merk op dat de I2C-stuurprogrammabestanden identiek zijn aan de bestanden die we eerder voor de PCA8574A gebruikten. Om het programma te testen, koppelt u de ATtiny2313 los en sluit u de ATmega168 aan. Laat de I2C-bus aangesloten op de Ram en start op. De resultaten zijn anders omdat we nu meer gegevens schrijven en lezen. LED 1 op PD7 moet knipperen bij initialisatie. Druk op de knop en de gegevens worden uit het geheugen uitgelezen en weergegeven. De LED's op de PCA8574 moeten in de volgende volgorde knipperen: P1, P0 & P2, (allemaal uit), P0 & P1, P1 & P2. Ten slotte moeten de poort-LED's allemaal uitgaan. Druk nogmaals op de knop om dit te herhalen. Oh, maar wacht, zeg je. Is dit niet voor de EEPROM? Omdat we toegang hebben tot een geheugenapparaat op hetzelfde I2C-adres, werkt hetzelfde programma voor zowel de Ram als de EEPROM. Schakel uit en verplaats SDA en SCL van de Ram naar de EEPROM en voer het programma opnieuw uit. Het zou precies hetzelfde moeten werken. Merk op dat de EEPROM en de Ram niet tegelijkertijd op de I2C-bus kunnen worden aangesloten, omdat ze hetzelfde adres delen. (De slimmeriken onder jullie kunnen overwegen om de programmeerbare adresbits op de Ram te veranderen, maar dat zal nog steeds niet werken. De 24C16 gebruikt het hele blok adressen dat voor de Ram kan worden geprogrammeerd.) Oké, laten we eens kijken naar dit laatste programma. Open TWI_I2C_EEPROM.c. Het eerste dat opvalt is dat ik heb aangegeven hoe de volledige 24C16 EEPROM moet worden geadresseerd. Het is toegankelijk in blokken van 256 bytes op 8 verschillende I2C-slave-adressen. Zie hoe MEMORY_ADDR wordt gedefinieerd als het startadres op 50 hexadecimaal; daarom werkte de Ram. Als je toegang wilt tot andere blokken van de 24C16, gebruik dan de andere adressen zoals ik heb aangegeven. Kijk eens hoe ik heb ingesteld om naar het geheugen te schrijven. Eerst wordt het slave-adres met de lees-/schrijfbit ingesteld in de buffer, dan het startadres van 00, dan 16 bytes aan data. De functie TWI_Start_Read_Write wordt aangeroepen om de gegevens te schrijven (zoals voorheen) met de berichtgrootte ingesteld op 18. Wanneer de knop wordt ingedrukt, gebruiken we TWI_Start_Random_Read en TWI_Read_Data_From_Buffer om de gegevens terug te lezen. Elke derde byte wordt weergegeven op de Port Expander-LED's. Ten slotte worden de LED's uitgeschakeld om te wachten op de volgende druk op de knop. Je vraagt je misschien af waarom ik ervoor heb gekozen om 16 bytes te schrijven. Als je het datablad aandachtig leest, zul je zien dat de 24C16 een schrijfcyclus uitvoert wanneer hij 16 bytes ontvangt, zelfs als er meer bytes worden verzonden. Dus dat leek me een mooi nummer om te gebruiken. Als u ervoor kiest om dit te vergroten, moet u de grootte van MESSAGEBUF_SIZE wijzigen. U moet ook de waarde TWI_BUFFER_SIZE wijzigen in TWI_Master.h. Dit komt omdat het stuurprogramma de gegevens uit de berichtenbuffer kopieert voor gebruik door de onderbrekingsserviceroutine. Gefeliciteerd! U bent nu klaar om de I2C-bus in uw eigen projecten te gebruiken!

Stap 7: Webbronnen

Hier zijn de links naar de datasheets voor de onderdelen die voor de experimenten zijn gebruikt. Je zou deze zeker moeten kopen als je niets anders krijgt. Port ExpanderRamEEPROM Als maker van I2C heeft NXP (Philips) een heleboel geweldige dingen. (Ze gebruiken graag vierkante haken in hun URL's, dus ik kan ze hier niet correct opnemen. Sorry.] Om naar het I2C-gebied te gaan, selecteert u Interface in de lijst met producten. U kunt naar hun I2C-site gaan en toegang tot alle datasheets en app-notities die ze aanbieden. De I2C-busbeschrijving en technische details in het bijzonder zijn hier. Verkrijg de ATtiny2313 en ATmega168-datasheets (databoeken?) van Atmel. De Atmel-toepassingsnotities zijn hier. Kijk naar AVR310 en AVR315. Pak ook de code. Kijk hier voor nog veel meer I2C-dingen.

Stap 8: opmerkingen voor geeks

Voor de echte nerd die de details wil weten, zijn hier enkele dingen om in gedachten te houden als je kijkt naar de Atmel Apps Notes en drivercode: - De methode voor het adresseren en besturen van een I2C-apparaat maakt geen deel uit van de specificatie! Behalve het slave-adres en de lees-/schrijfbit, zijn opdrachten, modi, enz. niet gespecificeerd en specifiek voor een bepaald apparaat. Om dit heel duidelijk te maken, merk op dat het schema dat in het Atmel-voorbeeld wordt gebruikt alleen op dat voorbeeld van toepassing is en vrijwel niet-standaard is.- De USI-implementatie verschilt op een paar belangrijke manieren van de TWI-implementatie. + Bij USI wordt het klokken geleverd door software; bij TWI wordt het geleverd door een Bit Rate Generator. + De USI-methode maakt geen gebruik van interrupts; de TWI wel. Dit is logisch, aangezien de Mega-familie (met behulp van TWI) veel andere dingen zou kunnen doen en niet zou moeten worden opgejaagd door I2C-overdrachten. Een interrupt-gedreven versie voor USI is zeker mogelijk, het is alleen niet geïmplementeerd in deze Instructable. + De USI-hardware is niet geoptimaliseerd voor I2C en kan alleen 8 bit-overdrachten aan. Dit betekent dat er twee overdrachten nodig zijn om de negende bit te verzenden (NACK of ACK). De hardware van TWI handelt dit automatisch af. Dit maakt de implementatie van het USI-stuurprogramma iets gecompliceerder. + Foutdetectie voor de TWI wordt hardwarematig afgehandeld. De USI vereist handeling in software die de zaken enigszins compliceert. + De TWI-hardware regelt rechtstreeks de configuratie van de poort. De USI-hardware vereist dat de poortbits worden geconfigureerd voordat de poort kan worden gebruikt. Je zult dit zien in de Master_Initialize-routine voor de USI.- Atmel beweert dat het mogelijk is om AVR-poort-pull-ups te gebruiken voor de I2C-bus-pull-ups. Ik heb nog geen manier gevonden om die aanpak te laten werken. Het gebruik van twee externe weerstanden lijkt een vrij eenvoudig schema, dus ik heb hier niet veel tijd aan besteed.

Aanbevolen: