Hallo! Ich würde mich über Programmierbeispiele und -aufgaben im Assembler-Bereich erfreuen! Speziell Aufgaben mit Musterlösungen usw. würden meinen Fleiß noch mehr anspornen, um die µC's noch genauerer kennenzulerenen. Die Seite ist übringens wirklich super für Einsteiger! Gregi
;*********************************************************************** **** ;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
Hallo Ralf, das Programm find ich gut, könntest du auch die Include Dateien posten ? Mich interessiert das DCF77 da ich hierzu gerade was programmieren will. (siehe : "DCF77 Funkuhr für Atmel" in NG: DE.SCI.ELECTRONICS) Gruss Stefan
Beitrag #6130732 wurde von einem Moderator gelöscht.
Beitrag #6130735 wurde von einem Moderator gelöscht.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.