- Waarom Timer als we Delay () hebben?
- PIC-microcontroller-timers:
- Programmering en werkuitleg:
- Schakelschema en Proteus-simulatie:
Dit wordt de vijfde tutorial in onze PIC Tutorial Series, die je zal helpen om Timers te leren en te gebruiken in PIC16F877A. In onze vorige tutorials waren we begonnen met Inleiding tot PIC en MPLABX IDE, daarna schreven we ons eerste PIC-programma om de LED te laten knipperen met behulp van PIC en maakten vervolgens een LED-knipperende sequentie met behulp van de vertragingsfunctie in PIC Microcontroller. Laten we nu dezelfde LED-knipperreeks gebruiken die we hebben gebruikt in eerdere zelfstudiehardware en hiermee zullen we leren hoe we timers kunnen gebruiken in onze PIC MCU. We hebben zojuist nog een knop in het LED-bord toegevoegd voor deze tutorial. Doorloop de tutorial voor meer informatie.
Timers zijn een van de belangrijkste werkpaarden voor een embedded programmeur. Elke applicatie die we ontwerpen, zal op de een of andere manier een timing-applicatie bevatten, zoals iets AAN of UIT zetten na een gespecificeerd tijdsinterval. Oké, maar waarom hebben we timers nodig als we al vertragingsmacro's (__delay_ms ()) hebben die hetzelfde doen !!
Waarom Timer als we Delay () hebben?
Een vertragingsmacro wordt een "dumpvertraging" genoemd. Omdat tijdens de uitvoering van de vertragingsfunctie de MCU dump zit door gewoon een vertraging te creëren. Tijdens dit proces kan de MCU niet naar zijn ADC-waarden luisteren of iets uit zijn registers lezen. Daarom is het niet aan te raden om vertragingsfuncties te gebruiken, behalve voor toepassingen zoals het knipperen van LED's, waarbij de tijdvertraging niet nauwkeurig of lang hoeft te zijn.
De vertragingsmacro's hebben ook de volgende tekortkomingen,
- De waarde van de vertraging moet een constante zijn voor vertragingsmacro's; het kan niet worden gewijzigd tijdens de uitvoering van het programma. Daarom blijft de programmeur gedefinieerd.
- De vertraging is niet nauwkeurig in vergelijking met het gebruik van timers.
- Grotere waarden van vertragingen kunnen niet worden gemaakt met macro's, een vertraging van bijvoorbeeld een half uur kan niet worden gemaakt met vertragingsmacro's. De maximale vertraging die kan worden gebruikt, is gebaseerd op de gebruikte kristaloscillator.
PIC-microcontroller-timers:
Fysiek gezien is timer een register waarvan de waarde voortdurend toeneemt tot 255, en dan begint het helemaal opnieuw: 0, 1, 2, 3, 4… 255… 0, 1, 2, 3…..enzovoort.
De PIC16F877A PIC MCU heeft drie timermodules. Het zijn namen als Timer0, Timer1 en Timer2. Timer 0 en Timer 2 zijn 8-bit timers en Timer 1 is een 16-bit timer. In deze tutorial zullen we de Timer 0 gebruiken voor onze applicatie. Zodra we Timer 0 begrijpen, is het gemakkelijk om ook aan Timer 1 en Timer 2 te werken.
De Timer0 module timer / teller heeft de volgende kenmerken:
- 8-bit timer / teller
- Leesbaar en beschrijfbaar
- 8-bit software programmeerbare voorschrijver
- Interne of externe klok selecteren
- Onderbreken bij overloop van FFh tot 00h
- Rand selecteren voor externe klok
Om een timer te gebruiken, moeten we enkele van de mooie termen begrijpen, zoals 8-bit / 16-bit timer, Prescaler, Timer interrupts en Focs. Laten we nu eens kijken wat elk echt betekent. Zoals eerder gezegd zijn er zowel de 8-bits als de 16-bits timers in onze PIC MCU, het belangrijkste verschil tussen beide is dat de 16-bits timer een veel betere resolutie heeft dan de 8-bits timer.
Prescaler is een naam voor het deel van een microcontroller dat de oscillatorklok verdeelt voordat het logica bereikt die de timerstatus verhoogt. Het bereik van de prescaler-ID is van 1 tot 256 en de waarde van de prescaler kan worden ingesteld met behulp van het OPTION-register (hetzelfde register dat we hebben gebruikt voor pull-up-weerstanden). Bijvoorbeeld als de waarde van prescaler 64, vervolgens elke 64 ste puls de timer wordt met 1 verhoogd.
Naarmate de timer toeneemt en wanneer hij de maximale waarde van 255 bereikt, zal hij een interrupt activeren en zichzelf weer op 0 initialiseren. Deze onderbreking wordt de timeronderbreking genoemd. Deze onderbreking informeert de MCU dat deze specifieke tijd is verstreken.
De Fosc staat voor Frequency of the Oscillator, het is de frequentie van het gebruikte kristal. De tijd die nodig is voor het Timer register is afhankelijk van de waarde van Prescaler en de waarde van de Fosc.
Programmering en werkuitleg:
In deze tutorial zullen we twee knoppen instellen als twee inputs en 8 LED's als 8 outputs. De eerste knop wordt gebruikt om de tijdvertraging in te stellen (500 ms voor elke druk) en de tweede knop wordt gebruikt om de timerreeks te laten knipperen. Als de eerste knop bijvoorbeeld driemaal wordt ingedrukt (500 * 3 = 1500 ms), wordt de vertraging ingesteld op 1,5 seconde en wanneer knop twee wordt ingedrukt, gaat elke LED AAN en UIT met de vooraf gedefinieerde tijdvertraging. Bekijk de demonstratievideo aan het einde van deze zelfstudie.
Laten we, met deze basis in gedachten, eens kijken naar ons programma aan het einde van de sectie Code.
Het is oké als je het programma niet hebt gekregen, maar als je het wel hebt gedaan !! Geef jezelf een koekje en dump het programma om van je output te genieten. Voor anderen zal ik het programma opsplitsen in zinvolle delen en je uitleggen wat er in elk blok gebeurt.
Zoals altijd zijn de eerste paar regels van de code de configuratie-instellingen en header-bestanden, ik ga dit niet uitleggen omdat ik het al heb gedaan in mijn vorige tutorials.
Laten we vervolgens alle regels overslaan en rechtstreeks naar de leegte hoofdfunctie springen, waarbinnen we de PORT-configuratie voor de Timer0 hebben.
void main () {/ ***** Poortconfiguratie voor timer ****** / OPTION_REG = 0b00000101; // Timer0 met externe freq en 64 als prescalar // Activeert ook PULL UPs TMR0 = 100; // Laad de tijdwaarde voor 0.0019968s; delayValue kan tussen 0-256 liggen alleen TMR0IE = 1; // Schakel timer-interruptbit in PIE1-register GIE = 1 in; // Schakel Global Interrupt PEIE = 1 in; // Schakel de perifere onderbreking in / *********** ______ *********** /
Om dit te begrijpen, moeten we het OPTION-register in onze PIC-datasheet bekijken.
Zoals besproken in de vorige tutorial wordt bit 7 gebruikt om een zwakke pull-up weerstand voor de PORTB in te schakelen. Kijk naar de bovenstaande afbeelding, de bit 3 is gemaakt van 0 om de MCU te instrueren dat de volgende voorschrijver die wordt ingesteld moet worden gebruikt voor de timer en niet voor de WatchDogTimer (WDT). De timermodus wordt geselecteerd door bit 5 T0CS te wissen
(OPTION_REG <5>)
Nu wordt de bits2-0 gebruikt om de presalerwaarde voor de timer in te stellen. Zoals in de bovenstaande tabel wordt getoond, moeten de bits worden ingesteld als 101 om een presalerwaarde van 64 in te stellen.
Laten we vervolgens kijken naar de registers die zijn gekoppeld aan Timer0
De timer begint te verhogen zodra deze is ingesteld en loopt over na het bereiken van een waarde van 256, om de timeronderbreking op dit punt mogelijk te maken, moet het register TMR0IE hoog worden ingesteld. Aangezien Timer 0 zelf een randapparaat is, moeten we de randonderbreking inschakelen door PEIE = 1 te maken. Ten slotte moeten we de globale onderbreking inschakelen zodat de MCU tijdens elke bewerking op de hoogte wordt gesteld van de onderbreking, dit wordt gedaan door GIE = 1 te maken.
Vertraging = ((256-REG_val) * (Prescal * 4)) / Fosc
De bovenstaande formule wordt gebruikt om de waarde van Delay te berekenen.
Waar
REG_val = 100;
Prescal = 64
Fosc = 20000000
Dit op berekening geeft, Vertraging = 0,0019968s
De volgende reeks regels is om de I / O-poorten in te stellen.
/ ***** Poortconfiguratie voor I / O ****** / TRISB0 = 1; // Geef de MCU de instructie dat PORTB-pin 0 wordt gebruikt als invoer voor knop 1. TRISB1 = 1; // Instrueer de MCU dat de PORTB-pin 1 wordt gebruikt als invoer voor knop 1. TRISD = 0x00; // Instrueer de MCU dat alle pinnen op PORT D worden uitgevoerd PORTD = 0x00; // Initialiseer alle pinnen naar 0 / *********** ______ *********** /
Dit is hetzelfde als dat van onze vorige tutorial, omdat we dezelfde hardware gebruiken. Behalve dat we nog een knop hebben toegevoegd als invoer. Dit wordt gedaan door de regel TRISB1 = 1.
Vervolgens hebben we binnenstebuiten oneindige while- lus twee blokken code. De ene wordt gebruikt om de timerinvoer van de gebruiker te krijgen en de andere om de reeks vertragingen over de LED's uit te voeren. Ik heb ze uitgelegd door opmerkingen bij elke regel te gebruiken.
while (1) {count = 0; // Voer geen timer uit in de hoofdlus // ******* Verkrijg de nummervertraging van gebruiker **** ////// if (RB0 == 0 && flag == 0) // When input gegeven {get_scnds + = 1; // get_scnds = get_scnds + http: // Variabele vlag verhogen = 1; } if (RB0 == 1) // Om continue toename vlag = 0 te voorkomen; / *********** ______ *********** /
Een variabele genaamd get_scnds wordt opgehoogd elke keer dat de gebruiker op knop 1 drukt. Een vlag (softwaregedefinieerde) variabele wordt gebruikt om het oplopende proces vast te houden totdat de gebruiker zijn vinger van de knop verwijdert.
// ******* Voer een reeks uit met vertraging **** ////// while (RB1 == 0) {PORTD = 0b00000001 <
Het volgende blok komt in actie als knop twee wordt ingedrukt. Omdat de gebruiker de vereiste tijdvertraging al heeft gedefinieerd met knop één en deze is opgeslagen in de variabele get_scnds. We gebruiken een variabele genaamd hscnd, deze variabele wordt aangestuurd door de ISR (Interrupt service routine).
De onderbrekingsserviceroutine is een onderbreking die wordt aangeroepen elke keer dat de Timer0 overloopt. Laten we eens kijken hoe het wordt bestuurd door de ISR in het volgende blok, zoals we de tijdsvertraging met een halve seconde (0,5s) willen verhogen bij elke druk op de knop, dan moeten we variabele hscnd verhogen voor elke halve seconde. Als we onze timer over stroom voor elke 0.0019968s (~ 2ms) zijn geprogrammeerd om, om zo te tellen halve seconde tellen variabele moet 250 omdat 250 * 2ms = 0,5 seconde. Dus als de telling 250 krijgt (250 * 2ms = 0,5 seconde), betekent dit dat het een halve seconde heeft geduurd, dus we verhogen hscnd met 1 en initialiseren de telling naar nul.
void interrupt timer_isr () {if (TMR0IF == 1) // Timervlag is geactiveerd vanwege timeroverloop {TMR0 = 100; // Laad de timerwaarde TMR0IF = 0; // Wis timer-interruptvlaggetelling ++; } if (count == 250) {hscnd + = 1; // hscnd wordt opgehoogd voor elke halve seconde count = 0; }}
Dus we gebruiken deze waarde en vergelijken deze met onze hscnd en verschuiven onze LED op basis van de door de gebruiker gedefinieerde tijd. Het lijkt ook erg op de laatste tutorial.
Dat is het, we hebben ons programma begrepen en werken.
Schakelschema en Proteus-simulatie:
Laten we zoals gewoonlijk eerst de output verifiëren met Proteus, ik heb hier de schematische bestanden van de Proteus gelinkt.
Voeg een knop toe aan ons vorige LED-bord en onze hardware is klaar voor gebruik. Het zou er ongeveer zo uit moeten zien:
Nadat de verbinding is gemaakt, uploadt u de code en controleert u de uitvoer. Als je een probleem hebt, gebruik dan het commentaargedeelte. Bekijk ook de onderstaande video om het hele proces te begrijpen.