Onderbreekt. Wat zijn interrupts in microcontrollers? Sla het project en de werkruimte op

Vandaag zullen we kijken naar het concept van onderbreking en hoe we het kunnen gebruiken. Natuurlijk kunnen we niet zonder trainingsprogramma, maar deze keer laten we de LED's niet knipperen. Al goed. Laten we zoiets als een deurbel maken.

Taak: laat de microcontroller een pieptoon uitzenden wanneer u op een knop drukt.
Diagram voor ons voorbeeld. Projectbestanden.

We maken een ringproject in de oude werkruimte.
Stel de projectinstellingen in voor de Release-configuratie:

Selecteer het type microcontroller.
Algemene opties > Doel > Processorconfiguratie
Ik heb deze ATmega8535.

Sta het gebruik toe van bitnamen die in het headerbestand zijn gedefinieerd
Schakel in Algemene opties > Systeem het selectievakje Bitdefinities inschakelen in I/O-Include-bestanden in
Tot nu toe hebben we nog geen bitnamen gebruikt, maar vandaag hebben we ze nodig.

Wijzig het uitvoerbestandstype.
Linker > Uitvoer.
Vink in het veld Uitvoerbestand het vakje Standaard negeren aan en vervang de d90-extensie door hex
In het veld Formaat selecteert u Overige en in het vervolgkeuzemenu Uitvoerformaat selecteert u het bestandstype intel-standaard

Sla het project en de werkruimte op.

__________________________________________ Onderbreken ___________________________

Stel je de situatie voor. Je zit op je werk en buigt je over weer een ander microcontrollerprogramma. De baas komt naar je toe en zegt: “Luister, Pash, we hebben oscilloscopen gekocht voor onze afdeling - Tektronix, vierkanaals. Help Vasya ze te slepen.’ Je denkt: "Nou, my, alleen de gedachte stond in de weg... en op jou." En de baas kijkt je zo aan, en zijn ogen zijn zo vriendelijk, zo vriendelijk. Hoe kun je hem weigeren? Nou, je laat alles vallen en gaat met een vriend oscilloscopen kopen. Ze hebben het binnengebracht. Wij hebben gerapporteerd. En ze gingen weer aan hun programma zitten. Dit is ongeveer hoe het interruptmechanisme eruit ziet.

Heel eenvoudig, maar er zijn een aantal fundamentele punten.
Ten eerste:
- je hebt je werk gedaan
- tegelijkertijd kocht iemand oscilloscopen
- bij het optreden van de gebeurtenis “oscilloscopen aangeschaft” - onderbreekt u uw werk
- u doet al een tijdje ander werk: u draagt ​​oscilloscopen
- daarna keert u terug naar uw werkplek en gaat u verder met uw werk waar u gebleven was

Ten tweede:
- je zou gemakkelijk je baas kunnen sturen en nergens heen kunnen gaan
- nadat je naar oscilloscopen bent vertrokken, kun je daar lange tijd blijven, of zelfs helemaal niet terugkeren
- als u terugkeert naar uw werkplek, bent u uw briljante ideeën misschien al vergeten

Dit lijkt allemaal erg op wat er in een microcontroller gebeurt. AVR-microcontrollers omvatten een hele reeks randapparatuur (timers/tellers, analoog-naar-digitaal-omzetter, analoge comparator, asynchrone zendontvanger... enz.). De kracht van de microcontroller is dat al deze apparaten parallel en onafhankelijk van elkaar kunnen werken, maar ook parallel aan het programma dat wordt uitgevoerd. Elk randapparaat kan een interrupt activeren wanneer een specifieke gebeurtenis plaatsvindt. De interrupt zal alleen plaatsvinden als deze is ingeschakeld. Onderbrekingsinschakeling wordt voor elk apparaat afzonderlijk ingesteld. Bovendien is er een globale enable/disable-vlag voor alle interrupts - dit is de I-vlag in het SREG-register. Wanneer er een interrupt optreedt, slaat de microcontroller de inhoud van de pc-programmateller op de stapel op, dat wil zeggen dat hij de locatie onthoudt waarop deze werd onderbroken. Laadt het adres van de corresponderende interruptvector in de programmateller en springt naar dat adres. Er wordt een onvoorwaardelijk sprongcommando gegeven, dat naar de subroutine voor interruptverwerking gaat. Schakelt interrupts uit door de I-vlag te resetten, voert de subroutine uit. Nadat de interruptafhandelingsroutine is uitgevoerd, maakt de microcontroller interrupts mogelijk door de I-vlag in te stellen en herstelt hij de inhoud van de programmateller, dat wil zeggen dat hij terugkeert naar dezelfde plaats in het programma waar hij werd onderbroken.

In theorie zou de interrupthandler de inhoud van de microcontrollerregisters niet mogen beschadigen, omdat deze gegevens kunnen bevatten van het programma dat op dat moment wordt uitgevoerd. Om dit te doen, wordt aan het begin van de subroutine voor het afhandelen van interrupts de inhoud van de microcontrollerregisters op de stapel opgeslagen en aan het einde van de subroutine worden ze hersteld. Na het verlaten van de interrupt kan de microcontroller dus doorgaan met het uitvoeren van het programma alsof er niets is gebeurd. Bij het programmeren in assembler schrijft de programmeur zelf registeropslag voor; in C gebeurt dit door de compiler.

_______________________________________________________________

Laten we het nu over de timer hebben. ATmega8535 heeft drie timers/tellers aan boord: twee van acht bits (T0, T2) en één van zestien bits (T1). We zullen een acht-bits timer/teller T0 gebruiken. Deze timer bestaat uit drie registers: het besturingsregister TCCR0, het telregister TCNTO en het vergelijkingsregister OCR0. Wanneer de timer wordt gestart, verhoogt het tellerregister TCNTO zijn waarde met één voor elke klokflank. De klokfrequentie wordt geselecteerd uit verschillende mogelijke waarden in het controleregister TCCR0. Met behulp van dit register wordt ook de bedrijfsmodus van de timer ingesteld. Timer T0 kan een interrupt activeren bij het optreden van een “overflow” -gebeurtenis - dit is wanneer het telregister TCNT0 overstroomt, en bij het optreden van een "toeval" -gebeurtenis - dit is wanneer de waarde van het telregister TCNT0 gelijk wordt aan de waarde van het vergelijkingsregister OCR0. De vlaggen die deze interrupts mogelijk maken, bevinden zich in het TIMSK-register.
We zullen de T0-timer/teller configureren om een ​​“match”-gebeurtenisonderbreking op 5 kHz te activeren. In de handlerfunctie keren we de status om van de microcontrolleruitgang waarop de piëzoluidspreker is aangesloten. De piëzo-geluidsfrequentie zal dus gelijk zijn aan 2,5 kHz. (Het is de piëzoluidspreker die is aangesloten! Verwar het niet. De weerstand van een piëzoluidspreker is afhankelijk van de frequentie en bij 2,5 KHz zijn het meestal eenheden van Com, dus hij kan rechtstreeks op de uitgang van de microcontroller worden aangesloten, zonder begrenzingsweerstand) .

Nu over het programma. Het is niet meer mogelijk om het programma regel voor regel te schrijven, dus ik zal de tekst meteen geven. Hieronder zullen we alle lijnen één voor één analyseren en alles zal duidelijk worden. Ik heb bewust geen macro's gebruikt; het programma is klein en ik wil het niet rommelig maken.

int voornaamst( leegte )
{
//I/O-poorten instellen
DDRD = (0<POORTD = (1<

// stel timer T0 in
TCCR0 = (1<TCNT0 = 0;
OCR0 = 0xc8;

// schakel interrupts in
__enable_interrupt();

//hoofdprogrammalus – polling van de knop
terwijl(1){
als((PELD & (1<TIMSK = (1<anders
TIMSK = 0;
}
opbrengst 0;
}

//interrupt-handler voor timer T0

__onderbreken leegte Timer0CompVect( leegte)
{
POORT ^= (1<}

Poortinstellingen

In onze schakeling zijn op poort D een knop en een piëzoluidspreker aangesloten. De pin waarop de knop is aangesloten, moet als ingang worden geconfigureerd en de pull-up-weerstand moet worden ingeschakeld. De pin waarop de piëzoluidspreker is aangesloten, moet op uitvoer staan.

DDRD = (0<POORTD = (1<

De timer instellen

De werkingsmodus van de T0-timer is CTC (reset bij toeval), het kloksignaal is clk/8. Dit geven we weer in het TCCR0-register

TCCR0 = (1<

Voor het geval dat, resetten we telregister TCNT0

Schrijf 0xc8 naar het vergelijkingsregister OCR0. Waarom? Omdat ik erop had gerekend rekenmachine. Nou, op papier ziet deze berekening er zo uit.
Klokfrequentie van de microcontroller 8 MHz
Het timerkloksignaal is 8000000 Hz/8 = 1000000 Hz.
Tijd van één timerklok 1/1000000 = 1 µs
De tijd van één cyclus van de frequentie die we nodig hebben is 1/5000 Hz = 200 μs
Hoeveel timertikken passen er in 200 µs? 200/1 = 200 tikken
200 in hexadecimaal = 0xс8

Voor een gedetailleerde beschrijving van de T0-timer, zie de documentatie bij de ATMega8535.

We hebben de timer geconfigureerd en een algemene onderbreking mogelijk gemaakt met behulp van de ingebouwde functie.

__enable_interrupt();

Poll-knop

Wanneer de knop niet wordt ingedrukt, is de uitgang van de microcontroller verbonden met stroom via een interne pull-up-weerstand, dat wil zeggen dat er een weerstand op de uitgang zit; wanneer de knop wordt ingedrukt, wordt de uitgang kortgesloten met aarde, dat wil zeggen dat er is een nul op de uitvoer. Om te bepalen of er een knop is ingedrukt, moet u de inhoud van het PIND-register lezen en de waarde van de nulbit controleren (er is een knop verbonden met PD0). We zullen de knop in een eindeloze lus ondervragen.

terwijl (1)
{
als((PELD & (1<//Als de knop wordt ingedrukt, moet de microcontroller piepen
}
anders {
//zo niet, zwijg dan als een vis
}
}

Vergeet niet dat == geen toewijzingsoperator = is.

Bedieningsknop indrukken/loslaten

Door op de knop te drukken, schakelen we de onderbreking van timer T0 in, en door deze los te laten, schakelen we deze uit. Om dit te doen, zullen we de OCIE0-bit van het TIMSK-register manipuleren

TIMSK = (1<// sta onderbreking van timer T0 toe vanwege de toevalsgebeurtenis

TIMSK = 0; //onderbreking uitschakelen

Omdat we slechts één timer gebruiken, is het niet nodig om afzonderlijke bits in te stellen of opnieuw in te stellen.

Onderbreekfunctie

_____________________ Functiesyntaxis onderbreken _____________________

De interruptfunctie wordt gespecificeerd met behulp van de #pragma vector= richtlijn en een functiewoord __onderbreken. De functie moet van het type void zijn en mag geen parameters bevatten.

#pragmavector = Adres
__onderbreken leegte Naam( leegte)
{
//onze code bevindt zich hier
}

Naam– functienaam, kies naar eigen goeddunken
Adres– interruptvectoradres, kan worden gespecificeerd met een nummer of met namen die zijn gedefinieerd in het headerbestand van de microcontroller (iom8535.h – sectie Interrupt Vector Definitions)

______________________________________________________________

Voor onze taak ziet de interrupthandlerfunctie er als volgt uit

#pragma-vector = TIMER0_COMP_vect
__onderbreken leegte Timer0CompVect( leegte)
{
POORT ^= (1<// keer het signaal op pin PD1 om
}

Nou dat is alles. Ik hoop dat alles duidelijk is.
In het volgende artikel laten we de microcontroller een melodie spelen.

Interruptsystemen vormen een belangrijk onderdeel van elk besturingssysteem.

Hoe efficiënt het microprocessorsysteem zijn functies uitvoert, hangt grotendeels af van de werking ervan. De algemene structuur van het MK-51 interruptsysteem wordt getoond in Fig. 14.3.

Microcontrollers uit de MK-51-familie bieden ondersteuning voor vijf interruptbronnen:

* twee externe interrupts die binnenkomen via de ingangen INTO en INT1 (respectievelijk poortlijnen P3: P3.2 en P3.3);

* twee onderbrekingen van timers/tellers T/C0 en T/C1;

* seriële poortonderbreking.

Interruptverzoeken worden vastgelegd in de speciale functieregisters van de microcontroller: vlaggen IE0, IE1, TF0, TF1 interruptverzoeken van INT0, INT1, T/C0 en T/C1 zijn opgenomen in het TCON-controleregister (tabel 14.4), en vlaggen RI en TI-verzoeken om een ​​interrupt vanaf de seriële poort - in het SCON-register voor het besturen van de seriële poort.

Tabel 14.4. TCON-registerformaat

0 IT0 Instellen van het type interrupt INT0

1 IE0 Onderbrekingsverzoekvlag INT0

2 IT1 Instellen van het type interrupt INT1

3 IE1 Onderbrekingsverzoekvlag INT1

4 TR0 Schakel timer/teller 0 in

5 TF0 Overloopvlag (onderbrekingsverzoek) timer/teller 0

6 TR1 Schakel timer/teller 1 in

7 TF1 Overloopvlag (onderbrekingsverzoek) van timer/teller 1

Vlaggen TF0 en TF1 worden door hardware ingesteld wanneer de overeenkomstige timer/teller overloopt (meer precies, wanneer T/Cx overgaat van de toestand "allemaal enen" naar de toestand "allemaal nullen").

Vlaggen IE0 en IE1 worden ingesteld door hardware van respectievelijk externe interrupts IT0 en IT1. Een extern verzoek kan ervoor zorgen dat de vlag wordt ingesteld wanneer het signaalniveau op de overeenkomstige ingang laag is, of wanneer dit signaal overschakelt van hoog naar laag niveau (met een frequentie die niet hoger is dan de helft van de externe klokfrequentie van de MK).

Het verzoektype wordt geconfigureerd door software die de IT0- en IT1-bits in het TCON-controleregister instelt. Het instellen van ITx = 0 configureert het interruptsysteem om een ​​laag signaalniveau aan te vragen, ITx = 1 - stelt de interrupt in om een ​​laag signaalniveau aan te vragen.

De TI- en RI-vlaggen worden door de seriële interfacehardware ingesteld na respectievelijk het einde van de verzending of na het einde van de ontvangst.

Alle opgegeven interruptverzoekvlaggen zijn programmatisch beschikbaar voor instelling en resetten. Het instellen van de interruptverzoekvlag in software resulteert in hetzelfde antwoord van de microcontroller als het instellen van dezelfde vlag in hardware.

Vlaggen TFO en TF1 worden hardwarematig gereset wanneer de besturing wordt overgedragen naar de overeenkomstige interruptroutine.

Het resetten van de IEx-vlaggen wordt in de hardware alleen uitgevoerd bij het bedienen van de interrupt als de interrupt is geconfigureerd om de val van het INTx-signaal waar te nemen. Als de interrupt is geconfigureerd om het niveau van het verzoeksignaal waar te nemen, moet het resetten van de IEx-vlag worden uitgevoerd door het interruptserviceprogramma, dat op de interruptbron inwerkt om het verzoek te verwijderen.

De TI- en RI-vlaggen kunnen alleen softwarematig worden gereset.

Elk type interrupt wordt individueel in- of uitgeschakeld door het instellen of wissen van de overeenkomstige bits van het IE-interrupt-inschakelregister. Dit register bevat ook een algemeen uitschakelbit voor alle interrupts. Het formaat van het IE-register wordt gegeven in de tabel. 14.5.

Tabel 14.5. Toewijzing van IE-registerbits

Positie registreren

Beetje geheugensteuntjes

Functie

Schakel onderbrekingen van alle bronnen uit

Niet gebruikt

Niet gebruikt

Onderbreken van uitschakelen seriële poort

Schakel T/C1-timer/telleronderbreking uit

Schakel interrupt van externe bron INT1 uit

Timer/teller onderbreken T/C0 uitschakelen

Schakel interrupt van externe bron INT0 uit

Aan elk type interrupt kan programmatisch een van de twee mogelijke prioriteiten worden toegewezen: 0 - laagste of 1 - hoogste.

Prioriteiten worden geconfigureerd door het overeenkomstige bit in het IP-onderbrekingsprioriteitregister in te stellen of te wissen. Het formaat van dit register vindt u in de tabel. 14.6.

Wanneer er gelijktijdig interruptverzoeken worden ontvangen van bronnen met verschillende prioriteiten, wordt het verzoek van de bron met hogere prioriteit als eerste verwerkt.

In het geval van gelijktijdige ontvangst van meerdere interruptverzoeken met dezelfde prioriteit, wordt de volgorde van hun verwerking bepaald door de hardware van de microcontroller en kan deze niet softwarematig worden gewijzigd. Deze volgorde komt overeen met de volgorde van de polling-interruptverzoekvlaggen, die er als volgt uitziet:

IT0 -> TF0 -> IT1 -> TF1 -> (RI, TI)

Tabel 14.6. IP-registerbittoewijzingen

Registerpositie Bit-ezelsbruggetje Functie

7 - Niet gebruikt

6 - Niet gebruikt

5 - Niet gebruikt

4 PS Seriële poortonderbrekingsprioriteit

3 PT1 timer/teller onderbrekingsprioriteit T/C1

2 PX1 Prioriteit onderbreking van externe bron INT1

1 PT0 timer/teller onderbrekingsprioriteit T/C0

0 PX0 Onderbrekingsprioriteit van externe bron INT0

Een in hardware geïmplementeerde interrupthandleraanroep bestaat uit de volgende acties:

* het opslaan van de waarde van de programmateller op de stapel;

De ingangspunten van de interrupthandler voor elke interruptbron zijn hardwarematig vastgelegd. Hun waarden worden gegeven in de tabel. 14.7.

Tabel 14.7. Adressen van toegangspunten voor interrupthandlers

Bron onderbreken

Adressen van toegangspunten voor interrupthandlers

Externe onderbreking( ITO)

Timer-teller (TFO)

Externe onderbreking(IT1)

Timer-teller(TF1)

Seriële poort (R1 of T1)

Het eerste commando van de interrupthandler moet zich op het opgegeven adres bevinden. In de regel is zo'n commando een commando om onvoorwaardelijk naar de plek in het programma te springen waar de handler zich daadwerkelijk bevindt.

Bij het overschakelen naar de interruptafhandelingsroutine worden automatisch, ongeacht de status van het IE-register, alle interrupts met een prioriteitsniveau gelijk aan het prioriteitsniveau van de onderhouden interrupt uitgeschakeld - dat wil zeggen dat geneste interrupts met een gelijk prioriteitsniveau worden uitgeschakeld . Een interrupt met lage prioriteit (met een "0" in de corresponderende bit van het IP-register) kan dus worden onderbroken door een interrupt met hoge prioriteit (met een "1" in de corresponderende bit van het IP-register), maar niet door een interrupt met een lage prioriteit (met een "0" in de corresponderende bit van het IP-register). een lage prioriteit. Het onderhouden van een interrupt met hoge prioriteit kan niet worden onderbroken door een andere bron.

Het terugkeren van de interrupt-handler wordt bereikt met behulp van de RETI-instructie, die vanuit de stapel de waarde herstelt van de pc-programmateller die daar was opgeslagen op het moment dat de interrupt-handler werd aangeroepen, en de interruptprioriteitlogica.

Een van de voordelen van de ATmega8-microcontroller is het brede scala aan verschillende interrupts.

Onderbreken is een gebeurtenis waarbij de uitvoering van het hoofdprogramma wordt opgeschort en een functie wordt aangeroepen die een interrupt van een bepaald type afhandelt.

Interrupts zijn onderverdeeld in intern en extern. Bronnen van interne interrupts zijn onder meer ingebouwde microcontrollermodules (timers, USART-transceiver, enz.). Externe interrupts treden op wanneer externe signalen aankomen op de pinnen van de microcontroller (bijvoorbeeld signalen op de RESET- en INT-pinnen). De aard van de signalen die leiden tot het optreden van een interrupt wordt ingesteld in het besturingsregister MCUCR, in het bijzonder in de bits - ISC00 (bit 0) en ISC01 (bit 1) voor ingang INT 0; ISC10 (bit2) en ISC11 (bit3) voor INT1-ingang.

In de ATmega8-microcontroller heeft elke interrupt zijn eigen interrupt onderbrekingsvector(adres aan het begin van het programmageheugengebied waarin het commando voor het springen naar de opgegeven interruptroutine is opgeslagen). In mega8 hebben alle interrupts dezelfde prioriteit. Als er meerdere interrupts tegelijkertijd plaatsvinden, wordt de interrupt met het laagste vectornummer als eerste verwerkt.

Onderbreek vectoren in Atmega8

Adres Bron onderbreken Beschrijving
0x0000 RESET Signaal resetten
0x0001 INT0 Extern interruptverzoek op INT0-ingang
0x0002 INT1 Extern interruptverzoek op INT1-ingang
0x0003 T/C1 Timerregistratie T/C1
0x0004 T/C1 Match T/C1 Timer Vergelijk Register A
0x0005 T/C1 Match met vergelijkregister B van timer T/C1
0x0006 T/C1 T/C1 teller overloop
0x0007 T/C0 T/C0-telleroverloop
0x0008 SPI SPI-gegevensoverdracht voltooid
0x0009 UART De UART-transceiver heeft het ontvangen van gegevens voltooid.
0x000A UART UART-gegevensregister is leeg
0x000B UART De gegevensoverdracht door de UART-transceiver is voltooid
0x000C ANA_COMP Onderbreking van analoge comparator

Beheer onderbreken

4 registers zijn verantwoordelijk voor het beheer van interrupts in ATmega8:

GIMSK(ook bekend als GICR) - verbied/inschakel interrupts op basis van signalen op ingangen INT0, INT1

GIFR- beheer van alle externe interrupts

TIMSK, TIFR- beheer van onderbrekingen van timers/tellers

Register GIMSK(GICR)

INTFx=1: er heeft zich een interrupt voorgedaan op de INTx-ingang. Bij het starten van de interruptafhandelingsroutine wordt INTFx automatisch teruggezet naar de logstatus. 0

Register TIMSK

7 6 5 4 3 2 1 0
TOIE1
OCIE1A
OCIE1B
-
TICIE
-
TOIE0
-

TOIE1=1: T/C1 overlooponderbreking ingeschakeld

OCIE1A=1: onderbreken wanneer vergelijkingsregister A overeenkomt met de inhoud van teller T/C1 ingeschakeld

OCIE1B=1: onderbreken wanneer vergelijkingsregister B overeenkomt met de inhoud van teller T/C1 ingeschakeld

TICIE=1: interrupt ingeschakeld wanneer aan de opnamevoorwaarde is voldaan

TOIE0=1: T/C0-overlooponderbreking ingeschakeld

Register TIFR

7 6 5 4 3 2 1 0
TOV1
OCF1A
OCF1B
-
ICF1
-
TOV0
-

TOV1=1: T/C1-overloop heeft plaatsgevonden

OCF1A=1: vergelijkingsregister A viel samen met de toegestane inhoud van teller T/C1

OCF1B=1: vergelijkingsregister B komt overeen met de inhoud van teller T/C1 toegestaan

ICF=1: er is voldaan aan de opnamevoorwaarden

TOV0=1: Er heeft zich een T/C0-overloop voorgedaan

Bij het betreden van de subroutine voor het afhandelen van interrupts wordt de TIFR-registervlag die overeenkomt met de interrupt automatisch teruggezet naar de logstatus. 0

Interrupts werken alleen als algemene interrupts zijn ingeschakeld in het SREG-statusregister (bit 7 = 1). Wanneer er een interrupt optreedt, wordt deze bit automatisch teruggezet op 0, waardoor daaropvolgende interrupts worden uitgeschakeld.

In dit voorbeeld is de INT0-pin ingeschakeld in de pull-up-invoermodus. Wanneer de pin met behulp van een knop wordt kortgesloten naar aarde, wordt er een logische 0 op ingesteld (de rand van het signaal daalt van de voedingsspanning naar 0) en wordt de interrupthandler geactiveerd, waardoor de lamp wordt ingeschakeld die is aangesloten op de nulpin van de poort B

ongeldig lampON()
{
POORTB.0=1;
DDRB.0=1;
}

interrupt void ext_int0_isr(void)
{
lampAAN();
}

DDRD.2=0;
POORT.2=1;

SREG|= (1 terwijl(1) (

Het bovenstaande voorbeeld laat ook zien hoe interruptvectoren worden ingesteld in Code Vision AVR (interrupt void ext_int0_isr(void)). Interruptvectoren worden op dezelfde manier ingesteld voor andere gevallen:

EXT_INT0 2
EXT_INT1 3
TIM2_COMP 4
TIM2_OVF 5
TIM1_CAPT 6
TIM1_COMPA 7
TIM1_COMPB 8
TIM1_OVF 9
TIM0_OVF 10
SPI_STC 11
USART_RXC 12
USART_DRE 13
USART_TXC 14
ADC_INT 15
EE_RDY 16
ANA_COMP 17
TWI 18
SPM_READY 19

Waar worden externe interrupts voor gebruikt?

Een onderbreking is een gebeurtenis waardoor de uitvoering van de hoofdprogrammacode (bijvoorbeeld de hoofdfunctie) wordt onderbroken en de besturing wordt overgedragen aan de interrupthandler van de functie. Dienovereenkomstig zijn externe interrupts bepaalde externe gebeurtenissen die de uitvoering van de hoofdprogrammacode onderbreken.

Met externe interrupts kunt u snel en gegarandeerd reageren op externe gebeurtenissen. Daarom is het meest voorkomende gebruik van externe interrupts de implementatie van pulstellers, het meten van frequentie of pulsduur, software-implementatie van uart, one-wire, i2c, spi, evenals het verwerken van signalen van externe randapparatuur.

Het werkingsprincipe van externe interrupts in AVR

Om de microcontroller te laten leren over externe gebeurtenissen, worden discrete ingangen INT0 INT1, enz. gebruikt. Discreet betekent dat ze werken met logische niveaus: 0 en 1.
0 is geen spanning aan de ingang
1 — aanwezigheid van spanning aan de ingang, die gelijk is aan de voedingsspanning van de microcontroller.

Externe interrupts kunnen in twee typen worden verdeeld:

  • externe interrupts op niveau
  • externe randonderbrekingen

Externe interrupts op niveau

De externe interrupttrigger kan worden geconfigureerd op laag of hoog. Als de interrupt bijvoorbeeld op logisch laag is ingesteld, treedt deze op wanneer de spanning aan de INT-ingang nul is. Als de interrupt op een hoog niveau is ingesteld, treedt deze op wanneer de ingang logisch 1 is.
Wanneer u met op niveaus gebaseerde interrupts werkt, moet u er rekening mee houden dat zolang de INT-invoer het juiste niveau heeft, de interrupt voortdurend zal optreden. Die. als er een interrupt optreedt, bijvoorbeeld op een laag niveau, en het programma deze verwerkt, maar als bij het verlaten van de interrupt-handler de invoer laag blijft, dan zal de interrupt opnieuw afgaan en zal de interrupt-handler opnieuw worden aangeroepen, en dit gaat door totdat het hoge invoerniveau verschijnt. Om dit te voorkomen, moet u dit type onderbreking in de handler uitschakelen of opnieuw configureren naar een ander niveau.

Externe randonderbreking

Een interrupt op een stijgende flank, of, zoals ze soms zeggen, een stijgend signaal, treedt op als het signaalniveau op de INT-ingang verandert van 0 naar 1. Een interrupt op een dalende flank (dalend signaal) ontstaat wanneer het signaalniveau op de INT-ingang verandert INT-invoer verandert van 1 naar 0.
Het is ook mogelijk om de interrupt zo te configureren dat deze reageert op elke verandering aan de INT-ingang, d.w.z. het zal voorkomen langs zowel de voor- als de achterrand.

Externe interrupts configureren in AVR

Externe interrupts in avr atmega8 geconfigureerd met behulp van bits ISCxx register MCUCR .

Afhankelijkheid van de triggerconditie van de externe interrupt INT0 van de ISC0x-bit van het MCUCR-register in avr atmega8

Voor externe onderbreking INT1 , de installatie gebeurt op dezelfde manier, er worden alleen bits gebruikt ISC11 ISC10 .

Voorbeeldexterne interrupt-instellingen voor avr atmega8:

//reset alle ISCxx-bits MCUCR &= ~( (1 <<ISC11) | (1<<ISC10) | (1<< ISC01) | (1<< ISC00) ) MCUCR |= (1 << ISC01) | (1 << ISC00) ;

//reset alle bits ISCxx MCUCR &= ~((1<

Schakel externe interrupts in avr atmega in

Om externe interrupts te laten werken, moeten ze worden ingeschakeld door de overeenkomstige bits in het register op 1 te zetten GICR .

Beetje INT0 verantwoordelijk voor het in-/uitschakelen van externe interrupts INT0 , en beetje INT1 respectievelijk voor externe onderbreking INT1 .

Het is ook noodzakelijk dat de globale interrupt enable-vlag wordt ingesteld.

Voorbeeldcode voor het inschakelen van externe interrupt INT0 voor avr atmega8:

// schakel externe interrupt in INT0 GICR |= (1<

Voorbeeld van het gebruik van externe interrupts in AVR atmega

Als voorbeeld zal ik een pulstellerprogramma geven. Het programma telt het aantal pulsen op de INTO-ingang en geeft één keer per seconde het telresultaat weer in de uart.

#erbij betrekken #erbij betrekken #erbij betrekken #erbij betrekken // tellervariabele vluchtig, niet-ondertekend lang int0_cnt = 0; // configureren van externe interrupt INT0 ongeldig int0_init(nietig) ( //set om INT0 op een stijgende flank te activeren MCUCR |= (1 << ISC01) | (1 << ISC00) ; // schakel externe interrupt INT0 in GICR |= (1 <<INT0) ; ) //functie externe interrupthandler INT0 ISR( INT0_vect ) ( int0_cnt++; ) //UART-installatie void uart_init( void ) ( //de uitwisselingssnelheid instellen UBRRH = 0; UBRRL = 3; //115200 bij kwarts 7,3728 MHz //8 databits, 1 stopbit, geen pariteit UCSRC = ( 1 << URSEL ) | ( 1 << UCSZ1 ) | (1 << UCSZ0 ) ; //laat gegevensontvangst en -overdracht toe UCSRB = ( 1 << TXEN ) | (1 << RXEN ) ; ) //byte-overdracht via UART int uart_putc( char c, BESTAND * bestand ) ( // wacht op het einde van de verzending van de vorige byte terwijl (( UCSRA & ( 1 << UDRE ) ) == 0 ); UDR = c; retour 0; ) BESTAND uart_stream = FDEV_SETUP_STREAM(uart_putc, NULL, _FDEV_SETUP_WRITE ) ; int hoofd( ) ( //tijdelijke variabele niet-ondertekende lange tmp; stdout = & uart_stream; int0_init() ; uart_init() ; sei() ; terwijl (1) ( //disable interrupts terwijl de tellerwaarde wordt gekopieerd cli() ; tmp = int0_cnt; // schakel interrupts in sei() ; printf("int0_cnt = %lu \r\n", tmp); //pauzeer 1 seconde _delay_ms(1000); ) retourneer 0; )

#erbij betrekken #erbij betrekken #erbij betrekken #erbij betrekken //tellervariabele vluchtig niet-ondertekend lang int0_cnt = 0; // configureren van de externe interrupt INT0 void int0_init(void) ( // configureren van INT0 om te activeren op een stijgende flank MCUCR |= (1<

De stapel is een geheugengebied dat de CPU gebruikt om retouradressen van subroutines op te slaan en te herstellen.
Bijna alle AVR-microcontrollers hebben een stack in SRAM. Om het huidige element (bovenaan de stapel) aan te spreken, wordt de stapelwijzer SP (Stack Pointer) gebruikt. Dit is een RVV SPL van één byte voor modellen met een datageheugencapaciteit van maximaal 256 bytes, of een SPH:SPL van twee bytes (SPH - high byte, SPL - low byte).

Wanneer de microprocessor een van de oproepinstructies rcall/call/ecall/icall/eicall tegenkomt, wordt het adres van het volgende woord in het programmageheugen door hardware naar de stapel gekopieerd. Wanneer het ret-commando de subroutine verlaat, wordt het retouradres hersteld van de stapel naar de programmateller. In modellen met een programmageheugencapaciteit van 128 en 256 kwords zal het opslaan van de pc op de stapel 3 bytes vereisen, voor alle andere - 2 bytes. Bij het opslaan van elke byte wordt de inhoud van SP met één verminderd, en bij herstel wordt deze dienovereenkomstig verhoogd.

Fig.9 Stapellocatie in datageheugen

De programmeur moet helemaal aan het begin van het programma zelfstandig de locatie van de stapel bepalen. Vanuit het oogpunt van de maximale diepte moet de bovenkant van de stapel helemaal aan het uiteinde van de SRAM worden geplaatst, zoals weergegeven in figuur 9:

Neem "m8def.inc" op ldi temp,low(RAMEND) ;set SP = RAMEND uit SPL,temp ;voor ATmega8 SP = 0x045F ldi temp,high(RAMEND) uit SPH,temp

De RAMEND-constante uit het standaard headerbestand m8def.inc heeft de waarde van het adres van de laatste SRAM-cel.

Applicatieprogrammavariabelen bevinden zich in het SRAM-adresbereik tussen RBB en de huidige SP-positie. Daarom is het erg belangrijk om eerst de maximale stapelgrootte (stapeldiepte) in te schatten. Het kan gebeuren dat de bovenkant van de stapel te hoog wordt en gebruikersgegevens begint te “overschrijven”, en dit is een van de moeilijkste fouten om te detecteren!

De AVR-stack heeft naast het opslaan van retouradressen nog een ander zeer belangrijk doel. Hiermee kunt u alle gegevens opslaan met behulp van de opdrachten push Rr (laden naar de stapel) en pop Rd (uit de stapel halen) die speciaal voor dit doel zijn ontworpen. Elke keer dat een push Rr wordt uitgevoerd, wordt de inhoud van Rr naar de stapel gekopieerd, waarna SP met één wordt verlaagd. Wanneer pop Rr wordt uitgevoerd, wordt de inhoud van de stapelcel waarnaar SP verwijst, hersteld naar Rr, en wordt de waarde van SP zelf verhoogd. Dit soort stapel heeft een Last In First Out-organisatie: het register dat is opgeslagen door het laatste push-commando zal worden hersteld door het eerste pop-commando:

; SP Stack-niveau na het push-commando R16 ;save R16 0x045F R16 ? ? druk op R17 ;opslaan R17 0x045E R16 R17 ? druk op R18 ;opslaan R18 0x045D R16 R17 R18 ̣̣̣̣̣̣̣ pop R18 ;herstellen R18 0x045D R16 R17 ? pop R17; herstel R17 0x045E R16? ? pop R16; herstel R16 0x045F? ? ?

Met behulp van de stapel kunt u heel eenvoudig de inhoud van registers omwisselen:

; Ruil R16<->R17 SP Stackniveau na push-commando R16 ;opslaan R16 0x045F R16 ? druk op R17 ;opslaan R17 0x045E R16 R17 pop R16 ;herstellen R16 0x045E R16 ? pop R17; herstel R17 0x045F? ?


Afb. 10 Voorbeeld van stapelbediening

Figuur 10 toont een klein stukje code dat een stapsgewijs proces laat zien van het veranderen van de stapel bij het betreden en verlaten van de toggle-subroutine en het opslaan en herstellen van register R17. Dit is een typisch voorbeeld waarbij push/pop-instructies nodig kunnen zijn. De toggle-subroutine gebruikt RON R17 voor zijn behoeften, maar hetzelfde register kan ook tijdens het hoofdprogramma worden gebruikt. Om datacorruptie te voorkomen, wordt R17 daarom vóór wijziging op de stapel geladen en daaruit hersteld vóór de ret-opdracht.