PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Erneut Schieberegister



oZe
25.11.2010, 09:20
Hallo Jungs!
Ich habe erneut ein Problem mit Schieberegistern (74HC595). Ich bin momentan dabei eine Qlocktwo nachzubauen und habe dazu einen AtMega8 mit 3 kaskadierten Schieberegistern beschaltet ohne das SPI Interface zu nutzen. Hinter den Schieberegistern hänge 3 Transistorarrays (ULN2981).
Ich nutze von den 24 Ausgängen die mir nun zur verfügung stehen 20 um die einzelnen Worte der Uhr anzusteuern allerdings harkt es jetzt an der Software realisierung.
Die Uhr ist ja in 5 Minuten Schritten genau, sodass ich im Programm die Schieberegister alle 5 Minuten neu beschreiben muss allerdings stellt sich folgendes Problem:
Ich habe eine Stundenvariable, eine Minutenvariable und eine Sekundenvariabele die durch einen Timer hochgezählt werden. Jetzt muss ich allerdings jeweils die Bitmuster irgendwo speichern die zur jeweiligen Uhrzeit gehören. Da jede Stunde 12 unterschiedliche Bitmuster benötigt wären das also 12*12 Bitmuster und ich kann ja schlecht 144 If abfragen hintereinander machen wie z.b. so:

if (Stunden == 12 && Minuten == 0 && Minuten < 5)
{
Bitmuster für 12:00 ausgeben
}
if (Stunden == 12 && Minuten > 4 && Minuten < 10)
{
Bitmuster für 12:05 ausgeben
}
...
...

Das muss doch irgendwie einfacher gehen. Hat da jemand einen Tipp für mich? Ist es hier sinnvoll die 144 Bitmuster mit Hilfe von DATA abzuspeichern und darauf zuzugreifen? WIe genau müsste das aussehen.

Ich hab einfach keine andere Idee wie das sonst zu realisieren wäre ohne die 144 If abfragen.

Danke für eure Hilfe!

PicNick
25.11.2010, 12:48
Es gibt Leute, die würden die Pattern für 0-9 speichern und die dann nach Bedarf zusammensetzen.
Aber ich kenn diese "Qlocktwo" nicht, vielleicht ist da alles anders. Ich werd' den Herrn Google fragen.

Ahja. Da muss man über die Zahlen in einer Tabelle zu den Worten finden, und dann normal die erforderlichen Buchstaben als Pattern abarbeiten.
Ist halt ein paar mal um die Ecke

BoGe-Ro
25.11.2010, 15:44
Hallo,

ich kenn jetzt die Uhr nicht - hab ebenfalls nur kurz gegoogled und gesehen, dass die Anzeige dem "sprachgebrauch" entspricht.
Wenn es pro Stunde 12 verschiedene Anzeigen gibt (ich stell mir jetzt so etwas wie 10_nach oder 10_vor oder viertel_nach oder einfach viertel und dreiviertel) dann ist das ja rein minutenabhängig und wird wohl durch 12 if's oder besser 12 case-Zeilen erfasst.
Das stundenabhängige sind einfach betrachtet auch 12 Fälle...aber die entsprechen ja lediglich dem Bitmuster was der Stundenvariable zugeordnet wird, oder eben dem Bitmuster von Stundenvariable+1.

ich würde also

select case Minutenvariable
case is <7 :
MinutenBitmuster für 5-nach
Stundenbitmuster für Stunde
case is<12:
MinutenBitmuster für 10-nach
Stundenbitmuster für Stunde
case is<17:
MinutenBitmuster für viertel
Stundenbitmuster für Stunde
...
case is<57:
MinutenBitmuster für 5-vor
Stundenbitmuster für Stunde+1
end select

Das ist jetzt nicht getestet, nur so aus dem Kopf hingeschrieben - und sieht auch ziemlich anders als deine Lösung aus - mehr Bascom-ähnlich

for_ro
25.11.2010, 16:04
Hallo,
ich habe das in Bascom so gemacht, dass ich das Muster in einem Array abgespeichert habe, getrennt für Stunden und Minuten.
Der Index ins Array geht für die Minuten einfach über Minuten/5.

Für die Stunden ist es etwas aufwändiger, da du schon vor der Stunde mit ihr arbeitest. Dies ist ab fünf_vor_halb_<stunde> (z.B. 4.25 Uhr) der Fall (in einigen Gebieten auch schon bei 10_vor_halb_fünf). Also musst du unterscheiden, ob die Minuten <25 (bzw. <20) sind, dann einfach die Stunde. Ansonsten Stunde+1.

oZe
25.11.2010, 23:22
Ja also die Uhr ist wie gesagt einfach per google zu finden an die Jungs die das Ding noch nie gesehen haben.
@BoGe-Ro: Deine Lösung ist vom Prinzip her ja funktionisfähig aber das Problem ist die Zeile "Ausgabe des Bitmusters für die Stunde". Da gibt es ja wieder 12 verschiedene Möglichkeiten, sodass ich dort wieder 12 If abfragen machen müsste um das passende Bitmuster auszugeben. Dazu kommt noch das wenn ich zuerst das Bitmuster für die Minuten in die Schieberegister taktet und anschließend das Bitmuster für die Stunde eintakte, das dann zuerst die Minuten aufleuchten würden ohne stunden angabe und danach die Stunde ohne die Minuten. Der Controller ist zwar locker schnell genug das man das mit bloßem auge nicht sehen würde aber trotzdem nicht grade ideal.


@for_ro: Das würde ja vorraussetzen, das ich 2 verschiedene Schieberegister Kaskaden für Minuten und Stunden hätte. Bei mir ist es eine große Schieberegisterkette für Stunden UND Minuten.
Trotzdem hast du mich auf eine Idee gebracht. Ich könnte es so machen wie du vorgeschlagen hast und die Minuten Bitmuster und Stunden Bitmuster in Arrays zu schreiben und bei der Ausgabe diese beiden Arrays zu kombinieren. Keine schlechte Idee denke ich. Danke für diesen wirklich hilfreichen Hinweis ;-)

Trotzdem bin ich gerne für weitere Vorschläge offen! Ich finds übrigens nach wie vor super das einem hier so gut geholfen wird bei der Realisierung eines solchen Projekts. Ich versuche natürlich auch etwas zurück zu geben soweit mir das Möglich ist. Das ist aber meist in der Hardware Ecke ;-)

for_ro
26.11.2010, 14:59
Das würde ja vorraussetzen, das ich 2 verschiedene Schieberegister Kaskaden für Minuten und Stunden hätte.
... und bei der Ausgabe diese beiden Arrays zu kombinieren. Keine schlechte Idee denke ich. Danke für diesen wirklich hilfreichen Hinweis ;-)
Ich würde halt nicht die Arrays kombinieren, sondern einfach die gefundenen bitmuster hintereinanderhängen.
Außerdem könntest du die Bitmuster auch in zwei separaten Befehlen an deine Schieberegister Kette ausgeben.

BoGe-Ro
27.11.2010, 10:01
Hallo,

wie wäre doch der Weg über Data und LookUp?

du würdest zwei Datafelder anlegen, eins für die Stundenbitmuster und eins für die Minutenbitmuster.

Du gibst einer Stundenbitmusterhilfsvariablen den Wert der aktuellen Stunde.

danach schiebst du dann deinen Minutenzähler über eine Case-Auswahl und weist einer Variable die Werte 1 bis 12 zu, je nachdem welches Bitmuster dran wäre für die aktuelle Minute.
innerhalb dieser Minuten-Case-Auswahl, an den Stellen, wo die Stunde nicht mehr auf die aktuelle Stunde sondern auf die nachfolgende bezogen wird, erhöhst du die Stundenbitmusterhilfsvariablen um eins.

Also beispielsweise in ostdeutsch: bei 09:10 Uhr kannst du schreiben "zehn nach neun", 5 Minuten später "viertel zehn", und nochmals 5 Minuten später "20 nach 9".
Du hättest also die völlige Freiheit, nur abhängig von der aktuellen Minute auszuwählen, auf welche Stunde die zeitangabe bezogen wird.

Nach diesen 12 Case-Auswahlmöglichkeiten führst du die LookUp's in den beiden Data-Feldern durch und hast jeweils 2 Bitmuster, die deiner Ausgabe entsprechen.


Gruß BoGe-Ro

oZe
28.11.2010, 13:58
Ja das klingt für mich auch nach ner guten Idee wobei ich mir nicht sicher bin was Platzsparender ist. Die Arrays haben den Nachteil das es in Bascom ja keine Bit Arrays gibt (wobei das glaub ich nichtmal an Bascom sondern ehr an den AVR`s liegt) und ich somit einen anderen Datentyp nehmen muss was Platz verschwendet.
Die Data Lookup Methode habe ich noch nie angewendet und steig nicht ganz hinter die Syntax der Befehle. Ich hab in der Bascomhilfe nachgesehen und ein bischen google bemüht. Ich kann ja sowas ähnliches wie das hier machen:

Datenfeld:
DATA Wert1,Wert2,Wert3
DATA Wert1,Wert2,Wert3
...
...


Jetzt weiß ich aber nicht wie ich diese Datenfelder genau anspreche weil ich ja nur einen Namen des Feldes habe (Datenfeld) aber mehrere Zeilen.


Trotzdem wie ich bereits sagte: Alles gute Ansätze und ihr habt mich schonmal dahin geführt nur noch 2x 12 Abfragen zu brauchen anstatt von 144.

for_ro
28.11.2010, 14:39
Hallo oZe,
du brauchst dazu überhaupt keine Abfragen. Egal ob du die Werte in ein Array packst oder dir jedesmal über Lookup aus dem Data Bereich ausliest. Wie du das "ausrechnen" kannst, habe ich dir oben beschrieben.
Bei der Qlocktwo hast du ja die Wörter
FÜNF ZEHN VOR NACH VIERTEL HALB VOR NACH
für die Minuten und
EINS ZWEI DREI VIER FÜNF SECHS SIEBEN ACHT NEUN ZEHN ELF ZWÖLF
für die Stunden.
Den 8 Wörtern der Minute ordnest du 8 Bit, also 1 Byte zu.

FÜNF ZEHN VOR NACH VIERTEL HALB VOR NACH
Fünf_nach = 10010000
Zehn_nach = 01010000
Viertel_nach = 00001001
usw. insgesamt 12 Werte. Du musst dazu also 12 Byte abspeichern.
Das gleiche Prinzip könntest du für die Stunden machen.

EINS ZWEI DREI VIER FÜNF SECHS SIEBEN ACHT NEUN ZEHN ELF
Eins = 100000000000
Zwei = 010000000000
Drei = 001000000000
usw. insgesamt 12 Werte. Du müsstest dazu also 12 Word (16 Bit) abspeichern.
Dies wäre aber eigentlich zu aufwändig, da immer nur eine Position den Wert 1 haben kann. Auch das könnte man wieder ausrechnen.

oZe
28.11.2010, 21:11
Ok ich schau mir das nochmal in Ruhe an. Ich hab mometan leider nicht soviel Zeit wg. Uni etc. aber ich danke dir schonmal für deine Hilfe! Ich denke nächste Woche sollte ich dazu kommen das alles mal zu testen.

oZe
03.01.2011, 01:06
Sooo ich bin jetzt endlich dazu gekommen mal ein bischen zu programmieren und jetzt gibts leider Probleme... Mein Programm läuft eindeutig auf dem Controller da die Kontroll LED im Sekundentakt blinkt aber leider wird an den Schieberegistern nichts ausgegeben...

Vielleicht kann ja mal jemand drüber schaun:


$regfile = "m8def.dat"
$crystal = 8000000

'Ports einstellen
Config Portb.0 = Output 'SRData
Config Portb.3 = Output 'PWM
Config Portd.7 = Output 'SCK
Config Portd.6 = Output 'RCK
Config Portd.5 = Output 'Reset
Config Portd.2 = Output 'LED
Config Pinc.3 = Input 'Taster1
Config Pinc.4 = Input 'Taster2
Config Pinc.5 = Input 'Taster3

'Alias definieren
Rck Alias Portd.6
Sck Alias Portd.7
Datasr Alias Portb.0
Resetsr Alias Portd.5
Led Alias Portd.2
Pwm Alias Portb.3
Taster1 Alias Pinc.3
Taster2 Alias Pinc.4
Taster3 Alias Pinc.5

'Portpegel setzen
Rck = 0
Sck = 0
Datasr = 0
Resetsr = 0
Led = 0
Pwm = 1
Taster1 = 1
Taster2 = 1
Taster3 = 1

'Timer konfigurieren
Config Timer1 = Timer , Prescale = 256
Enable Timer1
On Timer1 Sekundentakt
Enable Interrupts
Timer1 = 34285

'Config Timer2 = Pwm , Pwm = 8 , Compare A Pwm = Clear Up , Prescale = 1


'Variablen definieren
Dim Sekunden As Integer
Dim Minuten As Byte
Dim Stunden As Byte
Sekunden = 0
Minuten = 0
Stunden = 12

'Bitmuster erstellen und Array befüllen
Dim Stundenarray(12) As Word
Dim Minutenarray(12) As Byte
Dim I As Byte
Dim Stdpos As Byte
Dim Minpos As Byte

Minutenarray(1) = &B00000000 'Voll
Minutenarray(2) = &B10000001 'Fünf nach
Minutenarray(3) = &B10000010 'Zehn nach
Minutenarray(4) = &B00010001 'Viertel nach
Minutenarray(5) = &B00100110 'Zehn vor Halb
Minutenarray(6) = &B00100101 'Fünf vor Halb
Minutenarray(7) = &B00100000 'Halb
Minutenarray(8) = &B00101001 'Fünf nach Halb
Minutenarray(9) = &B00101010 'Zehn nach Halb
Minutenarray(10) = &B01010000 'Viertel vor
Minutenarray(11) = &B01000010 'Zehn vor
Minutenarray(12) = &B01000001 'Fünf vor

Stundenarray(1) = &B0000000100000000 'Eins
Stundenarray(2) = &B0000001000000000 'Zwei
Stundenarray(3) = &B0000010000000000 'Drei
Stundenarray(4) = &B0000100000000000 'Vier
Stundenarray(5) = &B0001000000000000 'Fünf
Stundenarray(6) = &B0010000000000000 'Sechs
Stundenarray(7) = &B0100000000000000 'Sieben
Stundenarray(8) = &B1000000000000000 'Acht
Stundenarray(9) = &B0000000000010000 'Neun
Stundenarray(10) = &B0000000000100000 'Zehn
Stundenarray(11) = &B0000000001000000 'Elf
Stundenarray(12) = &B0000000010000000 'Zwölf



'Hauptschleife
Do

'Arrayposition berechnen Bsp: Minuten = 3 ===> Arrayposition 1 muss ausgegeben werden
Minpos = Minuten / 5
Minpos = Minpos + 1


'Überprüfen ob die Stunde + 1 ausgegeben werden muss. Bsp: 05:31 ===> Halb Sechs
Stdpos = Stunden
If Minuten >= 5 Then
Stdpos = Stdpos + 1
End If

'Stundenarray an der Position "Stunden" in die Schieberegister takten
For I = 1 To 16 Step 1
Datasr = Stundenarray(Stunden).I
Toggle Sck
Toggle Sck
Next A

'Minutenarray an der Position "Minpos" in die Schieberegister takten
For I = 1 To 8 Step 1
Datasr = Minutenarray(Minpos).I
Toggle Sck
Toggle Sck
Next A

'Latch der Schieberegister auf Ausgänge schalten
Toggle Rck
Toggle Rck


'In Idle Mode wechseln zum strom sparen und um unnötiges beschreiben der Schieberegister
'zu vermeiden. Geweckt wird im Sekundentakt des Timers.
POWER IDLE

Loop
End




'Interrupt Routine für den Timer1. Läuft Sekündlich über.
Sekundentakt:
Timer1 = 34285
Toggle Led

If Sekunden < 59 Then
Sekunden = Sekunden + 1
Else
Sekunden = 1
Minuten = Minuten + 1
End If

If Minuten >= 59 Then
Minuten = 0
Stunden = Stunden + 1
End If

If Stunden > 12 Then
Stunden = 1
Minuten = 0
End If



Return



Wo liegt mein Fehler? Falls Ihr mehr Infos braucht dann geb ich die natürlich so bald wie möglich raus. Danke schonmal!

Edit: Hier schonmal der Schaltplan falls der auch von interesse ist:
http://rapidshare.com/files/440502830/Qlocktwo.pdf

Michael
03.01.2011, 09:13
Hallo Oze,


For I = 1 To 8 Step 1
Datasr = Minutenarray(Minpos).I
Variablen zählt man von Null an, ein Byte von 0-7, ein Word von 0-15.
Es muß also For I = 0 To 7 heißen.


Toggle Sck
Toggle Sck
das ist auch gefährlich, besser du schreibst stattdessen:
Sck = 0
Sck = 1



POWER IDLE
kannst du ja erstmal weglassen bis der Rest läuft.

Gruß, Michael

oZe
03.01.2011, 09:32
Ah danke! Ich war mir nicht sicher ob die Bits von 0 oder 1 an gezählt werden in Bascom weil die Arrays ja z.b. von 1 an gezählt werden. Dachte das wär da analog. Ich werd mal testen obs daran liegt obwohl ich das ehr nicht denke. Ich würde ja so nur alles um ein Bit versetzt ausgeben was aber wenigstens zu irgendeiner ausgabe führen würde und nicht einfach zu nichts. Sowas wie eine Speicherzugriffsverletzung gibt es doch nicht auf Mikrocontrollern oder?
Das Toggle SCK werd ich auch umschreiben und ebenfalls für RCK ändern. Power Idle werde ich auch mal rausnehmen.
Ich berichte später obs was geholfen hat.
Danke dir schonmal für deine Hilfe!

Michael
03.01.2011, 09:59
Hallo Oze,

in deinem Schaltplan sehe ich 3 Schieberegister von denen das letzte nur mit 4 Bit benutzt wird, insgesamt also 20 Bit.
Deine Software schiebt aber 16 Bit für Stundenarray und nochmal 8 Bit für Minutenarray aus. Immer 4 Bit zuviel.
Da dein Schaltplan nicht komplett ist, kann ich nur vermuten, daß das so nicht stimmt.
Was ist denn an K1 links angeschlossen?

Gruß, Michael

stefan_Z
03.01.2011, 10:02
Speicherzugriffsverletzung gibts ganz klar - wenn dir der Stack überläuft z.B.
Das merkt man dann an sehr komischem Fehlverhalten und andauernden Resets, etc.
Was er genau macht, wenn du Bit.9 von nem Byte änderst weiß ich nicht - ich vermute mal Bit.0 von der nächsten Variable ändern. Oder irgend etwas noch schlechteres :-)

oZe
03.01.2011, 10:09
Doch doch das ist so gewollt. Ich schiebe immer 4 führende Nullen in die Schieberegister die nicht genutzt werden um alle schieberegister komplett zu nutzen und mir somit in der Software das Reseten der Schieberegister zu ersparen. Den Speicher für die 4 zusätzlichen Nullen habe ich ja eh durch die Word Variabeln reserviert und verschwende somit auch keinen Platz.
An K1 sind die einzelnen Wörter der Uhr angeschlossen. Momentan ist das jeweils eine LED zum testen. Später werden dann dort jeweils LED Arrays angeschlossen um die Wörter zu hinterleuchten.

Ich habe die von dir vorgeschlagenen Änderungen jetzt umgesetzt und habe damit leider keinen Erfolg. Es wird nach wie vor nichts ausgegeben (also es leuchtet keine der 20 LED`s).
Was mich auch noch stutzig macht: Ich habe die Platine jetzt mal ein bischen laufen lassen und die Status LED mal beobachtet. Dort sehe ich teilweise keinen sauberen Sekundentakt mehr. Ca nach 40 Sekunden bleibt die LED für 2 Sekunden an und teilweise auch mal für 2 Sekunden aus. Ich habe leider keinen Debugger so das ich nicht sehen kann ob an dieser Stelle zufällig ein Reset ausgelöst wird.

Nochmal zum verständnis der Schieberegister: Ich muss doch einfach 24 Werte an den Dateneingang des ersten Schieberegisters takten und anschließend einen Flankenwechsel an RCK auslösen um die eingetakteten Werde auf die Ausgänge der Schieberegister zu schalten oder?

oZe
03.01.2011, 10:12
@Stefan_z: Hälst du es für möglich das ich einen Stacküberlauf habe in meinem Programm? Ich habe den Stack nicht explizit festgelegt im Code und benutze somit die Bascom vorgaben (HW Stack: 32 Soft Stack = 8 und Frame = 24). Ist das zu wenig? Ich habe keinen Ahnung wie ich diese Werte korrekt vorberechnen kann.

stefan_Z
03.01.2011, 10:21
Also viel wirst du nicht brauchen, die werden bei vielen Sub-Sprüngen wichtig.
Ich würde die Arrays durch Konstanten ersetzen, die ändern sich ja nicht, oder hab ichs übersehen? Damit sparst du schonmal gut RAM.

Und Minpos = Minuten / 5 kann ja auch kein allzu genauer Wert sein - da wird die Bruchzahl ins byte geschrieben.

Ich würde - wie bei allen Hardware-Sachen erstmal ne ganz doofe Routine schreiben, dir dir ein Muster ins SR taktet. Wenn das funktioniert, ist der Rest schnell gemacht.

oZe
03.01.2011, 10:28
Also ich glaube ich hab den fehler: Ich halte den Reseteingang der Schieberegister auf 0. Der sollte aber auf 1 liegen was ich übersehen habe da er Low Aktiv ist genau wie der Reset vom AVR.

Wo du aber grade sagst das Minpos = Minuten/5 nicht geht mach ich mir ernsthaft sorgen um meine Software. Normalerweise kenn ich das so, dass wenn man eine Integerzahl teilt und ein Bruch rauskommt die Nachkommastellen abgeschnitten werden. Also sowas wie 3/5 = 0 oder 7/5 = 1. Das nutze ich ja extra aus in meiner Software.

Die Arrays konstant zu machen werde ich auch mal tun. Das schadet auf jedenfall nicht da diese nicht geändert werden.

Ich berichte später ob mein Resetproblem sich gelöst hat.

oZe
03.01.2011, 10:50
So ich habs getestet: Es lag tatsächlich an dem Reseteingang. Die Uhr lass ich jetzt mal durchlaufen und schaue ob das wirklich alles sauber durchschaltet so wie ich das möchte. Was mir noch ein bischen sorge macht ist der unsaubere Sekundentakt an der Status LED aber ich werde mal sehen wie genau die Uhr läuft. Ich hab momentan aber auch noch den internen Takt an und schalte dann mal auf das Quarz um wenns genauer werden soll.

stefan_Z
03.01.2011, 11:19
Also die Ungenauigkeit des Taktes sollte für dich nicht wahrnehmbar sein - das bewegt sich im Bereich der ppm.
Ich vermute eher, dass der nicht richtig schlafen geht oder sowas.
Und verlege mal die ganze Rechnerei vom INT in die Main-Loop!
Im INT nur noch ein Flag setzen und das dann in der Main abfragen.
Wenns gesetzt ist einmal rechnen, shiften, schlafen.

oZe
03.01.2011, 11:24
Also momentan schläft er gar nicht weils ichs noch auskommentiert habe nach deinem Ratschlag.
Ich verlege das ganze dann wie du sagst in die Main Loop und dann sehen wir weiter aber erstmal werd ich jetzt pause machen und die uhr einfach nen paar stündchen laufen lassen und die abweichung checken.

Ich danke euch ganz herzlich für die hilfe und im besonderen Stefan_z der mir jetzt die letzten Denkanstösse gegeben hat!

stefan_Z
03.01.2011, 11:27
Dim sek_flag as bit

ISR:
Set sek_flag
Return

Main:
If sek_flag = 1 then
<Rechnerei>
else
Sleep
end if

oZe
03.01.2011, 23:36
Hab ich eingebaut allerdings noch ohne Sleep. Die Led spinnt trotzdem irgendwie. In unregelmäßigen Abständen Toggelt die Led nicht. Ich kann da kein System hinter feststellen. Es passiert einfach nicht immer.
Woran kann das noch liegen? Naja ich teste jetzt mal wieder die genauigkeit der Uhr. Ich hatte noch einen fehler in der Software, sodass die Sekundenvariable nicht von 0 bis 59 gezählt hat sondern von 1 bis 59 und somit immer eine Sekunde zuwenig pro Minute gezählt wurde.
Hier der Übersichtlichkeit halber nochmal der neue Code:




$regfile = "m8def.dat"
$crystal = 8000000

'Ports einstellen
Config Portb.0 = Output 'SRData
Config Portb.3 = Output 'PWM
Config Portd.7 = Output 'SCK
Config Portd.6 = Output 'RCK
Config Portd.5 = Output 'Reset
Config Portd.2 = Output 'LED
Config Pinc.3 = Input 'Taster1
Config Pinc.4 = Input 'Taster2
Config Pinc.5 = Input 'Taster3

'Alias definieren
Rck Alias Portd.6
Sck Alias Portd.7
Datasr Alias Portb.0
Resetsr Alias Portd.5
Led Alias Portd.2
Pwm Alias Portb.3
Taster1 Alias Pinc.3
Taster2 Alias Pinc.4
Taster3 Alias Pinc.5

'Portpegel setzen
Rck = 0
Sck = 0
Datasr = 0
Resetsr = 1
Led = 0
Pwm = 1
Taster1 = 1
Taster2 = 1
Taster3 = 1

'Timer konfigurieren
Config Timer1 = Timer , Prescale = 256
Enable Timer1
On Timer1 Sekundentakt
Enable Interrupts
Timer1 = 34285

'Config Timer2 = Pwm , Pwm = 8 , Compare A Pwm = Clear Up , Prescale = 1


'Variablen definieren
Dim Sek_flag As Bit
Dim Sekunden As Integer
Dim Minuten As Byte
Dim Stunden As Byte
Sekunden = 0
Minuten = 0
Stunden = 12

'Bitmuster erstellen und Array befüllen
Dim Stundenarray(12) As Word
Dim Minutenarray(12) As Byte
Dim I As Byte
Dim Stdpos As Byte
Dim Minpos As Byte

Minutenarray(1) = &B00000000 'Voll
Minutenarray(2) = &B10000001 'Fünf nach
Minutenarray(3) = &B10000010 'Zehn nach
Minutenarray(4) = &B00010001 'Viertel nach
Minutenarray(5) = &B00100110 'Zehn vor Halb
Minutenarray(6) = &B00100101 'Fünf vor Halb
Minutenarray(7) = &B00100000 'Halb
Minutenarray(8) = &B00101001 'Fünf nach Halb
Minutenarray(9) = &B00101010 'Zehn nach Halb
Minutenarray(10) = &B01010000 'Viertel vor
Minutenarray(11) = &B01000010 'Zehn vor
Minutenarray(12) = &B01000001 'Fünf vor

Stundenarray(1) = &B0000000100000000 'Eins
Stundenarray(2) = &B0000001000000000 'Zwei
Stundenarray(3) = &B0000010000000000 'Drei
Stundenarray(4) = &B0000100000000000 'Vier
Stundenarray(5) = &B0001000000000000 'Fünf
Stundenarray(6) = &B0010000000000000 'Sechs
Stundenarray(7) = &B0100000000000000 'Sieben
Stundenarray(8) = &B1000000000000000 'Acht
Stundenarray(9) = &B0000000000010000 'Neun
Stundenarray(10) = &B0000000000100000 'Zehn
Stundenarray(11) = &B0000000001000000 'Elf
Stundenarray(12) = &B0000000010000000 'Zwölf



'Hauptschleife
Do
If Sek_flag = 1 Then
If Sekunden < 59 Then
Sekunden = Sekunden + 1
Else
Sekunden = 0
Minuten = Minuten + 1
End If

If Minuten >= 59 Then
Minuten = 0
Stunden = Stunden + 1
End If

If Stunden > 12 Then
Stunden = 1
Minuten = 0
End If
Sek_flag = 0
End If

'Arrayposition berechnen Bsp: Minuten = 3 ===> Arrayposition 1 muss ausgegeben werden
Minpos = Minuten / 5
Minpos = Minpos + 1


'Überprüfen ob die Stunde + 1 ausgegeben werden muss. Bsp: 05:31 ===> Halb Sechs
Stdpos = Stunden
If Minuten >= 5 Then
Stdpos = Stdpos + 1
End If

'Stundenarray an der Position "Stunden" in die Schieberegister takten
For I = 0 To 15 Step 1
Datasr = Stundenarray(Stunden).I
Toggle Sck
Toggle Sck
Next A

'Minutenarray an der Position "Minpos" in die Schieberegister takten
For I = 0 To 7 Step 1
Datasr = Minutenarray(Minpos).I
Sck = 1
Sck = 0
Next A

'Latch der Schieberegister auf Ausgänge schalten
Rck = 1
Rck = 0


'In Idle Mode wechseln zum strom sparen und um unnötiges beschreiben der Schieberegister
'zu vermeiden. Geweckt wird im Sekundentakt des Timers.
'POWER IDLE

Loop
End




'Interrupt Routine für den Timer1. Läuft Sekündlich über.
Sekundentakt:
Timer1 = 34285
Toggle Led
Sek_flag = 1
Return

stefan_Z
04.01.2011, 01:00
LED auch mit dem Flag machen im Main-Loop (wird aber nicht viel helfen :-) )...

Ansonsten bau halt ne Terminal-Ausgabe fürs Debugging ein.

oZe
04.01.2011, 11:16
Ja das ist wohl ehr unwahrscheinlich das das was bringt. Ich hab noch eine vermutung:
Kann es sein das es daran liegt, dass ich momentan den internen RC Oszillator benutze und trotzdem an XTAL ein 8MHz Quarz hängt und das mir da irgendwie zwischen funkt? Ich kann momentan das externe Quarz nicht aktivieren weil mein Programmer kein Quarz hat und ich somit nicht mehr programmieren könnte nach dem umfusen. Ich hab in meiner Werkstatt aber noch nen anderen ISP liegen mti Quarz. Den werd ich wohl mal holen und dann umfusen auf externen Takt.

Hat sonst noch einer eine Idee woran diese Taktaussetzer liegen könnten? Die Uhr lief jetzt 7 Stundne über nacht und ich hab schon eine Abweichung von mehr als 5 Minuten...

stefan_Z
04.01.2011, 16:14
Ich wundere mich grad im Nachhinein, wieso du nicht einfach nen Uhrenquarz und die eingebaute Uhrenroutinen nutzt :-)

Deine Abweichung liegt so bei 2% wenn ich richtig gerechnet habe...
Das ist garnicht mal soo ungenau, der interne R-Oszi kann mehr :-)

oZe
04.01.2011, 16:18
Ja Uhrenquarz... Das hätte ich selbstverständlich benutzen können aber später ist man immer schlauer ^^
Kanns also sein das die abweichung wirklich am RC Oszillator liegt? Naja ist ja sowieso spekulation. Ich werds einfach mal testen mit Quarz.
Danke!

stefan_Z
04.01.2011, 16:46
Der interne is auf jeden fall recht ungenau, ja.
Man kann den aber auch noch irgendwie kallibrieren - musste mal googeln.

oZe
04.01.2011, 19:33
So!
Ich hab jetzt mal das externe Quarz aktiviert und siehe da: Die Uhr läuft bisher sehr genau. Mal sehen wies morgen früh aussieht!
Ich hätte nicht gedacht das der interne Oszillator SO ungenau ist aber aus Fehlern wird man ja bekanntlich schlau.
Jetzt hab ich noch eine winzig kleine Frage: Der Timer muss ja vorgeladen werden um genau eine Sekunde zu realisieren. Hierbei sagt RN Wissen das der korrekte Wert 34285 bei einem Prescaler von 256 ist. Ich hab jetzt allerdings noch ein Berechnungstool aus irgend einem Forum runtergeladen und da unterscheidet sich der Wert um 1 (34286).
Was ist jetzt richtig und was falsch? Ich denke das der unterschied wirklich fast nichts ausmacht aber so eine Uhr läuft ja nicht nur eine Woche sondern wohl ehr ein Jahr da wird sich der unterschied schon bermerkbar machen fürchte ich.

Um zu einem Abschluss zu kommen: Danke Stefan für deine wirklich sehr gute Hilfe! Das Problem mit der teilweise hängenden Status LED habe ich gelöst bekommen indem ich auch das LED Toggeln in die Main Loop gepackt habe auch wenn ich mir nciht im geringsten erklären kann warum das was gebracht hat ^^