Ich, als Microkontroler-Anfänger bin über dieses Projekt gestolpert und habe wirklich viel davon gelernt. Z.B. wie man einen schönen BCD-7Segment-Decoder programmiert und wie man überhaupt ein Programm (in AVR-asm) struckturiert usw...
Also erstmal das Steckbrett:

Typisch Breadboard - mit Drahtverhau...
Man beachte die Anzeige:

Wie ich dieses klassische Rot und diese winzigen LEDs mag.
Einfach mal hier vorbeischauen.
(und JA die Siemens DL340M sind um Größenordnungen besser. aber für den Steckbrettaufbau irgendwie zu Schade)
Die Bediehnung der Uhr hab ich bei der aus "meinem" Auto abgeschaut: einfach aber nicht ausbaufähig. Mit einem Taster kann ein "reset" ausgelöst werden: dann zeigt die Uhr wieder 01:00 an. Mit einem weiteren werden die Stunden gestellt: jeder Tastendruck lässt dei Anteige eine Stunde weiterschalten. Und mit einem dritten Taster wird das gleiche mit der Minutenanzeige gemacht.
Die Schaltung werde ich nochmal schön mit Eagle aufhübschen, bis dahin muss der Code reichen.
; einfache Uhr mit 4stelliger LED Anzeige
; Anzeige ist DL340M - 7 Segement mit gem. Kathode
; by DH8SZ nach GPL
; Version 0.0.1 - Zählanzeige mit int.RC als Taktgeber und keiner Stellmöglichkeit
; Version 0.0.1a - statt Zeit werden Festwerte Angezeigt - Test
; Version 0.0.1b - Anzeige wieder normal - timer beschleunigt
; Version 0.0.1c - reti für interrupt-return geändert
; Version 0.0.2 - zählt nun bis 24:00 und der Dezimalpunkt der 2. Stundenstelle blinkt
; Version 0.0.3 - Tasten zum stellen: reset, PD2, PD3
; Version 0.0.3a - alte zählung + bugfixes in ledoff
; Version 0.0.3b - neue zählung (i.o.) + dezimalpunkt blinkt nun wirklich
; Version 0.0.4 - Sekunden 1:1 für Testaufbau
; Version 0.0.4a - LED-Multiplexfrequenz verdoppelt
; Display:
; -----
; I g I
; e I I f
; I I
; -----
; I d I
; b I I c
; I I
; -----
; a
; Ports (Display DL340M)
; PB0 - Pin4 - c
; PB1 - Pin9 - f
; PB2 - Pin3 - a
; PB3 - Pin6 - d
; PB4 - Pin13 - g
; PB5 - Pin2 - b
; PB6 - Pin11 - e
; PB7 - Pin5 - 5
;
; PD0 - Pin14 - kat.System1
; PD1 - Pin12 - kat.system2
; PD4 - Pin8 - kat.System3
; PD5 - Pin9 - kat.System4
.include "tn2313def.inc"
.def w1=R14
.def W2=R15
.def temp=R16
.def temp2=R17
.def std10=R18
.def std01=R19
.def min10=R20
.def min01=R21
.def sek10=R22
.def sek01=R23
;===========================================================================
.dseg
;alles leer
;===========================================================================
.cseg
.org 0x0000
rjmp reset ; Der Start des Programmes
.org 0x0001
rjmp stunden_stellen ;Interruptroutine zum Stunden erhöhen
.org 0x0002
rjmp minuten_stellen ;Interruptroutine zum Minuten erhöhen
.org 0x0004
rjmp takt ; Interruptroutine zum Sekunden zählen
charset:
; hier kommt die Tabelle für die BCD/7segment Umsetzung hin
.include "charset.asm"
;===========================================================================
; Initianisierung
;===========================================================================
reset:
;initialisieren des Stackpointers
ldi temp, RAMEND
out SPL, temp
;Analogkomparatoren abschalten
sbi ACSR,7
;Voreinstellungen für Uhrzeit
ldi std10, 0x00
ldi std01, 0x01
ldi min10, 0x00
ldi min01, 0x00
;Ausgabeports initianisieren PB7:0 = Ausgabe und 0
ldi temp, 0xff
out DDRB, temp
ldi temp, 0x00
out PORTB, temp
;Ports PD0, PB1, PB4, PB5 = Ausgabe und 1 / PB2, PB3 als Eingänge und pullup an
ldi temp, 0b00110011
out DDRD, temp
ldi temp, 0b00111111
out PORTD, temp
;INT0 und INT1 initialisieren
ldi temp, 0b00001010 ;fallende Flanke an INT0 und INT1 ist Auslöser
out mcucr, temp
ldi temp, 0b11000000 ;INT0 und INT1 freischalten
out gimsk, temp
;Timer/Counter1 (16Bit) initianisieren
;TCCR1B = 0 0 0 0 1 1 0 1 = no InputNoiseCanceler, InputCaptureEdgeSelect, Mode=CTC, Prescaler=1024
ldi temp, 0x0d
;ldi temp, 0x0c ;prescaler auf /256 statt /1024
out TCCR1B, temp
;OCR1A - Top für Counter setzen = 3200
ldi temp, 0x0c
ldi temp2, 0x80
out OCR1AH, temp
out OCR1AL, temp2
;TIMSK --> enabele OCIE1A output Compare Interrupt
ldi temp, 0x40
out TIMSK, temp
;TCNT1 auf 0 reseten
clr temp
out TCNT1H, temp
out TCNT1L, temp
;Interrupt erlauben
sei
;===========================================================================
; Hauptprogramm
;===========================================================================
main:
;Stunden darstellen - 10er Stelle
mov temp, std10
rcall convert
out PORTB, temp2
cbi PORTD, 5
rcall wait2ms
rcall ledoff
;Stunden darstellen - 1er Stelle - Dezimalpunkt blinkt im sekundentakt
mov temp, std01
rcall convert
sbrc sek01, 0
ori temp2, 0b10000000
out PORTB, temp2
cbi PORTD, 4
rcall wait2ms
rcall ledoff
;Minuten darstellen - 10er Stelle
mov temp, min10
rcall convert
out PORTB, temp2
cbi PORTD, 1
rcall wait2ms
rcall ledoff
;Minuten darstellen - 1er Stelle
mov temp, min01
rcall convert
out PORTB, temp2
cbi PORTD, 0
rcall wait2ms
rcall ledoff
;zurück zum Mainloop
rjmp main
;======================================================================
; Unterprogramme
;======================================================================
takt:
;dieses Unterprogramm wird ein mal pro Sekunde angesprungen
cli
inc sek01
cpi sek01, 0x0a
brlo takt_ende
clr sek01
inc sek10
cpi sek10, 0x06
brlo takt_ende
clr sek10
inc min01
cpi min01, 0x0a
brlo takt_ende
clr min01
inc min10
cpi min10, 0x06
brlo takt_ende
clr min10
inc std01
cpi std01, 0x04
brlo takt_ende
cpi std10, 0x02
brlo takt_01
clr std01
clr std10
rjmp takt_ende
takt_01:
cpi std01, 0x0a
brlo takt_ende
clr std01
inc std10
cpi std10, 0x0a
brlo takt_ende
clr std10
takt_ende:
sei
reti
;--------------------------------------------------------------------------
stunden_stellen: ;dieser Teil ist auch zum Stundn hochzählen
inc std01
cpi std01, 0x04
brlo stunden_ende
cpi std10, 0x02
brlo stunden_01
clr std01
clr std10
rjmp stunden_ende
stunden_01:
cpi std01, 0x0a
brlo stunden_ende
clr std01
inc std10
cpi std10, 0x0a
brlo stunden_ende
clr std10
stunden_ende:
reti
;---------------------------------------------------------------------------
minuten_stellen: ;minuten bei tastendruck hochzählen
inc min01
cpi min01, 0x0a
brlo minuten_ende
clr min01
inc min10
cpi min10, 0x06
brlo minuten_ende
clr min10
minuten_ende:
reti
;---------------------------------------------------------------------------
convert:
;convertiert BCD (temp) zu 7segment (temp2)
ldi ZL, LOW(charset<<1)
ldi ZH, HIGH(charset<<1)
add ZL, temp
lpm temp2, Z+
ret
;---------------------------------------------------------------------------
ledoff:
;Anzeige ausschalten
ldi temp, 0x00
out PORTB, temp
ldi temp, 0b00111111
out PORTD, temp
ret
;---------------------------------------------------------------------------
wait2ms:
;verzögrung für 1 ms at 3,2768MHz
ldi temp, 0x0d
mov w1, temp
clr w2
wait2ms_loop:
dec w2
brne wait2ms_loop
dec w1
brne wait2ms_loop
ret
Man, da hab ich mir ja ne Naht zusammengetippt: da wird tatsächlich jede Stelle der Anzeige in einem eigenen Register hochgezählt. Und bei einem Überlauf natürlich kompliziert verglichen und gesprungen...
mal sehn ob das noch einfacher zu lösen ist...
Nun hab ich keinen Pin mehr frei. Das Bedienkonzept ist auch eine Sackgasse und die Genauigkeit ist noch weiter zu prüfen.
Für meine nächse Uhr werde ich nen ATMega48 nehmen, der hat ein paar Beinchen mehr und es lässt sich dann auch noch eine Weckfunktion mit einbauen.
p.s. natürlich hab ich auch noch eine Zeichentabelle für den BCD-7Segment-Umsetzer:
; Carsetfile für BCD - zu - 7segment Umsetung
.db 0b01110111, 0b00000011 ;0 ,1
.db 0b00111110, 0b00011111 ;2, 3
.db 0b01001011, 0b01011101 ;4, 5
.db 0b01111101, 0b01010011 ;6, 7
.db 0b01111111, 0b01011111 ;8, 9
.db 0b01111110, 0b01101101 ;A, b
.db 0b00101100, 0b00101111 ;c, d
.db 0b01111100, 0b01111000 ;E, F