PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Problem bei Binäruhr



walkonshit
07.04.2009, 12:09
Hallo,

ich habe vor kurzen angefangen, eine Binäruhr mit LED-Anzeige zu bauen. Mittlerweile habe ich die Platine fertig gelötet und habe mi9ch an den Code gemacht. Nun stehe ich allerdings vor dem Problem, dass der Atmega samt seiner schaltung nicht so wollen wie ich.


$regfile "m8def.dat"
$crystal = 16000000

Dim Sec As Byte
Dim Minu As Byte
Dim Hour As Byte
Dim Flag As Bit
Dim X As Byte
Dim Y As Byte
'Dim Tag As Integer
Sec = 0
Minu = 0
Hour = 0

Config Portd = Output
Config Portc = Output
Config Portb = Output

Config Timer1 = Timer , Prescale = 256
Load Timer1 , 3036

Enable Timer1

On Timer1 Timer_interrupt
Enable Interrupts

' Portd.0 = 0
'Tag = 0
Do
'(
If Tag > 976 Then
Incr Sec
Tag = 0
If Portd.0 = 1 Then Portd.0 = 0
Else
Portd.0 = 1
End If
')

For X = 0 To 2
Y = X + 3
Portb.y = Sec.x
Next

X = 0
Y = 0

For X = 3 To 5
Y = X - 3
Portc.y = Sec.x
Next

X = 0
Y = 0

For X = 3 To 5
Y = X - 3
Portb.y = Minu.x
Next

X = 0
Y = 0

For X = 0 To 2
Y = X + 5
Portd.y = Minu.x
Next

X = 0
Y = 0

For X = 0 To 4
Portd.x = Hour.x
Next

X = 0
Y = 0

Flag = 0
If Flag = 0 Then
If Sec > 59 Then
Sec = 0
Incr Minu
End If

If Minu > 59 Then
Minu = 0
Incr Hour
End If

If Hour > 23 Then
Hour = 0
End If

End If

Loop


'Do
'Loop

Timer_interrupt:

Incr Sec

Flag = 1


'Toggle Portd.0
Load Timer1 , 3036
Return



Soweit so gut. Zur Zeit läuft die Schaltung über ein 4,5 V Netzteil, woher vermutlich die Ungenauigkeit des Quarzoszillators stammt. Das aktuelle Problem ist allerdings, dass bis auf 3 LEDs (32, 16, 8 Sekunden) alle nur wild am flakern sind.
Die Beschaltung der Ports:


PD0 = 1 h
PD1 = 2 h
PD2 = 4 h
PD3 = 8 h
PD4 = 16 h
PD5 = 1 min
PD6 = 2 min
PD7 = 4 min
PB0 = 8 min
PB1 = 16 min
PB2 = 32 min
PB3 = 1 sek
PB4 = 2 sek
PB5 = 4 sek
PC0 = 8 sek
PC1 = 16 sek
PC2 = 32 sek


Ich hoffe ihr könnt mir da weiter helfen

MfG DaRe

for_ro
07.04.2009, 12:48
Config Timer1 = Timer , Prescale = 256
Load Timer1 , 3036


Load Timer1, 3036 setzt den Timer Wert auf 65536-3036=62500, sodass nur noch 3036 Schritte bis zum Überlauf sind.
16.000.000 / 256 = 62500 Ich denke, du solltest
Load Timer1, 62500
setzen. Eigentlich müsste die Uhr dadurch ca. 20 x so schnell laufen wie normal.
Ob der rest so stimmt kann ich nicht sagen. Da bin ich noch nicht durchgestiegen.

Gruß

Rolf

walkonshit
07.04.2009, 12:58
Oh okay...
ich habe den Wert geändert und stelle fest, dass soweit alles gut läuft. Allerdings nur eine Minute, danach flakern die Stunden- und Minuten-LEDs wieder wild drauf los.

Edit: Die Variable Sec behält den Wert 60 und Min steigt pro Zyklus der Do-Loop-Schleife um 1. Ergo: Sec = 0 wird nicht durchgeführt, aber warum?

Dirk
07.04.2009, 19:08
Hallo walkonshit,

deine Bitmanipulationen habe ich mir nicht genauer angesehen.
Grundsätzlich hast du eine Do-Loop Schleife, die mit Maximalgeschwindigkeit durchläuft. Darein haut dann der Interrupt jede Sekunde und erhöht die Sekunde um 1 und setzt ein Flag.
Das Flag wird in der Do-Loop-Schleife konstant auf 0 gesetzt.

Warum diese "wilde" Konstruktion?
Vorschlag:
1. Einmalig wird die Binäruhr nach der Uhrzeit gestellt (alle Bits gesetzt).
2. Dann gehts in die Do-Loop Schleife, die gar nichts macht (leere Schleife) bis ein Interrupt kommt.
3. Dann wird die Sekundenanzeige neu dargestellt und nur bei Überlauf die Minuten und Stunden geändert.
4. Danach gehts wieder in die leere Schleife an den Anfang (warten auf nächste Sekunde).

Dann wird die Anzeige ganz ruhig und völlig entspannt.

Gruß Dirk

walkonshit
07.04.2009, 19:24
Ich dachte es is vielleicht geschickter die Routinen ausserhalb des Interupts zu lassen, da sonst der Interrupt zuviele Zyklen verbraucht. Okay ich merke grad selber Blödsinn...Egal dennoch, selbst wenn ich das Programm umschreibe habe ich doch immer noch das Problem, dass die Variable SEC nicht auf 0 gesetzt wird.

Dirk
07.04.2009, 20:15
... wenn ich das Programm umschreibe habe ich doch immer noch das Problem, dass die Variable SEC nicht auf 0 gesetzt wird.
Ich weiß nicht genau, warum das nicht klappt.
Allerdings kann dein Prog erstaunliche Effekte produzieren:
Stell dir vor, der Interrupt würde in eine dieser Schleifen ...

For X = 0 To 2
Y = X + 3
Portb.y = Sec.x
Next

X = 0
Y = 0

For X = 3 To 5
Y = X - 3
Portc.y = Sec.x
Next
... reinhauen.
Der Effekt wäre, dass sehr merkwürdige Dinge angezeigt würden, weil der Sec-Wert in der Schleife geändert (inkrementiert) wird.

Oder:
Wenn er hier reinhauen würde...
Flag = 0
==> Interrupt haut HIER rein!
If Flag = 0 Then
If Sec > 59 Then
Sec = 0
Incr Minu
End If
... dann ist ja Flag = 1 und der Sec-Überlauf fände nicht statt.

Also: Umschreiben!

Gruß Dirk

walkonshit
07.04.2009, 20:20
Okay...da hast du natürlich Recht. Ich habe den Code abgeändert und siehe da...ebenfalls werden die Variablen nicht resettet.



$regfile "m8def.dat"
$crystal = 16000000
$sim
Dim Sec As Byte
Dim Minu As Byte
Dim Hour As Byte
Dim Flag As Bit
Dim X As Byte
Dim Y As Byte
Sec = 0
Minu = 0
Hour = 0

Config Portd = Output
Config Portc = Output
Config Portb = Output

Config Timer1 = Timer , Prescale = 256
Load Timer1 , 62500

Enable Timer1

On Timer1 Timer_interrupt
Enable Interrupts


Do
Loop

Timer_interrupt:

Incr Sec

If Sec > 59 Then
Minu = Minu + 1
Sec = 0


If Minu > 59 Then
Minu = 0
Hour = Hour + 1


If Hour > 23 Then
Hour = 0
End If
End If
End If

For X = 0 To 2
Y = X + 3
Portb.y = Sec.x
Next

X = 0
Y = 0

For X = 3 To 5
Y = X - 3
Portc.y = Sec.x
Next

X = 0
Y = 0

For X = 3 To 5
Y = X - 3
Portb.y = Minu.x
Next

X = 0
Y = 0

For X = 0 To 2
Y = X + 5
Portd.y = Minu.x
Next

X = 0
Y = 0

For X = 0 To 4
Portd.x = Hour.x
Next

X = 0
Y = 0

Load Timer1 , 62500
Return



Langsam wirds merkwürdig.

MfG DaRe

for_ro
07.04.2009, 20:36
Ich dachte es is vielleicht geschickter die Routinen ausserhalb des Interupts zu lassen, da sonst der Interrupt zuviele Zyklen verbraucht.
Nicht aus dem Grund, aber machen würde ich das wirklich genau so.
Bei mir wird die Variable Sec übrigens in ASM Farbe dargestellt. Daher habe ich die Variable mal auf Seco geändert. Dann funktioniert dein Programm.
Zusätzlich noch ein wenig aufgeräumt sieht es dann so aus:


$regfile "m8def.dat"
$crystal = 16000000

Dim Seco As Byte
Dim Minu As Byte
Dim Hour As Byte
Dim Flag As Bit
Dim X As Byte
Dim Y As Byte
'Dim Tag As Integer
Seco = 0
Minu = 0
Hour = 0

Config Portd = Output
Config Portc = Output
Config Portb = Output
Config Timer1 = Timer , Prescale = 256
Load Timer1 , 62500

Enable Timer1

On Timer1 Timer_interrupt
Enable Interrupts

' Portd.0 = 0
'Tag = 0
Do
If Flag = 1 Then
'(
If Tag > 976 Then
Incr Sec
Tag = 0
If Portd.0 = 1 Then Portd.0 = 0
Else
Portd.0 = 1
End If
')
Flag = 0
If Seco > 59 Then
Seco = 0
Incr Minu
End If
If Minu > 59 Then
Minu = 0
Incr Hour
End If
If Hour > 23 Then
Hour = 0
End If
Portb.3 = Seco.0
Portb.4 = Seco.1
Portb.5 = Seco.2
Portc.0 = Seco.3
Portc.1 = Seco.4
Portc.2 = Seco.5
Portd.5 = Minu.0
Portd.6 = Minu.1
Portd.7 = Minu.2
Portb.0 = Minu.3
Portb.1 = Minu.4
Portb.2 = Minu.5
Portd.0 = Hour.0
Portd.1 = Hour.1
Portd.2 = Hour.2
Portd.3 = Hour.3
Portd.4 = Hour.4
End If
Loop


Timer_interrupt:
Load Timer1 , 62500
Incr Seco
Flag = 1
'Toggle Portd.0
Return

Gruß

Rolf