; ******************************************************************************* ; *** Max7219 Displaytreiber-Ansteuerung ; *** Beispielprogramm zur Anzeige einer laufenden Uhrzeit ; *** mit Stunden, Minuten, Sekunden und hunderstel Sekunden ; ******************************************************************************* ;Quarzfrequenz: 24 MHz ;Prozessordefinition: INCLUDE 89c2051.mc ; Benutzte Portleitungen: Max_Clock EQU P1.1 Max_ChipSelect EQU P1.2 Max_DataIn EQU P1.3 ;Verwendete Speicheradressen: Max_Adresse EQU 20h Max_Daten EQU 21h Stunde EQU 22h Minute EQU 23h Sekunde EQU 24h Hundertstel_Sek EQU 25h Merker EQU 26h ;******************************************************************************* LJMP Initialisierung ;Überspringe Interruptroutine nach einem Reset ;******************************************************************************* Echtzeit-Realisierung: ; Der Timer 0 zählt nach dem Starten immer bis zum Überlauf hoch und löst mit ; dem Überlaufen einen Interrupt aus. Mit Auslösen des Interrupt's springt der ; Programmzähler auf die Adresse (000Bh). ; Der Wert des Timer's wird mit jedem Maschinentakt (1/12 Oszillatortakt) ; um einen erhöht. Um eine Zeitbasis von 10 mS zu errreichen, wird der Timer ; auf den Wert B1E0h voreingestellt. Bis zum Überlauf müssen nun 10000h-B1E0h ; = 4E20h = 20000 Maschinentakte erfolgen. Da bei einer Oszillatorfrequenz ; von 24 MHz der Maschinentakt 0.5 uS lang ist, beträgt die Zeit bis ; zum Überlauf die gewünschten 10mS = 1 hundertstel Sekunde. ; Da die Einsprungzeit eines Interrupts aber zwischen 3 und 8 Maschinentakte ; liegen kann, muss die bereits vergangene Zeit zur Voreinstellung addiert ; werden. Der Timer zählt auch nach dem Auslösen eines Interrupts einfach ; weiter, daher steht die seit der Interruptauslösung vergangene Zeit im ; Timer Low Byte. Zusätzlich werden noch 3 Takte für die Abarbeitung von ; MOV A,TL0 / ADD A,#E3h / MOV TL0,A addiert: (000Bh): ;Einsprungadresse Interrupt Timer 0 ;Realisierung der 10mS Echtzeit: MOV A,TL0 ADD A,#E3h ;A = TL0 = Zeit seit Überlauf + Grundeinstellung E0 + 3) MOV TL0,A MOV TH0,#B1h ;Grundeinstellung Timer 0 High Byte ;Hochzählen der Hundertstel Sekunden: INC Hundertstel_Sek ;100 * 10 mS um: Hundertstel_Sek löschen, Sekunden hochzählen IF Hundertstel_Sek = #100 THEN MOV Hundertstel_Sek,#0 INC Sekunde ;60 Sekunden um: Sekunden löschen, Minuten hochzählen IF Sekunde = #60 THEN MOV Sekunde,#0 INC Minute ;60 Minuten um: Minuten löschen, Stunden hochzählen IF Minute = #60 THEN MOV Minute,#0 INC Stunde ;24 Stunden um: Stunden löschen IF Stunde = #24 THEN MOV Stunde,#0 END IF END IF END IF LCALL Aktualisiere_Zeitanzeige ;Zurück aus der Interruptbehandlung ins Programm: RETI ;******************************************************************************* Initialisierung: ;Uhrzeit auf "00:00:00" setzen: MOV Hundertstel_Sek,#0 MOV Sekunde,#0 MOV Stunde,#0 MOV Minute,#0 ;Grundeinstellung des Timer 0 und des dazugehörigen Interrupts: MOV TMOD,#01h ;Timer 0 Modus = 1 MOV TH0,#B1h ;High Byte vom Timer 0 setzen MOV TL0,#E3h ;Low Byte vom Timer 0 setzen SETB EA ;Interruptbehandlung aktivieren SETB ET0 ;Interrupt für Timer 0 aktivieren SETB TR0 ;Timer 0 Start ;Initialisierung des Max7219: LCALL Max_DISP_INIT LCALL Max_DISP_CLEAR LJMP Hauptprogramm ;******************************************************************************* Hauptprogramm: ;Endlosschleife... LJMP Hauptprogramm ;************************************************ Aktualisiere_Zeitanzeige: ;Datenpointer auf das Datenfeld mit den Display Zahlen des MAX7219 setzen: MOV DPTR,#Max_Disp_Zahlen ;R0 auf die Adresse (nicht den Wert!) des Stundenspeichers setzen. ;Der Begriff "Stunde" wurde als 22h definiert - > R0 = 22h: MOV R0,#Stunde FOR Max_Adresse = #1 to #8 ;Max_Adresse hochzählen MOV A,@R0 ;Zahl in Zehnerstelle (B) und Einerstelle (A) zerlegen: MOV B,#255 CLR C Zehnerstelle: SUBB A,#10 INC B JNC Zehnerstelle ADD A,#10 ;Kurz die Einerstelle merken, da die Zehnerstelle zuerst gebraucht wird: MOV Merker, A ;Zehnerstelle ausgeben: MOV A,B MOVC A,@A+DPTR MOV Max_Daten, A LCALL Max_DISP_OUT ;Anweisung an den Max7219 senden ;Einerstelle ausgeben: INC Max_Adresse MOV A,Merker MOVC A,@A+DPTR SETB Acc.7 ;Trennpunkt setzen: 00.00.00.00. MOV Max_Daten, A LCALL Max_DISP_OUT ;Anweisung an den Max7219 senden ;R0 auf die nächste Adresse (Stunde - > Minute - > Sekunde - > Int.z.) setzen INC R0 NEXT RET ; ********************************************************************** ; *** Unterprogramm MAX_DISP_INIT ; ********************************************************************** ; *** Der Baustein Max7219 hat insgesamt 14 Register: ; *** Adr.: 00: NOP (No Operation) ; *** 01-08: Digits 1-8 ; *** 09: Dekodier-Modus (00h = 00000000 = keine Dekodierung ; *** 01h = 00000001 = Dekodierung Dig0 ; *** 02h = 00000010 = Dekodierung Dig1 ; *** .. = ........ = Dekodierung .... ; *** FFh = 11111111 = Dekodierung Dig0-7) ; *** ; *** 0A: Helligkeit der Anzeige (00 = dunkel bis 0F = hell) ; *** 0B: Anzahl der verwendeten Digits ; *** 0C: Operation (1 = Normalbetrieb, 0 = Shutdown) ; *** 0F: Selbst Test (0 = Normalbetrieb, 1 = Display Test) ; *** genauere Beschreibung siehe Datenblatt! ; ********************************************************************** Max_DISP_INIT: MOV Max_Adresse,#0Bh ;Adresse 0Bh = Scan Limit MOV Max_Daten,#07h ;Scan Limit = 8 Digits LCALL Max_DISP_OUT ;Anweisung an den Max7219 senden MOV Max_Adresse,#09h ;Adresse 09h = Dekodiermodus MOV Max_Daten,#00h ;Dekodiermodus = 00h = > keine Digits dekodieren LCALL Max_DISP_OUT ;Anweisung an den Max7219 senden MOV Max_Adresse,#0Ah ;Adresse 0Ah = Helligkeit MOV Max_Daten,#0Fh ;Helligkeit = 0Fh = > größte Helligkeit LCALL Max_DISP_OUT ;Anweisung an den Max7219 senden MOV Max_Adresse,#0Ch ;Adresse 0Ch = Operationsmodus MOV Max_Daten,#01h ;Operationsmodus = 01h = > Normalbetrieb LCALL Max_DISP_OUT ;Anweisung an den Max7219 senden RET ; ********************************************************************** ; *** Unterprogramm LED_clr ; ********************************************************************** ; *** Jedes Digit wird definiert zurückgesetzt (blank) ; ********************************************************************** Max_DISP_CLEAR: FOR Max_Adresse = #1 to #8 ;Digit 1-8 ansprechen MOV Max_Daten,#0Fh ;0Fh = Alle Segmente aus, blank LCALL Max_DISP_OUT ;Ausgabe an die Anzeige NEXT Max_Daten RET ; ********************************************************************** ; *** Unterprogramm Max_DISP_OUT ; ********************************************************************** ; *** Adresse und Befehl werden seriell ausgegeben ; ********************************************************************** Max_DISP_OUT: CLR Max_ChipSelect ;active LOW ! ;HighByte (Adresse) ausgeben: MOV A,#10000000b MOV R2,A ;Bit 0 - 7 der Max_Adresse in den MAX7219 schieben: FOR R3 = #0 to #7 ANL A,Max_Adresse ;Adressbit an den MAX7219 legen: IF A = #0 THEN CLR Max_DataIn ELSE SETB Max_DataIn END IF ;Bit in den MAX7219 schieben: SETB Max_Clock CLR Max_Clock ;Vergleichsbit durchrotieren MOV A,R2 RR A MOV R2,A NEXT R3 ;LowByte (Daten) ausgeben: MOV A,#10000000b MOV R2,A ;Bit 0 - 7 der Max_Daten in den MAX7219 schieben: FOR R3 = #0 to #7 ANL A,Max_Daten ;Datenbit an den MAX7219 legen: IF A = #0 THEN CLR Max_DataIn ELSE SETB Max_DataIn END IF ;Bit in den MAX7219 schieben: SETB Max_Clock CLR Max_Clock ;Vergleichsbit durchrotieren MOV A,R2 RR A MOV R2,A NEXT R3 SETB Max_ChipSelect ;Übertragung der Adresse/Daten beendet RET MAX_Disp_Zahlen: DB 01111110b, 00110000b, 01101101b, 01111001b, 00110011b DB 01011011b, 01011111b, 01110000b, 01111111b, 01111011b