Prosty Timer na 8051

20141218_112548 (Medium)

Dawno już nie miałem okazji pisać czegokolwiek na 8051. Potrzeba zrodziła się przypadkowo  – kolega potrzebował  (na wczoraj) prosty sterownik, który coś tam ma wyłączać po odliczeniu zadanego czasu. Dokładność minutowa (czyli bez nadmiernego spalania się), zakres nastaw 0-20 minut, fajnie jakby miał wyświetlacz, obsługę krańcówki i przekaźnik na wyjściu, obudowa – niekoniecznie.

Aby ratować kolegę, przystąpiłem do działania i właściwie jeszcze tego samego dnia powstał prototyp. Prosty układ (do którego wykorzystałem gotową płytkę ze starych zapasów) i bardzo prymitywny, z technicznego punktu widzenia, software. Dlaczego prymitywny ? Bo profesjonalista zrobiłby to na przerwaniach Timer`a – ja poszedłem na łatwiznę i odliczanie czasu odbywa się w pętlach czasowych. Nie powiem, żebym nie próbował – chciałem zrobić to jak należy, ale czas gonił, sprzęcik w kosmos nie miał lecieć, a obsługa Timerów przysparzała mi nieoczekiwanych problemów/błędów.

Za pewne nie ma się czym chwalić, ale postanowiłem projekt opublikować. Jak zwykle przyświecał mi cel – może komuś się przyda … (jak nie w całości, to choćby fragmenty kodu).

Na początek PDF – 89C52 – który jest sercem układu.

Do kontrolera podłączone są 3 przyciski typu Switch (jeden na PCB i 2 zewnętrzne). Dane wyświetlane są na LCD 2×16 (magistrala 8-bit). Co istotne, to dobór opóźnienia (pętli), których wartości są uzależnione od zastosowanego taktującego rezonatora kwarcowego. Nie możecie traktować ich „na sztywno” – trzeba je dobrać eksperymentalnie.

Program wykorzystuje pierwszy bank rejestrów R, w których przechowuje stany poszczególnych pętli, służących odliczaniu czasu, nastawy i znaczniki. Nie pytajcie dlaczego -tak było mi najłatwiej.

Kolejna uwaga – wszystkie wykorzystywane procedury (obsługa LCD, pętle czasowe itp) to też moje, zapewne słabo zoptymalizowane, rozwiązania (np. : LCD – wyłącznie obsługa 8-bit, bez flagi zajętości). Jak macie swoje lepsze, lub znajdziecie w necie – spokojnie można je wdrożyć – użyłem to co miałem – pisane dawno i „na kolanie”.

;**********************************************************
; ATMEL 89C52
; KONTROLER - TIMER 0-20 minut
;**********************************************************

; PORT P0 WYSWIETLACZ LCD 2X16

E       EQU P2.7         ; ENABLED - LCD
RS      EQU P2.6         ; RS - LCD

GO      EQU P3.7         ; SWITCH START
PK      EQU P2.5         ; PORT - PRZEKAZNIK

PLUS    EQU P3.2         ; INT0 - SWITCH ZWIEKSZ CZAS
MINUS   EQU P3.3         ; INT1 - SWITCH ZMNIEJSZ CZAS

;********************************************************************

LJMP START               ; PRZESKOCZ DO ADRESU STARTU

ORG 03H                  ; ADRES OBSLUGI - PRZERWANIA OD INT0
PUSH PSW                 ; ZABEZPIECZ NA STOSIE REJESTR PSW
PUSH ACC                 ; ZABEZPIECZ NA STOSIE AKUMULATOR
AJMP PRZERWANIE_0        ; SKOCZ DO OBSLUGI PRZERWANIA INT0
                         ; NALEZY PAMIETAC O ZDJECIU ZE STOSU PRZY
                         ; WYJSCIU Z PROC. PRZERWANIA

ORG 13H                  ; ADRES OBSLUGI - PRZERWANIA OD INT1
PUSH PSW
PUSH ACC
AJMP PRZERWANIE_1

ORG 100H                 ; PRZESTAWIENIE ADRESU ABY NIE NAMIESZAC Z PRZERWANIAMI

START:
    MOV R0,#5            ; W R5 - WARTOSC NASTAWIONYCH MINUT
    MOV R1,#35           ; W R1 - ODLICZANIE CZASU - NAJSZYBSZA PETLA
    MOV R2,#1            ; W R2 - ODLICZANIE CZASU - SREDNIA PETLA
    MOV R3,#1            ; W R3 - TRZECIA PETLA ZLICZAJACA SEKUNDY
    MOV R4,#00H          ; W R4 - SLOWO KONTROLNE
                         ; ZNACZNIK START 00H - STOP, 01H START

    SETB EX0             ; ZEZWOLENIE NA PRZERWANIA OD EXTERNAL 0
    SETB EX1             ; ZEZWOLENIE NA PRZERWANIA OD EXTERNAL 1
    SETB EA              ; GLOBALNE ZEZWOLENIE NA PRZERWANIA

    LCALL SET_LCD        ; ZAINICJUJ LCD
    SETB E               ; ENABLED LCD

    MOV DPTR,#TXT_1      ; TXT - 1
    LCALL WR_TXT         ; WYPISZ

    MOV R6,#00H          ; LCD LINIA NIZEJ
    MOV R7,#01H
    LCALL POZ_CUR        ; USTAW KURSOR W DRUGIEJ LINII

    MOV DPTR,#TXT_2      ; TXT - 2
    LCALL WR_TXT         ; WYPISZ

; GLOWNA PETLA PROGRAMU ***********************************************

START_2:

    JB GO,DUPA           ; SPRAWDZ CZY SWITCH START WCISNIETY
    MOV R4,#01H          ; WCISNIETY - USTAW ZNACZNIK START W REJESTRZE
                         ; KONTROLNYM (NA 01)
    LCALL CLR_LCD        ; WYCZYSC LCD
    MOV DPTR,#TXT_5      ; WYPISZ - START
    LCALL WR_TXT

    LCALL WAIT_100       ; PAUZA - 100

    LCALL KONTROLA       ; WYWOLAJ PROCEDURE WYSWIETLENIA AKTUALNEGO
                         ; CZASU W 2 LINII LCD

DUPA:
    CJNE R4,#01H,DUPA_2  ; JESLI W R4 ZNACZNIK START (#01H) TO WYKONAJ PONIZEJ,
                         ; JESLI NIE IDZ DO DUPA_2
    CJNE R0,#00H,DUPA_3  ; SPRAWDZ CZY ODLICZANIE NIE ZESZLO DO 0 MINUT
                         ; JESLI TAK WYWOLAJ ZMODYFIKOWANA PROCEDURE ODLICZANIA
                         ; ODLICZANIE_S2, JESLI NIE IDZ DO DUPA_3 CZYLI
                         ; PODSTAWOWEJ PROCEDURY ODLICZANIA
    LCALL ODLICZANIE_S2
    LCALL KONTROLA       ; WYSWIETL CZAS
    SJMP DUPA_2          ; IDZ NA KONIEC I ZAMKNIJ PETLE

DUPA_3:
    LCALL ODLICZANIE_S   ; WYWOLAJ PODSTAWOWA PROCEDURE ODLICZANIA CZASU
    LCALL KONTROLA       ; WYSWIETLA CZAS

DUPA_2:
    LCALL WAIT_100       ; PAUZA
    LJMP START_2         ; ZAMKNIECIE PETLI - POWROT NA POCZATEK

;======================================================================

ODLICZANIE_S:            ; PODSTAWOWA PROCEDURA ODLICZANIA OPOZNIENIA
                         ; WYWOLANA DLA STANU MINUT > 0

    DJNZ R1,CZAS_01
    MOV R1,#35           ; MODYFIKACJA PETLI = CZAS
    DJNZ R2,CZAS_01
    MOV R2,#1            ; MODYFIKACJA PETLI = CZAS
    DJNZ R3,CZAS_01
    MOV R3,#59           ; R3 - LICZNIK SEKUND
    DJNZ R0,CZAS_01      ; DLA ZERO MINUT WYKONAJ PONIZEJ

CZAS_01:

    RET                  ; POWROT

ODLICZANIE_S2:           ; ZMODYFIKOWANA PROCEDURA - BEZ R0 (MINUT)
                         ; WYWOLANA TYLKO DLA 0 MINUT

    DJNZ R1,CZAS_02
    MOV R1,#35
    DJNZ R2,CZAS_02
    MOV R2,#1
    DJNZ R3,CZAS_02      ; R3 - LICZNIK SEKUND
                         ; JESLI=0 WYSWIETLA W 1 LINII NAPIS STOP

    MOV R6,#00H          ; POZYCJA KURSORA
    MOV R7,#00H          ; POZYCJA KURSORA
    LCALL POZ_CUR

    MOV DPTR,#TXT_6      ; "STOP"
    LCALL WR_TXT

    LCALL KONTROLA       ; W 2 LINII WYSWIETL CZAS (MA BYC 0.00)

    MOV R4,#00H          ; USTAW REJESTR KONTROLNY NA STOP
                         ; ZATRZYMAJ ODLICZANIE
    CPL PK               ; ZMIEN BIT NA KTORYM JEST PRZEKAZNIK
                         ; TU OCZYWISCIE POWINNO BYC SETB LUB CLR

CZAS_02:
    RET                  ; POWROT Z ODLICZANIE_S2

;************* OBSLUGA PRZERWAN **********************************

PRZERWANIE_0:

    MOV R4,#00H          ; PRZERWANIE INT0 - PO WYWOLANIU
                         ; USTAW STARTOWE STANY LICZNIKOW PETLI
    MOV R1,#35
    MOV R2,#1
    MOV R3,#1

    LCALL CLR_LCD
    MOV DPTR,#TXT_3
    LCALL WR_TXT

    MOV R7,#01H
    LCALL POZ_CUR

    CJNE R0,#01,PRZ_01   ; SPRAWDZ CZY ZNACZNIK MINUT - R0
                         ; OSIAGNAL WARTOSC 1
    SJMP PRZ_02          ; JESLI R0=1 PRZESKOCZ DEKREMENTACJE

    PRZ_01:
    DEC R0               ; DEKREMENTUJ R0 - LICZNIK MINUT

PRZ_02:
    MOV A,R0             ; WPISZ R0 DO ACC ABY WYSWIETLIC W DEC
    LCALL YAS            ; WYSWIETL W DEC

    LCALL WAIT_500       ; DLUGA PAUZA - ELIMINACJA WIELOKROTNEGO
                         ; WYWOLANIA INT0

    POP ACC              ; ZDEJMIJ ZE STOSU ACC
    POP PSW              ; ZDEJMIJ ZE STOSU PSW

    RETI                 ; POWROT Z OBSLUGI PRZERWANIA INT0

PRZERWANIE_1:

    MOV R4,#00H
    MOV R1,#35
    MOV R2,#1
    MOV R3,#1
    LCALL CLR_LCD
    MOV DPTR,#TXT_4
    LCALL WR_TXT
    MOV R7,#01H
    LCALL POZ_CUR
    CJNE R0,#20,PRZ_11    ; SPRAWDZ CZY ZNACZNIK MINUT OSIAGNAL WARTOSC
                          ; = 20, CZYLI ZALOZONA MAX WARTOSC

    SJMP PRZ_12

PRZ_11:
    INC R0                ; INKREMENTUJ R0

PRZ_12:
    MOV A,R0
    LCALL YAS
    LCALL WAIT_500
    POP ACC
    POP PSW
    RETI

;*****************************************************************************
;*****************************************************************************
;*****************************************************************************

KONTROLA:                           ; KONTROLNE WYSWIETLENIE NA LCD

   MOV R6,#00H                      ; USTAW KURSOR NA 0,1 (POCZATEK 2 LINII)
   MOV R7,#01H
   LCALL POZ_CUR
   MOV A,R0
   LCALL YAS
   MOV A,#00101110B                 ; KROPKA
   LCALL WR_DATA
   MOV A,R3
   LCALL YAS

   RET

;-----------------------------------------------------------------------
; PROCEDURA ZAMIANY 1 BAJT HEX < OD 64H NA 1 BAJT SPAKOWANE BCD
;-----------------------------------------------------------------------

HEX_BCD_64H:

   PUSH B
   MOV B,#10
   DIV AB
   SWAP A
   ADD A,B
   POP B
   RET

;----------------------------------------------------------------------
;PROCEDURA WYSWIETLAJACA ZAWARTOSC ACC NA 2 POZ. W HEX
;----------------------------------------------------------------------

YAS:

   PUSH ACC
   PUSH B
   LCALL HEX_BCD_64H
   PUSH ACC
   ANL A,#0F0H
   SWAP A
   ADD A,#30H
   LCALL WR_DATA
   POP ACC
   ANL A,#0FH
   ADD A,#30H
   LCALL WR_DATA
   POP B
   POP ACC
   RET

;----------------------------------------------------
; PROCEDURA WYPISUJACA TEXT NA LCD
; W DPTR ADRES TEXTU
;----------------------------------------------------

WR_TXT:

   PUSH ACC
   WR_SERV_1:
   CLR A
   MOVC A,@A+DPTR
   JZ WR_SERV_2
   LCALL WR_DATA
   INC DPTR
   SJMP WR_SERV_1
   WR_SERV_2:
   POP ACC
   RET

;---------------------------------------------------------------
; PROCEDURA CZYSZCZACA ZAWARTOSC LCD
;---------------------------------------------------------------

CLR_LCD:
    PUSH ACC
    MOV A,#00000001B
    LCALL WR_CRT
    POP ACC
    RET

;------------------------------------------------------------------------
; PROC. USTAWIAJACA POZYCJE KURSORA
;------------------------------------------------------------------------

; R6 WSPOLRZEDNA X (0-19) - JESLI LCD TO 2 X 20
; R7 WSPOLRZEDNA Y (0-1)

POZ_CUR:

    PUSH ACC
    CJNE R7,#00H,P_S_1
    MOV A,R6
    SETB ACC.7
    LCALL WR_CRT
    POP ACC
    RET
P_S_1:
    MOV A,R6
    ADD A,#40H
    SETB ACC.7
    LCALL WR_CRT
    POP ACC
    RET

;-------------------------------------------------------------------------
; ZAPIS ROZKAZU DO LCD
;-------------------------------------------------------------------------

WR_CRT:
    CLR RS
    LCALL WAIT_25
    MOV P0,A
    SETB E
    CLR E
    LCALL WAIT_25
    SETB E
    RET

;--------------------------------------------------------------------------
; ZAPIS DANEJ DO LCD
;--------------------------------------------------------------------------

WR_DATA:
    SETB RS
    SETB E
    MOV P0,A
    CLR E
    LCALL WAIT_25
    RET

;--------------------------------------------------------------------------
; INICJALIZACJA LCD - PODSTAWOWE USTAWIENIA ROZRUCHOWE LCD
;--------------------------------------------------------------------------

SET_LCD:

    MOV A,#00000001B
    LCALL WR_CRT

    MOV A,#00001100B
    LCALL WR_CRT

    MOV A,#00111000B
    LCALL WR_CRT

    MOV A,#00000110B
    LCALL WR_CRT

RET

;------------------------------------------------------------------------
; PROSTE PROCEDURY OPOZNIEN - ZWYKLE PETLE
;------------------------------------------------------------------------

WAIT_500:
    LCALL WAIT_100
    LCALL WAIT_100
    LCALL WAIT_100
    LCALL WAIT_100
    LCALL WAIT_100
    RET

WAIT_100:
    LCALL WAIT_25
    LCALL WAIT_25
    LCALL WAIT_25
    LCALL WAIT_25
    RET

WAIT_25:
    LCALL WAIT_05
    LCALL WAIT_05
    LCALL WAIT_05
    LCALL WAIT_05
    LCALL WAIT_05
    RET

WAIT_05:
    PUSH ACC
    PUSH B
    MOV B,#10
SSS:
    MOV A,#25
    DJNZ ACC,$
    DJNZ B,SSS
    POP B
    POP ACC
    RET

;************** TEXTY *******************************

TXT_1:
 DB "TIMER",0
TXT_2:
 DB "YAS 01.04.2015",0

TXT_3:
 DB "SWITCH - MINUS",0

TXT_4:
 DB "SWITCH - PLUS",0

TXT_5:
 DB "START",0

TXT_6:
 DB "STOP ",0

Ponieważ urządzenie powstało, ale nie zostało wdrożone i wykorzystane, nie było sensu dopieszczania software`u. Nie zaimplementowałem obsługi krańcówki, a i przekaźnik w tej edycji działa na zasadzie zmiany stanu bitu – CPL.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

1 + dziesięć =