Hallo, ich brauch mal eure Hilfe
Ich habe vor eine Stoppuhr zu bauen. Dazu hab ich mir eine Platine
gemacht, die den LCD Bildschirm EA W204-BNLED mit dem Atmega 8
verbindet.
Über PC5,4,3,2 sollen Taster angeschlossen werden. Um die Zeit zu sarten
und um 2 zeiten zu stoppen können. Der 4 Taster dient dem Reset.
Wollte es erst über den Timer 2 machen. aber da springen die Zeiten
irgendiwe.
Dann habe ich mir einen Uhrenquarz bestellt. Damit kriege ich es aber
acuuh nicht hin.
Also... nen bissel Code mußte schon selber machen. Hier gibt's nur Hilfe
zur Selbsthilfe. Zeig deinen Timer-Code und wir sehen uns an warum der
Timer, nunja, "springt".
Eine gescheite Stoppuhr ist für jemanand mit wenig Programmiererfahrung
schon recht sportlich.
Wie läft das Display? über Serielle Schnittstelle oder über Protokoll
und SPI/I2C? Das Display ist nochmal ne Baustelle für sich.
1. Du läßt im Interrupt nen Timer laufen (Start ab dem ersten
Flankenwechsel. Zum Ausschalten nimmste ja nen anderen Taster. Da
brauchste auch nix entprellen. Gar nix. Dann zählste einfach in einer
Interrupt-Routine die Timer-überläufe, liest sie in der Hauptschleife
aus und rechnest sie in Sekunden, Minuten etc um.
2. Du mißt mit der Compare-Capture Einheit des Timers. Das erfordert
aber schon ein bissel Hirnschmalz und vor allen Dingen Lesen des
Datenblatts. Der Vorteil hiervon ist daß du sehr kurze Zeitabstände
erfassen kannst (z.B. Pulsbreitenerkennung eines Modellbau-Servos).
den Uhrenquarz hast Du wo angeschlossen??
$crystal = 3686400
Das ist der Controllertakt
Das hier ist dann wenn der Uhrenquarz richtig angeschlossen ist und
richtig konfiguriert eine Subroutine der Timerinterruptroutine ...
Sectic:
Locate 1 , 1
Lcd I
Return
LCD-Kommandos haben nichts(!) in Interrupts verloren, die dauern ewig in
der Abarbeitung und der Controller hängt derweil im Interrupt fest, neue
Interrupts werden glattweg ignoriert.
> Config Clock = Soft> Enable Interrupts> Time$ = "0:00:00"
Und die Sache mit der eingebauten Uhr - die vergisst du am besten gleich
wieder. Die bringt dich hier nicht weiter.
Das Programmierer-Leben ist nun mal kein Ponyhof. In den meisten Fällen
muss man als Programmierer selber ran und sich um die Logik kümmern. Die
Logik, wie eine Uhr weitergeschaltet wird, ist ja nun wirklich keine
Raketentechnik.
Karl Heinz Buchegger schrieb:>> Config Clock = Soft>> Enable Interrupts>> Time$ = "0:00:00">> Und die Sache mit der eingebauten Uhr - die vergisst du am besten gleich> wieder. Die bringt dich hier nicht weiter.> Das Programmierer-Leben ist nun mal kein Ponyhof. In den meisten Fällen> muss man als Programmierer selber ran und sich um die Logik kümmern. Die> Logik, wie eine Uhr weitergeschaltet wird, ist ja nun wirklich keine> Raketentechnik.
na, na, die Bascomroutinen für die Uhr gehen schon, kein Grund da zum
hauen ... es fehlen einfach noch n paar Grundlagen.
$regfile = "m8def.dat"
'$crystal = 1000000
$crystal = 3686400
'Einstellungen für Lcd Display
'-------------------------
Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 ,
Db7 = Portd.7 , E = Portd.3 , Rs = Portd.2
Config Lcd = 20 * 4
Cls
Cursor Off
'Deklaration für Uhr'
Config Clock = Soft
Enable Interrupts
Time$ = "0:00:00"
Config Pinc.5 = Input
Config Pinc.4 = Input
Config Pinc.3 = Input
Portc.5 = 1 ' pullups einschalten
Portc.4 = 1 ' pullups einschalten
Portc.3 = 1 ' pullups einschalten
Dim I As Integer
dim Redraw_flag as byte
Redrawflag = 0
I = 0
Do
if Redraw_flag = 1 then
Redraw_flag = 0
Locate 1 , 1
Lcd "Boot 1: " ; Time$
Locate 2 , 1
Lcd "Boot 2: " ; Time$
Locate 3 , 1
Lcd I
endif
Loop
End
Sectic:
Redraw_flag = 1
Return
Die Uhr wird dennoch springen, weil die LCD-Ausgabe einfach bremst, aber
es geht kein Zähler verloren
Fhutdhb Ufzjjuz schrieb:> na, na, die Bascomroutinen für die Uhr gehen schon,
Das Ziel ist aber eine Stoppuhr mit 2 voneinander getrennten 'Kanälen'.
Da kommst du mit dem hier
Do
if Redraw_flag = 1 then
Redraw_flag = 0
Locate 1 , 1
Lcd "Boot 1: " ; Time$
Locate 2 , 1
Lcd "Boot 2: " ; Time$
Locate 3 , 1
Lcd I
endif
nicht wirklich weiter. Oder willst du ständig Strings durch die Gegend
kopieren, wenn der Taster betätigt wird?
(Und da der Appetit bekanntlich mit dem Essen kommt: Zum Berechnen der
Differenzzeit wandelst du dann den String wieder in Zahlen zurück?)
Das bischen Arbeit in einer ISR, die vom Timer alle x Zeiteinheiten
(muss ja nicht ganze Sekunden sein) angestossen wird, ist nun wirklich
nichts was einen groß umbringt. Dafür hat man dann aber auch alles unter
Kontrolle. Der Knackpunkt ist der Timer - da wie dort.
(Und ein paar Basistechniken zu kennen schadet nicht. Das nächste mal
macht er eine Eieruhr, die runterzählt und steht dann erst recht wieder
da, wie der Ochs vorm Tor)
Ja, da hast Du Recht, Strings hin und her schubsen ist nicht
zielführend, er hat ja die Variable I, deren Verarbeitung noch aussteht
... die zwei Zeilen Time$ sind sowieso identisch, auch da hat er noch ne
Baustelle.
Die Tastenverarbeitung kommt auch noch dazu ... er steht halt noch am
Anfang des Lernprozesses.
Auch Du wirst irgendwann angefangen haben und wenn Du Dir heute Deine
Erstlingswerke ansiehst wird Dich auch das kalte Grausen packen, oder?
Mir zumindest gehts so :o)
Mir ging es zunächst darum die "Handbremse" LCD aus der ISR raus zu
bekommen und den Grund dafür zu verdeutlichen.
Fhutdhb Ufzjjuz schrieb:> Die Tastenverarbeitung kommt auch noch dazu ... er steht halt noch am> Anfang des Lernprozesses.
Das ist schon klar.
> Auch Du wirst irgendwann angefangen haben und wenn Du Dir heute Deine> Erstlingswerke ansiehst wird Dich auch das kalte Grausen packen, oder?
Oooooohhhh ja. :-)
> Mir ging es zunächst darum die "Handbremse" LCD aus der ISR raus zu> bekommen und den Grund dafür zu verdeutlichen.
Und das hast du sehr gut gemacht.
(Obwohl, wenn es bei 2 Texten alle 1 Sekunde ausgeben, an der Ausgabe
hackelt, dann ist noch was faul :-)
Vor-Stopper schrieb:> Wie läft das Display? über Serielle Schnittstelle oder über Protokoll> und SPI/I2C? Das Display ist nochmal ne Baustelle für sich.
Also das Display habe ich versucht so ähnlich wie das Display vom MyAVR
LCD v2.5 anzuschließen. Siehe auch Dateianhang.
Was ist denn nun besser? Wenn ich einen Uhrenquarz nehme, mit dem
internen 1MHz quarz arbeite und den Uhrenquarz für die $Time-Funktion
ohne Kondensatoren an den Eingängen des normalen Quarz nutze oder wenn
ich einen normalen Quarz nehme und es über die Timerfunktion mache?
Karl Heinz Buchegger schrieb:> Das Ziel ist aber eine Stoppuhr mit 2 voneinander getrennten 'Kanälen'.
Naja ich möchte beide Zeiten mit einem Notausknopf beim runterdrücken
starten. Resettet werden sollen die Zeiten wenn ich ihn wieder hoch
ziehe. Und dann habe ich am liebsten noch einen Taster. Wenn ich den
taster das erste mal drücke soll zeit 1 stehen bleiben (bzw. die zeit
weiterzählen und sich die erste zeile nichtmehr verändern) und beim 2.
drücken auf den taster soll zeit 2 stehen bleiben.
Hi
>Also das Display habe ich versucht so ähnlich wie das Display vom MyAVR>LCD v2.5 anzuschließen. Siehe auch Dateianhang.
Die können anscheinend auch keine Datenblätter lesen. DB0...3 vom
Display gehören nicht an GND. Die Pins haben interne
Pull-Up-Widerstände.
MfG Spess
funktioniert mit meinem myavr mk2 board ganz gut, aber die zeiten laufen
irgendwie in einer anderen geschwindigkeit als gedacht. Da hatte ich
dann den Crystal 3,6864 verwendet und die intervalle zum hochzählen
entsprechend eingestellt
spess53 schrieb:> Die können anscheinend auch keine Datenblätter lesen. DB0...3 vom> Display gehören nicht an GND. Die Pins haben interne> Pull-Up-Widerstände.
Stimmt hatte die Schaltung von dem 16x2 Display übernommen. Hab mit dem
falschen Datenblatt verglichen. Hab mir jetzt mal das richtige genommen.
Dann muss ich ja anscheinend meine Platine nochmal neu machen
Hi
>Dann muss ich ja anscheinend meine Platine nochmal neu machen
Na ja, da RW fest auf Masse liegt passiert da außer etwas mehr
Stromverbrauch nichts ernsthaftes.
MfG Spess
Silvio Franz schrieb:> funktioniert mit meinem myavr mk2 board ganz gut, aber die zeiten laufen> irgendwie in einer anderen geschwindigkeit als gedacht. Da hatte ich> dann den Crystal 3,6864 verwendet und die intervalle zum hochzählen> entsprechend eingestellt
Wenn du dich hier nicht verrechnet hast
Config Timer1 = Timer , Prescale = 64
Const Timervorgabe = 40536
(ich hab jetzt nicht nachgerechnet), dann stimmt in so einem Fall die
CRYSTAL Angabe nicht.
Beachte: Du kannst in Crystal reinschreiben was immer du willst. Nur
weil du da eine Zahl reinschreibst, heist das noch lange nicht, dass der
µC auch mit dieser Frequenz läuft.
Genau dasselbe mit dem Quarz. Nur weil du einen Quarz physisch an den µC
angeschlossen hast, heist das noch lange nicht, dass der auch benutzt
wird. Du musst mittels der Fuse-Bits den AVR auch umstellen, so dass der
Quarz auch tatsächlich benutzt wird. Wenn du das nicht tust, dann läuft
der µC nachwievor auf den internen 1Mhz, so wie im Auslieferungszustand.
Rechnest du dann mit 3.4Mhz ist klar, dass deine Zeiten hinten und vorne
nicht stimmen.
Habe die Fusebits auf externen Quarz umgestellt.
Aber die Fusebitsvon meinem MK2 Board kopiert
Wichtig wäre mir jetzt erstmal ob ich die Datenleitungen 0 bis 7 an PD0
bis PD7 vom Atmega anschließn soll oder nicht
Silvio Franz schrieb:> Wichtig wäre mir jetzt erstmal ob ich die Datenleitungen 0 bis 7 an PD0> bis PD7 vom Atmega anschließn soll oder nicht
Du kannst. Musst aber nicht.
Diese LCD kann man in 2 MOdi betreiben.
4-Bit Modus und 8-Bit Modus.
8-Bit Modus: die volle Breitseite D0 bis D7 wird angeschlossen
4-Bit MOdus: nur D4 bis D7 werden angeschlossen, D0 bis D3 bleiben frei.
In der Theorie ist der 8Bit Modus natürlich schneller. In der Praxis
spielts aber keine wirkliche Rolle. Dafür spart man im 4Bit Modus an
Leitungen und belegt mit den kompletten LCD Leitungen nur einen einzige
Port (und den nicht zur Gänze)
> Was ist denn nun besser? Wenn ich einen Uhrenquarz nehme, mit dem> internen 1MHz quarz arbeite
den gibt es nicht.
Die internen 1Mhz werden von einem RC-Schwingkreis erzeugt. Die sind
ungefähr so konstant, wie der Wasserstand in der Donau.
> und den Uhrenquarz für die $Time-Funktion
Uhrenquarz kann man nehmen.
> ich einen normalen Quarz nehme und es über die Timerfunktion mache?
Das wäre das, wie ich es machen würde.
Damit stehen mir alle Möglichkeiten offen.
Ich brauch nicht noch eine Zusatzbeschaltung und mit einem Timer im CTC
Modus und Weiterzählung in einer ISR erreicht man mit wenig
Softwareaufwand eine genau gehende Uhr, die dann auch Zehntel oder
Hunderstelsekunden macht. Und der Abgleich (den man auch bei einem
Uhrenquarz machen muss!) ist nicht das große Problem, solange es nur um
einen Kurzzeittimer geht. Wenn die Uhr in einem Jahr Laufzeit möglichst
geringe Abweichung haben soll, dann sieht die Sache anders aus, dann
zählt die exakte Kentniss der genauen Schwingfrequenz. Aber bei
Zeiträumen von ein paar Minuten/STunden kann man das meist ignorieren,
dass ein 4.000 Mhz Quarz eben nicht exakt 4000000 Schwingungen in der
Sekunde macht, sondern 58 mehr oder weniger.
So wie Du hier die Subroutinen einbindest brauchst Du das Declare nicht.
wie passt das:
Config Pind.2 = Input
Config Pind.3 = Input
....
zu dem?
Config Portd.2 = 0
Config Portd.3 = 0
Die Configs sind fürs Data Direction Register, hier passt das zufällig
mit der 0 und dem Input ... das zweite mal Config also weglassen.
dann hier:
Debounce Pind.2 , 0 , Start1 , Sub
Debounce Pind.3 , 0 , Stop1 , Sub
Debounce Pind.2 , 0 , Reset1 , Sub
Debounce Pind.3 , 0 , Reset1 , Sub
Du drückst also den Taster D.2 für Start, da enablest Du den Timer, und
gleich danach wird Reset1 ausgeführt, der disabled und noch dazu n "wait
1" dabei hat.
Dein LCD wird bei jedem Durchlauf der Mainloop überschrieben, was extrem
Zeitaufwändig ist, also da bessser auf Refreshflag gehen zur
Aktualisierung.
Wenn Du Start drückst, dann macht es Sinn, den Timer auf den Startwert
zu setzen, damit der nicht irgendwo schon hoch steht und die erste
zehntel zu kurz wird.
für Zehntel hab ich heraus bei $crystal = 3686400:
Config Timer1 = Timer, Prescale = 8
Timervorgabe = 19456
ach so, eins noch, Bascom hat den wunderbaren Befehl "Alias", den
verwende ich persönlich sehr gerne.
Man kann da definieren wie z.B. n Taster heißt und den Namen dann im
Code beliebig verwenden.
Also in dem Fall:
Taster_start Alias Pind.2
Taster_stop Alias Pind.3
Config Taster_start = Input
Config Taster_stop = Input
Debounce Taster_start , 0 , Start1 , Sub
Debounce Taster_stop , 0 , Stop1 , Sub
ist eine Frage des persönlichen Geschmacks, hat aber auch praktische
Gesichtspunte. Will man nen Code von einem µC zum anderen portieren,
wenn Dir z.B. für die Funktion n ATTiny2313 reichen sollte, kann man
einfach einmal die Aliaszuordnung ändern und die Änderung geht auf den
ganzen Code über.
Silvio Franz schrieb:> Dann muss ich ja anscheinend meine Platine nochmal neu machen
nee, mit Teppichmesser die Leiterbahn auftrennen oder pins mit
Seitenschneider kappen und D0 bis D3 floaten lassen. passt.
ist gängige Methode beim "rework"
Fhutdhb Ufzjjuz schrieb:> Silvio Franz schrieb:>> Dann muss ich ja anscheinend meine Platine nochmal neu machen>> nee, mit Teppichmesser die Leiterbahn auftrennen oder pins mit> Seitenschneider kappen und D0 bis D3 floaten lassen. passt.>> ist gängige Methode beim "rework"
Yup
Und Silvio. Wart jetzt erst mal ab, was sonst noch so alles auftaucht.
Mit Teppichmesser, etwas dünnem Draht und einem Lötkolben, kann man so
manche Falschverdrahtung oder Umverdrahtung vornehmen, ohne gleich
jedesmal eine neue Platine machen zu müssen. Nenn die jetzige einfach
Version 0.9. Wichtig: Jede Änderung an der Platine gleich im
Platinen_layout_Programm nachziehen, sonst vergisst man sie.
Und wenn dann alles fertig ist, das Programm zur Zufriedenheit läuft,
alle Hardwaremacken zunächst provisorisch mit Messer und Kabel gefixt
wurden, erst dann ist es Zeit die Version 1.0 der Platine zu machen. (So
man dann noch Lust dazu hat. Es ist gar nicht so ungewöhnlich, dass man
dann sagt: Ah, geh. Ob da jetzt ein paar dünne Kabel aus Fädeldraht an
der Platine sind oder nicht, ist doch nur ein optisches 'Problem'. Passt
schon. Gehäuse her, Platine rein, keiner siehts mehr und mich störts
nicht)
Na war nicht so tragisch. habe ja erstmal ne lochrasterplatine gemacht.
So also Display geht jetzt erstmal. Hab die 4 Bitvariante gemacht.
Es zeigt mir bei folgendem Code aber immer Fragezeichen, Slasch und Os
an. Hab meinen Crsytal auf 3686400 gestellt und die Fusebits gesetzt.
Weiß nicht genau warum. Wenn er mir dann die richtigen Zeichen anzeigt
mach ich mit der uhr weiter
Code von Programm wo er Fragezeichen anzeigt
Silvio Franz schrieb:> Es zeigt mir bei folgendem Code aber immer Fragezeichen, Slasch und Os> an. Hab meinen Crsytal auf 3686400 gestellt und die Fusebits gesetzt.>> Weiß nicht genau warum.
Systematisch vorgehen:
alles aus dem Programm raus, was nicht unmittelbar mit dem Problem 'LCD'
zu tun hat
Auf dem LCD einen Teststring ausgeben, der es einem auch ermöglicht
mögliche systematische Fehler in der Verkabelung zu erkennen
Was wird angezeigt, welche Zeichen?
Wie lautet der ASCII Code dieser Zeichen? Am besten bitweise aufmalen.
Daneben gegenüberstellen die ASCII Codes von A B C D etc. aufschreiben.
Ebenfalls binär. Gibt es Auffälligkeiten, wie zb das bestimmte, immer
gleiche Bits vertauscht sind?
Wenn ja: Dann hast du dich einfach bei deiner Verkabelung verhaut und zb
2 Kabel gekreuzt, was nicht hätte sein sollen.
(Und darum ist Flachbandkabel so einer Einzelverdrahtung immer
überlegen. Damit ist es deutlich schwieriger, nur 2 Drähte zu
vertauschen. Entweder das Kabel ist um 180 verdreht drauf und alles ist
falsch oder alles ist richtig, wenn die Lötpads auf den Platinen in der
richtigen Reihenfolge sind.)
Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 ,
Db7 = Portd.7 , E = Portd.2 , Rs = Portd.3
Config Pind.2 = Input
Config Pind.3 = Input
Portd.2 = 1
Portd.3 = 1
D.2 und D.3 hast Du schonmal mit Deinen Tastern ... soll das so sein?
... eher nicht, oder?
ach so, hinter dem config lcdpin kannst Du noch n Initlcd setzen zur
Sicherheit.
In meinem Testprogramm hatte ich ja noch keine Schalter drin und das
mit dem Teststring und ausrechnen welches Kabel vll vertauscht ist mache
ich noch.
Ma cystall oder der Baudrate kann es aber nicht liegen oder?
Wenn ich bei meiner Bluetoothverbindung die Bausrate falsch einstelle
kommt auch so ein unsinn raus.
Wie macht bascom das eigendlich wenn ich ein String von drei zeichen
sende, sendet der dann bei ABC
65,66,67
oder macht er die Zeichenlänge voll
also 65,66,67,32,32,32,32,32,32...?
Silvio Franz schrieb:> Ma cystall oder der Baudrate kann es aber nicht liegen oder?
Dann würdest du das LCD gar nicht initialisiert bekommen. Aus der
Tatsache, dass das LCD überhaupt was anzeigt, kann man schliessen, dass
da schon einiges richtig sein muss. Unter anderem ist das Timing schon
mal so falsch nicht.
> Wie macht bascom das eigendlich wenn ich ein String von drei zeichen> sende, sendet der dann bei ABC> 65,66,67
Wenn du "ABC" ans Display gibst, dann kriegt das Display auch A B C und
sonst nichts. Wenn du ABC und 3 Leerzeichen willst, dann musst du eben
"ABC " ausgeben lassen.
> oder macht er die Zeichenlänge voll> also 65,66,67,32,32,32,32,32,32...?
Warum soll er das tun?
Das ergibt doch keinen Sinn. Damit würde sich jegliche Technik des "Ich
schreib aufs LCD nur die Dinge die sich geändert haben" von selbst
verbieten.
Also Programm läuft schon ganz gut.
Habe einen Schalter zum Stopuhr anschalten und resetten
und einen Taster zum Zeiten anhalten
Taster 1x betätigt zeit 1 bleibt stehen
Taster noch 1x betätigt zeit 2 bleibt stehen
Jetzt soll er mir die Differenzeit in Zeile 4 anzeigen
Aber dabei kommt nur murks raus
Irgendwie kann Bascom nicht vernünftig rechnen
Oder ich bin zu doof daür
Könnt ihr nochmal über den Code gucken?
Und einen richtigen Startwert für die Uhr brauche ich noch
Also Taster funktionieren jetzt auch
Nur noch 2 Probleme
Differenzeit geht nicht
Zeit nicht richtig
Ich habe einen Startwert von 19456 bei Timer 1
Die Uhr zeigt nach einer reellen Minute aber erst ca. 45s an
Einer eine Idee?
es müssten genau gesagt 42,2 Sekunden sein :o)
weil?? ... ja, der Timer eben nicht nach Überlauf auf die Vorgabe neu
gesetzt wird in der ISR ;o)
probiers mal so:
Timer1_isr:
Timer1 = Timervorgabe
If Zehntelsekunden < 9 Then
Zehntelsekunden = Zehntelsekunden + 1
Else
Zehntelsekunden = 0
If Sekunden < 59 Then
Sekunden = Sekunden + 1
Else
Sekunden = 0
Minuten = Minuten + 1
End If
End If
Return
Das bedeutet, der Timer Overflow wird jedes mal ausgelöst wenn der Timer
65535 erreicht, aber was macht er dann?? Er zählt wieder von 0 los, bis
wieder die 65535, es sei denn, er wird auf nen anderen Wert gesetzt,
dann zählt er von diesem los.
Fhutdhb Ufzjjuz schrieb:> es müssten genau gesagt 42,2 Sekunden sein
Danke, da hast du recht
Habe ich nur noch das Problem, dass bei der Zeitdifferenz irgendwas
total verbockt ist