- Varför Timer när vi har fördröjning ()?
- PIC-mikrokontroller Timers:
- Programmering och arbetsförklaring:
- Kretsschema och Proteus-simulering:
Detta kommer att vara den femte självstudien i vår PIC-handledningsserie, som hjälper dig att lära dig och använda timers i PIC16F877A. I våra tidigare självstudier hade vi börjat med Introduktion till PIC och MPLABX IDE, sedan skrev vi vårt första PIC-program för att blinka LED med PIC och gjorde sedan en LED-blinkande sekvens med hjälp av fördröjningsfunktionen i PIC Microcontroller. Låt oss nu använda samma LED Blinking-sekvens som vi har använt i tidigare tutorial-hårdvara och med detta kommer vi att lära oss hur man använder timers i vår PIC MCU. Vi har precis lagt till ytterligare en knapp i LED-kortet för denna handledning. Gå igenom handledningen för att lära dig mer.
Timers är en av de viktiga arbetshästarna för en inbäddad programmerare. Varje applikation som vi designar kommer på något sätt att involvera en tidsapplikation, som att sätta PÅ eller AV något efter ett visst tidsintervall. Okej, men varför behöver vi timers när vi redan har fördröjningsmakron (__delay_ms ()) som gör samma sak !!
Varför Timer när vi har fördröjning ()?
Ett fördröjningsmakro kallas en "dump" -fördröjning. Eftersom MCU sitter under dumpningen genom att bara skapa en fördröjning. Under denna process kan MCU inte lyssna på dess ADC-värden eller läsa någonting från sina register. Därför är det inte tillrådligt att använda fördröjningsfunktioner förutom applikationer som lysdioder som blinkar där tidsfördröjningen inte behöver vara exakt eller lång.
Fördröjningsmakronen har också följande korta kommande,
- Värdet på fördröjning måste vara en konstant för fördröjningsmakron; den kan inte ändras under programkörning. Därför är det fortfarande programmerardefinierat.
- Förseningen kommer inte att vara korrekt jämfört med att använda timer.
- Större värden för förseningar kan inte skapas med makron, till exempel kan en fördröjning på en halvtimme inte skapas av fördröjningsmakron. Den maximala fördröjningen som kan användas baseras på den kristalloscillator som används.
PIC-mikrokontroller Timers:
Fysiskt är timer ett register vars värde ständigt ökar till 255, och sedan börjar det om igen: 0, 1, 2, 3, 4… 255…. 0, 1, 2, 3……etc.
Den PIC16F877A PIC MCU har tre timer moduler. De är namn som Timer0, Timer1 och Timer2. Timer 0 och Timer 2 är 8-bitars Timers och Timer 1 är en 16-bitars Timer. I denna handledning använder vi Timer 0 för vår applikation. När vi förstår Timer 0 kommer det att vara lätt att arbeta med Timer 1 och Timer 2 också.
Timer0-modulens timer / räknare har följande funktioner:
- 8-bitars timer / räknare
- Läsbar och skrivbar
- 8-bitars programvara programmerbar förskalare
- Val av intern eller extern klocka
- Avbryt vid överflöde från FFh till 00h
- Kantval för extern klocka
För att börja använda en timer bör vi förstå några av de snygga termerna som 8-bitars / 16-bitars timer, Prescaler, Timer-avbrott och Focs. Låt oss nu se vad var och en egentligen menar. Som sagt tidigare finns det både 8-bitars och 16-bitars timers i vår PIC MCU, den största skillnaden mellan dem är att 16-bitars timern har mycket bättre upplösning än 8-bitars timern.
Prescaler är ett namn för den del av en mikrokontroller som delar upp oscillatorklockan innan den når logik som ökar timerstatus. Området för prescaler-id är från 1 till 256 och värdet för Prescaler kan ställas in med hjälp av OPTION-registret (samma som vi använde för att dra upp motstånd). Till exempel om värdet på förskalaren är 64, kommer timern att ökas med 1 för varje 64: e puls.
När timern ökar och när den når sitt maximala värde på 255, kommer den att utlösa ett avbrott och initieras till 0 tillbaka igen. Detta avbrott kallas för Timer Interrupt. Detta avbrott informerar MCU om att den här tiden har gått.
Den Fosc står för frekvensen hos oscillatorn, är det frekvensen av Crystal används. Tiden det tar för timerregistret beror på värdet på Prescaler och värdet på Fosc.
Programmering och arbetsförklaring:
I denna handledning kommer vi att ställa in två knappar som två ingångar och 8 lysdioder som 8 utgångar. Den första knappen används för att ställa in tidsfördröjningen (500 ms för varje tryck) och den andra knappen kommer att användas för att starta timersekvensen att blinka. Till exempel, om den första knappen trycks in tre gånger (500 * 3 = 1500ms) kommer fördröjningen att ställas in på 1,5sek och när knappen två trycks in kommer varje LED att tändas och stängas av med den fördefinierade tidsfördröjningen. Kolla demonstrationsvideon i slutet av denna handledning.
Nu, med dessa grunder i åtanke, låt oss titta på vårt program som ges i slutet i kodavsnittet.
Det är okej om du inte fick programmet, men om du gjorde det !! Ge dig själv en cookie och dumpa programmet för att njuta av din produktion. För andra kommer jag att dela upp programmet i meningsfulla delar och förklara vad som händer i varje block.
Som alltid är de första raderna i koden konfigurationsinställningar och rubrikfiler, jag kommer inte att förklara detta eftersom jag redan har gjort det i mina tidigare självstudier.
Låt oss sedan hoppa över alla rader och hoppa rakt in i den ogiltiga huvudfunktionen, inom vilken vi har PORT-konfigurationen för Timer0.
void main () {/ ***** Portkonfiguration för timer ****** / OPTION_REG = 0b00000101; // Timer0 med extern freq och 64 som prescalar // Aktiverar även PULL UPs TMR0 = 100; // Ladda tidsvärdet för 0,0019968s; delayValue kan vara mellan 0-256 endast TMR0IE = 1; // Aktivera timeravbrottsbit i PIE1-registret GIE = 1; // Aktivera Global Interrupt PEIE = 1; // Aktivera perifert avbrott / *********** ______ *********** /
För att förstå detta måste vi titta på OPTION-registret i vårt PIC-datablad.
Som diskuterades i föregående handledning används bit 7 för att möjliggöra svag uppmotstånd för PORTB. Titta på figuren ovan, bit 3 är gjord 0 för att instruera MCU att följande förkalker som ställs in ska användas för timern och inte för WatchDogTimer (WDT). Timer-läge väljs genom att rensa bit 5 T0CS
(OPTION_REG <5>)
Nu används bitarna 2-0 för att ställa in förskalningsvärdet för timern. Som visas i tabellen ovan för att ställa in ett förskalningsvärde på 64 måste bitarna ställas in som 101.
Låt oss sedan titta på de register som är associerade med Timer0
Timern kommer att börja öka när den är inställd och överflödar efter att ha nått ett värde på 256, för att möjliggöra att Timer-avbrottet under denna punkt måste registret TMR0IE ställas in högt. Eftersom Timer 0 själv är en perifer måste vi aktivera Peripheral Interrupt genom att göra PEIE = 1. Slutligen måste vi aktivera Global Interrupt så att MCU kommer att meddelas om Interrupt under varje operation, detta görs genom att göra GIE = 1.
Fördröjning = ((256-REG_val) * (Prescal * 4)) / Fosc
Ovanstående formel används för att beräkna värdet på fördröjning.
Var
REG_val = 100;
Prescal = 64
Fosc = 20000000
Detta vid beräkning ger, Fördröjning = 0,0019968s
Nästa uppsättning rader är att ställa in I / O-portarna.
/ ***** Portkonfiguration för I / O ****** / TRISB0 = 1; // Instruera MCU att PORTB-stift 0 används som ingång för knapp 1. TRISB1 = 1; // Instruera MCU att PORTB-stift 1 används som ingång för knapp 1. TRISD = 0x00; // Instruera MCU att alla stift på PORT D matas ut PORTD = 0x00; // Initiera alla stift till 0 / *********** ______ *********** /
Det här är detsamma som i vår tidigare handledning eftersom vi använder samma hårdvara. Förutom att vi har lagt till en annan knapp som ingång. Detta görs med linjen TRISB1 = 1.
Nästa, inifrån och ut oändligt medan loop har vi två block av kod. En används för att få timeringången från användaren och den andra för att utföra fördröjningssekvensen över lysdioderna. Jag har förklarat dem genom att använda kommentarer mot varje rad.
medan (1) {count = 0; // Kör inte timer medan du är i huvudslinga // ******* Få nummerfördröjningen från användaren **** ////// if (RB0 == 0 && flagga == 0) // När ingång som ges {get_scnds + = 1; // get_scnds = get_scnds + http: // Increment variable flag = 1; } om (RB0 == 1) // För att förhindra kontinuerlig inkrementeringsflagga = 0; / *********** ______ *********** /
En variabel som kallas get_scnds ökas varje gång användaren trycker på knappen 1. En flagga (programvarudefinierad) används för att hålla inkrementeringsprocessen tills användaren tar bort sitt finger från knappen.
// ******* Kör sekvens med fördröjning **** ////// medan (RB1 == 0) {PORTD = 0b00000001 <
Nästa block träder i kraft om du trycker på knapp två. Eftersom användaren redan har definierat den fördröjda tidsfördröjningen med knappen en och den har sparats i variabeln get_scnds. Vi använder en variabel som heter hscnd, denna variabel styrs av ISR (Interrupt service routine).
Den avbrottsservicerutin är ett avbrott som kommer att kallas varje gång Timer0 är svämmar över. Låt oss se hur den styrs av ISR i nästa block, som om vi vill öka tidsfördröjningen med en halv sekund (0,5 sek) på varje knapptryckning, då måste vi öka variabeln hscnd för varje halv sekund. Eftersom vi har programmerat vår timer till överflöde för varje 0,0019968s (~ 2ms), så att räkna en halv sekund räknevariabel bör vara 250 eftersom 250 * 2ms = 0,5 sekund. Så när räkningen blir 250 (250 * 2ms = 0,5 sekund) betyder det att det har gått en halv sekund så vi ökar hscnd med 1 och initialiserar räkningen till noll.
ogiltig interrupt timer_isr () {if (TMR0IF == 1) // Timerflagga har utlösts på grund av timeröverflöde {TMR0 = 100; // Ladda timern Värde TMR0IF = 0; // Rensa timer avbryta flaggantal ++; } if (count == 250) {hscnd + = 1; // hscnd kommer att ökas för varje halvsekunds räkning = 0; }}
Så vi använder detta värde och jämför det med vår hscnd och förskjuter vår LED baserat på den användardefinierade tiden. Det liknar också den senaste handboken.
Det är det vi har vårt program förstått och fungerar.
Kretsschema och Proteus-simulering:
Som vanligt kan vi verifiera utdata med Proteus först, jag har länkat här de schematiska filerna för Proteus.
Lägg till en knapp på vårt tidigare LED-kort och vår hårdvara är redo att gå. Det borde se ut så här:
När anslutningen är klar, ladda upp koden och verifiera utdata. Om du har några problem, använd kommentarsektionen. Läs också videon nedan för att förstå hela processen.