;***********************************************************************
****
;PZE4, die PersonalZeitErfassung, smatro, 08/1998
;***********************************************************************
****
;Pinbelegungen:
;PA0 39 = CE des LCD-Displays (2*16)
;PA1 38 = 1.Spalte Keyboard über R1k (1,4,7,*) & R/W Display
;PA2 37 = 2.Spalte Keyboard über R1k (2,5,8,0) & C/D Display
;PA3 36 = 3.Spalte Keyboard über R1k (3,6,9,#)
;PA4 35 = 1.Zeile Keyboard über Dio (1,2,3) & Display D4
;PA5 34 = 2.Zeile Keyboard über Dio (4,5,6) & Display D5
;PA6 33 = 3.Zeile Keyboard über Dio (7,8,9) & Display D6
;PA7 32 = 4.Zeile Keyboard über Dio (*,0,#) & Display D7
;PB0 01 = RST-Chipkarte (braun)
;PB1 02 = CLK-Chipkarte (orange)
;PB2 03 = I/O-Chipkarte (gelb)
;PB3 04 = VPP-Chipkarte (grün)
;PB4 05 = CS Flash
;PB5 06 = PRG
;PB6 07 = PRG + SO(Flash) + SI(Flash)
;PB7 08 = PRG + SCK(Flash)
;PD0 10 = RxD
;PD1 11 = TxD
;PD2 12 = LED & Taster
;PD3 13 = LED & Taster
;PD4 14 = LED & Taster
;PD5 15 =
;PD6 16 = LED (High=On), Piper über Elko
;PD7 17 = Eingang Highpulse der Funkuhr
.equ RS = 0x60 ;Start des RAM-Bereiches
.equ bit0 = 0x01 ;nötig für die Befehle SBR und CBR
.equ bit1 = 0x02 ;dies sind eigentlich versteckte
.equ bit2 = 0x04 ;ANDI und ORI-Befehle
.equ bit3 = 0x05
.equ bit4 = 0x10
.equ bit5 = 0x20
.equ bit6 = 0x40
.equ bit7 = 0x80
;Kommandos für die Datenübertragung über die ser. Schnittstelle
(Datentyp)
.equ DFLASH = 0b10000000 ;Achtung: in Bits 0-6 = Nr. des 4k-Blocks
.equ DSYS = 1
.equ DRAM = 121
.equ DEEPROM = 122
.equ DROM = 123
.equ ALLFL = 124
.equ ECHO = 127 ;Sende Datentyp zurück, der in den Daten st.
;***********************************************************************
****
;Daten, welche eigentlich im Eeprom liegen sollten
.equ selbst = 0x10 ;Eepr0x00, eigene Gerätenummer
.equ wohin = 0x01 ;Eepr0x01, zu welchem Gerät die Daten hin s.
;***********************************************************************
****
.include "8515def.inc"
;Reset- und Interruptvektortabelle:
rjmp reset ;Reset Handle
rjmp noint ;IRQ0 Handle
rjmp noint ;IRQ1 Handle
rjmp noint ;Tim1 Capture Handle
rjmp noint ;Tim1 compareA Handle
rjmp noint ;Tim1 compareB Handle
rjmp noint ;IRQ0 Handle
ti0: rjmp timer0int ;Tim0 overflow Handle
; rjmp noint ;Spi Handle
; rjmp noint ;Uart Rx complete Handle
; rjmp noint ;Udr empty Handle
; rjmp noint ;Uart Tx complete Handle
; rjmp noint ;Analog-Compare Handle
;************************** Registervariablen
********************************
.def stunde = r1
.def dcflagl = r2 ;Zaehler, wie lange Funkuhr/Lowpegel
.def dcflagh = r3 ;Zaehler, wie lange Funkuhr/Highpegel
.def dcfoldl = r4 ;Zaehler low, alte Sekunde
.def dcfoldh = r5 ;Zaehler high, alte Sekunde
.def parity = r6 ;Parityzwischenspeicher (Min, Stu, Rest)
.def int1 = r7
.def int2 = r8 ;Interrupt-Sicherungsregister
.def temp5 = r9
.def temp6 = r10
.def d32cnt = r11 ;32ms-Counter für die Datenübertragung
.def mshigh = r12 ;High-Byte des 32ms-Counter (1831 je Min)
.def temp1 = r16
.def temp2 = r17 ;temporaere Variablen für alle Zwecke
.def temp3 = r18
.def temp4 = r19
.def mslow = r20 ;msxxxx ist der Millisekundencounter
.def minute = r21
.def dcfsek = r22
.def flag1 = r23 ;flag1-Bits: für den Datentransfer, u.a.
;Register r24-r31 werden für 16-Bit-Operationen benutzt
;******************************* RAM-Adressen
*********************************
.equ dcfmin = 0x60
.equ dcfstu = 0x61
.equ dcftag = 0x62 ;DCF-Werte werden vom UP dcflook beschrieben
.equ dcfmon = 0x63
.equ dcfjahr = 0x64
.equ dcfwota = 0x65 ;Bits0-2 = Wochentag (1=Mo),
Bit7=Sommerzeitbit
.equ dcfchk = 0x66 ;Pruefsumme 2er aufeinanderfolgender Minuten
.equ tag = 0x67 ;Tag des Monats
.equ mon = 0x68 ;interne Uhr: Monat
.equ jahr = 0x69 ;Jahr
.equ wota = 0x6a ;0-2 = Wochentag, Bit7=1=Sommerz. 6=1=DCFsync.
.equ lastms = 0x6b ;Merker fürs's letzte mslow
.equ pipton = 0x6c ;Zaehler für die Tonausgabe
.equ lastkey = 0x6d ;Merker für gedr. Taste
.equ bufl = 0x6e
.equ bufh = 0x6f ;Stringadresse für die LCD-Laufschrift
.equ lcdunten= 0x70 ;Puffer fuer untere LCD-Zeile
.equ outputl = 0x80 ;Adresse (Low-Teil) zur Ausgabe
.equ outputh = 0x81 ;(Ausgabeadresse: seriell, LCD, Flash, RAM...)
.equ pageadr = 0x82 ;Flash-Pageadresse (*2, denn Bit0=Buffer-adr8)
.equ flbufadr= 0x84 ;Flash-Buffer-Adresse
.equ derrcnt = flbufadr+1 ;Errorcounter
.equ dptrl = derrcnt+1 ;2 Bytes Datenpointer (1=anwen,2=vonwem...)
.equ dptrh = dptrl+1
.equ dbytes = dptrh+1 ;Gesamtzahl der zu übertr. Bytes
.equ dpcrc = dbytes+2 ;Prüfsumme
.equ dtyp = dpcrc+2 ;Datentyp (Art der Daten des Transfers)
.equ dwohin = dtyp+1 ;Adresse, wo die Daten Hin sollen
.equ flblock = dwohin+1 ;Flash-Blocknr. (für ges. Flash aussenden)
.equ dbuf = flblock+1 ;Start des Daten-Buffers (128 Bytes)
.equ dbufend = dbuf+138 ;Header + 128 Datenbytes + CRC + Reserve
;***********************************************************************
*******
;****************** Datenübertragung über die ser. Schnittstelle
**************
;***********************************************************************
*******
;Das DÜ-Format: 0A 34 CDEF ...... 7788
;1. 0A: 1 Byte, Adr. des Gerätes, wohin die Sendung soll (FE=an alle)
;2. 34: 1 Byte, Adresse des Gerätes, von welcher die Sendung kommt
;3. CDEF: 2 Bytes, Zahl aller Bytes dieses Blockes (ab Daten bis
CRC-Ende)
;5. 99: 1 Byte, Typ der Daten(7=1=Flash, SYS=1, RAM=121, EEPROM=122)
;6. ....: die eigentlichen Daten (max 0x8000)
;X. 7788: Prüfsumme (2Bytes: an,von,Bytezahl und Daten)
;Die Bedeutung der Einzelbits des Flagregisters flag1:
;Bit0=1: TX-Betrieb ist zur Zeit aktiv!
;Bit1=1: RX-Betrieb aktiv!
;Bit2=1: min 32ms war Ruhe auf der Leitung, Empf./Sendung darf starten
;Bit7=1: dann Systemdaten automatisch alle x ms ausgegeben
;***********************************************************************
*******
due: sbrc flag1,0 ;skip, wenn TX-Daten nicht zu senden sind
rjmp dsend ;TX-Daten senden (nächstes Byte)
sbrc flag1,1
rjmp receiv ;wenn zur Zeit Empfang läuft
sbrc flag1,2
rjmp wzeit_ok ;Pflicht-Ruhezeit um, nach Zeichen sehen
;***********************************************************************
*******
;wir befinden uns noch in der Pflichtruhezeit:
sbis USR,7 ;Bit7=1: Zeichen im Buffer
rjmp nochar ;wenn kein Zeichen vorhanden
;innerhalb der Ruhezeit wurde 1 Byte empfangen (verbotener Weise)
in temp3,UDR ;Zeichen verwerfen
dinit2: rjmp dinit
;prüfen, ob Ruhezeit schon lange genug
nochar: mov temp1,d32cnt
cpi temp1,2 ;schon min 32ms (1-2*32) vorbei?
brcc de3 ;ja!
ret ;nein
de3: sbr flag1,bit2 ;Kennung, daß ab jetzt RX/TX erlaubt ist
ret
;***********************************************************************
*******
;Empfang: (min 1 Zeichen wurde schon empfangen)
receiv: mov temp1,d32cnt
cpi temp1,2 ;schon zu lange Pause?
brcc rec8 ;ja: nachsehen, ob Datensatz gültig
sbis USR,7 ;Bit7=1: Zeichen im Buffer
ret
in temp3,USR ;Fehlerbits 3 & 4
andi temp3,0x18
brne dinit2 ;Frame- oder Overloaderror
in temp3,UDR ;Zeichen laden
rec2: clr d32cnt ;32ms-Counter (TX/RX-Wartezaehler) = 0
rcall dpinc ;Datenpointer incrementieren
cpi r26,dbufend ;Datenpufferende schon überschritten?
breq dinit2 ;Fehler!!! (zu viele Bytes empfangen)
st x,temp3 ;und Daten im Buffer ablegen
ret
;***********************************************************************
*******
;längere Pause nach dem Datenempfang, Datenblock prüfen, zuerst, ob
;die im Block angeg. Datenlänge mit der eingelesenen übereinstimmt
rec8: ldd r26,y-RS+dptrl
ldd r27,y-RS+dptrh
ldd r30,y-RS+dbuf+3 ;Zahl der Bytes laden (Low-Wert)
ldd r31,y-RS+dbuf+2
sub r26,r30
sbc r27,r31
tst r27
brne dinit2 ;Fehler: falsche Berechn. Bytes zu Blockende
cpi r26,dbuf+3
dinit3: brne dinit2
;Prüfsumme testen (mitgeschickte mit ausgerechneter)
rcall dpinc
sbiw r26,2 ;Ptr zeigt jetzt auf's 1.Byte der CRC
ldi r30,low(dbuf)
ldi r31,high(dbuf) ;z=Bufferanfang
ldi temp1,0
ldi temp2,0
rec10: ld temp3,z+
add temp1,temp3
brcc rec11
inc temp2
rec11: cp r30,r26
brne rec10
cp r31,r27
brne rec10 ;noch nicht beim CRC-Pointer angelangt
ld temp3,x+
cp temp3,temp2 ;Vergleich eingeles. mit berechn. Pr.-summe
brne dinit2 ;High-Byte stimmt nicht!
ld temp3,x+
cp temp3,temp1
brne dinit2 ;Low-Byte stimmt nicht!
;hier Empfang der Bytes OK!, Prüfsumme und CRC waren in Ordnung
ldi temp1,0
std y-RS+flblock,temp1;erst evt. laufende allFlashausgabe stoppen
ldd temp1,y-RS+dbuf+1 ;der Absender ist auch die neue Adresse
std y-RS+dwohin,temp1
ldd temp1,y-RS+dbuf+4 ;Datentyp laden
cpi temp1,ECHO
brne rec20 ;war kein Echo-Befehl
ldd temp1,y-RS+dbuf+5 ;der Befehl, welcher vom Echo angefordert wur.
std y-RS+dtyp,temp1 ;nach Pflichtruhezeit diesen Befehl ausf.
rjmp recend
rec20: cpi temp1,ALLFL ;Befehl, alle Flash-4k-Blöcke senden?
brne rec30
rcall allflash
rjmp recend
rec30:
recend: rjmp dinit
;***********************************************************************
*******
;die Pflichtwarteezeit wurde eingehalten, nachschauen, ob 1.Zeichen da
ist,
;oder ein Block zu senden ist (in dtyp steht Wert >0)
wzeit_ok:
sbis USR,7 ;Bit7=1: Zeichen im Buffer
rjmp wz4 ;wenn kein Zeichen empfangen wurde
in temp3,USR ;Fehlerbits 3 & 4
andi temp3,0x18
brne dinit3 ;Frame- oder Overloaderror
in temp3,UDR ;1.Zeichen laden
ldi temp1,low(dbuf-1) ;Adresse des Datenpuffer (dann pre-inc)
std y-RS+dptrl,temp1
ldi temp1,high(dbuf-1);wo die Daten hin sollen
std y-RS+dptrh,temp1
cpi temp3,0xfe ;Code für Sendung an alle
breq adrok
cpi temp3,selbst ;Code für Sendung an mich
breq adrok
rjmp dinit ;1.Zeichen weder an alle(FE) noch an mich
;das 1.Z. wurde empfangen, und es stimmt sogar (0xfe oder meine Ge.-Nr)
adrok:
sbr flag1,bit1 ;Kennung, RX-Betrieb startet
rjmp rec2 ;und Z. normal abspeichern!
wz4: ;kein Zeichen im Buffer, aber in dtyp nachsehen ob Block zu senden
ist
ldd temp1,y-RS+dtyp
tst temp1 ;liegt schon 'ne Sendung an?
brne dsstart
ldd temp1,y-RS+flblock
tst temp1 ;flblock <> 0: Gesamtflashausgabe läuft
breq wz6 ;keine solche!
;Gesamtflash-Ausgabe (Nr. des 4k-Block steht in fblock)
bst d32cnt,4 ;Bit4 (16*32ms) lange Ruhezeit schon um?
brtc wz6 ;nein
dec temp1
std y-RS+flblock,temp1;beim nächsten Mal Block tiefer senden
ori temp1,128
std y-RS+dtyp,temp1
rjmp dsstart
wz6: bst flag1,7
brts asend ;wenn autom. Sys.-datenausgabe eingeschaltet
wzret: ret ;nein
;Zeit abgelaufen? (Vorbereitung für neuen System-Datensatz senden)
asend: in temp1,TCNT0 ;letzten Wert des 32ms-Counters laden
andi temp1,63 ;Zufallswert (0..63, 0..2sek)
add temp1,d32cnt
brcc wzret ;Wartezeit von 6-8 sek.
ldi temp1,DRAM ;Datentyp RAM-Ausgabe
std y-RS+dtyp,temp1
ldi temp1,0xfe ;Sendung immer an alle
std y-RS+dwohin,temp1
dsstart:
sbr flag1,bit0 ;Kennung, Datensendung starten
;***********************************************************************
*******
dsend: sbis USR,5 ;skip if bit 5 in USR is set (Tx ist frei)
ret ;Ende (Zeichen noch nicht ausgesendet)
clr d32cnt ;32ms-Counter (TX/RX-Wartezaehler) = 0
rcall dpinc ;Datenpointer+1
tst r27 ;schon >255?
brne ds8 ;ab 256 sowieso nur Daten
cpi r26,1 ;1.Byte (an wen)?
brne ds2
;noch vor Aussendung des 1.Bytes einige Initialisierungen
ldd temp3,y-RS+dtyp ;Datentyp laden
ldi r26,150+5 ;Anz. der zu übertr. Bytes (RAM)
ldi r27,0
cpi temp3,DRAM
breq ds3
ldi r26,5 ;Offset, denn 5Bytes Header + 2Bytes CRC
ldi r27,2 ;2*256=512 Bytes (Eepromgröße)
cpi temp3,DEEPROM
breq ds3
ldi r27,16 ;Flash: Blockgröße = 16 * 256 Bytes = 4096
ds3: rcall dbd4 ;Zahl der Bytes merken
ldd temp1,y-RS+dwohin ;wohin die Daten sollen (Adressat)
cpi temp1,255 ;Kennung, daß es die Default-Adresse sein soll
brne dsout
ldi temp1,wohin ;Default-Adresse
dsout: ldd r26,y-RS+dpcrc
ldd r27,y-RS+dpcrc+1
add r26,temp1
brcc dso2
inc r27
dso2: rcall crc2 ;und neue Prüfsumme merken
dso3: out UDR,temp1
ret
ds2: ldi temp1,selbst
cpi r26,2 ;2.Byte (selbst)?
breq dsout
ldd temp1,y-RS+dbytes+1
cpi r26,3 ;3.Byte (Bytezahl, Highwert)?
breq dsout
ldd temp1,y-RS+dbytes
cpi r26,4 ;4.Byte (Bytezahl, Lowwert)?
breq dsout
ldd temp1,y-RS+dtyp ;Datentyp (Befehl)
cpi r26,5 ;5.Byte (Typ)
brne ds8
rcall dbdec ;Bytezähler ab 5.Byte decr.
rjmp dsout
ds8: rcall holedatenbyte ;Daten ab dem 6.Byte
rcall dbdec ;Bytezähler decrementieren (ab 5.Byte)
tst r27 ;Highbyte noch >0?
brne dsout ;ja
cpi r26,2 ;letzten beiden Bytes (Checksumme)?
brcc dsout ;nein
ldd temp1,y-RS+dpcrc+1
cpi r26,1 ;vorletzte Byte (=Prüfsumme/High)?
breq dso3 ;ja, ohne Prüfsummenberechn. ausgeben
;vor dem Aussenden des letzten Bytes noch einiges initialisieren
ldd temp1,y-RS+dpcrc
ldi temp2,0
std y-RS+dtyp,temp2 ;Datentyp=0: keine ausstehende Datensendung
; ldi temp2,255
; std y-RS+dwohin,temp2 ;Kennung, daß nächste Sendung an Defaultadr.
rcall dinit
rjmp dso3 ;nach der Initialis. noch letzt. Z. ausgeben
;***********************************************************************
*******
;div. Utis für den seriellen Datenstrom (Initialisierungen u.s.w.)
dpinc: ;Datenstrom-Datenpointer 1 weiter
ldd r26,y-RS+dptrl
ldd r27,y-RS+dptrh
adiw r26,1 ;Zero gesetzt, wenn jetzt 0
dpi4: std y-RS+dptrl,r26
std y-RS+dptrh,r27
ret
;*****
dbdec: ;Datenstrom-Byte-Zähler -1
ldd r26,y-RS+dbytes
ldd r27,y-RS+dbytes+1
sbiw r26,1
dbd4: std y-RS+dbytes,r26
std y-RS+dbytes+1,r27
ret
;*****
dinit: clr d32cnt ;32ms-Counter = 0 (neue Wartezeit beginnt)
in r26,UDR ;Zeichen verwerfen
ldi r26,0
ldi r27,0
andi flag1,0b11111000 ;TX-Sendung fertig, Ruhezeit muß folgen
rcall dbd4 ;Byte-Zähler rücksetzen
rcall dpi4 ;Ptr auch (bei Sendestart beginnt's bei 1)
crc2: std y-RS+dpcrc,r26
std y-RS+dpcrc+1,r27
ret1: ret
;*********
;1 Datenbyte zum Senden holen, wahlweise vom (ext.)Flash, Ram oder
Eeprom
holedatenbyte:
ldi r30,low(0-6) ;5 Bytes Header weg (1.Datenbyte>z=0)
ldi r31,high(0-6)
add r30,r26
brcc hob2
inc r31
hob2: add r31,r27
;Z zeigt auf Byte-Nr. welches zu holen ist
ldd temp2,y-RS+dtyp
sbrc temp2,7 ;skip, wenn nicht Datentyp Flash (7=1)
rjmp flbyte ;wenn's ein Flash
ld temp1,z ;aus RAM-Zelle (z) Byte holen
cpi temp2,DRAM ;Datentyp RAM?
breq ret1
mov temp1,r30 ;bleibt noch Eeprom übrig:
mov temp2,r31 ;z zeigt auf Adresse im Eeprom
rjmp eeread
flbyte: ;Flashbyte nach temp1 laden (dtyp, Bits0-6 ist
Pageadresse*16,PA4-PA10)
rcall fl_ok ;noch busy?
brpl flbyte ;ja: weitert warten!
ldd temp1,y-RS+dtyp
mov temp4,temp1 ;PA4...PA10
swap temp4
andi temp4,0x07 ;UP verlangt in temp4 PA8-PA10
swap temp1
andi temp1,0xf0 ;denn unteren Bits schon in r31
add r31,temp1 ;OK: Falshadr. in z & temp4
rcall flbrd ;Flashbyteread
rjmp foend
;***********************************************************************
*******
;Timer 0 Interrupt wird alle 32,768ms aufgerufen (8Mhz-Quarz)
timer0int:
in int1,SREG
inc d32cnt ;32ms-Zaehler fuer Datenübertragung nötig
dec mslow ;ms-Zaehler - 1
brne t0end
dec mshigh
brpl t0end ;1831 gezaehlt, eine min ist um
ldi mslow,high(1831) ;1831: nur 1.792ms fehlen je Minute
mov mshigh,mslow ;(Mist: r0-r15 geht nicht mit ldi)
ldi mslow,low(1831) ;und wieder von vorn anfangen
inc minute
t01: cpi minute,60 ;Stunde voll?
brcs t0end
ldd minute,y-RS+wota
cbr minute,bit6 ;löschen (Zeit nicht mehr DCF-syncr.)
std y-RS+wota,minute
ldi minute,0 ;0te Min. und naechste Stunde
inc stunde ;Datumskorrektur außerhalb Int
t0end: sbis PIND,7 ;ueberspringe, wenn Funk(pind7) high
rjmp t02 ;wenn low-Pegel
and dcflagl,dcflagl ;alte High/Lowwerte schon abgesp.
breq t04
mov dcfoldl,dcflagl ;vorherige High-/Lowwerte merken
mov dcfoldh,dcflagh
clr dcflagh
t04: inc dcflagh ;diesen High-Pegel merken
clr dcflagl ;danach Lowpegelzaehler bei 0
rjmp t03
t02: inc dcflagl ;merken: Lowpegel an PORTD-7
t03: out SREG,int1
noint: reti
;***********************************************************************
*******
;****************** Hauptprogrammeinsprung nach Reset
*************************
;***********************************************************************
*******
str1: .db " smarti4 - die Zeiterfassung, smartronic 1998",255
.dw str1*2
reset:
ldi temp1,0xff ;Watchdog kommt nach 2 Sek
out WDTCR,temp1
ldi temp1,low(RAMEND)
out SPL,temp1 ;init Stack Pointer Low
ldi temp1,high(RAMEND)
out SPH,temp1 ;init Stack Pointer High
ldi r28,RS ;Pointer Y immer am RAM-Anfang
ldi r29,0
ldi temp1,51
out UBRR,temp1 ;9600 Baud
ldi temp1,0x18
out UCR,temp1 ;Rx/Tx enable
ldi temp1,0x20
out MCUCR,temp1 ;Sleep-Mode enabled
ldi temp1,0b00111111 ;SI=pull-up(PB5), PB4=Out (CS/Flash)
out PORTB,temp1
ldi temp1,0b11010000 ;7=SCK, 6=SO,SI, 4=CS (Flash)
out DDRB,temp1
ldi temp1,0b01011100 ;PD6=LED/Piper (1=Output)
out DDRD,temp1
ldi temp1,0b00000111 ;1=high (wenn DDRD=Input, dann pull-up)
out PORTD,temp1
ldi temp1,5
out TCCR0,temp1 ;T0: CLK/1024
ldi temp1,2
out TIMSK,temp1 ;T0: Int frei
ldi temp1,low(serout) ;Adresse für alle auszugebenden Zeichen
ldi temp2,high(serout)
std y+outputl-RS,temp1
std y+outputh-RS,temp2
sei ;set enable interrupt
rcall lcdinit ;LCD-Display erstmalig initalisieren
rcall pip
rcall kb ;Tastaturport initialisieren
rcall fl_ok
rcall hout
ldi temp1,low(str1*2) ;ganz wichtig: ROM-Adressen immer *2!!
std y-RS+bufl,temp1
ldi temp1,high(str1*2)
std y-RS+bufh,temp1
ldi flag1,128 ;Sysdaten automatisch senden!
rcall dinit
rcall lcducls
ldi temp2,0
std y-RS+dtyp,temp2
std y-RS+flblock,temp2
;************************** Programm-Hauptschleife
****************************
mainloop: ;zuerst die zeitkritischen Funktionen
wdr ;Watchdog ruecksetzen
rcall due ;Datentransfer (Byte für Byte) pruefen
in temp1,TCNT0 ;letzten Wert des 32ms-Counters laden
andi temp1,0xf0 ;jeden 16. Zaehlerstand ausfiltern (16*125us)
ldd temp2,y-RS+lastms
cp temp1,temp2
std y-RS+lastms,temp1
breq mainloop
;zeitunkritische Funktionen (Aufruf nur alle 2ms)
rcall kb ;Tastatur abfragen, Taste in lastkey ablegen
rcall kstring ;evt. Tastendr. im Buffer ablegen (lcdunten)
rcall befehl ;Buffer(lcdu) auf Befehl prüfen + evt. ausf.
rcall strout ;Laufschrift auf ob. Zeile ausgeben
rcall ton ;evt. Tonausgabe (Pegel umschalten)
rcall dcflook ;Funkuhr-High-Low-Impulse ansehen + abspei.
rcall uhr ;schauen, ob nach 23:59, dann Datum korr.
ldd temp1,y-RS+lastms ;ist alle 1000*256*125ns = 0
tst temp1
brne mainloop ;branch, wenn noch nicht 32768usek vorbei
;zeitunkritische Funktionen (Aufruf nur alle 32.7ms)
mov temp1,mslow ;Int-Counter laden (*33ms)
andi temp1,7 ;*33ms
brne mainloop ;noch nicht vorbei
;zeitunkritische Funktionen (Aufruf nur alle x * 33ms)
rcall laufschrift
mov temp1,mslow ;Int-Counter laden (*33ms)
andi temp1,31 ;*33ms
brne mainloop ;noch nicht vorbei
;zeitunkritische Funktionen (Aufruf nur alle 32 * 32.768ms = 1.048sek)
rjmp mainloop
;***********************************************************************
*******
;************************** allgemeine Routinen
*******************************
;***********************************************************************
*******
;Im Buffer (lcdunten) nachsehen, ob ein gültiger Befehl vom Keyboard
oder
;von der ser. Schnittstelle eingetroffen ist, diesen dann ausführen
befehl:
ldi r27,0
ldi r26,lcdunten+16 ;Ende des Buffer+1
ldi temp2,16
bf10: ld temp1,-x ;vom Bufferende her einlesen
cpi temp1,'#' ;denn Befehl erst gültig mit #-Bestätigung!
breq bf40 ;dann Befehl suchen und ausf.
cpi temp1,' '
brne bfret ;anders Z. als ' ' oder '#': erstmal Ende
dec temp2
brne bf10 ;wenn noch nicht alle 16Z. rückwärts
bfret: ret
;Am Ende der Eingabe stand ein #, jetzt suchen, ob diese Ziffernkette
exist.
bf40: ldi r30,low(beftab*2)
ldi r31,high(beftab*2)
bf42: mov temp2,r26
subi temp2,lcdunten-1
ldi r26,lcdunten ;Länge des String im Buffer
bf41: ld temp1,x+
lpm
; mov temp3,r0
; cpi temp3,'#'
; breq bfound ;Vergleich stimmt
cp temp1,r0 ;Vergleich Eingabe/ROM
brne bf44 ;ungleich: nexte Ziffernkette
cpi temp1,'#'
breq bfound ;Vergleich stimmt
ld temp3,z+ ;Pointer+1
dec temp2
brne bf41 ;noch nicht Ende der Z.-Kette
bf44: lpm
ld temp1,z+
mov temp3,r0
cpi temp3,'#'
brne bf44 ;# n. gefu.
ld temp1,z+
ld temp1,z+
lpm
mov temp3,r0
cpi temp3,0xff ;Endez. gefu?
breq bfend
rjmp bf42
bfound: ld temp1,z+
lpm
mov temp1,r0
ld temp2,z+
lpm
mov r31,r0
mov r30,temp1
rcall lcducls
ijmp
bfend: rjmp lcducls
;***********************************************************************
*******
;Befehlstabelle: gerade Anzahl von Ziffern + # (Ende immer mit #)
beftab: .db "99901#"
.dw sendflash
.db "99902#"
.dw serout
.db "99903#" ;den gesamten Flash-Inhalt senden
.dw allflash
.db "9990999#"
.dw clearflash
.dw 0xffff ;Endekennung
;*******************************
clearflash:
rjmp flclr
;*******************************
sendflash:
ldi temp1,128 ;Flash, 0ten 4k-Block senden
sf2: std y-RS+dtyp,temp1
ret
;*******************************
allflash: ;alle Flash-Blöcke (je 4k) senden (beim letzten anfangen)
rcall flhigh ;Flashgröße (D021: temp1=4=1024 Pages)
swap temp1 ;D021=64 Blöcke a 4096Bytes
std y-RS+flblock,temp1
ret
;***********************************************************************
*******
;Eeprom lesen (Adresse in temp1-low und temp2-high, Wertrückgabe in
tem1):
eer0: ldi temp2,0 ;Highadresse ja oft 0
eeread: sbic EECR,EEWE ;OK, wenn EEWE gelöscht
rjmp eeread ;sonst noch warten
out EEARH,temp2 ;output address (high)
out EEARL,temp1 ;output address (low)
sbi EECR,EERE ;set EEPROM Read strobe
in temp1,EEDR ;get data
ret
;***********************************************************************
*******
;Eingabepuffer loeschen (wird auch gleichzeitig in unterer Displayz.
angezeigt)
lcducls:
ldi r26,lcdunten
ldi r27,0
ldi temp2,32
ldi temp1,16
lu2: st x+,temp2 ;in die Speicherstelle ein Leerz.
dec temp1
brne lu2
ret
;***********************************************************************
*******
;kurzen Pip ausgeben!
pip: ldi temp1,50 ;Zahl der Halbwellen
ldi temp3,64
pi2: ldi r25,2 ;2*128us (500ns * 256)
pi3: sbiw r24,1
brne pi3 ;je Schleife 4*125ns=500ns (8Mhz)
in temp2,PORTD
eor temp2,temp3
out PORTD,temp2 ;Piper umschalten
dec temp1
brne pi2
ret
;***********************************************************************
*******
;Tonausgabe per Hauptprogrammschleife (jeweils einmal Pegel umschalten)
ton: ldd temp1,y-RS+pipton
tst temp1
breq tret ;keine Tonausgabe
dec temp1
std y-RS+pipton,temp1
in temp1,PORTD
andi temp1,0xbf ;alles ausser Bit 6
sbis PORTD,6 ;Bit schon high?
ori temp1,0x40 ;ansonsten einschalten
out PORTD,temp1
tret: ret
;***********************************************************************
*******
;UP gibt Zeichen in temp1 aus (Pointer in outputl/h)
output: ldd r30,y-RS+outputl
ldd r31,y-RS+outputh
ijmp ;springe nach z (=r30/r31, =(outputl/h) )
;***********************************************************************
*******
;UP gibt Zeichen in temp1 auf ser. Schnittstelle aus
serout:
sbis USR,5 ;skip if bit 5 in USR is set
rjmp serout ;sonst weiter warten, ob Tx frei
out UDR,temp1
ret
;***********************************************************************
*******
zout: ;UP gibt Zahl (in temp1) aus
ldi temp2,255
subi temp1,256-10
zo2: inc temp2
subi temp1,10
cpi temp1,10
brcc zo2
push temp1
mov temp1,temp2
subi temp1,256-48
rcall output ;Ausgabe auf dem akt. Ausgabepfad
pop temp1
subi temp1,256-48
rjmp output
;***********************************************************************
*******
;UP gibt Hex-Zahl (in temp1) auf der ser. Schnittstelle aus
hout: mov temp2,temp1
swap temp2
rcall ho2
mov temp2,temp1
ho2: andi temp2,0x0f
cpi temp2,10
brcs ho3
subi temp2,256-7 ;ab 10 +7 (a..f)
ho3: subi temp2,256-48
push temp1
mov temp1,temp2
rcall output ;Ausgabe auf dem akt. Ausgabepfad
pop temp1
ret
;***********************************************************************
*******
;Uhr wird bis 23.59 vom Timer0-Int bearbeitet. Hier erfolgt evt.
Datumseinst.
uhr: mov temp1,stunde
cpi temp1,24
brcc u2
ret
;Mitternacht vorbei, Datum korrigieren!
u2: ldi r30,low(dcfmin)
ldi r31,high(dcfmin) ;Z-Register beinhaltet Variblenadresse
ldd temp1,z+wota-dcfmin
mov temp2,temp1
andi temp1,0b10111000 ;DCF-Sync-Kennung abschalten
inc temp2
andi temp2,0x07 ;Wochentag 1(Mo)...7(So)
breq u3
ldi temp2,1 ;beim Montag wieder anfangen!
u3: or temp2,temp1
std z+wota-dcfmin,temp1
ldd temp2,z+mon-dcfmin ;Monat nach temp2
ldd temp1,z+tag-dcfmin ;Tag laden (temp1)
inc temp1 ;naechster Tag
cpi temp2,8 ;August oder spaeter?
brcs u4
dec temp2 ;nun hat 1.Monat 31, jeder 2. 30 Tage
u4: ldi temp3,31
sbrc temp2,0
ldi temp3,32 ;verbotene Tageszahl für unger. Monate
cpi temp2,2 ;Februar?
brne u6
ldi temp3,29
u6: cp temp1,temp3 ;verbotene Tageszahl erreicht?
brcs u11 ;kein neuer Monat
ldi temp1,1 ;erster Tag im neuen Monat
ldd temp3,z+mon-dcfmin ;Monat nach temp3
ldd temp4,z+jahr-dcfmin ;Jahr nach temp4
inc temp3 ;naechster Monat
cpi temp3,13
brcs u9
ldi temp3,1 ;1.Monat im neuen Jahr
inc temp4
cpi temp4,100
brcs u9 ;Jahr 100 noch nicht erreicht
subi temp4,100
u9: std z+mon-dcfmin,temp3
std z+jahr-dcfmin,temp4
u11: std z+tag-dcfmin,temp1
ret
;***********************************************************************
******
.include "keyb34.asm"
.include "dcf.asm"
.include "lcd2_16.asm"
.include "spi.asm"
;***********************************************************************
******
.exit
;Buffertransfer
ldi r26,low(dbuf+1)
ldi r27,high(dbuf+1)
ldi r30,low(lcdunten)
ldi r31,high(lcdunten)
ldi temp1,16
rec99: ld temp2,x+
cpi temp2,32
brcc rec98
ldi temp2,'?'
rec98: st z+,temp2
dec temp1
brne rec99