Prosty Timer na 8051
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.
