- Hvorfor timer når vi har forsinkelse ()?
- PIC-mikrocontroller-tidtakere:
- Programmering og arbeidsforklaring:
- Kretsdiagram og Proteus-simulering:
Dette vil være den femte opplæringen i vår PIC-opplæringsserie, som vil hjelpe deg å lære og bruke timere i PIC16F877A. I våre tidligere veiledninger hadde vi startet med Introduksjon til PIC og MPLABX IDE, så skrev vi vårt første PIC-program for å blinke LED-en ved hjelp av PIC og lagde deretter en LED-blinkende sekvens ved å bruke forsinkelsesfunksjon i PIC Microcontroller. La oss nå bruke den samme LED-blinkende sekvensen som vi har brukt i forrige opplæringsmaskinvare, og med dette vil vi lære hvordan du bruker timere i vår PIC MCU. Vi har nettopp lagt til en knapp til i LED-kortet for denne opplæringen. Gå gjennom veiledningen for å lære mer.
Timere er en av de viktigste arbeidshestene for en innebygd programmerer. Hver applikasjon vi designer, vil på en eller annen måte innebære en tidsapplikasjon, som å slå på eller AV noe etter et spesifisert tidsintervall. Ok, men hvorfor trenger vi timere når vi allerede har forsinkelsesmakroer (__delay_ms ()) som gjør det samme !!
Hvorfor timer når vi har forsinkelse ()?
En forsinkelsesmakro kalles en "dump" forsinkelse. Fordi under utførelsen av Delay-funksjonen sitter MCU dump ved å bare skape en forsinkelse. Under denne prosessen kan MCU ikke lytte til ADC-verdiene eller lese noe fra sine registre. Derfor er det ikke tilrådelig å bruke forsinkelsesfunksjoner bortsett fra applikasjoner som LED-blinking der tidsforsinkelsen ikke trenger å være nøyaktig eller lang.
Forsinkelsesmakroene har også følgende korte inntekter,
- Verdien av forsinkelse må være en konstant for forsinkelsesmakroer; det kan ikke endres under programutførelse. Derfor er det fortsatt programmørdefinert.
- Forsinkelsen vil ikke være nøyaktig sammenlignet med bruk av tidtakere.
- Større verdier av forsinkelser kan ikke opprettes ved hjelp av makroer, for eksempel kan en forsinkelse på en halv time ikke opprettes av forsinkelsesmakroer. Maksimal forsinkelse som kan brukes er basert på Crystal oscillator som brukes.
PIC-mikrocontroller-tidtakere:
Fysisk er tidtakeren et register hvis verdi kontinuerlig øker til 255, og deretter starter den på nytt: 0, 1, 2, 3, 4… 255…. 0, 1, 2, 3……etc.
Den PIC16F877A PIC MCU har tre Timer moduler. De er navnene Timer0, Timer1 og Timer2. Timer 0 og Timer 2 er 8-biters Timers og Timer 1 er en 16-biters Timer. I denne opplæringen bruker vi Timer 0 for applikasjonen vår. Når vi forstår Timer 0, vil det også være enkelt å jobbe med Timer 1 og Timer 2.
Timer0-modulens timer / teller har følgende funksjoner:
- 8-bit timer / teller
- Lesbar og skrivbar
- 8-bit programvare programmerbar prescaler
- Valg av intern eller ekstern klokke
- Avbryt ved overløp fra FFh til 00h
- Kantvalg for ekstern klokke
For å begynne å bruke en tidtaker, bør vi forstå noen av de fancy begrepene som 8-bit / 16-bit timer, Prescaler, Timer interrupts og Focs. La oss nå se hva hver enkelt virkelig betyr. Som sagt tidligere er det både 8-biters og 16-biters tidtakere i vår PIC MCU, den største forskjellen mellom dem er at 16-biters tidtakere har mye bedre oppløsning enn 8-biters tidtakere.
Prescaler er et navn på den delen av en mikrokontroller som deler oscillatorklokken før den når logikken som øker tidtakerstatusen. Omfanget av prescaler-ID er fra 1 til 256, og verdien til Prescaler kan stilles inn ved hjelp av OPTION Register (Den samme som vi brukte for å trekke opp motstander). For eksempel hvis verdien av preskalerer-er 64, og deretter for hver 64 th puls Timer vil bli inkrementert med en.
Når timeren øker, og når den når sin maksimale verdi på 255, vil den utløse et avbrudd og initialisere seg til 0 tilbake igjen. Dette avbruddet kalles for Timer Interrupt. Dette avbruddet informerer MCU om at denne tiden har gått.
Den Fosc står for frekvensen til oscillatoren, er det frekvensen av Crystal brukt. Tiden det tar for Timer-registeret, avhenger av verdien til Prescaler og verdien av Fosc.
Programmering og arbeidsforklaring:
I denne opplæringen vil vi sette to knapper som to innganger og 8 LED som 8 utganger. Den første knappen vil bli brukt til å stille tidsforsinkelsen (500 ms for hvert trykk), og den andre knappen vil bli brukt til å starte timersekvensen med å blinke. For eksempel, hvis den første knappen trykkes tre ganger (500 * 3 = 1500 ms) vil forsinkelsen bli satt til 1,5 sek., Og når du trykker på knappen to, vil hver LED slå seg på og av med den forhåndsdefinerte tidsforsinkelsen. Sjekk demonstrasjonsvideoen på slutten av denne veiledningen.
Nå, med disse grunnleggende tingene i bakhodet, la oss se på programmet vårt som er gitt på slutten i delen Kode.
Det er greit hvis du ikke fikk programmet, men hvis du fikk det !! Gi deg selv en informasjonskapsel og dump programmet for å glede deg over utdataene dine. For andre vil jeg dele programmet inn i meningsfylte deler og forklare deg hva som skjer i hver blokk.
Som alltid er de første linjene i koden konfigurasjonsinnstillinger og headerfiler, jeg kommer ikke til å forklare dette siden jeg allerede har gjort det i mine tidligere veiledninger.
La oss deretter hoppe over alle linjene og hoppe rett inn i den ugyldige hovedfunksjonen, der vi har PORT-konfigurasjonen for Timer0.
ugyldig hoved () {/ ***** Portkonfigurasjon for tidtaker ****** / OPTION_REG = 0b00000101; // Timer0 med ekstern freq og 64 som prescalar // Aktiverer også PULL UPs TMR0 = 100; // Last inn tidsverdien for 0,0019968s; delayValue kan være mellom 0-256 bare TMR0IE = 1; // Aktiver tidsavbruddsbit i PIE1-registeret GIE = 1; // Aktiver Global Interrupt PEIE = 1; // Aktiver perifer interrupt / *********** ______ *********** /
For å forstå dette må vi se på OPTION Register i PIC databladet vårt.
Som diskutert i forrige opplæring, brukes bit 7 for å muliggjøre svak opptrekksmotstand for PORTB. Se på figuren ovenfor, bit 3 er laget 0 for å instruere MCU om at følgende prescaler som blir satt skal brukes til timeren og ikke til WatchDogTimer (WDT). Timer-modus velges ved å fjerne bit 5 T0CS
(OPTION_REG <5>)
Nå brukes bits2-0 til å stille inn prescaler-verdien for timeren. Som vist i tabellen ovenfor for å sette en prescaler-verdi på 64, må bitene settes til 101.
La oss deretter se på registrene som er tilknyttet Timer0
Timeren vil begynne å øke når den er innstilt og flyter over etter å ha nådd en verdi på 256, for å aktivere Timer-avbrudd i løpet av dette punktet, må registeret TMR0IE settes høyt. Siden Timer 0 i seg selv er en periferiutstyr, må vi aktivere Peripheral Interrupt ved å lage PEIE = 1. Endelig må vi aktivere Global Interrupt slik at MCU vil bli varslet om Interrupt under enhver operasjon. Dette gjøres ved å gjøre GIE = 1.
Forsinkelse = ((256-REG_val) * (Prescal * 4)) / Fosc
Ovenstående formel brukes til å beregne verdien av forsinkelse.
Hvor
REG_val = 100;
Prescal = 64
Fosc = 20000000
Dette ved beregning gir, Forsinkelse = 0,0019968s
Det neste linjesettet er å sette I / U-portene.
/ ***** Portkonfigurasjon for I / O ****** / TRISB0 = 1; // Instruer MCU at PORTB pin 0 brukes som inngang for knapp 1. TRISB1 = 1; // Instruer MCU at PORTB pin 1 brukes som inngang for knapp 1. TRISD = 0x00; // Instruer MCU at alle pinner på PORT D er utgang PORTD = 0x00; // Initialiser alle pinnene til 0 / *********** ______ *********** /
Dette er det samme som i vår forrige opplæring siden vi bruker samme maskinvare. Bortsett fra at vi har lagt til en annen knapp som input. Dette gjøres med linjen TRISB1 = 1.
Deretter har vi to uendelige mens vi har to kodeblokker. Den ene brukes til å få tidtakerinngangen fra brukeren, og den andre til å utføre forsinkelsessekvensen over lysdiodene. Jeg har forklart dem ved å bruke kommentarer mot hver linje.
mens (1) {count = 0; // Ikke kjør tidtakeren mens du er i hovedsløyfen // ******* Få tallforsinkelsen fra brukeren **** ////// if (RB0 == 0 && flagg == 0) // Når inngang gitt {get_scnds + = 1; // get_scnds = get_scnds + http: // Increment variable flag = 1; } if (RB0 == 1) // For å forhindre kontinuerlig inkrementeringsflagg = 0; / *********** ______ *********** /
En variabel kalt get_scnds økes hver gang brukeren trykker på knappen 1. Et flagg (programvaredefinert) -variabel brukes til å holde inkrementeringsprosessen til brukeren fjerner fingeren fra knappen.
// ******* Utfør sekvens med forsinkelse **** ////// mens (RB1 == 0) {PORTD = 0b00000001 <
Neste blokk kommer i gang hvis du trykker på knapp to. Siden brukeren allerede har definert den nødvendige tidsforsinkelsen ved hjelp av knapp 1, og den er lagret i variabelen get_scnds. Vi bruker en variabel kalt hscnd, denne variabelen styres av ISR (Interrupt service routine).
Den avbryte tjenesten rutine er en Interrupt som vil bli kalt hver gang Timer0 er overløp. La oss se hvordan den blir styrt av ISR i neste blokk, som om vi vil øke tidsforsinkelsen med et halvt sekund (0,5 sek.) På hvert knappetrykk, så må vi øke variabel hscnd for hvert halve sekund. Som vi har programmert timeren vår til overstrøm for hver 0,0019968s (~ 2ms), så å telle variabelen for et halvt sekund skal være 250 fordi 250 * 2ms = 0,5 sekund. Så når telling blir 250 (250 * 2ms = 0,5 sekund), betyr det at det har gått et halvt sekund, så vi øker hscnd med 1 og initialiserer tellingen til null.
ugyldig interrupt timer_isr () {if (TMR0IF == 1) // Timer-flagg har blitt utløst på grunn av timeroverløp {TMR0 = 100; // Last inn tidtakeren Verdi TMR0IF = 0; // Clear timer interrupt flag count ++; } if (count == 250) {hscnd + = 1; // hscnd vil økes for hvert halve sekundstall = 0; }}
Så vi bruker denne verdien og sammenligner den med vår hscnd og skifter vår LED basert på den brukerdefinerte tiden. Det ligner også veldig på den siste opplæringen.
Det er det vi har programmet vårt forstått og fungerer.
Kretsdiagram og Proteus-simulering:
Som vanlig kan vi verifisere utdataene ved hjelp av Proteus først, jeg har her koblet de skjematiske filene til Proteus.
Legg til en knapp på vårt forrige LED-kort, og maskinvaren vår er klar til bruk. Det skal se ut slik:
Etter at tilkoblingen er gjort, laster du opp koden og bekrefter utdataene. Hvis du har problemer, kan du bruke kommentarfeltet. Sjekk også videoen nedenfor for å forstå hele prosessen.