Odliczanie od zadanego czasu wykorzystując przerwania Timera    strona główna:
A po co ten Excel ;-)
 
    Kontynuuję naukę i przyszła pora na następny program. Jego zadaniem będzie odliczanie czasu do Alarmu. Taki Czasomierz z możliwością  
określenia czasu począkowego: przyciski S1 określenie minut, S2 - sekund, i odliczanie co 1s do zera po kliknięciu na S3.  
    Mała dygresja... :-)  
Nie traktujcie moich kodów dot. mikrokontrolerów za optymalne bo na pewno wiele im będzie brakowało.. Nie zamieszczam czegoś czego nie   
sprawdziłem. Program działa zgodnie z przeznaczeniem ale nie jestem teraz na etapie konsultowania optymalności kodu z kimkolwiek.. Na razie  
muszę zgłębić temat na własną rękę. Popróbować. Zobaczyć jakie mozliwości daje ta zabawka :-) A że kiedyś się będę śmiał z tych kodów to   
prawie pewne.. Mimo wszystko zamieszczam swoje wypociny. Fakt że TO DZIAŁA daje mi wielką satysfakcję :-)  
 
'----------------------------------------------------------  
'      Program odlicza od zadanego czasu w dół co 1s  
'               tkuchta1          2012-06-28  
'                  EvB4.3v4  AtMega32 16Mh  
'  
'Przyciski:  
'  - S1 - programowanie minut  
'  - S2 - programowanie sekund  
'  - S3 - start odliczania lub reset  
'  - S4 - określa kierunek zmiany S1 i S2  
 
' Wykorzystano:  
'  - PortC - wyświetlacz LCD 16*2  
'  - PortB - przyciski S1-S4  
'  - TIMER0  
'  
'----------------------------------------------------------  
 
'$sim  
$RegFile = "m32def.dat"  
$Crystal = 16000000  
 
Config Lcd = 16 * 2  
Config Lcdpin = Pin , Db4 = Portc.5 , Db5 = Portc.4 , Db6 = Portc.3 , Db7 = Portc.2 , E = Portc.6 , Rs = Portc.7  
Cursor Off  
 
Config PinB.0 = Input : Set PORTB.0  
Config PinB.1 = Input : Set PORTB.1  
Config PinB.2 = Input : Set PORTB.2  
Config PinB.3 = Input : Set PORTB.3  
 
Config TIMER1 = Timer , Prescale = 256  
Enable Interrupts  
 
Dim m as byte : m = 0  
Dim s As byte : s = 0  
Dim sM AS String * 2 , sS As String * 2  
Dim edit AS bit : edit = 0  
Dim incr_decr AS Bit : incr_decr = 0  
Dim Info AS String * 2  
Dim start_stop As bit : start_stop = 0  
Dim i as Byte , ii as Byte  
 
Cls  
LCD "Gotowy!!"  
 
Do  
 
   'start / stop pod S3  
   If PinB.2 = 0 Then  
      Toggle start_stop  
      edit = 1  
 
      If start_stop = 0 then  
         Stop TIMER1  
         s = 0 : m = 0  
      Else  
         If s > 0 or m > 0 Then  
            Enable TIMER1  
            On timer1 Odmierz_1s  
            Load TIMER1 = 62500  
            Start Timer1  
         end If  
      end If  
 
      Do : Loop until PinB.2 = 1  
   end If  
 
 
   If start_stop = 0 then  
 
      'zniana wartości minut pod S1  
      If PinB.0 = 0 Then  
         edit = 1  
         If incr_decr = 0 Then  
            If m < 60 Then incr m Else m = 0  
         else  
            If m > 0 Then decr m Else m = 59  
         end If  
 
         Do : Loop until PinB.0 = 1  
      end If  
 
      'zmiana wartości sekund pod S2  
      If PinB.1 = 0 Then  
         edit = 1  
         If incr_decr = 0 Then  
            If s < 60 Then incr s Else s = 0  
         else  
            If s > 0 Then decr s Else s = 59  
         end If  
 
         Do : Loop until PinB.1 = 1  
      end If  
 
      ' zniana Incr / Decr pod S4  
      If PinB.3 = 0 Then  
         edit = 1  
         Toggle incr_decr  
 
         Do : Loop until PinB.3 = 1  
      end If  
 
   end If  
 
   ' jeżeli nastapiła zmiana s, m, lub info to wyświetl  
   ' bieżacą informację na LCD  
 
   If edit = 1 then  
      sM = STR(m)  
      sS = STR(s)  
 
      CLS  
      Locate 1 , 1 : LCD Format(sM , "00") ; ":" ; Format(sS , "00")  
 
      If start_stop = 0 then  
         If incr_decr = 0 then Info = "In" else Info = "De"  
         Locate 2 , 1 : LCD "Kierunek: " ; Info ; "cr"  
      Else  
         Locate 2 , 1 : LCD "...Leci..."  
      end If  
 
      edit = 0  
   end If  
 
Loop  
 
end  
 
Odmierz_1s:  
 
   Load timer1 = 62500  
 
   edit = 1  
 
   If s > 0 then  
      Decr s  
   Else  
      If m > 0 then  
         Decr m  
         s = 59  
      end IF  
   End IF  
   If s = 0 and m = 0 then  
      Stop TIMER1  
      start_stop = 0  
 
      CLS  
 
      For i = 1 to 6  
         ii = i mod 2  
         If ii = 0 Then  
            LCD "Alarm!!!"  
         Else  
            CLS  
         End If  
 
         Waitms 500  
      Next  
 
   end If  
 
Return  
 
 
No to jak to działa... :-)  
 
Config Lcd = 16 * 2  
Config Lcdpin = Pin , Db4 = Portc.5 , Db5 = Portc.4 , Db6 = Portc.3 , Db7 = Portc.2 , E = Portc.6 , Rs = Portc.7  
 
Wyjściem będzie wyświetlacz LCD.   
 
Config PinB.0 = Input : Set PORTB.0  
Config PinB.1 = Input : Set PORTB.1  
Config PinB.2 = Input : Set PORTB.2  
Config PinB.3 = Input : Set PORTB.3  
 
Wejściami będą przyciski S1 - S4 (te przyciski wykorzystuję do obsługi programu)  
 
Config TIMER1 = Timer , Prescale = 256  
Enable Interrupts  
 
Konfiguruję TIMER1 jako Timer a taktowanie zegara dzielę preskalerem na 256. Kwarc w mikrokontrolerze to 16MHz dzieląc na 256 otrzymuję   
62500. Jak załaduję do Timer'a właśnie 62500 to dojdzie do przepełnienia właśnie co 1s.  
 
Dim m as byte : m = 0  
Dim s As byte : s = 0  
Dim sM AS String * 2 , sS As String * 2  
 
Zmienna m to ilość minut, s ilość sekund. sM i sS to tekstowe reprezentacje ilości minut i sekund. Po co mi to? Tu Funkcja Format nie przyjmuje  
liczby a tekst do zformatowania nie napiszę więc Format(s,"00") a Format(Str(s),"00") jest już dla BasCom'a zbyt skmplikowane :-|   
Denerwujące nie? :-P Niby prosta linijka a podczas kompilacji wyrzuca błąd i dość chwilę musiałem na to patrzeć żeby złapać że po prostu nie   
można tu zagnieżdżać funkcji. :-)  
 
Dim edit AS bit : edit = 0  
 
Po co mi to? Program leci w nieskończonej pętli. Najpierw sprawdza czy któryś z przycisków zostałkliknięty następnie wyświetla na LCD pewne  
informacje. Jednak odświeżenie ekranu nie powinno się odbywać za każdym "kółkiem" pętli. Na LCD trzeba zaktualizować dane jeżeli dojdzie  
do jakiejś zmiany. W przeciwnym razie ekran denerwująco murga - odświeżając dane. Ta zmienna pomaga mi w odświeżaniu ekranu tylko jak   
zajdzie taka potrzeba. A więc jak kliknę jakiś przycisk lub dojdzie do przepełnienia Timer'a to edit = 1, odświeżę LCD i edit = 0 :-)  
 
Dim incr_decr AS Bit : incr_decr = 0  
 
Wymysliłem sobie że podczas ustawiania czasu do odliczania chciałbym decydować o kierunku zmiany minut lub sekund. Domyślenie (0) jest to  
inkrementacja (m = m + 1) jednak jak mi się kliknie za dużo... No właśnie :-) Klikam na S4 i zmieniam kierunek.. Ta zmienna będzie właśnie   
decydowac czy inkrementować (0) lub dekrementować (1) ilość minut /sekund po kliknięciu na S1/S2  
 
Dim start_stop As bit : start_stop = 0  
 
Ta zmienna będzie "blokowała" przyciski S1,S2 i S4 na czas odliczania czasu. Uznałem że nie ma sensu zmieniać ilości minut/sekund lub  
kierunku zmiany podczas odliczania czasu. Jeżeli chciałbym zatrzymać odliczanie przed alarmem to, tym samym przyciskiem (S3) którym  
rozpocząłem odliczanie mogę też to odliczanie przerwać.  
 
Omawianie oprogramowania przycisków zacznę do S1 choć w programie zaczynam od S3  
 
      'zniana wartości minut pod S1  
      If PinB.0 = 0 Then  
         edit = 1  
         If incr_decr = 0 Then  
            If m < 60 Then incr m Else m = 0  
         else  
            If m > 0 Then decr m Else m = 59  
         end If  
 
         Do : Loop until PinB.0 = 1  
      end If  
 
Po kliknięciu na S1 (PinB.0): zaznaczam że dokonano zmiany która będzie musiała zostać pokazana na LCD i w zależności od wartości zmiennej  
incr_decr zwiększam/zmniejszam wartosć zmiennej m (ilość minut). Pętelka na końcu czeka aż użytkownik zwolni klawisz. (Ps: czytam o czymś  
co nie będzie wymagało takich pętli ale ... Pamalutku :-) to na razie działa)  
 
Obsługa S2 jest analogiczna.  
 
Obsługa S4:  
 
      If PinB.3 = 0 Then  
         edit = 1  
         Toggle incr_decr  
 
         Do : Loop until PinB.3 = 1  
      end If  
 
przełącznik zmiennej incr_decr.  
 
Do tej pory omówione przyciski działają ...  
 
   If start_stop = 0 then  
 
Pozostaje jeszcze S3 - włącznik odliczania lub przerwanie i reset.  
 
   If PinB.2 = 0 Then  
      Toggle start_stop  
      edit = 1  
 
      If start_stop = 0 then  
         Stop TIMER1  
         s = 0 : m = 0  
      Else  
         If s > 0 or m > 0 Then  
            Enable TIMER1  
            On timer1 Odmierz_1s  
            Load TIMER1 = 62500  
            Start Timer1  
         end If  
      end If  
 
      Do : Loop until PinB.2 = 1  
   end If  
 
Po kliknięciu na ten przycisk, rzełączam zmienną start_stop. Jeżeli jest ona = 0 (a więc licznik działa, chcę przerwać odliczanie) to Zatrzymuję  
TIMER1 i zeruję zmienne m i s. Jeżeli chciałbym dopiero rozpocząć odliczanie: Okreslam że program obsługi przerwania (to co bezdzie się miało  
wykonać po przerwaniu) zaczyna się od etykiety: Odmierz_1s. Do Timer1 zapisuję liczbe 62500 z która będzie odliczana i Startuję Timer.  
 
Odmierz_1s:  
 
   Load timer1 = 62500  
 
   edit = 1  
 
   If s > 0 then  
      Decr s  
   Else  
      If m > 0 then  
         Decr m  
         s = 59  
      end IF  
   End IF  
   If s = 0 and m = 0 then  
      Stop TIMER1  
      start_stop = 0  
 
      CLS  
 
      For i = 1 to 6  
         ii = i mod 2  
         If ii = 0 Then  
            LCD "Alarm!!!"  
         Else  
            CLS  
         End If  
 
         Waitms 500  
      Next  
 
   end If  
 
Return  
 
Program ten znajduje się po zakończeniu programu głównego. Ponownie ustawiam Timer na 62500 określając czas do następnego przerwania  
zaznaczam że zmiana ta będzie musiała być pokazana na LCD (edit = 1) odpowiednio zmniejszam wartość zmiennej s i/lub m. Jeżeli s i m są  
już = 0: Zatrzymuje Timer1, zmieniam wartość zmiennej start_stop = 0 (umożliwia działanie S1,S2,S4 do ponownego ustawienia czasu) i   
trzykrotne wyświetlenie tekstu Alarm!!! Przerwane Czyszczeniem Wyświetlacza na 0,5s co 0,5s.   
Pytanie czemu bawię się e przerwania Timera1 a nie wykorzystuję "Metody" Wait/Waitms? Odpowiedź - Przerwania są dokładniejsze. :-)