wtorek, 31 stycznia 2017

Timery


W mikrokontrolerach PIC (PIC24/ds33) mamy trzy typy Timerów : A, B, C
Wszystkie Timery są standardowo 16 bitowe (PIC24/ds33). Jest możliwość połączenia dwóch Timerów z grupy B lub C i stworzyć jeden timer 32 bitowy .
• Typ A timer (Timer1)
• Typ B timer (Timer2, Timer4, Timer6 and Timer8), określane jako Timerx
• Typ C timer (Timer3, Timer5, Timer7 and Timer9), określane jako Timery


Cechą charakterystyczną Typu A jest możliwość podpięcia oscylatora zegarkowego typu 32 kHz i wtedy timer typu A tyka nam jak zegarek mu zagra :) Drugą cechą wyróżniającą typ A jest tryb licznika asynchronicznego (Asynchronous Counter mode). Co oznacza , że timer zlicza nam tak jak mu będzie taktowało zewnętrzne źródło i w tym trybie nie ma synchronizacji zegarem systemowym
Cechą charakterystyczną dla typu B i C jest możliwość łączenia timerów z tych grup jako timery 32 bitowe.
Cechą charakterystyczną typu C jest współpraca z modułem ADC.

To tyle ogólnie o typach timerów a teraz pokrótce o trybach pracy timerów :

Timer mode
Najbardziej popularny tryb , którego będziemy najczęściej używać , na obrazku poniżej mamy sposób ustawienia Timera1 (typ A) i przebiegi czasowe zdarzeń . Wykres w zasadzie wszystko tłumaczy a kod pokazuje w jakich rejestrach trzeba grzebać i na jakich bitach.:



Gated Timer mode
W trybie Gated timer (bramkowany timer) jest wyzwalany zboczem narastającym sygnału zewnetrznego podanego na nóżkę TnCK. Timer zlicza w takt zegara wewnętrznego dopóki trwa poziom wysoki sygnału zewnętrznego. Przerwanie jest generowane przy każdym zboczu opadającym sygnału zewnętrznego. Timer ten przyda się w pomiarach czasu trwania jakiegoś procesu.
W praktyce możemy z tego trybu skorzystać np. jeśli chcemy zmierzyć czas nasłonecznienia za jakiś okres czasu.
I wym przypadku pismo obrazkowe najlepiej tłumaczy o co biega :




Synchronous Counter mode
W tym trybie pracy , każde narastające zbocze sygnału zewnętrznego (niezależne od zegara systemowego) jest zliczane . Przy czym cała ta operacja jest synchronizowana przez zegar systemowy . Przerwanie generuje przepełnienie rejestru TMRx (0-65535) lub ustawiona wartość w rejestrze PRx.
Możemy sobie zarzyczyć np. aby po zliczeniu 1000 narastających zbócz :) sygnału zewnętrznego wygenerowało nam się przerwanie i taki przykład serwuje nam nota katalogowa ale przebiegów już zabrakło :) :


 
Asynchronous Counter mode (Type A timer only)
Ten tryb zarezerwowany jest tylko dla timera typu A. Zliczany jest każdy narastający sygnał z zewnętrznego źródła (niezależne od zegara systemowego) ale w tym przypadku brak synchronizacji zegarem systemowym. Daje to różne ciekawe możliwości m.in. podpinamy kwarc zegarkowy 32 kHz i po zliczeniu 32767 zbócz narastających generujemy przerwanie co daje nam przerwanie co 1 sekundę. Poniżej stosowny przykład z noty katalogowej :

Podsumowaniem artykułu niech będzie użycie Timera w praktyce czyli zamigajmy ponownie diodą LED. W artykule http://strefapic.blogspot.com/2017/01/pierwsze-mruganie-led-artyku-w-budowie.html zmusiliśmy diodę LED do migania za pomocą brzydkich delay-ów. Spróbujmy tym razem w miejsce delay-ów zastosować programowy timer dla którego podstawę czasu 100 ms będzie generował Timer1 (typ A). Za jednym zamachem poznamy jak się używa timery sprzętowe i programowe. Efektem działania programu jest miganie diody LED co 1 sekundę. Timer1 ustawiono tak aby zgłaszał przerwanie co 100 ms a Timer Programowy umożliwi nam zmianę stanu diody LED po odliczeniu 10 przerwań Timera1.
Timer Programowy jest tutaj pomocnikiem , który umożliwia dowolne wydłużanie podstawy timera sprzętowego. Taki zabieg wynika z tego, że 16-bitowy timer sprzętowy da nam maksymalnie ciut ponad 400 ms czyli trochę brakuje do 1 s. Gdyby zastosować timer 32 bitowy a taka możliwość jest !!!! w naszym PIC24 to hulaj dusza, ograniczenie od góry to ok 27 tys sekund (ok 7.5 h)!!!!.Czyli timer 32 bitowy można ustawić tak aby przerwanie generować nawet co ok 7.5 h jak dla mnie mocna właściwość.


Pozdrawiam
picmajster.blog@gmail.com


Link :
http://ww1.microchip.com/downloads/en/DeviceDoc/70244B.pdf


  1 #include "xc.h" /* wykrywa rodzaj procka i includuje odpowiedni plik 
  2 nagłówkowy "p24HJ128GP502.h"*/
  3 #include <stdio.h>
  4 #include <stdlib.h>
  5 #include <stdint.h> /*dyrektywy do uint8_t itp*/
  6 #define FCY 40000000UL /* podajemy wartość ustawionego zegara (40 MHz), ważne 
  7 aby przed includowaniem <libpic30.h>, potrzebne to jest to wyliczania delay-i*/
  8 #include <libpic30.h> // biblioteka dająca dostęp do delay-i.
  9 
 10  /*
 11   * to co możemy ustawić za pomocą '#pragma' jest dostępne w pliku 
 12   * xc16/docs/config_index.html
 13   */
 14  #pragma config JTAGEN = OFF
 15  // Watchdog timer enable/disable by user software
 16  #pragma config FWDTEN = OFF 
 17   
 18  //********************Start Ustawień Zegara************************
 19  /* 
 20   * Fcy - zegar instrukcji , Fosc - zegar rdzenia (jest zawsze dwa razy wiekszy 
 21   * od zegara instrukcji)) Ustawiamy zegar instrukcji na 40 Mhz z wewnętrznego 
 22   * oscylatora Fin=7.37 MHz w/g wzoru Fcy=Fosc/2 gdzie Fosc=Fin x (M/(N1+N2))
 23   * gdzie M=43, N2=2, N1=2 ustawiane w rejestrach PLLFBD/PLLPOST/PLLPRE
 24   */
 25  //Select Internal FRC (Fast RC Oscillator)
 26  #pragma config FNOSC = FRC // FOSCSEL-->FNOSC=0b000 (Fast RC Oscillator (FRC))
 27  //Enable Clock Switching and Configure
 28  #pragma config FCKSM = CSECMD //FOSC-->FCKSM=0b01 - włącz zegar
 29  #pragma config OSCIOFNC = OFF //FOSC-->OSCIOFNC=1 - Fcy będzie na pinie OSCO
 30 
 31 /*Blok makra/definicje*/
 32 #define LED1_TOG PORTA ^= (1<<_PORTA_RA1_POSITION) /*zmienia stan bitu na przeciwny*/
 33 /*Koniec Bloku makra/definicje*/
 34 
 35 /*Blok deklaracje funkcji*/
 36 void InitTimer1(void); //deklaracja funkcji do inicjacji Timera1
 37 /*Koniec Bloku deklaracje funkcji*/
 38 
 39 /* Blok deklaracje/definicje zmiennych globalnych*/
 40     /*Timery Programowe*/
 41      volatile uint8_t Timer1_Programowy , Timer2_Programowy ;
 42 /*Koniec Bloku deklaracje/definicje zmiennych globalnych*/
 43 
 44  int main(void) { 
 45      
 46  /*Config PLL prescaler, PLL postscaler, PLL divisor*/
 47       PLLFBD = 41 ; //M=43 (0 bit to 2 stąd 41 = 43 patrz w rejestrze), tutaj 3.685 x 43 = 158.455MHz
 48       CLKDIVbits.PLLPRE=0 ;  //N1=2, tutaj 7.37 MHz / 2 = 3.685 MHz
 49       CLKDIVbits.PLLPOST=0 ; //N2=2, tutaj 158.455 MHz / 2 = 79.2275 MHz (Fosc)
 50    /*   
 51    * UWAGA przerwania muszą być wyłączone podczas wywoływania poniższych 
 52    * dwóch funkcji __builtin_write_...brak definicji w pliku nagłówkowym
 53    * to wewnętrzne funkcje kompilatora patrz help M-LAB IDE
 54    * i datasheet str 140(11.6.3.1 Control Register Lock)
 55    */
 56   /*Initiate Clock Switch to Internal FRC with PLL (OSCCON-->NOSC = 0b001)*/
 57       __builtin_write_OSCCONH(0x01); //tutaj argumentem jest wartość z NOSC
 58   /*Start clock switching*/
 59       __builtin_write_OSCCONL(0x01);
 60       
 61   /*Wait for Clock switch to occur*/
 62       while(OSCCONbits.COSC !=0b001);
 63       
 64       /*Wait for PLL to lock*/
 65       while(OSCCONbits.LOCK !=1) {};
 66   //**************************Koniec ustawień zegara***********************
 67    /*
 68     * wyłączamy ADC , wszystkie piny chcemy mieć cyfrowe
 69     * pojedyńczo piny analogowe wyłączamy w rejestrze AD1PCFGL 
 70     * Po resecie procka piny oznaczone ANx są w trybie analogowych wejść.
 71     */
 72       PMD1bits.AD1MD=1 ; //wyłączamy ADC
 73       /* 
 74        * ustawiamy wszystkie piny analogowe (oznacznone ANx) jako cyfrowe
 75        * do zmiany mamy piny AN0-AN5 i AN9-AN12 co daje hex na 16 bitach = 0x1E3F
 76        */
 77       AD1PCFGL = 0x1E3F ;
 78       
 79       TRISAbits.TRISA1 = 0 ; // RA1 jako wyjście
 80       
 81       InitTimer1(); /*wywołanie funkcji odpalającej Timer1, przerwanie co 100ms*/
 82       
 83       while(1)
 84       {
 85           /*Główna Pętla Programu*/
 86           if(!Timer1_Programowy) {
 87               Timer1_Programowy = 10 ; /*Timer1 sprzętowy x Timer1_Programowy = 100ms x 10 = 1 s*/
 88               LED1_TOG ; /*zmieniaj stan wyjścia na przeciwny*/
 89           }
 90                             
 91        }
 92           
 93       return 0;   
 94   }
 95 
 96 void InitTimer1(void){
 97     /*konfiguracja Timer1*/
 98     T1CONbits.TON = 0 ; /*Stop the timer1*/
 99     TMR1 = 0x0000 ;/*Clear timer register*/
100     /*Zegar ok 40 MHz Prescaler 1:64; PR1 Preload = 61897; Actual Interrupt Time = 100 ms*/
101     T1CONbits.TCKPS = 0b10 ; /*Prescaler 1:64*/
102    
103     /*konfiguracja przerwań*/
104     IFS0bits.T1IF        = 0; /*Clear Timer1 Interrupt Flag*/
105     IEC0bits.T1IE        = 1; /*Enable Timer1 Interrupt*/
106     
107     /*ustaw priorytet dla przerwania*/
108     IPC0bits.T1IP = 0b100 ; /*Set Timer1 Interrupt Prioryty Level 4*/
109 
110 /*TMR1 zlicza do wartości ustawionej w PR1 jeśli TMR1=PR1 zgłaszane jest przerwanie*/
111 /*40MHz / Prescaler / PR1 = ok 10 Hz (100ms)*/    
112     PR1          = 61897; /*Load period value*/
113     T1CONbits.TON = 1 ; /*Start the timer1*/    
114 }
115 
116 /*Obsługa wektora przerwania dla Timer1*/
117 void __attribute__((interrupt, no_auto_psv))_T1Interrupt()
118 {
119 /*kod użytkownika do obsługi przerwania*/
120     uint8_t x;
121     x = Timer1_Programowy ;
122     if (x) Timer1_Programowy = --x ;
123     x = Timer2_Programowy ;
124     if (x) Timer2_Programowy = --x ;
125 
126     /* Clear Timer1 interrupt */
127 IFS0bits.T1IF = 0 ; /*Clear Timer1 Interrupt Flag*/
128 }

Brak komentarzy:

Prześlij komentarz