AVR Assembler handledning 10 (7 / 10 steg)
Steg 7: Kodning Master
Slutligen har vi nog förståelse av vad som händer bakom kulisserna som vi kan gå igenom min kod, rad för rad, för både Master och slav microcontrollers. Observera att om du tittar på den bifogade uppförandekoden hittar rikliga kommentarer runt allt vi diskutera här.
Låt oss börja med några nya rader vi utökar vår Reset avsnitt:
LDS temp, PRR < br > andi temp, 0b01011111 < br > sts PRR, temp < br > ldi temp, 255 < br > sts TWBR, temp < br > ldi temp, (1--TWPS1) | (1--TWPS0) < br > sts TWSR, temp < br > ldi temp, (1--TWINT) | (1--TWEN) < br > sts TWCR, temp
där du kommer att påminna om att den "-" tecken bör lämnas SKIFT operatörer.
Okej. Vi vet redan vad ovanstående kod gör sedan vi diskuterade det tidigare. Den första delen helt enkelt stänger av makt minskade register bitar för timer/counter och det tolerabla VECKOINTAGET. Den andra delen anger bithastighet SCL och sedan stänger av TW mellanjobbet och gör det tolerabla VECKOINTAGET.
Nästa sak vi gör är att lägga en linje till våra viktigaste rutin som anropar TWI subrutin. Här ' tis:
huvudsakliga: < br > rcall button_push < br > rcall random < br > rcall dice < br > rcall cykel < br > rcall tw_transmit < br > rcall display < br > rjmp viktigaste
Varsel som vi kallar tw_transmit subrutinen rätt när vi Visa den animerade tärningarna rulla och precis innan vi visar resultatet av tärningarna rulla på dice rullen lysdioder.
Nu får vi till våra Master TWI subrutin:
tw_transmit: < br > ldi temp, (1--TWINT) | (1--TWSTA) | (1--TWEN) < br > sts TWCR, temp
TWEN gör det tolerabla VECKOINTAGET, TWSTA skickar en "startvillkoret" ner den tråd som är den fallande puls under en hög SCL cykel som vi diskuterat tidigare, och skriver TWINT = 1 till kontroll register stänger av flaggan avbrott (dvs resultaten i TWINT = 0) och börjar sända ett datapaket.
rcall tw_wait
Detta är en subrutin skrev vi som bara sitter runt väntar på TWI-användargränssnittet för att slutföra vårt kommando.
LDS temp, TWSR < br > andi temp, 0b11111000 < br > cpi temp, 0x08 < br > brne fel
Allt detta gör är kontrollera statusregistret för att se vad som finns därinne. Närhelst det tolerabla VECKOINTAGET gör något laddas den aktuella statusen för raderna i detta register. Så du kan kontrollera och kontrollera att kommandot du faktiskt gjorde det till linjen och erkändes av slav. Den andra raden anger våra prescaler bitar till noll (kom ihåg att vi har dem satt till 1 att få våra SCL frekvensen vara 490Hz). Det har att ställa dessa till noll så att vi kan jämföra statusregistret med koderna i tabell 22-2. Observera att statuskod 0x08 betyder startvillkoret skickades och erkänt. Tja, vad är 0x08 i binär? Det är 0b00001000. Så ser du att vi hade glömt att maskera de första tre bitarna, vår TWSR skulle innehålla 0b00001011 = 0x0b och comparsion skulle misslyckas. Om du inte anger de prescaler bitarna som vi gjorde och bara lämnade dem som nollor måste du skulle inte maskera dessa bitar. Den ovan avslutas med en paus för att en hanterare för fel att vi måste skriva som skulle hända om vi inte fick rätt statuskoden. Nu låt oss välja ut vilken slav som vi vill prata med:
LDI temp, 0b10100000 < br > sts TWDR, temp < br > ldi temp, (1--TWINT) | (1--TWEN) < br > sts TWCR, temp
Först fyller vi dataregister, TWDR, slav adressen och den läsa/skriva lite. 7-bitars slav-adress vi valde slumpmässigt (att undvika de databladet berättade för oss att inte använda) är 0b1010000 och vi tack 0 på slutet för att menar vi vill "Skriva" till slav. Om vi hade kryssade en 1 på slutet innebär vi vill "Läs" från slav. Då vi aktivera TWI raderna genom att skriva TWINT = 1 att kontrollera registret att rensa avbrottet. TWEN = 1 finns bara det så att det stannar 1 och det tolerabla VECKOINTAGET stannar "aktiverad". Detta kommer att skicka de 8 bitarna data ner SDA linjen till slav och slaven tar linjen till marken för att bekräfta mottagandet. Vi väntar på att överföringen till komplett använda vår tw_wait rutin (diskuteras nedan i slutet) och kolla statusregistret för att se till att den fick alla skickade och erkände precis som vi gjorde ovan med startsignalen:
rcall tw_wait < br > lds temp, TWSR < br > andi temp, 0b11111000 < br > cpi temp, 0x18 < br > brne fel
Nu vill vi faktiskt skicka våra data. Sedan vi skickade adress slav, och skriva lite, det kommer att sitta där, dreglar i väntan, för 32653 klockcykler ;) redo för att läsa nästa 8 bitar av SDA tråd och skicka dem direkt till är det egna TWDR register. Vi vill skicka tärningarna rulla. Så är här hur vi gör det:
LDI temp, 0 < br > sts TWDR, temp < br > ldi temp, (1--TWINT) | (1--TWEN) < br > sts TWCR, temp < br > rcall tw_wait < br > lds temp, TWSR < br > andi temp, 0b11111000 < br > cpi temp, 0x28 < br > brne fel
Först vi läsa in 0 i registret över data, då vi vända på raderna och skicka den. Sedan vi vänta för överföring till komplett, och slutligen vi kontrollera status att se till att det var skickat och erkända. Anledningen till att vi skickat en nolla är eftersom vi kommer att skicka 2 byte. Den första byten kommer få lastas in i "playercashH" av slav, och den andra byten kommer få lastas in i "playercashL" av slav. Kom ihåg att vi så småningom vill skicka två byte så att vi kan fylla upp 4-siffrig display. Vi behöver inte dem denna gång så vi bara skicka en nolla till först. Men jag lägga den här eftersom den visar hur att skicka mer än en byte av data och även vi kommer att använda den här vägen nästa gång.
STS TWDR, dicetotal < br > ldi temp, (1--TWINT) | (1--TWEN) < br > sts TWCR, temp < br > rcall tw_wait < br > lds temp, TWSR < br > andi temp, 0b11111000 < br > cpi temp, 0x28 < br > brne fel
Ovanstående borde vara ganska enkelt att förstå. Vi helt enkelt ladda upp data registret igen, denna gång med totalen rulla på de två tärningarna, och skicka den över, kontrollera status efter raderna gå döda. Slaven kommer läsa detta till playercashL. Nu är vi färdiga. Så vi hoppa till våra avsluta kommandon:
rjmp tw_return
Här är våra fel hanterare. Jag antar att detta aldrig kommer att få utförat så allt den gör är att skicka en stoppsignal till raden och sedan hoppa tillbaka till början och försöka hela igen.
FEL: < br > ldi temp, (1--TWINT) | (1--TWSTO) | (1--TWEN) < br > sts TWCR, temp < br > rjmp tw_transmit
Slutligen rensningen och exit:
tw_return: < br > ldi temp, (1--TWINT) | (1--TWSTO) | (1--TWEN) < br > sts TWCR, temp < br > ret
Detta bara skickar en stoppsignal ner linjen (eftersom vi har vänt TWSTO stop avlång knapp strömbrytare), vänder globala avbryter tillbaka på, och återgår till "main". För att avsluta upp diskussionen om befälhavaren kod, är här den tw_wait rutinen:
tw_wait: < br > lds temp, TWCR < br > sbrs temp, TWINT < br > rjmp tw_wait < br > ret
Nu låt oss titta på slav koden.