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.