Eine 24-Stunden-Uhr          

von Gerd Sinning                       
Elektronik-Labor   Projekte   AVR 


Digital ist ja einfach, aber wie geht es analog? Da war die Idee, ein normales Quarzuhrwerk in eine analoge 24 Stunden Uhr umzubauen. Das sieht ganz nett aus und hat auch sonst wohl keiner. Das gibt es auch als Armbanduhr zu kaufen, hier ist die selbstgebaute Version für die Wand. Dazu braucht man ein Quarzuhrwerk, etwas Geduld und eine ruhige Hand. Mal schauen, wie das funktioniert. Jedenfalls vorsichtig öffnen, die kleinen Teile haben die Tendenz, unter den Tisch zu rollen und für immer zu verschwinden. Dann sieht man eine Spule und zwischen dem Metallbügel an der Spule ist ein kleiner runder Magnet mit einem Zahnrad. Der Chip auf der Platine unter der Spule erzeugt jede Sekunde einen Impuls (30 ms von hi auf lo), mal links, mal rechts. Das ist wie ein kleiner Schrittmotor, der Magnet mit dem Zahnrad dreht sich im Magnetfeld der Spule und treibt die Zahnräder an. So geht die 12 Stunden Uhr. (Siehe auch http://www.b-kainka.de/bastel70.htm)

Die Platine mit dem chip und dem Quarz , rechts die Anschlüsse für die Spule, da lötet man die Drähte für die neue Steuerung durch den ATtiny2313 an. Die Drähte oben werden abgelötet. Das war nur die Spannungsverorgung (+-) für den Test

Die neue Ansteuerung für die Spule mit dem ATtiny2313, 2 Volt und 250 ms Zeitskala.

Wenn man nun die Spule nicht jede Sekunde sondern nur alle 2 Sekunden ansteuert, dann läuft die Uhr halb so schnell. Das wird die 24 Stunden Uhr. Die Ansteuerung übernimmt ein ATtiny2313. Der ist dafür gut geeignet, denn er hat einen 16 bit Timer T1, bei 4 Mhz und einem Prescaler von 64 und 62500 für OCR1AH/L gibt es einen compare interrupt von einer Sekunde, toggl1 an PINB3 macht daraus ein 2 Sekunden Signal. Den 30 ms Impuls für die Spule erzeugt ein delay, PB0 mal links, PB1 mal rechts auf low geschaltet. PB0 und PB1 werden mit der Spule verbunden, die hat 190 Ohm. Das war alles, nun in aller Ruhe zusammensetzen. Man kann noch ein paar LEDs anschließen, die LED an PIND6 leuchtet von 18 h bis 6 h, die Leds an PIND5 und PIND4 blitzen 30 ms. Ohne LEDs braucht der ATtiny2313 etwa 1 mA bei 2,5 Volt, das geht noch mit Akkus, aber mit Leds ist ein Netzteil besser

Es gibt auch noch eine serielle Schnittstelle, wenn man ein '?' sendet, dann schickt der ATtiny2313 die Stunden, Minuten und Sekunden zurück. Mit 's' und 2 bytes für OCR1AH/L kann man die Taktfrequenz von Timer1 ändern, allerdings binär. Wer bis hierher gekommen ist, der schafft auch das noch. Marszeit geht aucht, dieTage sind 40 Minuten länger als ein Erdentag, also 1480 Minuten. Damit wäre OCR1AH/L 64236. Ein Muss für zukünftige Astronauten, die genaue Marszeit an der Wand.

Das Programm ist in Assembler und funktioniert prima: 24CLK11.zip

;***************************************************************************
; ATiny2313 24 h clock with standard clockwork
;
; ATiny2313 GS 10-2015
; The timing is adapted for 4 MHz
;
;***************************************************************************
; ATiny2313 PDIP
;
; (RESET/dW) PA2 1 20 VCC
; (RXD) PD0 2 19 PB7 (UCSK/SCK/PCINT7)
; (TXD) PD1 3 18 PB6 (MISO/DO/PCINT6)
; (XTAL2) PA1 4 17 PB5 (MOSI/DI/SDA/PCINT5)
; (XTAL1) PA0 5 16 PB4 (OC1B/PCINT4)
; (CKOUT/XCK/INT0)PD2 6 15 PB3 (OC1A/PCINT3)
; (INT1) PD3 7 14 PB2 (OC0A/PCINT2)
; (T0) PD4 8 13 PB1 (AIN1/PCINT1)
; (OC0B/T1) PD5 9 12 PB0 (AIN0/PCINT0)
; GND 10 11 PD6 (ICP)
;***************************************************************************

.DEVICE ATtiny2313 ;for gavrasm

.equ clock = 4000000
.equ baudrate = 9600
.equ baudval = clock/(16*baudrate)-1
; more Definitions

.equ c_value = 62500-1 ;Compare value for output compare interrupt T1 1 s
.equ c1s = 6 ; Wait (6 * 5 ms)
.equ c5ms = clock/800 ; 5 ms Wait

.equ Nighton = PIND6 ; PIND6 out Nighton 18h-6h
.equ Led0 = PIND5 ; small panel Leds
.equ Led1 = PIND4 ;
.equ Led2 = PIND3 ;
.equ coil0 = PINB0 ; coil
.equ coil1 = PINB1 ; coil
.equ toggle = PINB2 ;
.equ toggl1 = PINB3 ;

.def zero = r14
.def sr = r15

.def temp = r16
.def count = r17
.def Mincnt = r18
.def next_step = r19
.def second = r20
.def minute = r21
.def hour = r22
.def cnt24h = r23
.def ScratchH = r26 ; use in bcd2bin
.def ScratchL = r27 ; use in bcd2bin
.def ZL = r30
.def ZH = r31


.cseg
.org 0
rjmp RESET
reti
reti ; INT1
reti
rjmp T1OC1A ; T1 Compare Match A interrupt vector
reti
reti
rjmp RX_COMPLETE_INT


;**********************************************************************
; Timer1 Compare Match A interrupt **********************
; 1000 ms
;**********************************************************************

T1OC1A: in sr,sreg

inc next_step
sbis PINB, toggle ; skip if set
sbi PORTB, toggle ; set output
sbic PINB, toggle ; skip if set
cbi PORTB, toggle

sbis PINB, toggl1 ; skip if set
rjmp OC1set
cbi PORTB, toggl1 ; clr output
sbi PortB, coil1
cbi PortB, coil0
sbi PORTD, Led0
rcall Delay1s
cbi PORTD, Led0
rjmp OC1sec

OC1set:
sbi PORTB, toggl1
cbi PortB, coil1
sbi PortB, coil0
sbi PORTD, Led1
rcall Delay1s
cbi PORTD, Led1

OC1sec:
sbi PortB, coil1
sbi PortB, coil0

inc second
cpi second,60
brne OC1Ab
clr second
inc minute

OC1min:
cpi minute,60
brne OC1Ab
clr minute

inc hour
inc cnt24h ; 24 h
cpi hour,12 ; 12 h clock
brne OC1hr1
clr hour
OC1hr1:
cpi cnt24h,24 ; 24 h
brne OC1Ab
clr cnt24h

OC1Ab:
cpi cnt24h, 18 ; Nighton 18-6
brne OC_off
sbi PORTD, Nighton
rjmp OC_out
OC_off:
cpi cnt24h, 6
brne OC_out
cbi PORTD, Nighton
OC_out:
out SREG,sr
reti

;**********************************************************************
; Interrupt routine for incoming bytes on the RS232 link
;**********************************************************************

RX_COMPLETE_INT:
in sr, SREG
push temp
in temp,UDR

cpi temp,'s' ; main timer speed => s+binary
brne rx_7
rcall SerIn
out OCR1AH,temp
rcall SerIn
out OCR1AL,temp
rjmp rx_exit
rx_7:
cpi temp,'?' ; send
brne rx_15
ldi temp,'H' ; reply with H hms
rcall send_char
mov temp,hour
rcall send_char
mov temp,minute
rcall send_char
mov temp,second
rcall send_char
rjmp rx_exit

; unknown command, just ignore it
rx_15:

rx_exit:
pop temp
out SREG, sr
reti

;**********************************************
;* SerIn Returns serial port input in temp *
;**********************************************
SerIn:
sbis USR,RXC ;wait for a character
rjmp SerIn
in temp,UDR ;read value
ret

; send char in temp
;
send_char:
sbis UCSRA, UDRE ; wait for UDR
rjmp send_char ; no, wait some more
out UDR,temp ; send char
ret ; and return

;********************************************************************
reset:
ldi temp,low(RAMEND) ;Initialize stackpointer
out SPL,temp

;************** Ports *****************************************************
; Port B
ldi temp,0b11111111 ; ports are output, 1 = output , 0 = input
out DDRB,temp ; to data direction register
ldi temp,0b00000011 ; set pullup and pins 0,1 hi
out PORTB, temp ; 1 = pull-up , 0 = float

; Port D
ldi temp,0b01111111 ; output PD6543
out DDRD,temp ; to data direction register D
ldi temp,0b10000000 ; set pullup
out PORTD, temp ; 1 = pull-up , 0 = float

;************** RS 232 ***************************************************
ldi temp,low(baudval) ; UBRRL set uart speed
out UBRRL,temp
ldi temp,high(baudval) ; UBRRH set uart speed
out UBRRH,temp
; 98 = 10011000
ldi temp,0x90 ; UCSRB=UCR enable RXint and enable rx only
out UCSRB,temp ; UCSRB: RXCIE TXCIE UDRIE RXEN TXEN UCSZ2 RXB8 TXB8

;************** Timer1 ***************************************************

ldi temp,high(c_value) ;Load compare high value
out OCR1AH,temp
ldi temp,low(c_value) ;Load compare low value
out OCR1AL,temp
ldi temp,0x00
out TCNT1H,temp ;Clear timer high byte
out TCNT1L,temp ;Clear timer low byte
out TCCR1A,temp ;TOIE1 OCIE1A OCIE1B – ICIE1 OCIE0B TOIE0 OCIE0A: TIMSK
ldi temp,(1<<OCIE1A ) ; | 1<< TOIE0)
out TIFR,temp ;Clear pending timer interrupt
out TIMSK,temp ;Enable Timer compare interrupt
ldi temp,0b00001011 ; start
out TCCR1B,temp ;Clear timer on compare match,CK/64

;*************** misc *****************************************************
sbi ACSR,ACD ; to minimize current draw

sbi PortB, coil0
sbi PortB, coil1
sei ; Enable gobal iterrupt

;****************main************************************************

sbi PORTD, Nighton ; test leds
sbi PORTD, Led0
sbi PORTD, Led1
clr next_step
testnight:
cpi next_step, 1 ; 1 sec time
brlo testnight
cbi PORTD, Led0
cbi PORTD, Led1
cbi PORTD, Nighton


;***************************************************************************
m1:
clr count ; start at 00:00:00
clr second ; counters
clr minute
clr hour
clr cnt24h
clr Mincnt
clr next_step

main:

rjmp main

;***************************************************************************
; Delay
;
Delay1s:
ldi count,c1s ; x * 5 ms wait
Delay1s1:
rcall Delay5ms
dec count
brne Delay1s1
ret
;
; Delay by 5 ms
;
Delay5ms:
push ZH
push ZL
ldi ZH,HIGH(c5ms)
ldi ZL,LOW(c5ms)
Delay5ms1:
sbiw ZL,1
brne Delay5ms1
pop ZL
pop ZH
ret

LedSetPanel:
cpi Mincnt, 0
brne LSP1
cbi PORTD, Led0
cbi PORTD, Led1
cbi PORTD, Led2
rjmp LSPex
LSP1:
cpi Mincnt, 1
brne LSP2
sbi PORTD, Led0
cbi PORTD, Led1
cbi PORTD, Led2
rjmp LSPex
LSP2:
cpi Mincnt, 2
brne LSP3
cbi PORTD, Led0
sbi PORTD, Led1
cbi PORTD, Led2
rjmp LSPex
LSP3:
cpi Mincnt, 3
brne LSP4
sbi PORTD, Led0
sbi PORTD, Led1
cbi PORTD, Led2
rjmp LSPex
LSP4:
cpi Mincnt, 4
brne LSPex
cbi PORTD, Led0
cbi PORTD, Led1
sbi PORTD, Led2
LSPex: ret
;***************************************************************************



 Elektronik-Labor   Projekte   AVR