Pfad: Home ==> AVR-DE ==> Anwendungen ==> Dünne-Berg-Uhr ==> Quellcode   This page in english: Flag EN Logo
Duenne-Berg-Uhr

Quellcode für die Dünne-Berg-Uhr


Quellcode im Assemblerformat hier.

;
; **********************************************
; * Binaere Uhr mit 20 LEDs und ATmega8A       *
; * Version 1, April 2017                      *
; * (C)2017 by http://www.avr-asm-tutorial.net *
; **********************************************
;
.NOLIST
.INCLUDE "m8Adef.inc" ; Headerdatei fuer ATMEGA8A
.LIST
;
; =====================================
;  A S S E M B L E R - S C H A L T E R
; =====================================
;
; Diese Assemblerschalter fuer normalen Ablauf = 0
.equ speed = 0 ; 0 = normal, 1 = Minuten testen, 2 = Stunden testen
.equ fast = 0 ; Schneller Ablauf fuer Debug (Prescaler=1)
;
; Dieser Schalter ist Geschmackssache, pbcd=1 ist schneller
.equ pbcd = 1 ; 1 = Uhrzeit in Packed BCD, 0 = Binaer
;
; ============================================
;   H A R D W A R E I N F O R M A T I O N E N 
; ============================================
;
; ATmega8A
;             ________________
;  ISP6+   1 /                |28
;  RESET o--|reset         PC5|--o StdZ2
;          2|                 |27
;  SekE1 o--|PD0           PC4|--o StdZ1
;          3|                 |26
;  SekE2 o--|PD1           PC3|--o StdE8
;          4|                 |25
;  SekE4 o--|PD2           PC2|--o StdE4
;          5|                 |24
;  SekE8 o--|PD3           PC1|--o StdE2
;          6|                 |23
;  SekZ1 o--|PD4           PC0|--o StdE1
;          7|                 |22
;   +5 V o--|vcc           gnd|--o NC
;          8|                 |21
;    0 V o--|gnd          AREF|--o NC
;          9|                 |20
;  Quarz o--|XTAL1        AVCC|--o NC
; 2,4576  10|                 |19
;   MHz  o--|XTAL2     PB5/SCK|--o MinZ4+ISP6-SCK
;         11|                 |18
;  SekZ2 o--|PD5      PB4/MISO|--o MinZ2+ISP6-MISO
;         12|                 |17
;  SekZ4 o--|PD6      PB3/MOSI|--o MinZ1+ISP6-MOSI
;         13|                 |16
;  MinE1 o--|PD7           PB2|--o MinE8
;         14|                 |15
;  MinE2 o--|PB0           PB1|--o MinE4
;           |_________________|
; 
;
; ================================================
; K O N S T A N T E N   Z U M  E I N S T E L L E N
; ================================================
;
.equ clock = 2457600 ; Taktfrequenz, externer Quarz
;
; =======================================================
;  F E S T E + A B G E L E I T E T E  K O N S T A N T E N 
; =======================================================
;
.if speed == 0 ; normale Geschwindigkeit
  .equ cPresc = 1024 ; Teiler fuer Timer 1
  .equ cCtc = clock/cPresc - 1 ; Teiler Timer 1
  .elif speed == 1 ; Minutentest
  .equ cPresc = 64
  .equ cCtc = clock/cPresc/60 - 1
  .else ; Stundentest
  .equ cPresc = 1
  .equ cCtc = (clock/cPresc+1800)/3600 - 1 
  .endif
;
; ============================================
;   R E G I S T E R D E F I N I T I O N E N
; ============================================
;
; frei: R0 bis R15
.def rmp1 = R16 ; Vielzweckregister 1
.def rmp2 = R17 ; Vielzweckregister 2
.def rSek = R18 ; Sekunden
.def rMin = R19 ; Minuten
.def rStd = R20 ; Stunden
.def rPD = R21  ; Portausgabe Register Port D 
.def rPB = R22  ; dto., Port B
.def rPC = R23  ; dto., Port C
; frei: R24 bis R31
;
; ============================================
;       S R A M   D E F I N I T I O N E N
; ============================================
;
.DSEG
.ORG  0X0060
; (SRAM nur fuer Interrupt und Call-Stack verwendet)
;
; ==============================================
;   R E S E T   U N D   I N T   V E K T O R E N
; ==============================================
;
.CSEG
.ORG $0000
	rjmp Main ; Reset-Vektor
	reti ; INT0
	reti ; INT1
	reti ; TC2COMP
	reti ; TC2OVF
	reti ; TC1CAPT
	rjmp SekInt ; TC1COMPA, Sekundeninterrupt
	reti ; TC1COMPB
	reti ; TC1OVF
	reti ; TC0OVF
	reti ; SPI_STC
	reti ; UART-RX
	reti ; UART-UDRE
	reti ; UART-TXC
	reti ; ADC
	reti ; EERDY
	reti ; ANACOMP
	reti ; TWI
	reti ; SPMRDY
;
; ==========================================
;    I N T E R R U P T   S E R V I C E
; ==========================================
;
; Sekunden-Interrupt
; Da keine anderen Interrupts und keine 
;   weiteren Ablaeufe zu bearbeiten sind,
;   erfolgt der gesamte Ablauf innerhalb
;   der Interrupt-Service-Routine
SekInt: ; Sekunden-Interrupt
	inc rSek ; naechste Sekunde
.if pbcd == 1
; Packed-BCD
	ldi rmp1,0x06 ; fuer Packed-BCD-Halbuebertrag
	add rSek,rmp1 ; Halbuebertrag?
	brhs SekInt1 ; Ja, teste Sekunden=60
	sub rSek,rmp1 ; kein Halbuebertrag, ziehe wieder ab
	rjmp SekInt4 ; fertig zur Ausgabe
SekInt1:
	cpi rSek,0x60 ; 60 Sekunden?
	brcs SekInt4 ; Nein, zur Ausgabe
	clr rSek ; Sekunden = 0
	inc rMin ; naechste Minute
	add rMin,rmp1 ; Halbuebertrag?
	brhs SekInt2 ; ja, teste 60 Minuten
	sub rMin,rmp1 ; Nein, wieder abziehen
	rjmp SekInt4 ; Zur Ausgabe
SekInt2:
	cpi rMin,0x60 ; 60 Minuten?
	brcs SekInt4 ; Nein, zur Ausgabe
	clr rMin ; Minuten = 0
	inc rStd ; naechste Stunde
	add rStd,rmp1 ; Halbuebertrag?
	brhs SekInt3 ; Ja, teste Stunden=24
	sub rStd,rmp1 ; nein, ziehe wieder ab
	rjmp SekInt4 ; zur Ausgabe
SekInt3:
	cpi rStd,0x24 ; 24 Stunden?
	brcs SekInt4 ; nein, zur Ausgabe
	clr rStd ; Stunden auf Null
SekInt4: ; Ausgabe vorbereiten
	mov rPC,rStd ; Port C sind die Stunden
	mov rPD,rSek ; Port D sind die Sekunden
	lsl rPD ; oberstes Bit herausrollen
	mov rPB,rMin ; Port B sind die Minuten
	lsr rPB ; unterstes Bit herausrollen
	ror rPD ; und in oberstes Bit Port D hinein
	com rPD ; Portbits umkehren wegen LED-Polaritaet
	com rPB
	andi rPB,0x3F ; oberste Bits maskieren
	com rPC
	andi rPB,0x3F ; oberste Bits maskieren
	; Ausgabe an Ports
	out PORTD,rPD
	out PORTB,rPB
	out PORTC,rPC
	reti ; fertig
	.else
	; Binaere Uhrzeit in drei Registern
	cpi rSek,60 ; 60 Sekunden?
	brcs SekInt1 ; nein, Ausgabe
	clr rSek ; ja, Sekunden auf Null
	inc rMin ; naechste Minute
	cpi rMin,60 ; 60 Minuten?
	brcs SekInt1 ; nein, Ausgabe
	clr rMin ; ja, Minuten auf Null
	inc rStd ; naechste Stunde
	cpi rStd,24 ; 24 Stunden?
	brcs SekInt1 ; nein, Ausgabe
	clr rStd ; ja, Stunden auf Null
SekInt1: ; Ausgabe vorbereiten
	mov rmp1,rSek ; Sekunden in Register
	rcall Div10 ; durch 10 dividieren
	mov rPD,rmp1 ; Zehnerrest in Portregister D
	swap rmp2 ; Zehner in oberes Nibble
	or rPD,rmp2 ; Oberes und unteres Nibble kombinieren
	; Minuten
	mov rmp1,rMin ; Minuten in Register
	rcall Div10 ; Division durch 10
	lsr rmp1 ; Einer rechts schieben
	brcc SekInt2 ; Kein Carry, Sekundenregister ok
	sbr rPD,0x80 ; setze oberstes Bit Sekundenregister
SekInt2:
	lsl rmp2 ; Schiebe Zehner drei Mal links
	lsl rmp2
	lsl rmp2
	or rmp1,rmp2 ; Kombiniere mit unteren Bits
	mov rPB,rmp1 ; und in Portregister B
	; Stunden
	mov rmp1,rStd ; Stunden in Register
	rcall Div10 ; Division durch 10
	swap rmp2 ; Zehner in oberes Nibble
	or rmp1,rmp2 ; oberes und unteres Nibble kombinieren
	mov rPC,rmp1 ; und in Portregister C
	; Invertieren vor der Ausgabe wegen LED-Polaritaet
	com rPD
	com rPB
	andi rPB,0x3F ; obere Bits ausblenden
	com rPC
	andi rPC,0x3F ; obere Bits ausblenden
	; Portregister auf Ports ausgeben
	out PORTD,rPD
	out PORTB,rPB
	out PORTC,rPC
	reti
;
; Dividiere rmp1 durch 10
; Ergebnis in rmp2, Rest in rmp1
Div10:
	clr rmp2 ; Divisionsergebnis leeren
Div10a:
	subi rmp1,10 ; Zehn abziehen
	brcs Div10b ; Carry, fertig 
	inc rmp2 ; Ergebnis erhoehen
	rjmp Div10a ; und weiter dividieren
Div10b:
	subi rmp1,-10 ; 10 zum Rest wieder addieren
	ret ; fertig
	.endif
;
; ============================================
;    H A U P T P R O G R A M M    I N I T
; ============================================
;
Main:
; Initiiere Stapel
	ldi rmp1, HIGH(RAMEND) ; Initiiere MSB Stapel
	out SPH,rmp1
	ldi rmp1, LOW(RAMEND) ; Initiiere LSB Stapel
	out SPL,rmp1
; Init PORT D
	ldi rmp1,0xFF ; alle als Ausgang
	out DDRD,rmp1
	out PORTD,rmp1
; Init Port B
	ldi rmp1,0x3F ; alle als Ausgang
	out DDRB,rmp1
	out PORTB,rmp1
; Init Port C
	out DDRC,rmp1 ; alle als Ausgang
	out PORTC,rmp1
; Init Uhrzeit, Stellen der Uhr auf 12:00:00
.if pbcd == 1
	ldi rStd,0x12 ; Packed-BCD-Uhrzeit
	ldi rMin,0x00
	ldi rSek,0x00
	.else
	ldi rStd,12 ; Binaer-Uhrzeit
	ldi rMin,0
	ldi rSek,0
	.endif
; Init Timer 1
	ldi rmp1,High(cCtc) ; CTC-A-Wert setzen
	out OCR1AH,rmp1
	ldi rmp1,Low(cCtc)
	out OCR1AL,rmp1
	ldi rmp1,0 ; Timer-Mode Normal/CTC-A
	out TCCR1A,rmp1
.if (fast == 1) | (speed == 2) ; bei Schnell und bei Stundentest
	ldi rmp1,(1<<>WGM12)|(1<<>CS10) ; Prescaler = 1
	.elif speed == 0 ; Normalbetrieb
	ldi rmp1,(1<<>WGM12)|(1<<>CS12)|(1<<>CS10) ; normal, Prescaler=1024
	.elif speed == 1
	ldi rmp1,(1<<>WGM12)|(1<<>CS11)|(1<<>CS10) ; Prescaler=64
	.endif
	out TCCR1B,rmp1 ; Timer Mode CTC-A, Prescaler
	ldi rmp1,1<<>OCIE1A ; Compare-A-Interrupt
	out TIMSK,rmp1 ; in Timer-Interrupt Maske
;
; Sleep und Interrupts
	ldi rmp1,1<<>SE ; Enable sleep mode idle
	out MCUCR,rmp1 ; in MCU-Kontrollport
	sei ; Enable Interrupts
;
; ============================================
;     P R O G R A M M - S C H L E I F E
; ============================================
;
Loop:
	sleep ; Schlafen legen
	nop ; Dummy fuer Aufwecken
	rjmp loop ; Zurueck nach Loop
;
; Ende Quellcode
; Copyright
.db "(C)2017 by Gerhard Schmidt  " ; menschenlesbar
.db "C(2)10 7ybG ehrra dcSmhdi t " ; wortgerecht
;



©2017 by http://www.avr-asm-tutorial.net