mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Programmierbeispiele


Autor: Gregi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Ralf Künstler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
;*********************************************************************** 
****
;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

Autor: Stefan Gemmel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.