LED Clock R5: Software



Sourcecode rtc_igr_7seg.a51
Hexfile rtc_igr_7seg.hex




Quelltext:



;**********************************************************************
;rtc - Uhrenprogramm für 8051
;
;Funktionen:
;  - Auslesen und Schreiben einer RTC
;  - Stellen der Uhrzeit über einen Drehencoder
;  - Anzeigen der Zeit über eine 7-Segmentanzeige
;  - Weckfunktion
;  - Speichern der Weckzeit im internen EEprom
;
;
; Copyright (C) 2005  Thomas Elste 
;
; This program is free software; you can redistribute it and/or
; modify it under the terms of the GNU General Public License
; as published by the Free Software Foundation; either version 2
; of the License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
;
;**********************************************************************

;Definitionen
#cpu = 89S8252

;Makros
#def movb(x, y) {mov c, (y): mov (x), c}
#def mod(x,y){if a=#(x)h: mov a, #0h : end if:if a=#f9h: mov a, #(y)h : end if}
#def rinc {inc dptr : movx a, @dptr}
#def winc {inc dptr : movx @dptr, a : mov a, wmcon : loop while not bit acc.1 : mov a, wmcon : end loop}

;Konstanten
#const normal_address=71h
#const change_address=61h
#const dp_const=10
#const rtc_counter_const=100
#const wz_eeprom=001h, is_valid=aah

;I/O Mapping 
#bit rwr=p2.6, rrd=p2.5, adr=p2.7,
#bit dreh_l=p3.0, dreh_r=p3.1, dreh_tast=p3.2
#bit alarm_led=p3.7, buzzer=p3.5
#bit cs_h10=p0.3, cs_h1=p0.2, cs_m10=p0.1, cs_m1=p0.0


;Variablen
#byte mY10=7ch, 	SmY10=6ch
#byte mY1=7bh, 	SmY1=6bh
#byte mMo10=7ah, 	SmMo10=6ah
#byte mMo1=79h, 	SmMo1=69h
#byte mD10=78h,	SmD10=68h
#byte mD1=77h, 	SmD1=67h
#byte mW=76h, 	SmW=66h
#byte mH10=75h, 	SmH10=65h
#byte mH1=74h, 	SmH1=64h
#byte mMi10=73h, 	SmMi10=63h
#byte mMi1=72h, 	SmMi1=62h
#byte mS10=71h, 	SmS10=61h
#byte mS1=70h, 	SmS1=60h

#byte show_ptr
#byte dp_timer
#byte tmp, buzzer_counter, rtc_counter

#bit alt_0=2fh.7, alt_1=2fh.6, neu_0=2fh.5, neu_1=2fh.4
#bit is_hour=2fh.3, stellen=2fh.2
#bit dp_active, time_has_changed
#bit alarm_is_on, alarm_button_pressed, buzzer_is_on
#bit buzzer_skip

#byte WmH10, WmH1, WmMi10, WmMi1

ajmp Initialisierung

; Interruptvektoren
EXTI0:	; externer Interrupt 0
ajmp Externer Interrupt 0

Timer 0:	; Timer 0 Interrupt
ajmp Timer 0 Interrupt

EXTI1:	 ; externer Interrupt 1
ajmp Externer Interrupt 1

Timer 1:	; Timer 1 Interrupt
ajmp Timer 1 Interrupt


Initialisierung:

; Konfiguration
orl WMCON, # 18h	; Internes EEPROM zum Lesen
								; und zum Schreiben verwenden.
orl TMOD, # 11h  ; Timer0 und 1 sind 16-Bit Timer
mov th0, #0h
mov tl0, #0h
setb TR0	; Timer 0 läuft.
clr TR1
setb EX0	; externen Interrupt 1 freigeben
setb EX1
clr IT0
clr IT1
setb PX0	; Priorität für externen Interrupt 1
setb EA
setb ET0	; Timer 0 Interrupt freigeben
setb ET1

;Initialisierung der Variablen
mov show_ptr, #normal_address    ;normalen offset für die anzeige laden
mov dp_timer, #dp_const
mov rtc_counter, #rtc_counter_const
mov p1, #00h
setb neu_0 : setb neu_1 : setb alt_1 : setb alt_0
clr rwr : clr rrd : clr adr : clr stellen
clr cs_h10 : clr cs_h1 : clr cs_m10 : clr cs_m1
clr alarm_is_on :clr alarm_led : clr alarm_button_pressed
clr buzzer : clr buzzer_is_on

; Weckzeit aus dem EEprom lesen
mov dptr, #wz_eeprom
movx a, @dptr
if a=#is_valid
else
	mov a, #is_valid
	movx @dptr, a
	mov a, wmcon
	loop while not bit acc.1
		mov a, wmcon
	end loop
	mov a, #0
	winc
	mov a, #0
	winc	
	mov a, #6
	winc
	mov a, #0
	winc
	mov a, #0
	winc	
end if
lcall read_eeprom

; Speicherbereich für die Anzeige während des Stellens
; mit 0f initialisieren
for r0=#6
	mov a, #change_address
	add a, r0
	mov r1, a
	mov @r1, #0fh
next
		
; vorm Start die RTC  lesen
lcall read_rtc

;Hauptschleife
main:
	
	;RTC in festen Intervallen abfragen
	mov a, rtc_counter
	if a=#0
		lcall read_rtc
		mov a, #rtc_counter_const
	else
		dec a
	end if
	mov rtc_counter, a
	
	
	;for r0=#2h
	;	lcall warten
	;next
	
	; Display schreiben
	lcall write_display
	
	;for r0=#2h
		lcall warten
	;next	
	
	; Stellmodus aktiv
	if bit stellen
		clr tr0			;Doppelpkt Timer stopp
		clr dp_active	;Doppelpkt aus
		lcall sub_stellen
		setb ea
		clr stellen
		setb tr0
	end if
	
	; Alarm-Button wurde gedrückt	
	if bit alarm_button_pressed
		lcall sub_alarm_button
	end if
	
	; ist die Weckfunktion aktiviert muss die Zeit mit der
	; Weckzeit verglichen werden	
	if bit alarm_is_on
		lcall check_alarm
	end if
	
	; Timer1 aktiviert den Buzzer, wenn der Alarm ausgelöst
	;wurde	
	if bit buzzer_is_on
		setb tr1
	end if

jmp main


; aktuelle Uhrzeit in die RTC schreiben
write_rtc:
	; nur Stunden, Minuten und Sekunden	
	for r0=#6h
		mov a,#efh
		add a,r0
		anl a, #0fh
		mov p2,a		;anlegen der Adresse
		setb adr		;Adress latch enable
		clr adr			;Adress latch disable
		mov p2,#0fh	;bus clear
		mov a, #6fh
		add a, r0
		mov r1, a
		mov a, @r1
		anl a, #0fh
		mov p2, a		;daten anlegen
		setb rwr		;daten schreiben
		clr rwr			;wr löschen
	next
ret

; Uhrzeit aus der RTC lesen
read_rtc:
	for r0=#6h
		mov a,#efh
		add a,r0
		anl a, #0fh
		mov p2,a		;anlegen der Adresse
		setb adr		;Adress latch enable
		clr adr			;Adress latch disable
		mov a, #6fh
		add a, r0
		mov r1, a
		mov p2, #0fh	;bus clear	
		setb rrd		;read aktiv
		mov a, p2		;read
		clr rrd			;read clear
		mov @r1, a
	next
ret

; Uhrzeit auf dem Display Ausgeben
write_display:
	; für Muster für die 7-Segmentanzeige sind in einer
	; Tabelle abgelegt
	mov dptr, #7seg_tab
		
	mov a, show_ptr   ; Pointer für richtigen Bereich laden
	add a, #4
	mov r0, a
	mov a, @r0
	if a=#0fh	;bei 0f soll nichts verändert werden
	elseif a=#0dh ; auch bei 0d nicht (Weckzeiteinstellung)
	else 
		anl a, #03h
	end if
	movc a, @a+dptr
	acall add_dp
	mov p1, a
	setb cs_h10
	acall warten	
	clr cs_h10
		
	mov a, show_ptr
	add a, #3
	mov r0, a
	mov a, @r0
	anl a, #0fh
	movc a, @a+dptr
	acall add_dp
	mov p1, a
	setb cs_h1
	acall warten	
	clr cs_h1
		
	mov a, show_ptr
	add a, #2
	mov r0, a
	mov a, @r0
	anl a, #0fh
	movc a, @a+dptr
	acall add_dp
	mov p1, a
	setb cs_m10
	acall warten	
	clr cs_m10
		
	mov a, show_ptr
	add a, #1
	mov r0, a
	mov a, @r0
	anl a, #0fh
	movc a, @a+dptr
	acall add_dp
	mov p1, a
	setb cs_m1
	acall warten	
	clr cs_m1
ret

; vergleicht die Weckzeit mit der aktuellen Zeit
; und löst bei Übereinstimmung den Alarm aus
check_alarm:
	mov a, mH10
	anl a, #03h
	mov tmp, a
	mov a, WmH10
	anl a, #03h
	if a=tmp
		mov a, mH1
		anl a, #0fh
		mov tmp, a
		mov a, WmH1
		anl a, #0fh
		if a=tmp
			mov a, mMi10
			anl a, #0fh
			mov tmp, a
			mov a, WmMi10
			anl a, #0fh
			if a=tmp
				mov a, mMi1
				anl a, #0fh
				mov tmp, a
				mov a, WmMi1
				anl a, #0fh
				if a=tmp
					setb buzzer_is_on
					jmp out_check_alarm
				end if
			end if
		end if
	end if
	clr tr1
	clr buzzer_is_on
	clr buzzer
out_check_alarm:
ret

warten:
mov r6,#01h
for r6
	mov r7,#afh
	for r7
	next
next
ret

; wertet den Alarmbutton aus
sub_alarm_button:
	loop while not bit p3.3
	end loop
	
	;wenn der Buzzer an ist, abschalten	
	if bit buzzer_is_on
		clr tr1
		clr buzzer_is_on
		clr buzzer
;		jmp out_sub_alarm_button
	end if
	
	; Weckfunktion toggeln	
	if not bit alarm_is_on
		setb alarm_is_on
		setb alarm_led
	else
		clr alarm_is_on
		clr alarm_led
	end if
	
	; Alarmstatus sichern
	lcall save_astat
	
out_sub_alarm_button:
	clr alarm_button_pressed
reti

; Stellroutine
sub_stellen:	
	loop while not bit dreh_tast	;prellschutz
	end loop
	
	clr time_has_changed
	mov show_ptr, #change_address   ;zeiger für die anzeigeroutine
					;auf neuen Ram bereich setzen
	
	;stunden
	setb is_hour	;bit zeigt sonderbehandlung für stunden an
	mov r1, #mH10	
	mov r0, #mH1	
	lcall merge	
	mov r2, a
	loop while bit dreh_tast   ;solange taste nicht erneut
				   ;gedrückt wurde
	   mov a, r2
	   mod(24,23)	;unter und überlaufstest
	   mov r2, a		;rücksichern
	   			;(kann sich ja was geändert haben)
	   mov r1, #SmH10	
	   mov r0, #SmH1
	   lcall split		;in den ram schreiben
	   			;(extra bereich für stellroutine)
	   lcall write_display  ;anzeige sub aufrufen
	   lcall dreh_coder	;drehcoder sub aufrufen
	end loop
	loop while not bit dreh_tast	;prellschutz
	end loop
	mov a, r2
    mov r1, #mH10
	mov r0, #mH1
	lcall split		;in den eigentlichen RAM-Bereich
				;zurückschreiben
	mov SmH10, #0fh
	mov SmH1, #0fh
	clr is_hour		;stunden bit wieder löschen
	;stunden ende
	
	;minuten
	mov r1, #mMi10
	mov r0, #mMi1
	lcall merge
	mov r2, a
	loop while bit dreh_tast
		mov a, r2
		mod(60,59)
		mov r2, a
		mov r1, #SmMi10
		mov r0, #SmMi1
		lcall split
		lcall write_display
		lcall dreh_coder
	end loop
	loop  while not bit dreh_tast
	end loop
	mov a, r2
	mov r1, #mMi10
	mov r0, #mMi1
	lcall split
	mov SmMi10, #0fh
	mov SmMi1, #0fh
	;minuten ende
	
	; todo: checken ob überhaupt was verändert
	; nur dann in die RTC schreiben
	if bit time_has_changed
		mov mS10, #f0h
		mov mS1, #f0h
		lcall write_rtc  ;neuen werte in die rtc schreiben
	end if
	
	clr time_has_changed
	
	;Weckzeit stunden
	setb is_hour  ;bit zeigt sonderbehandlung für stunden an
	mov r1, #WmH10	
	mov r0, #WmH1
	; Anzeige der Weckzeitkennung	
	mov SmMi10, #0eh
	mov SmMi1, #0eh	
	lcall merge	
	mov r2, a
	loop while bit dreh_tast
	   mov a, r2
	   mod(24,23)
	   mov r2, a
	   mov r1, #SmH10	
	   mov r0, #SmH1
	   lcall split
	   lcall write_display
	   lcall dreh_coder
	end loop
	loop while not bit dreh_tast
	end loop
	mov a, r2
    mov r1, #WmH10
	mov r0, #WmH1
	lcall split
	mov SmH10, #0fh
	mov SmH1, #0fh
	clr is_hour
	;Weckzeit stunden ende

	;Weckzeit minuten
	mov r1, #WmMi10
	mov r0, #WmMi1
	mov SmH10, #0dh
	mov SMH1, #0dh
	lcall merge
	mov r2, a
	loop while bit dreh_tast
		mov a, r2
		mod(60,59)
		mov r2, a
		mov r1, #SmMi10
		mov r0, #SmMi1
		lcall split
		lcall write_display
		lcall dreh_coder
	end loop
	loop  while not bit dreh_tast
	end loop
	mov a, r2
	mov r1, #WmMi10
	mov r0, #WmMi1
	lcall split
	mov SmMi10, #0fh
	mov SmMi1, #0fh
	mov SmH10, #0fh
	mov SMH1, #0fh
	;minuten ende
	
	; wenn sich die Weckzeit geändert hat
	; dann in EEprom sichern	
	if bit time_has_changed
		lcall write_eeprom
	end if

	mov show_ptr, #normal_address ;zeiger für anzeige zurück setzen
	lcall warten	
ret

;splittet wert in a
;schreibt high nibble an addresse in r1
;schreibt low nibble an addresse in r0
split:
	mov r7, a
	orl a, #f0h
	mov @r0, a
	mov a, r7
	swap a
	orl a, #f0h
	if bit is_hour  ;sonderbehandlung stunden
		orl a, #f8h
		anl a, #fbh	
	end if
	mov @r1, a
	mov a, r7
ret

;holt werte von addressen in r1 und r0
;low nibble aus r1 wird high nibble in a
;low nibble aus r0 wird low nibble in a
merge:
	mov a, @r0
	anl a, #0fh
	mov r7, a
	mov a, @r1
	anl a, #0fh
	if bit is_hour ;sonderbehandlung stunden
		anl a, #03h
	end if	
	swap a
	add a, r7
ret

;fragt den drehencoder ab
;zu verändernder wert muss in r2 stehen
dreh_coder:
	movb(alt_0, neu_0)		;alten zustand sichern
	movb(alt_1, neu_1)

	movb(neu_0, dreh_l)		;neuen zustand vom port lesen
	movb(neu_1, dreh_r)

	dptr=#geber_tab		;datenpointer für wertetabelle holen
	mov a, #0h

	if bit alt_0	;alter zustand codiert bytenummer aus tabelle
		inc a
		inc a
	end if
	
	if bit alt_1
		inc a
	end if

	movc a, @a+dptr

	if bit neu_0	;erstes bit neuer zustand codiert halbbyte
		swap a
	end if

	if bit neu_1	;zweites bit neuer zustand codiert viertelbyte
		rr a
		rr a
	end if

	anl a, #03h
	
	if a=#01h		;1 -> wert erhöhen
		mov a, r2
		add a, #1h
		da a			;bcd korrektur
		mov r2, a
		mov a, #0h
		setb time_has_changed
	end if
	if a=#02h			;2 -> wert verringern
		mov a, r2
		dec a
		mov r2, a
		anl a, #0fh
		if a=#0fh		;bcd korrektur manuell
  			mov a, r2
	  		anl a, #f0h
  			orl a, #09h
		else
  			mov a, r2
		end if
		mov r2, a
		setb time_has_changed
	end if
ret

; fügt den Doppelpunktstatus zur Ausgabe hinzu
add_dp:
;	if bit dp_active
		orl a, #80h
;	end if
ret

;liest die Weckzeit aus dem internen EEprom
read_eeprom:
	mov dptr, #wz_eeprom
	rinc
	if bit acc.0
		setb alarm_is_on
		setb alarm_led
	end if
	rinc
	mov WmH10, a
	rinc
	mov WmH1, a
	rinc
	mov WmMi10, a
	rinc
	mov WmMi1, a
ret

; schreibt die Weckzeit in den internen EEprom
write_eeprom:
	mov dptr, #wz_eeprom
	inc dptr
	mov a, WmH10
	winc
	mov a, WmH1
	winc
	mov a, WmMi10
	winc
	mov a, WmMi1
	winc
ret

; schreibt den Alarmstatus in den internen EEprom
save_astat:
	mov dptr, #wz_eeprom
	if bit alarm_is_on
		mov a, #ffh
	else
		mov a, #0h
	end if
	winc
ret


Externer Interrupt 0:
	clr ea	
	setb stellen
reti

Externer Interrupt 1:
	clr ex1
	setb alarm_button_pressed
reti

; toggelt den Doppelpunktstatus
; reaktiviert den Alarmbutton
Timer 0 Interrupt:
	push acc
	mov a, dp_timer
	if a=#0
		setb ex1
		cpl dp_active
		mov a, #dp_const
	else
		dec a
	end if
	mov dp_timer, a	
	pop acc
reti

; genertiert den Weckton
Timer 1 Interrupt:
	push acc
	mov a, buzzer_counter
	if a=#0
		cpl buzzer_skip
		mov a, #ffh
	else
		dec a
	end if
	mov buzzer_counter, a
	if bit buzzer_skip
		cpl buzzer
	else
		clr buzzer
	end if
	mov th1, #feh
	mov tl1, #ffh
	pop acc
reti

; Hilfstabelle für den Drehgeber
geber_tab:
	db 24h, 0h, 0h, 18h 

; Muster für die 7-Segmentanzeige
7seg_tab:
db 3fh, 06h, 5bh, 4fh, 66h, 6dh, 7dh, 07h, 7fh, 6fh
db 00h, 00h, 00h, 4ch, 58h, 00h





LED Clock R5 Index