Ich bräuchte mal wieder guten Tipps für mein nächstes Projekt.
Ich habe soweit meine Uhr mit Alarm hinbekommen und das zweite Projekt
RGB PWM ist auch bereits fertig und funktioniert.
Ich habe jetzt folgendes vor :
Ich habe einen PANASONIC Drehenkoder mit Schalter vom Pollin.
Eine Bespielbeschaltung habe ich auch fertig, sowie ein Beispielcode.
Nun zu meiner Frage. Wie sollte ich folgendes am besten umsetzen ?
Ich möchte mit dem Encoder Uhrzeit und Alarmzeit einstellen.
Den Taster würde ich an IntO anschliessen also in den Sub springen und
dort die Variablen Incr und Decr...würde sowas gehen ?
Eure Tipps waren immer gut, bevor ich festelle, daß mein Code so nicht
funzen kann...
Schnipsel :
///////////////////////////////
Config Int0 = Low Level
On Int0 Schalter
Enable Int0
Do
Uhr funktion und LCD Steuerung
loop
Schalter:
Drehenkoder auslesen
Return
Nein, das brauchst Du nicht extra anzugeben, weil die Portpins, an denen
der Enkoder dran sitzt, Bestandteil des Encoder-Befehls sind.
Zitat aus der Bascom Hilfe:
Var = ENCODER( pin1, pin2, LeftLabel, RightLabel , wait)
MfG Paul
Oder einfach mal ins Datenblatt dieses Drehgebers schaun und
feststellen, dass die Rastung genau auf die Flanke der Spur B fällt.
Dadurch ist nicht jeder Abfragealgorithmus geeignet.
Wenn man auf Flanke von Spur A prüft und zu diesem Zeitpunkt den Zustand
von Spur B liest, gibt es keine Probleme.
MfG
Datenblatt habe ich al erstes angeschaut, so habe ich die Beschaltung
vorgenommen. Codeschnipsel für den Encoder habe ich auch gefunden.
Hmm mir ist der Programmstruktur noch nicht ganz klar wie ich mit dem
Drehgeber meine Uhr / Alarm Projekt erweitern kann. Also mit dem Taster
möchte ich Subs realisieren wie die Parameter ( Stunde/Min und Alarm
Stunde und Minute) einstellen kann
Meine Idee ist, daß der Taster an den Eingang Int0 angeschlossen werden
sollte, damit beim Drücken ein Interrupt ausgelöst wird und sofort in
den Sub gesprungen wird. Ausserdem denke ich, muss ich den Taster mit
debounce Befehl abfragen..bei jedem Tastendruck muss eine Variable
hochgezählt werden. Wenn der Variable 1 ist dann springt man in den Sub
Uhr einstellen, wenn Variable ist 2 dann in den Alarmeinstellen Modus
wenn Variable ist grösser als 2 dann wieder zurück.
Problematisch wird, weil der AVR keine Multitasking beherscht, daß in
der Zeit die Uhr nicht weiterläuft oder ?
Ich weiss also noch nicht ganz genau ob der Struktur so okay ist, bevor
ich anfange den Code einzutippen. Ich habe auch bereits bemerkt, wenn
der Struktur schlecht ist, daß die LCD Anzeige dann flattert...
Thomas Kiss schrieb:> Meine Idee ist, daß der Taster an den Eingang Int0 angeschlossen werden> sollte, damit beim Drücken ein Interrupt ausgelöst wird und sofort in> den Sub gesprungen wird.
Du solltest dir eines tief ins Gedächtnis eingraben.
Es gibt nur einen einzigen Grund, warum man Taster an einen Interrupt
anhängt: Wenn der Taster den µC aus dem Tiefschlaf aufwecken muss.
Abgesehen von diesem Fall, werden Taster niemals mit einem Interrupt
ausgewertet.
> Ausserdem denke ich, muss ich den Taster mit> debounce Befehl abfragen..bei jedem Tastendruck muss eine Variable> hochgezählt werden. Wenn der Variable 1 ist dann springt man in den Sub> Uhr einstellen, wenn Variable ist 2 dann in den Alarmeinstellen Modus> wenn Variable ist grösser als 2 dann wieder zurück.>> Problematisch wird, weil der AVR keine Multitasking beherscht, daß in> der Zeit die Uhr nicht weiterläuft oder ?
Die Uhr wird interruptgetrieben ständig weitergezählt. Die macht ihr
Ding im Hintergrund selber. Bei richtiger Programmierung musst du dich
nicht darum kümmern.
Hallo Karl-Heinz, denke erstmal für den Ratschlag ( ist immer willkommen
)
Ich habe mal in einem andren Forum sowas mal gelesen, daß der Taster vom
Drehgeber an Int0 angeschlossen war..also ist mal falsch.
Nun die Frage ist immerwieder "richtige" Programmierung, was wirklich
nicht einfach ist, aber viel Spass macht !!! vorallem wenn man hier auch
sehr gute Tipps bekommt und wenns gelingt es umzusetzen !!
Thomas Kiss schrieb:> Datenblatt habe ich al erstes angeschaut, so habe ich die Beschaltung> vorgenommen.
Ich vermute ein Missverständnis.
Dieser Drehgeber hat die Besonderheit, dass die Rastung ziemlich genau
auf die Flanke der Spur B fällt. Üblich (und auch sinnvoll) ist es, dass
die Rastung an der Stelle erfolgt, wo beide Spuren stabile Pegel
liefern, also zwischen die Rastungen.
> Codeschnipsel für den Encoder habe ich auch gefunden.
Funktioniert es? Ist der Code erwiterbar (multitaskingfähig)?
>> Hmm mir ist der Programmstruktur noch nicht ganz klar wie ich mit dem> Drehgeber meine Uhr / Alarm Projekt erweitern kann. Also mit dem Taster> möchte ich Subs realisieren wie die Parameter ( Stunde/Min und Alarm> Stunde und Minute) einstellen kann
Da sind verschiedene Konzepte denkbar.
Z.B.:
Man prüft bei jedem Dreh-Ereignis die Taste (Zustand) und entscheidet
anhand des Tastenzustandes, ob man den Wert (ungedrückte Taste) oder die
Parameternummer (gedrückte Taste) ändert. Dies erfordert aber Feedback,
z.B. per Text-LCD.
Oder:
Mittels Taster (natürlich entprellt) zappt man im Ring durch die
Parameternummern, mit dem Drehgeber stellt man die Parameter ein. Auch
dies erfordert Feedback.
>> Meine Idee ist, daß der Taster an den Eingang Int0 angeschlossen werden> sollte, damit beim Drücken ein Interrupt ausgelöst wird und sofort in> den Sub gesprungen wird.
Das ist keine gute Idee, denn ein Interrupt reagiert auch auf
Störimpulse kürzester Dauer, die bereits beim Betätigen von
Lichtschaltern auftreten können. Das Ding wird Dich dann nach Strich und
Faden verarschen.
> Ausserdem denke ich, muss ich den Taster mit> debounce Befehl abfragen..
Der Debounce-Befehl ist nicht multitaskingfähig, da er Wartezeit
benötigt, in der die CPU nichts Anderes machen kann, weil die Wartezeit
durch Takte Zählen realisiert wird. Da Du für die Uhr sowiso einen Timer
brauchst, solltest Du diesen für die Tastenabfrage (Entptellung)
mitbenutzen.
> bei jedem Tastendruck muss eine Variable> hochgezählt werden. Wenn der Variable 1 ist dann springt man in den Sub> Uhr einstellen, wenn Variable ist 2 dann in den Alarmeinstellen Modus> wenn Variable ist grösser als 2 dann wieder zurück.
Das wäre eine Lösung, wobei ich diese etwas feiner aufsplitten würde um
Sekunden, Minuten und Stunden separat einstellen zu können. Das schont
Drehgeber und Fingerspitzen. ^^
>> Problematisch wird, weil der AVR keine Multitasking beherscht, daß in> der Zeit die Uhr nicht weiterläuft oder ?
Wer sagt denn Sowas? Selbstverständlich beherrscht der AVR Multitasking.
Der Bremsklotz ist Bascom. Viele Bascom-Befehle verschwenden Rechenzeit,
indem sie warten. Wenn man diese Befehle meidet und die Arbeit "zu Fuß"
macht, kann man sehr wohl Multitasking-Programme schreiben. Aber dann
kann man auch gleich in ASM programmieren.
>> Ich weiss also noch nicht ganz genau ob der Struktur so okay ist, bevor> ich anfange den Code einzutippen. Ich habe auch bereits bemerkt, wenn> der Struktur schlecht ist, daß die LCD Anzeige dann flattert...
Das kommt meist dann, wenn man das LCD zu oft beschreibt und dabei auch
noch den ganzen Schirm löscht. Ich lösche ein LCD nur ein einziges mal,
nämlich direkt nach der Initialisierung. Danach werden immer nur die
Textstellen überschrieben, die neuen Text erhalten sollen. Soll Text
gelöscht werden, so wird er mit Leerzeichen überschrieben.
Kurzer Ansatz für Deine Uhr:
Timer auf Intervall von 1ms einrichten. Darin Drehgeber abfragen. Aber
nicht mit Debounce, sondern multitaskingfähig:
http://www.rn-wissen.de/index.php/Drehencoder#Hannes-Lux-Methode_als_Alternative_zum_ENCODER-Befehl
Mit einem Teiler (Zählvariable) jeden 20. Interrupt (also alle 20ms) den
Takt für die Tastenentprellung ableiten. In diesem mit einem weiteren
Teiler (1 zu 50) den Sekundentakt ableiten. LCD nur selektiv bedienen
(also nur das, was sich ändert) und auch nur dann, wenn sich etwas
ändert.
MfG
uhhh..Kluchscheisser, hast sehr viele Infos gegeben, was ich noch
verdauen muss...
Ich habe mich hier mal ein bisschen eingelesen :
http://comwebnet.weimars.net/forum/showthread.php?tid=40
"Da Du für die Uhr sowiso einen Timer
brauchst, solltest Du diesen für die Tastenabfrage (Entptellung)
mitbenutzen."
also mit waitms ?
"Wenn man diese Befehle meidet und die Arbeit "zu Fuß"
macht, kann man sehr wohl Multitasking-Programme schreiben. Aber dann
kann man auch gleich in ASM programmieren."
welche Bascom Befehle sollte man vermeiden ? ( wie Goto )
Was wäre ein Bsp. für zu Fuß ?
"Das kommt meist dann, wenn man das LCD zu oft beschreibt und dabei auch
noch den ganzen Schirm löscht. Ich lösche ein LCD nur ein einziges mal,
nämlich direkt nach der Initialisierung. Danach werden immer nur die
Textstellen überschrieben, die neuen Text erhalten sollen. Soll Text
gelöscht werden, so wird er mit Leerzeichen überschrieben."
Habe bereits bei meinem erstem Prog auch bemerkt und habe es auch
richtig gemacht ( Leerzeichen usw..die Uhr fuzt sehr gut )
ich werde die "Dannegger'sche Methode als Alternative zum
ENCODER-Befehl"
mal erstmal Probieren..
Thomas Kiss schrieb:> uhhh..Kluchscheisser, hast sehr viele Infos gegeben, was ich noch> verdauen muss...>>> Ich habe mich hier mal ein bisschen eingelesen :>> http://comwebnet.weimars.net/forum/showthread.php?tid=40>> "Da Du für die Uhr sowiso einen Timer> brauchst, solltest Du diesen für die Tastenabfrage (Entptellung)> mitbenutzen.">> also mit waitms ?
Das hatten wir doch letztes mal schon besprochen (oder nicht).
Du willst in deinem Programm niemals, unter gar keinen Umständen, auf
keinen Fall, auch nicht unter Androhung der Todesstrafe, auf irgendetwas
warten!
Erinnerst du dich:
Der Schlüssel um meherer Aufgaben mehr oder weniger gleichzeitig
abarbeiten zu können liegt
* im Verlassen der Denkweise "Da muss ich eine Schleife machen und
darauf warten, dass ..."
* es gibt nur eine einzige Schleife im Programm
* in dieser Schleife werden Ereignisse der Reihe nach abgeprüft
wenn das Ereignis eingetreten ist, dann wird dieses Ereignis
bearbeitet. Aber immer nur kurz! wenig Funktionalität!
Die Power entsteht dadurch, dass diese Ereignisprüfung viele
tausend mal in der Sekunde durchgeführt wird.
* Warten wird mit Computerentzug nicht unter 2 Wochen bestraft
(*) oder verwechsle ich dich jetzt mit einem anderen. Es ging damals um
ein RGB-Nachtlicht, welches auf Tastendruck Dimmsequenzen durchspielt.
> welche Bascom Befehle sollte man vermeiden ? ( wie Goto )
alles was mit warten zu tun hat.
debounce ist zb so ein Kandidat. Intern wartet der Befehl eine kurze
Zeit.
Und genau das will man manchmal nicht.
Bei einfachen Programmen ist das kein Problem. Sobald die Ansprüche aber
steigen, ist es vorbei mit simplen Einfach-Lösungen.
Karl-Heinz !!! Böse...
"Warten wird mit Computerentzug nicht unter 2 Wochen bestraft"
Dann werde ich in bereits 5 Jahren fertig....LoL
Ich baue sowieso das Programm komplett neu auf...erstmal mit dem Encoder
spielen...Dann muss ich überlegen wie eine "saubere" Menüsystem aussehen
könnte ..Uhr kann ich schon ( denke ich ) coden...
"Bei einfachen Programmen ist das kein Problem. Sobald die Ansprüche
aber
steigen, ist es vorbei mit simplen Einfach-Lösungen." Meine Projekte
sind noch "einfache" Programme..oder ?
Thomas Kiss schrieb:> steigen, ist es vorbei mit simplen Einfach-Lösungen." Meine Projekte> sind noch "einfache" Programme..oder ?
Sobald es darum geht, seine Fühler in mehrere unterschiedliche
Input-Kanäle zu stecken, beginnt es interessant zu werden :-)
Dann es darf kein Input an einem der Kanäle übersehen werden, weil
woanders gewartet wird. Etwas spielt hier für dich: Aus µC Sicht sind
Menschen langsam, unglaublich langsam. Das heißt, eine zeitlang kommt
man damit durch, dass der µC mal ein paar Millisekunden nicht auf einen
Input-Pin schaut. So schnell sind deine Finger nicht. Aber irgendwann
wird es dann auch zuviel und das Programm kriegt Änderungen an Input
Pins nicht mehr mit, weil woanders zuoft und zuviel gewartet wird.
Und dann fängt es an interessant zu werden.
Thomas Kiss schrieb:> http://comwebnet.weimars.net/forum/showthread.php?tid=40
Erwarte bitte nicht, dass ich das alles nachlese und bewerte.
> also mit waitms ?
Nööö, waitms ist tödlich für Multitasking. Der Timer gibt die Termine
vor, an denen bestimmte Aufgaben erledigt werden.
Beitrag "Re: Ein kleines Projekt für BASCOM Änfänger Vol2">> "Wenn man diese Befehle meidet und die Arbeit "zu Fuß"> macht, kann man sehr wohl Multitasking-Programme schreiben. Aber dann> kann man auch gleich in ASM programmieren.">> welche Bascom Befehle sollte man vermeiden ? ( wie Goto )
Goto ist erlaubt, wenn man die Regeln einhält, ist aber meist nicht
nötig. Zu meiden sind die Befehle, die Wartezeiten eingebaut haben.
>> Was wäre ein Bsp. für zu Fuß ?
Dass man den Debounce-Befehl meidet und eine saubere Tastenentprellung
in den Timer-Interrupt einbaut. Im Roboternetz gibt es eine
Bascom-Umsetzung der Dannegger-Bulletproof-Entprellung, einen Link habe
ich jetzt nicht parat, weil weder RN noch Bascom meine Spielwiese sind.
Oder dass man den Befehl getadc meidet und den ADC direkt (über seine
I/O-Register) bedient, denn Getadc stellt den ADC erst dann auf Referenz
und Eingang ein, wenn eigentlich schon das Ergebnis gebraucht wird. Der
AVR muss also in einer Warteschleife verharren (und kann nix Anderes
tun!) während der ADC im Hintergrund sein Messprogramm durchklappert.
Die Warteschleife wird erst dann beendet, wenn die Wandlung fertig ist.
Zu Fuß würde man im Vorfeld die Parameter einstellen (ADMUX) und den ADC
starten, dann zur Tagesordnung (Hauptschleife) zurückkehren und andere
Dinge erledigen. Und immer mal wieder (in der Hauptschleife oder im
Timer-Int. nebenher) den ADC fragen, ob er denn schon fertig ist. Ist er
es nicht, so gehts mit der Tagesordnung weiter, ist er fertig, wird das
Ergebnis ganz nebenbei "mitgenommen".
Man kann den ADC auch per Interrupt bedienen, das würde ich in Bascom
aber vermeiden, da Bascom bei Aufruf der ISR zu viel Rechenzeit
vertrödelt um auch die Register zu sichern, die gar nicht gebraucht
werden.
> Habe bereits bei meinem erstem Prog auch bemerkt und habe es auch> richtig gemacht ( Leerzeichen usw..die Uhr fuzt sehr gut )
Dabei aber bitte nicht vergessen, dass der LCD-Zugriff Wartezeiten
enthält. Also keine LCD-Zugriffe an zeitkritischen Programmstellen
ausführen. Man sollte also LCD-Zugriffe in ISRs vermeiden, aber auch in
Programmteilen, die sehr häufig aufgerufen werden.
>> ich werde die "Dannegger'sche Methode als Alternative zum> ENCODER-Befehl"> mal erstmal Probieren..
Die ist auf alle Fälle multitaskingfähig. Es kann aber durchaus sein,
dass Peters Routine mit diesem unüblichen Drehgeber Probleme bereitet.
MfG
Deshalb habe ich vor 2 oder 3 Monaten mit AVR begonnen und bin froh, daß
ich dieses Forum "gefunden" habe..umd muss echt sagen, einige Leute sind
super nett hier..!! und vorallem soviel nerven haben, wenn es quälend
ist, wenn man die "einfachste" Sachen nicht umsetzen kann...
Thomas Kiss schrieb:> Ich bräuchte mal wieder guten Tipps für mein nächstes Projekt.
Tip für den nächsten Thread: Wähle doch bitte mal einen sinnvollen
Titel! auch wenn es schwer fällt, das Forum ist keine
Fortsetzungsgeschichte mit ungewissem Ausgang...
Habe mal den Beispielcode vom Screwdriver angeschaut..
Frage 1.
Er definiert den Timer :
Config Timer0 = Timer , Prescale = 256
On Timer0 Isr_timer0
Enable Timer0
Const Timer0_reload = 224 'Wert für
1ms
Ich kenne es so :
Config Timer1 = Timer , Prescale = 256
Enable Timer1
On Timer1 Takt
Enable Interrupts
Timer1 = 3036
Bitte um "technische" Erklärung
sowie zu diesem :
Isr_timer0:
Timer0 = Timer0_reload
Und dies ist wirklich die Härte..ich glaube ich muss es noch nicht
verstehen...ich denke wenn ich 80% vom Code verstehe, darf ich copy
paste machen..LoL..und nicht alles "selber Erfinden" und funzt doch
nicht..
Thomas Kiss schrieb:> Habe mal den Beispielcode vom Screwdriver angeschaut..>> Frage 1.>> Er definiert den Timer :> Config Timer0 = Timer , Prescale = 256> On Timer0 Isr_timer0> Enable Timer0> Const Timer0_reload = 224 'Wert für> 1ms>> Ich kenne es so :> Config Timer1 = Timer , Prescale = 256> Enable Timer1> On Timer1 Takt> Enable Interrupts> Timer1 = 3036>> Bitte um "technische" Erklärung
Wirf Beides weg und mach' es zu Fuß.
Warum?
Bascom-Config-Anweisungen berücksichtigen nicht alle Möglichkeiten, die
die Timer bieten, denn die Timer der verschiedenen AVRs sind recht
unterschiedlich mit Features ausgestattet.
Deshalb:
Nimm das Datenblatt, suche Dir die Bits und Register zur Steuerung des
Timers zusammen und bearbeite diese direkt. Nur dann weißt Du, dass der
Timer auch das macht, was Du von ihm willst.
Da Du aufgrund der zeitverschwendenden Registersicherung in der ISR
möglichst nur einen Timer-Interrupt nutzen solltest, hast Du freie
Auswahl betreffs Timer. Da bietet sich Timer1 im CTC-Mode an, damit
entfällt sein Preload und es gibt auch kein Jitter.
Ziel ist es, in exakt gleichmäßigen Zeitabständen eine Routine (ISR)
aufzurufen. Das ist mit allen Timern auf verschiedene Art und Weise
möglich. Der Eine macht es so, der Andere macht es anders. Manchmal ist
eine bestimmte Vorgehensweise ungeeignet, meist ist es aber egal.
Hauptsache die ISR wird im exakt eingehaltenen Intervall aufgerufen.
Punkt.
>> sowie zu diesem :>> Isr_timer0:> Timer0 = Timer0_reload
Was sagt die Zeile aus?
Isr_timer0: sagt, dass es sich um den Überlauf-Interrupt-Handler
handelt.
Dem Register "Timer0" (heißt eigentlich tcnt0) wird der Wert der
Konstante (oder Variable) Timer0_reload zugewiesen. Mit anderen Worten:
Timer0 wird auf den Startwert gesetzt, der nötig ist, das gewünschte
Intervall bis zum nächsten Überlauf exakt zu erreichen.
>> Und dies ist wirklich die Härte..ich glaube ich muss es noch nicht> verstehen...
Dann schmeiß Bascom weg und lerne Assembler, dann lernst Du wenigstens
die Architektur des AVRs richtig kennen, da Du dann keine Blackboxen
mehr hast, die Dich mehr verarschen als sie Dir helfen.
> ich denke wenn ich 80% vom Code verstehe, darf ich copy> paste machen
Nein, man sollte seinen Quelltext vollständig verstehen. Ich nutze auch
Routinen, die ich nicht selbst erfunden habe, aber ich habe sie
(zumindest vor der Erstbenutzung) vollständig verstanden und bin daher
auch in der Lage, sie jederzeit an sich ändernde Bedürfnisse anzupassen.
> ..LoL..und nicht alles "selber Erfinden" und funzt doch> nicht..
Man muss nicht alles selber erfinden, aber man muss es verstehen um
selbstständig arbeiten zu können. Oder willst Du etwa ewig am Tropf
dieses Forums hängen und Dir jede Kleinigkeit ausführlich erklären
lassen?
MfG
Hallo Kluchscheisser ( Name - Respect )
Bin nicht so ganz einverstanden. Klar, ich merke, hast echt viel auf dem
Kasten, was Progs anbelangt.
Ich denke Screwriver oder der Peter, werden keine Codes veröffentlichen
die nicht sauber sind.
"Nimm das Datenblatt, suche Dir die Bits und Register zur Steuerung des
Timers zusammen und bearbeite diese direkt. Nur dann weißt Du, dass der
Timer auch das macht, was Du von ihm willst."
Ehrlichgesagt, habe schon angeschaut aber brachten die Sachen nicht
weiter, aus dem Grund, weil ich mich mit Bascom befreundet habe. Ich
möchte nicht NOCH in Asembler auch einzusteigen, fehlt mir die Zeit, bin
froh, daß ich mit Bascom schon soweit bin.
Die "einfache" Sachen die ich mir bauen wollte, habe mit Hilfe der Leute
hier auch so hinbekommen, daß sie mir reichen, klar es gibt immer eine
bessere Variante, ich betrachte die ganze Sache als Spass an der Freude,
und nicht als Profiwerk..
"Oder willst Du etwa ewig am Tropf
dieses Forums hängen und Dir jede Kleinigkeit ausführlich erklären
lassen?"...
Ich habe nicht den Eindruck gehabt, daß es hier Probleme mit sowas gibt.
Klar wenn die Leute sagen, "habe kein Bock mehr zu helfen" das ist was
anderes !!!
Du mußt, ob Du willst oder nicht diesen Ratschlag vom "klugscheißenden
Konsulter" annehmen:
Zitat:
>"Nimm das Datenblatt, suche Dir die Bits und Register zur Steuerung des>Timers zusammen und bearbeite diese direkt. Nur dann weißt Du, dass der>Timer auch das macht, was Du von ihm willst."
Grund: Mit dem Config-Befehl kommst Du zwar an einige der Möglichkeiten
der Timer heran, aber nicht an alle. Damit verbaut man sich Chancen, die
man mit viel Gewürge wieder ausbügeln muß. Glaube mir: Auch ich mußte
diese Erfahrung machen.
Eine Hilfe dabei sind die Abbildungen im Datenblatt, in denen man sehen
kann, welche Register und welche Bits darin für die jeweilige Funktion
gebraucht werden. Das bedeutet nicht, daß Du Assembler lernen sollst,
aber es ist beruhigend, wenn man weiß, daß z.B. der Timer genau das
macht,
was ich ihm gesagt habe und er mir nicht als Black-Box erscheint.
Gutes Gelingen wünscht Dir
Paul
Heisst es wirklich, daß man mit Bascom nur "so etwa" die Funktionen
realisieren kann ?
spannend finde ich, wenn es so wäre, und selbst bei so einem einfaches
Beispiel, Bascom nicht mehr aussreicht, warum denn so oft für grössere
Sachen auch Bascom verwendet wird. Mir persönlich ist Bascom was Code
lesen anbelangt ist viel einfacher als sowas hier...
http://www.mikrocontroller.net/attachment/61322/drehencoder.asm
Paul Baumann schrieb:> Eine Hilfe dabei sind die Abbildungen im Datenblatt, in denen man sehen> kann, welche Register und welche Bits darin für die jeweilige Funktion> gebraucht werden.
Eine andere Hilfe sind IMHO die Tutorien hier
AVR-TutorialAVR-GCC-Tutorial
Auch wenn sie für andere Programmiersprachen gemacht sind.
Denn: Das Prinzip ist in allen Fällen immer wieder das gleiche.
Ob ich jetzt
ldi tmp, 1<<TOIE0
out TIMSK, tmp
schreibe, oder
TIMSK = 1<<TOIE0
oder (keine Ahnung wie sich das in BASCOM schreibt, aber es wird sehr
ähnlich sein)
....
spielt keine Rolle. Denn der wichtige Teil ist: Da wird das Bit mit dem
Namen TOIE0 im Register TIMSK auf 1 gesetzt. Und das wiederrum schaltet
den Overflow Interrupt für den Timer 0 ein.
D.h. auch wenn man sich jetzt die Details der jeweiligen Implementierung
in den Foren nicht ansieht, so sind doch die erläuternden Texte
nützlich.
Und gerade Timer sind so eine Sache. Oft (manchmal) ist es so, dass man
durch Setzen von ein paar Konfigurationsbits, den Timer dazu bringen
kann, ganz in Hardware die tollsten Dinge zu machen. Man muss nur die
Bits kennen.
> Das bedeutet nicht, daß Du Assembler lernen sollst,> aber es ist beruhigend, wenn man weiß, daß z.B. der Timer genau das> macht,> was ich ihm gesagt habe und er mir nicht als Black-Box erscheint.
Genau.
Wenns beim Auto unten klappert und man sich kategorisch weigert, stehen
zu bleiben und einfach nur unten mal reinzusehen, dann wird man nie
feststellen, dass einem die Werkstatt einfach nur bescheisst wenn sie
einen neuen Auspuff einbaut und in Wirklichkeit sich nur die Wärmematte
im Auspufftunnel gelöst hat und mit 2 neuen Schrauben festgeschraubt
werden muss. Denn das erkennt man auch, wenn man kein Automechaniker
ist.
Thomas Kiss schrieb:> Hallo Kluchscheisser ( Name - Respect )
Neben den vielen kompetenten und hilfsbereiten Forianern gibt es hier
auch ein paar Dummschwätzer und Streithammel (meist im OT zu finden).
Denen will ich mit meinem Nick gelegentlich einen Spiegel vorhalten.
Nebeneffekt: In meinem Umfeld wird Fachsimpeln inzwischen Kluchscheißern
genannt. ^^
>> Bin nicht so ganz einverstanden. Klar, ich merke, hast echt viel auf dem> Kasten, was Progs anbelangt.
Nööö, Peter, Karl-Heinz und einige Andere können da bedeutend mehr.
>> Ich denke Screwriver oder der Peter, werden keine Codes veröffentlichen> die nicht sauber sind.
Peter kannte zum Zeitpunkt der Veröffentlichung seines Codes den
Panasonic-Drehgeber noch nicht und konnte sich (wie ich und viele Andere
auch) nicht vorstellen, dass man überhaupt auf die Idee kommen kann,
sowas herzustellen.
>> "Nimm das Datenblatt, suche Dir die Bits und Register zur Steuerung des> Timers zusammen und bearbeite diese direkt. Nur dann weißt Du, dass der> Timer auch das macht, was Du von ihm willst.">> Ehrlichgesagt, habe schon angeschaut aber brachten die Sachen nicht> weiter, aus dem Grund, weil ich mich mit Bascom befreundet habe.
Bascom ermöglicht zwar schnellen Erfolg bei kleinen einfachen Projekten,
geht aber sehr verschwenderisch mit Ressourcen um. Es ist sehr
schwierig, gut funktionierende ASM-Programme in Bascom umzusetzen. Ein
Großteil meiner Programme wäre in Bascom schlicht unmöglich. Selbst wenn
man sie in C notieren wollte, müsste man neben C auch ASM beherrschen.
> Ich> möchte nicht NOCH in Asembler auch einzusteigen, fehlt mir die Zeit, bin> froh, daß ich mit Bascom schon soweit bin.
Bascom ohne genaue Kenntnis der AVR-Architektur ist eine Sackgasse, aber
ich wünsche Dir trotzdem viel Erfolg.
>> Die "einfache" Sachen die ich mir bauen wollte, habe mit Hilfe der Leute> hier auch so hinbekommen, daß sie mir reichen, klar es gibt immer eine> bessere Variante, ich betrachte die ganze Sache als Spass an der Freude,> und nicht als Profiwerk..
Eben, Bascom verleitet zu uneffizienten Algorithmen. Hat man sich diese
erstmal angewöhnt, ist es fast unmöglich Multitasking zu programmieren.
Und etwas komplexere Programme sind nunmal ohne Multitasking nicht
zufriedenstellend machbar.
Wie willst Du z.B. eine Wecktonerzeugung (getaktetes Piepsen) in das
laufende Programm einfügen? Mit Schleifen wird es Dir nicht gelingen,
dass dabei die Zeit weiter läuft, die Bedienelemente weiterhin abgefragt
werden, das LCD weiterhin aktualisiert wird usw...
>>> "Oder willst Du etwa ewig am Tropf> dieses Forums hängen und Dir jede Kleinigkeit ausführlich erklären> lassen?"...>> Ich habe nicht den Eindruck gehabt, daß es hier Probleme mit sowas gibt.
Das kommt darauf an, welche Fragen gestellt werden und wie der
Lernerfolg ist. Bei absoluter Beratungsresistenz werden sich die
kompetenten Leute zurückziehen und das Feld für Anfänger mit Halbwissen
frei machen.
Vielleicht solltest Du erstmal die bisher gegebenen Ratschläge umsetzen
ehe Du weitere Fragen stellst. Du denkst immernoch in Schleifen, lerne
endlich in Zuständen und Ereignissen zu denken. Anders bekommst Du keine
Programme gebacken, bei denen (scheinbar) mehrere Dinge gleichzeitig
ablaufen.
> Klar wenn die Leute sagen, "habe kein Bock mehr zu helfen" das ist was> anderes !!!
Bei entsprechenden Fragen wird Dir immer geholfen werden. Es muss aber
zu erkennen sein, dass die bisherige Hilfe gefruchtet hat, Du also das
bisher Geschriebene berücksichtigt hast. Wenn aber immer wieder Fragen
kommen, die zeigen, dass das bisher Genannte nicht berücksichtigt wurde,
dann wird die Hilfe irgendwann weniger.
MfG
Hier mal als Hinweis, wie man ein bestimmtes Bit in einem Register
in Bascom "angreifen" kann:
Timsk.toie0 = 1
Bedeutung:
Name_des_Registers.Bit_in_diesem_Register = 1 (oder 0)
Ich weiß, das ist hartes Brot, die Bedeutung der Bits und der Register
aus dem Englischen in's Deutsche zu übersetzen, -man muß ein Wörterbuch
dazu haben. Mit der Zeit hat man aber die "Lieblingsregister" im Kopf
und dann geht es auch besser.
MfG Paul
Thomas Kiss schrieb:> Ich glaube ic werde es nie lernen (((( traurig...
Falsch...
Du wirst es vermutlich nicht so schnell lernen, wie Du es gerne hättest.
Denn es genügt nicht, ein paar Überschriften zu können und sich damit
durchzumogeln (wie in der Schule oder Lehre), sondern hier ist konkretes
Wissen erforderlich, das man nirgends kaufen kann, sondern das man sich
Schritt für Schritt erarbeiten muss. Ich habe es auch nicht in ein paar
Wochen oder Monaten gelernt und ich bin immer noch am Lernen. Es gibt
allerhand Dinge betreffs AVR-Programmierung, bei denen ich mich nicht
für kompetent halte. Aber da halte ich mich im Forum mit meiner Meinung
zurück.
Du wirst wohl Deine Projekte erstmal etwas zurückstellen müssen und Dich
auf das Abarbeiten von Tutorials beschränken. Denn nur so lernst Du "das
Alfabet". Es nützt Dir nichts, die Vokabeln einer Programmiersprache
auswendig zu können, aber keinen Plan zu haben, wie man soe logisch
vorteilhaft einsetzt, wie man die Befehle verknüpfen muss, um einen
bestimmten Effekt zu erreichen.
Du wirst Dich auch damit beschäftigen müssen, Quelltexte anderer Leute
unter die Lupe zu nehmen und zu analysieren. Dummerweise gibt es im Netz
nicht nur gut geeignete Quelltexte, sondern auch eine Menge Müll und
auch eine Menge hochoptimierten Code, den man nicht so ohne Weiteres
versteht. Ein Programmierer schreibt (und kommentiert) eben so, dass ER
es versteht und in der Lage ist, den Code zu warten bzw. anzupassen.
Übung macht den Mais-Teer, ohne Fleiß kein Preis. Oder wie Peter sagt:
Du kannst einen Berg nicht mit einem Schritt besteigen...
Wichtig ist, dass Du lernst, selbstständig zu lernen (das meinte ich mit
dem "Tropf"). Fast alle Deiner Fragen sind in diesem Forum schon zigmal
gestellt und ausführlich beantwortet worden. Du solltest Dir also ruhig
mal die Zeit nehmen, etwas mit der Suche zu spielen und die Treffer zu
lesen und zu verstehen. Und nicht gleich immer aufgeben so nach dem
Motto: Kenn'ich nicht, ess'ich nicht, weg hier... Oftmals hilft es auch,
mehrere Threads zu einem Suchbegriff zu lesen, denn manchmal versteht
man es besser, wenn es von verschiedenen Leuten formuliert wurde.
MfG
Mal eine kleine Zwischenfrage....
Habe mal gesehen, daß in Bascom eine Softclock Funktion gibt mit einem
Uhrenquarz. 32.xxxKhz...
Nun die Frage, was ist "besser" die Soflock Version benutzen oder die
Standard Variante, also 16Mhz Quarz, Timer, usw, also wie bisher.
Vorteile , Nachteile ?
Thomas Kiss schrieb:> Vorteile , Nachteile ?
Ich sach mal so:
Uhrenquarze werden in rauhen Mengen, extrem präzise, für nahezu
unendlich viele Uhren hergestellt. Der Uhrmacher muss nur noch die
letzten Feinheiten mit Ziehkondensatoren ausgleichen.
Dahingegen ist es in den meisten Anwendungen völlig unerheblich, ob ein
16Mhz Quarz exakt 16000000Hz hat oder doch um 200Hz mehr oder weniger
schwingt.
Reicht dir das als Denkanstoss?
Acha....also erstmal habe ich gelernt wie eine Uhr "zu Fuss" zu
programmieren ist, ( meine Uhr mit Alarm, funzt sehr gut und genau )
So könnte ich mir die Arbeit "sparen" und softclock nehmen. Die
Variablen
Hour,Min usw werden bereitgestellt, diese Werte könnte ich mit dem
Encoder auch ändern...
Eine saubere Sache ??? oder meinen die Lehrer daß ich erst anders machen
soll, nur als Übung ?
PS: Gestern habe ich erstmal eine kleine Platine basteln müssen...
Kluchscheißender Consulter schrieb:> Schritt für Schritt erarbeiten muss. Ich habe es auch nicht in ein paar> Wochen oder Monaten gelernt und ich bin immer noch am Lernen.
Ich hatte mal einen Auszubildenden.
Informatiker.
D.h. der hat bei 0 angefangen und sein Job bestand nur darin
Programmieren zu lernen um dann irgendwann in die Produktionsmanschaft
überzuwechseln. Andere Tätigkeiten wie Kabel konfektionieren, Rechner
aufsetzen etc. ging so nebenbei, je nachdem wie die Dinge angefallen
sind.
Meine Vorstellung war in etwa:
Das erste Jahr ist lernen angesagt. Üben. Techniken lernen. Algorithmen
studieren. Fundiertes Wissen über die Programmiersprache (C++). etc.
Nach dem ersten Jahr kann man dann anfangen, ihn in die
Produktionsmanschaft zu übernehmen und ihn langsam in die vorhandenen
Bibliotheken einzuarbeiten mit ersten Aufgaben aus dem taglichen
Entwicklungsalltag zu betrauen.
Und genauso ist es auch gekommen. Es hat ein gutes Jahr gedauert, bis er
soweit war, dass ich ihn guten Gewissens auf richtigen, kundenfähigen
Code loslassen konnte. Und der junge Mann war einer von der cleveren
Sorte.
In seiner Berufschulklasse hingegen war er der Superstar. Die anderen
'Informatiker' konnten gerade mal PC-Zusammenschrauben und Kabel mit
genormten Steckern in genormte Buchsen stecken. Etwas überspitzt
ausgedrückt.
> Das erste Jahr ist lernen angesagt. Üben. Techniken lernen. Algorithmen> studieren. Fundiertes Wissen über die Programmiersprache (C++). etc.
@Kark-Heinz:
Soweit richtig, aber ich denke, das Wichtigste ist, "Lernen" zu lernen.
Also zu lernen, wie man sich Neuland selbstständig erarbeitet. Und nein,
ich will Dir nicht widersprechen, ich will nur ergänzen. Kennst mich
ja...
@Thomas:
> Habe mal gesehen, daß in Bascom eine Softclock Funktion gibt mit einem> Uhrenquarz. 32.xxxKhz...
Nimm Dir mal das Datenblatt vom Mega8 vor und schau gezielt nach dem
asynchronen Modus des Timer2. Erkenne dabei, dass die CPU mit dem
internen Takt (RC-Oszillator) läuft und nur der Timer2 den Uhrenquarz
nutzt. Erkenne auch, dass man mittels Sleep die CPU abschalten kann,
wobei der Timer2 aber mit dem Uhrenquarz stromsparend weiterklappert und
sogar in der Lage ist, mit seinem Interrupt den internen Takt wieder
einzuschalten.
Und wenn Du das verstanden hast, dann weißt Du, was Bascom mit Softclock
meint. Frage mich aber bitte nicht, wie gut und konsequent (und
effizient!!!) Bascom das umgesetzt hat.
Und wenn Du erkannt hast, wie toll dieses Feature ist, dann schau mal in
die Datenblätter der anderen AVRs und sei darüber enttäuscht, dass nicht
alle AVRs dieses nette Feature haben...
MfG
"Und wenn Du erkannt hast, wie toll dieses Feature ist, dann schau mal
in
die Datenblätter der anderen AVRs und sei darüber enttäuscht, dass nicht
alle AVRs dieses nette Feature haben..."
Das habe ich schon bemerkt...!!!
Habe Glück weil ich bisher nur Atmega8 verwendete..aber ich guckmal nach
dem asynchronen Modus des Timer2.
Hmm..Karl Heinz hat schon Recht...( Ich will nicht schleimen, aber es
ist für mich beeindruckend..was er auf dem Kasten hat)
Thomas Kiss schrieb:> "Und wenn Du erkannt hast, wie toll dieses Feature ist, dann schau mal> in> die Datenblätter der anderen AVRs und sei darüber enttäuscht, dass nicht> alle AVRs dieses nette Feature haben...">> Das habe ich schon bemerkt...!!!
Prima! Dann wird es ja langsam Zeit, drüber nachzudenken, ob man das
ganze Bascom-Blackbox-Geraffel nicht einfach meidet und direkt
hardwarenah programmiert. Und nein, ganz auf Bascom muss man dabei nicht
verzichten, Du musst Dich nicht in ASM einarbeiten. Obwohl es sehr
hilfreich wäre, zu erkennen, welche Operationen die CPU (und interne
Peripheriemodule) überhaupt kann und wie effizient sie ausgeführt werden
können. Das geht natürlich nur bei Kenntnis des Befehlssatzes
(Maschinencode, in ASM 1 zu 1 darstellbar).
>> Habe Glück weil ich bisher nur Atmega8 verwendete..aber ich guckmal nach> dem asynchronen Modus des Timer2.
Mach mal, ist interessant.
>> Hmm..Karl Heinz hat schon Recht...( Ich will nicht schleimen, aber es> ist für mich beeindruckend..was er auf dem Kasten hat)
Das war ihm aber auch nicht in die Wiege gelegt worden, das hat er sich
auch Schritt für Schritt erarbeitet. Und ja, meinen Respekt hat er auch,
aber das weiß er, das muss ich ihm nicht täglich sagen. Ich habe auch
schon allerhand von Karl-Heinz gelernt, es gelingt ihm aber nicht, mich
von C zu überzeugen. ^^
MfG
Thomas Kiss schrieb:> Hmm..Karl Heinz hat schon Recht...( Ich will nicht schleimen, aber es> ist für mich beeindruckend..was er auf dem Kasten hat)
Du vergisst, dass ich so um die 25 Jahre Vorsprung habe und meine ersten
Jahre auch steinig waren. Sogar steiniger als deine heute :-)
Wobei ich sagen muss, dass ich langsam alt werde. Mit den neuen
Entwicklungen kann ich nicht mehr mithalten.
So gesehen bin ich ein Dinosaurier. Oder nennen wir es Handwerker der
alten Schule. Ich kann dir jeden Schuh reparieren, nur was hilft mir das
wenn alle Welt nichts mehr reparieren lässt, sondern nur noch wegwirft
und neu kauft. Auch die Software-Entwicklung hat sich im Lauf der Zeit
verändert. Heute ist in der breiten Masse nicht mehr Algorithmen-Kentnis
gefragt, sondern intime Kentnisse von Frameworks. Es geht nicht mehr so
sehr darum, clevere Strategien auszuhecken, sondern mehr darum fertige
Klassen clever miteinander zu verknüpfen.
Und da denk ich dann oft viel zu kompliziert.
> Ich habe auch schon allerhand von Karl-Heinz gelernt, es gelingt ihm> aber nicht, mich von C zu überzeugen. ^^
Es muss ihm nicht gelingen, da er's gar nicht versucht. Im Gegensatz zu
Anderen versucht Karl Heinz nicht Dich von C zu überzeugen, bzw. dafür
missionarisch wirken zu wollen. Und auch dafür hat er meine Hochachtung.
> Es geht nicht mehr so> sehr darum, clevere Strategien auszuhecken, sondern mehr darum fertige> Klassen clever miteinander zu verknüpfen.
Damit komme ich auch nicht klar. Und dazu hat der AVR auch viel zu
knappe Ressourcen.
> Und da denk ich dann oft viel zu kompliziert.
Ich auch, deshalb nutze ich AVR-ASM, QBASIC und VB6 (Klassenfrei). Für
meine Zwecke reicht das. Und ich muss schließlich meine Brötchen nicht
damit verdienen, ist halt Hobby.
MfG
> da er's gar nicht versucht.
Dann weißt Du mehr als Karl-Heinz und ich. Er hat's versucht, ist aber
schon eine Weile her und es war auch nicht ganz öffentlich. ^^
MfG
> Dann weißt Du mehr als Karl-Heinz und ich. Er hat's versucht, ist aber> schon eine Weile her und es war auch nicht ganz öffentlich. ^^
Definiere Weile.
Ich urteile nach dem was ich hier sehe. Es ist mir klar, daß Karl Heinz
eine C-Präferenz hat, aber er drückt die nicht durch. Das ist mein
Eindruck.
Für mich sind solche Leute vorbilder die noch von der alten Schule sind.
Klar 20 Jahre Erfahrung gegen 3 Monate...
Ich betreibe alles hier als Hobby, weil die AVRs mich faszinieren wie
einfach eine "Uhr" machen kann..LoL....meine erste Uhr habe ich aus 4510
und 4511 gebaut !!!( Jugendzeit..lange Pause jetzt wieder in der Löterei
und Bastelei drin !! )
> Definiere Weile.
Warum sollte ich? - Bin ich Dir Rechenschaft schuldig? Bist Du mein
Chef?
> teilweise habe ich das Problem, dass die Codes in Asm oder C sind..hmm
Ja sicher, der AVR kann nur ASM (Maschinencode) und die
Profi-Programmierer schreiben ihre Software gern in C, wenn es das
Timing erlaubt. Das Datenblatt will aber nur das Prinzip der
Vorgehensweise erklären und keinen Baukasten zum Zusammenklicken von
Software bereitstellen.
MfG
> Warum sollte ich? - Bin ich Dir Rechenschaft schuldig?
Wie nennt sich dieses Leiden, eine pampige Antwort auf die Frage zu
geben, welchen Zeitraum "schon eine Weile her" bezeichnet ?
> Bist Du mein Chef?
Wärst Du aus Versehen mein Angestellter, dann sicher nicht sehr lange :D
MWS schrieb:>> Warum sollte ich? - Bin ich Dir Rechenschaft schuldig?>> Wie nennt sich dieses Leiden, eine pampige Antwort auf die Frage zu> geben, welchen Zeitraum "schon eine Weile her" bezeichnet ?>>> Bist Du mein Chef?>> Wärst Du aus Versehen mein Angestellter, dann sicher nicht sehr lange :D
Nun mal ganz langsam.
Du zweifelst meine Angabe an und stempelst mich damit unterschwellig zum
Lügner. Ist ok, ich gebe Dir mehr Info, aber eben nicht soviel, wie Du
gerne hättest. Denn ich sehe keinen Grund, nochmal zu recherchieren und
Dir genau Datum und Uhrzeit zu nennen.
Dein "Definiere Weile." klingt wie ein Befehl. Auf Befehle von Fremden
reagiere ich allergisch. Da ist mir eben spontan eingefallen, dass es
eigentlich gar keinen Grund gibt, einen Fremden gegenüber Rede und
Antwort zu stehen, besonders auch, weil ich hier nicht der Hilfesuchende
bin und es auch OT ist und nicht Teil des hier diskutierten Themas. Und
dies habe ich Dir versucht klarzumachen. Wenn Du das als pampig
betrachtest, ist das Deine Sache. Ich bin nicht Dein Befehlsempfänger
und das wollte ich Dir sagen.
Dass Du dies als "Leiden" bezeichnest, ist nicht meine Sache. Dass ich
nicht Dein Angetellter bin, ist gar nicht so verkehrt. Andererseits
würden wir uns dann besser kennen und wissen wie man miteinander
umzugehen hat.
So, und nun ist's wieder gut. Denn es war genausowenig meine Absicht,
Dir patzig zu kommen, wie es Deine Absicht war, mich der Lüge zu
bezichtigen und mir Befehle zu erteilen.
MfG
Hallo ? Um was gehts denn hier Bitte ?
Ich habe meinen Encoder angeschlossen und gleicht mit der Pollin Routine
getestet, funzt super gut...Danke nochmál an Screwdriver !!
Nun es geht jetzt darum, daß ich die Uhr einstellen kann
In mmeiner standard Uhr, werde ich wieder einsetzen oder doch Softclock
?
Nun mit Softclock wäre der Code einfacher, aber zu fuss ist es
spannender.
Die Routine läuft also in der Do loop schleife, sowie die Abfrage vom
Encoder
Call Encoder2() 'Wird zyklisch im Hauptprogramm aufgerufen
If Rotary_last <> Rotary Then 'Encoder gedreht?
Rotary_last = Rotary 'Neue Stellung merken
Print Rotary 'und Encoder-Wert ausgeben
End If
Hier müsste ich noch den Schalter Abfragen ob gedrückt wurde, wenn ja
dann sollte ich die Werte setzen...aber jetzt kommt meine Frage und
bitte um "saubere" Programmtips.
Wie 3 verschidene Werte setzen ?
Meine Idee, mit dem Tastendruck eine Variable hochzeählen.
Debounce Befehl also weglassen und mit if ?
If Taste=0 then
incr Menuzaehler
end if
if menuezaehler = 1 then
gosub Uhrstellen
end if
if menuzaehler = 2 then
gosub Minutestellen
end if
In den Subs
Uhrstellen:
S1 = Rotary
return
Minutestellen
S2=Rotary
return
so etwa ?
> Du zweifelst meine Angabe an und stempelst mich damit unterschwellig zum> Lügner. Ist ok, ich gebe Dir mehr Info, aber eben nicht soviel, wie Du> gerne hättest. Denn ich sehe keinen Grund, nochmal zu recherchieren und> Dir genau Datum und Uhrzeit zu nennen.> Dein "Definiere Weile." klingt wie ein Befehl. Auf Befehle von Fremden> reagiere ich allergisch.
Nein, das war kein Anzweifeln, das war nur ein kurze Frage, kannst es
auch "Bitte" nennen, mitzuteilen wann das denn war. Da hat keiner,
inklusive meiner Einer irgendetwas angezweifelt.
Ich habe nicht immer in diesem Forum mitgelesen, und halte es natürlich
für möglich, daß Karl Heinz ein wahrer und möglicherweise aggressiverer
Verfechter der reinen Lehre wahr :D
Nur hatte ich nie von ihm eine negative Aussage bezüglich anderer
Programmiersprache gelesen, im Gegenteil er hilft auch Bascom Jüngern
und denkt sich in deren Sprache rein.
Diese Frage diente also lediglich meinem eigenen Interesse, kannst auch
sagen Neugier.
Aber sieh's locker, kein Grund sich einem Selbstbewusstsein auf die Füße
getreten zu fühlen, war kein Angriff auf Deine Person. Ich hab' das
Gefühl, daß Du eine Menge Ahnung hast.
Daß Du auf Deine Antwort dann eine Passende von mir bekamst, braucht
Dich dann wirklich nicht zu wundern, die Chance für mich ein Mimöschen
zu werden, ging lange schon an mir vorbei.
Und sonst, wie gesagt, war nicht böse gemeint.
> MWS : Sorry aber "irgendwie" gehört es nicht zu diesem Thread oder ?
Ergab sich so. Hab's nicht vor weiter fortzuführen, wenn's Dich stört,
dann schreib an den Mod und lass die betreffenden Posts löschen.
> Naja stören tuts nicht aber es wurden in diesem Thread Sachen> geschrieben die nicht zum Thema passen.
Das ist eine grundlegende Eigenschaft der Diskussion, daß die manchmal
ihre eigenen Wege nimmt ;-)
Frage zu Design :
Kann ich sowas irgendwie zusammenfassen ? ( Übersichtlichkeit ) ?
If Menuezaehler = 1 Then
Gosub Uhr_stellen
End If
If Menuezaehler = 2 Then
Gosub Minute_stellen
End If
If Menuezaehler = 3 Then
Gosub Sekunde_stellen
End If
If Menuezaehler = 4 Then
Gosub Alarm_stunde_stellen
End If
If Menuezaehler = 5 Then
Gosub Alarm_minute_stellen
End If
Ist Select Case für sowas besser ?
Select Case Menuezaehler
Case 1 : Gosub Uhr_stellen
Case 2 : Gosub Minute_stellen
Case 3 : Gosub Sekunde_stellen
Case 4 : Gosub Alarm_stunde_stellen
Case 5 : Gosub Alarm_minute_stellen
End Select
Beitrag "BASCOM: Vorteil Case statt If.Then-Bedingung" ??
"Besser" ist ein weiter Begriff. Mit Select-Käse, äh Case ist es
übersicht
-licher und empfiehlt sich, wenn man mehr Fälle unterscheiden will als
2.
MfG Paul
Thomas Kiss schrieb:> Naja stören tuts nicht aber es wurden in diesem Thread Sachen> geschrieben die nicht zum Thema passen.>> Mod : Bitte "überflüssige" Sachen löschen
Kann man machen, ich hätte nichts dagegen.
Falls Du noch an Kritik zu Deinem Programm interessiert bist:
Du nutzt zwei Timer mit Interrupts. Besser ist es, beide Aufgaben von
einem Timer takten zu lassen (das schrieb ich Dir aber schon weiter
oben). Also der Timer erzeugt den 1ms-Interrupt. In diesem wird der
Encoder behandelt und mittels Zähler der 20ms-Takt abgeleitet. Darin
findet dann die Entprellung der Taste statt (Vergleich mit gemerktem
Zustand und Zählen der Abweichung vom Vorzustand) und es wird mit einem
weiteren Zähler der Sekundentakt erzeugt. Somit erschlägt 1
Timer-Interrupt alle Deine zeitkritischen Aufgaben.
Warum?
Bascom sichert bei jedem Interrupt-Aufruf alle Register (auch die, die
nicht benutzt werden!) und stellt sie beim Verlassen der ISR wieder her
(Push/Pop). Das kostet 128 Takte Rechenzeit pro Interrupt-Aufruf. Das
ist erstmal nicht viel, aber wenn mehrere Interrupts zeitgleich
auftreten, dann muss einer warten, bis der andere fertig ist. In
Verbindung mit Preload des Timerstandes (ist notwendig, weil Du ja den
Überlauf-Interrupt benutzt anstatt des viel komfortableren
Compare-Interrupts) kann es da schonmal vorkommen, dass der Timer
während der Wartezeit schon weiter gezählt hat, was Dein Preload aber
nicht berücksichtigt. Dann stimmen die Zeiten nicht mehr.
Also möglichst nur 1 Timer-Interrupt nutzen und dann bitte einen, der
jitterfrei arbeiten kann (Compare-Interrupt, möglichst im CTC-Modus).
Diesen dann auf das kleinste gemeinsame Vielfache der gewünschten
Frequenzen einstellen und daraus durch Software-Teiler die restlichen
Takte ableiten.
Noch ein Punkt, der zwar nicht falsch ist, mir persönlich aber nicht
gefällt, weil er nicht zukunftsicher ist:
In der ISR Takt: zählst Du die Zeit hoch. Das ist erstmal ok. Irgendwann
kommt da aber noch ein Kalender rein. Erst die Wochentage, dann Monat,
dann Jahre, Schaltjahre... Und dann fällt Dir ein, dass man ja auch an
die Geburtstage der Liebsten erinnern könnte. Und an die Termine, zu
denen man die Mülltonne rausstellen muss. Da wird es ganz schön eng in
der ISR, denn ISRs sollen so schnell wie möglich verlassen werden.
Deshalb ist es sinnvoll, solche Dinge in der Mainloop zu erledigen. Dazu
muss ein Merkersystem eingerichtet werden, mir dem Zustände und
Jobaufträge gemeldet werden (wie an einer Pinwand). Meist reichen
Bitvariablen (Boolean) als Merker, bei der Uhr würde ich den
Sekundenzähler als Merker missbrauchen. Und zwar so:
Die 1ms-ISR behandelt den Encoder und zählt 20 ISRs für den 20ms-Takt
ab.
Jede 20. ISR wird der Taster abgefragt und entprellt und das Ergebnis
(neuer Tastendruck, langer Tastendruck) dem Hauptprogramm per Merker
mitgeteilt, dann wird 50 Runden abgezählt, was den 1s-Takt ergibt.
Im 1s-Takt wird die Sekunde hochgezählt. Nur hochgezählt, nicht auf
Überlauf überprüft. Das kann die Mainloop machen. Und es wird noch ein
Merker für die nächste LCD-Ausgabe gesetzt. Die Mainloop weiß dann
anhand des Merkers, dass sie die Sekunden (und nur die) neu ausgeben
muss.
In der Mainloop wird die Sekunde auf >59 geprüft. Ist die Bedingung
erfüllt, so wird sie nicht etwa auf 0 gesetzt, sondern es werden 60
Sekunden subtrahiert. Damit erreicht man, dass es auch dann noch stimmt,
wenn die Mainloop aufgrund anderer Jobs mit mehr als 1s Verspätung zum
Zuge kommt. Und hier, also wenn sekunde>59 war, wird die gesamte Uhr mit
Kalender, Mülltermine, Geburtstagsblumenbestelltermine, Weckzeiten usw.
abgearbeitet. Denn dieser Teil der Mainloop wird nur einmal pro Minute
aufgerufen. Und jeder Teil, der sich geändert hat (und wirklich nur das,
was sich geändert hat), wird auch am LCD aktualisiert.
Dies wäre der Grundstein für einen Multitasking-Aufbau Deines
Programmes.
So, ich denke, nun hast Du erstmal wieder genug zu verdauen. Dein ganzes
Programm habe ich jetzt nicht bis in alle Ecken analysiert, dazu fehlt
mir einfach Zeit und Lust.
MfG
Hallo Kluhscheisser..erstmal vielen Dank, klar ich bin immer
interessiert, damit es es besser machen kann !!!
Ich muss wirklich viel "verdauen"..klar ich mache immer eins nach dem
andren. Als erstes werde ich mal probieren ob ich mit einem Timer
auskomme.
Frage wie könnte so ein Timer aussehen, wo 2 verschieden Takte erzeugt
werden, wenn ich es richtig verstanden habe ...
Bsp:?
Thomas Kiss schrieb:> Ist Select Case für sowas besser ?>>> Select Case Menuezaehler> Case 1 : Gosub Uhr_stellen> Case 2 : Gosub Minute_stellen> Case 3 : Gosub Sekunde_stellen> Case 4 : Gosub Alarm_stunde_stellen> Case 5 : Gosub Alarm_minute_stellen> End Select
Eher nicht, denn Du brauchst eigentlich nur eine Stellroutine. Dieser
musst Du den Wertebereich (60 Sek, 60 Min, 24 Std, 7 Wochentage, 31
Datumstage, 12 Monate) und den Index des zu verstellenden Parameters
mitteilen.
Alle Deine Daten passen ins Format Byte. Da liegt es nahe, alle Daten zu
einem Feld (Array) zusammenzufassen und per Index darauf zuzugreifen.
z.B.: Dim zeit(6)as Byte Darin enthalten wären dann unter Index 1 die
Stunden, 2 die Minuten, 3 die Sekunden, 4 die Weckzeit-Stunden, 5 die
Weckzeit-Minuten, 6 die Weckzeit-Sekunden. Dies ist dann jederzeit
erweiterbar. Dazu gibt es ein weiteres Array, welches in der
Init-Routine mit den Überlauf-Werten (60,60,24,60,60,24) geladen hast.
Das geht zwar auch aus dem Flash mittels Data und Lookup(), im SRAM ist
es aber schneller und es braucht ja nur 6 Bytes. Dann legst Du im Flash
noch (per Data) ein Array von Erklärtexten an, die Du mittels
Lookupstring (musst mal in der Hilfe nachschaun wie das richtig heißt)
aufs Display zauberst.
Dein Menüpunkt wird nun einfach als Index auf die Arrays genutzt.
Ändert sich der Menüpunkt (Taster wurde betätigt), so gibt die Mainloop
den Menütext aus.
Die Mainloop prüft nun regelmäßig den Encoderwert. Ist dieser nicht 0,
so wird das vom Index ausgewählte Element des Arrays um den Betrag des
Encoderwertes verändert und der Encoderwert wieder auf 0 gesetzt. Beim
Verändern wird der Unterlauf (unter 0, bedeutet beim Byte über 128) und
der Überlauf (> als Wert im zweiten Array) berücksichtigt und
korrigiert.
Man kann das aber auch in der 1ms-ISR erledigen, statt der Variablen
"Encoderwert" wird die Variable "Zeit(Menuzaehler)" verändert, statt mit
einer Konstante wird mit einer Feldvariablen "Wertebereich(Menuzaehler)"
verglichen und der Wertebereich begrenzt, also der Kreis geschlossen
(58,59,00,01... bzw. 01,00,59,58...).
Das Verwenden von Arrays erspart Dir eine Menge Programmcode, denn Du
sparst etliche Fallabfragen (IF, Käse) ein.
MfG
Die Idee ist gut wie immer...mal sehen wie ich es umsetzen kann, muss
ich mich erstmal bisschen in den grundlagen einlesen und mit einfache
Aufgabe extra probieren....
Finde leider noch keine Lösung für das "Problem" 1 Timer und 2
Aufageben..hmmm..grübel...
Thomas Kiss schrieb:> Hallo Kluhscheisser..erstmal vielen Dank, klar ich bin immer> interessiert, damit es es besser machen kann !!!>> Ich muss wirklich viel "verdauen"..klar ich mache immer eins nach dem> andren. Als erstes werde ich mal probieren ob ich mit einem Timer> auskomme.>> Frage wie könnte so ein Timer aussehen, wo 2 verschieden Takte erzeugt> werden, wenn ich es richtig verstanden habe ...>> Bsp:?
Nur grob, nicht geprüft:
Isr_1ms:
... 'Encoder behandeln
incr misek 'Millisekunden erhöhen
if misek >19 then
misek=0
... 'Tasten entprellen
incr ms20 '20ms-Einheiten erhöhen
if ms20>49 then
ms20=0
set merker.0 'LCD-Ausgabe anmelden
incr sekunde 'Sekunde erhöhen, Überlauf wird in Mainloop behandelt
endif
endif
return
Dem Merker kann man mittels Alias auch einen schönen Namen geben. ;-)
MfG
Thomas Kiss schrieb:> Die Idee ist gut wie immer...mal sehen wie ich es umsetzen kann, muss> ich mich erstmal bisschen in den grundlagen einlesen und mit einfache> Aufgabe extra probieren....
Eben. Ohne Kenntnis des Alfabetes ist es schwer, Bestseller-Romane zu
schreiben... ^^
>> Finde leider noch keine Lösung für das "Problem" 1 Timer und 2> Aufageben..hmmm..grübel...
Einfache "Nachteiler" mittels Zählvariablen nutzen und bei deren
Überlauf was zusätzliches tun (und wenn es nur das Setzen eines Merkers
für die Mainloop ist).
MfG
Kluchscheißender Consulter schrieb:
> Bascom sichert bei jedem Interrupt-Aufruf alle Register
Das stimmt so nicht, es werden eben nicht alle Register gesichert. Zwar
gibt das im momentanen Programmcode soweit ich sehe noch kein Problem,
es wäre jedoch falsch es sich so zu merken, denn daraus kann durchaus
eine unangenehme Fehlerquelle entstehen.
Siehe Hilfe unter PUSHALL.
MWS schrieb:> Kluchscheißender Consulter schrieb:>>> Bascom sichert bei jedem Interrupt-Aufruf alle Register>> Das stimmt so nicht, es werden eben nicht alle Register gesichert.
Ich verfolge die Weiterentwicklung von Bascom nicht, denn ich benutze
Bascom nicht, ich programmiere in ASM. Ich habe mich nur etwas mit
Bascom beschäftigt, weil einige Freunde meinten, Basic sei einfacher als
Assembler und ich ihnen bei einigen Programmen half und z.T. noch helfe.
Basic als solches ist mir vertraut, auf dem AVR verzichte ich aber gern
darauf. Soviel zur Rechtfertigung, warum ich Bascom nur oberflächlich
kenne. Basic (außerhalb der AVRs) kenne (und kann) ich schon gut zwei
Jahrzehnte. Es hat aber auf jeder Plattform andere Eigenheiten.
Es kann also durchaus sein, dass die neueste Version nur die benutzten
Register sichert, ich kenne es aber (von einer etwas älteren Version -
und ich definiere "etwas älter" nicht) so, dass Bascom bei ISR-Aufruf
entweder alle 32 Register sichert oder (per nosave) gar keins. Und
deshalb vermeide ich es, unnötig viele Interrupts nebeneinander laufen
zu lassen.
> Zwar> gibt das im momentanen Programmcode soweit ich sehe noch kein Problem,
Nein, es gibt noch kein Problem, aber dieses Programm ist ja erst
Volumen 3, es ist davon auszugehen, dass es nicht dabei bleibt, siehe
auch meine Anspielungen auf Müllkalender und
Geburtstagsblumenbestelltermin. Und warum soll man sich erst an Dinge
gewöhnen, die einem später im Weg liegen? Da ist es doch besser, gleich
solche Fehlerquellen von Anfang an zu vermeiden.
> es wäre jedoch falsch es sich so zu merken,
Was wäre falsch es (was?) sich so (wie?) zu merken? Du musst mir nicht
antworten, bist mir keine Rechenschaft schuldig, ich habe diese Aussage
nur nicht eindeutig verstanden.
> denn daraus kann durchaus> eine unangenehme Fehlerquelle entstehen.>> Siehe Hilfe unter PUSHALL.
Sorry, ich habe auf dem Web-Lappi kein Bascom installiert, außerdem muss
ich das nicht sooooo genau wissen, da ich recht gut ohne Bascom zurecht
komme. Das hört sich jetzt vielleicht etwas arrogant an, ist aber nicht
so gemeint. Denn die meisten meiner AVR-Programme wären mit Bascom
aufgrund der Ressourcenverschwendung gar nicht realisierbar gewesen.
Aber auch in ASM (da meide ich Registersicherung indem ich
Exklusiv-Register für SREG-Sicherung und ISR-Variablen verwende) würde
ich die verschiedenen hier benötigten Takte aus einem einzigen Interrupt
ableiten. In diesem speziellen Fall käme noch ein Task der Mainloop
dazu, der jede 1ms ein Zeichen aus einem Bildschirmspeicher an das LCD
schickt. Dies vermeidet LCD-Wartezeiten, denn die Textausgabe erfolgt
dann nicht mehr direkt ans LCD, sondern nur in den Bildschirmspeicher im
AVR-SRAM.
MfG
Thomas Kiss schrieb:> Dieser hier macht 1 ms und schreibt Rotary0>> Config Timer0 = Timer , Prescale = 256> On Timer0 Isr_timer0> Enable Timer0> Const Timer0_reload = 224>> Isr_timer0:> Timer0 = Timer0_reload> Rotary0 = Encoder(pinc.0 , Pinc.1 , Links , Rechts , 0)> Return>> ----------------------------------------------->> Also müstte ich "irgendwie" bei ISR_Timer0 dass nach 1000ms incr sekunde> macht...wie heisst eigentlich der "erzeugte" Takt also die Variable für> 1 ms..doofe Frage....
Du hast meinen Beitrag
Beitrag "Re: LCD Uhr mit Alarmfunktion mit Drehencoder in BASCOM (Ein kleines Projekt für BASCOM Änfänger Vol" gelesen?
MfG
> Es kann also durchaus sein, dass die neueste Version nur die benutzten> Register sichert, ich kenne es aber (von einer etwas älteren Version -> und ich definiere "etwas älter" nicht) so, dass Bascom bei ISR-Aufruf> entweder alle 32 Register sichert oder (per nosave) gar keins.
Meine älteste Version hier ist die 1.11.8.2 von ca. 2006, und bereits
die sichert ein paar Register nicht. Ich kenn' das auch nicht anders.
Ausfzug aus der 1.11.8.2 Hilfe zu On Interrupt:
When you omit NOSAVE all used registers will be saved. These are SREG ,
R31 to R16 and R11 to R0 with exception of R6,R8 and R9 .
> , außerdem muss ich das nicht sooooo genau wissen, da ich recht gut> ohne Bascom zurecht komme.
Nichts dagegen zu sagen, solange es nur Dich persönlich betrifft, aber
hier bringst Du jemand etwas bei, der's nicht kennt, und er sollte es
richtig lernen. Das war der Grund meines Hinweises.
MWS schrieb:> Nichts dagegen zu sagen, solange es nur Dich persönlich betrifft, aber> hier bringst Du jemand etwas bei, der's nicht kennt, und er sollte es> richtig lernen. Das war der Grund meines Hinweises.
Gut, dann halte ich mich zurück und überlasse Dir das Helfen.
MfG
> daß hier immerwieder "Krieg" gibt...
War kein Krieg, lediglich ein technisch fundierter Hinweis.
Besonders technischen Sachen sollten klar dargelegt werden, und wenn
eine Aussage falsch ist, dann ist sie halt falsch, da beißt die Maus
keinen Faden ab.
Wenn ich was Falsches schreib', geb ich's zu, sag Danke, was Neues
gelernt und gut ist. Da muss ich nicht beleidigte Leberwurst spielen.
Aber es gibt eben viele Motive, warum sich jemand hier im Forum aufhält
:D
Was willst Du wissen ? Wie man aus einem einzigen Timer0 eine Sekunde
generiert ? 1ms = 1/1000s, wurde die ISR 1000 mal aufgerufen ist eine
Sekunde rum, also Variable in der ISR hochzählen bis 1000 und dann ein
Bit setzen.
ne...."die Aufagbenstellung" war daß ich aus 2 Timer eins mache..
Also so :
Dieser Timer erzeugt also 1 sec..klar..
-----------------------------------------------
Config Timer1 = Timer , Prescale = 256 'Timer für
Uhr
Enable Timer1
On Timer1 Takt
Enable Interrupts
Timer1 = 3036
Takt:
Timer1 = 3036
Incr Sekunde
-----------------------------------------------
Dieser hier macht 1 ms und schreibt Rotary0
Config Timer0 = Timer , Prescale = 256
On Timer0 Isr_timer0
Enable Timer0
Const Timer0_reload = 224
Isr_timer0:
Timer0 = Timer0_reload
Rotary0 = Encoder(pinc.0 , Pinc.1 , Links , Rechts , 0)
Return
jeder einzelne weiss ich was die machen, aber wie eins machen für beide
Funktionen ?
> ne...."die Aufagbenstellung" war daß ich aus 2 Timer eins mache..
Sag' ich doch.
Du willst daß Sekunde in Timer0 erhöht wird. Das darf erst nach 1000
Aufrufen geschehen, also musst Du zählen. Wenn Du bei 1000 bist, die
Sekunde erhöhen und den Zähler wieder rücksetzen.
Als schreib' in Timer0 nach dem Encoder:
Nachtrag:
Dein Timer0 macht keine 1ms Zyklus, wenn die Daten von oben stimmen:
Damit wird's mit Deinem Wecker früher dunkel :-)
Für eine ms geht für Timer0 bei 16MHz kein gerader Teiler, rechne das
mal durch.
Du könntest durch 125 teilen, also Preload 131, dann kommst Du auf 2ms,
wenn Dir das reicht.
Außerdem versteh' ich den Sinn der Aufgabe nicht so recht, denn der
Jitter, d.h. die Zeit die Dir Timer1 Interrupt den Timer0 Interrupt
aufhalten kann, liegt bei ca. 120 Zyklen (das Meiste für den Aufruf der
ISR), das sind bei 16MHz 7.5µs und 0,75% Deiner gewünschten 1ms
Zykluszeit.
Das dürfte sich nicht auf das Ergebnis des Encoders auswirken, wenn der
Encoder z.B. 100Pulse pro Umdrehung macht, dann müsstest Du den Knopf
mit 80000U/Min drehen, um den gleichen Takt zu erreichen. Da wirst' in's
Schwitzen kommen :D
Schon klar, daß der Meßzyklus kleiner sein muss um keinen Impuls zu
verpassen, aber einfach nur mal ausgerechnet um ein Verhältnis zu geben.
Aber ich will Dich nicht von Deinem gewählten Ziel abbringen.
Hallo,
ich persönlich vermisse eine Rückantwort Deiner vorhergehenden
Projekte. Wäre schade, wenn die umfangreiche Hilfe für die Tonne
wäre. Zumindest werde ich den Eindruck nicht los.
Ich lese hier aus den Antworten heraus, einen schlanken Timer
mit möglichst genauen Sekundentakt zu Programmieren.
Dort wird ein Flag gesetzt und.... das schöne ist, ich kann
diesen Flag überall im Code benutzen.
Debounce ist ein einfacher Befehl, um Tasten zu entprellen,
den Timer zu nutzen, der ja sowieso im Hintergrund dudelt ist
aber effektiver.
Aber auch ich will Dich von deinen Vorhaben nicht abbringen.
Wigbert
Thomas Kiss schrieb:> ne...."die Aufagbenstellung" war daß ich aus 2 Timer eins mache..
Ich stelle Dir keine Aufgaben, ich teile Dir nur mit, was ich anders
machen würde weil ich es für besser halte.
> Dieser hier macht 1 ms und schreibt Rotary0>> Config Timer0 = Timer , Prescale = 256> On Timer0 Isr_timer0> Enable Timer0> Const Timer0_reload = 224
Nein, dieser macht nur etwa 1 ms. Warum?
Du taktest den AVR mit 16 MHz.
Du willst 1 kHz Interrupt-Takt, also 1 ms Intervall.
Das ist das Verhältnis 1 zu 16000, richtig?
Mit Vorteiler von 256 bleibt das Verhältnis 1 zu 6,25.
Kann der Timer mit Dezimalzahlen arbeiten?
Nein, kann er nicht. Also müssen wir uns was anderes ausdenken.
Es gibt ja noch den Vorteiler 64.
1600 / 64 ergibt 250.
Der Timer muss bei Vorteiler 64 250 Takte abzählen, um exakt 1 ms zu
erreichen.
Kann Timer0 (ein 8-Bit-Timer) das?
Ja, das kann er, sein Zählumfang ist 256, also nach 255 kommt 0.
Leider hat Timer0 des Mega8 keinen CTC-Modus, somit musst Du den Timer
von Hand auf den Startwert setzen. Dazu hast Du 64 CPU-Takte Zeit,
gerechnet ab Überlauf des Timer0.
Und jetzt kommt meine (sachlich falsche) Aussage zum Tragen, dass Bascom
bei Aufruf einer ISR "alle Register" sichert (richtig ist, und darauf
wollte ich hinaus, dass Bascom auch die Register sichert, die in der ISR
nicht gebraucht werden, es sind aber nicht alle 32, sondern nur 25 oder
28, je nachdem, wie man die Hilfe zu "On Interrupt" interpretiert).
Was macht der nun AVR beim Auftreten eines Interrupts?
Er braucht eine Latenzzeit von einigen Takten, um auf den Interrupt zu
reagieren. Er macht also seinen angefangenen Maschinenbefehl fertig,
schreibt (per Hardware) die Rücksprungadresse (2 Bytes) auf den Stack
und aktualisiert dabei den Stackpointer. Danach sperrt er global die
Interrupts und springt an die dem Interrupt entsprechende Adresse der
Interrupt-Sprungtabelle, die Bascom an den Beginn des Flash geschrieben
hat. Dort steht dann der Sprung zu Deinem Interrupt-Handler, also der
Routine, die Du für den Interrupt geschrieben hast. Diese Routine hat
Bascom natürlich in Maschinenbefehle übersetzt, denn der AVR kann ja
kein Basic. Und dabei hat Bascom die SREG- und Registersicherung
hinzugefügt. All das verbraucht natürlich Rechenzeit. Bei 28 zu
sichernden Registern sind das schon 56 Takte, denn jedes Push braucht 2
Takte. Das Sichern des SREG (push, in, push) kostet weitere 5 Takte,
sind schon 61 Takte. Oder nur 55 Takte, falls nur 25 Register gesichert
werden. Das wird mir persönlich ziemlich eng, man kann nicht exakt
vorhersagen, ob der Timer0 noch auf 0 steht, oder bereits auf 1, wenn in
der ISR endlich der Befehl zum Preload (Setzen des Timers auf den
Startwert) erreicht wird.
Deshalb würde ich diesen Takt nicht mittels Timer0 generieren, sondern
mittels Timer1. Das ist ein 16-Bit-Timer, kann also bis 65535 zählen und
hat zum Glück 2 Compare-Einheiten. Man muss also das Intervall nicht
mittels Preload einstellen, sondern kann es in das entsprechende
Compare-Register schreiben. Und als Zugabe hat dieser Timer noch den
CTC-Modus (clear to complete), also löscht seinen Zählerstand
automatisch per Hardware bei Erreichen des Zählerstandes im
Compare-Register. In diesem Modus braucht es kein Preload, Du musst Dich
außer in der Init nie wieder um diesen Timer kümmern. Er generiert Dir
in regelmäßigen Abständen Interrupts, ohne weiteres Zutun Deinerseits.
In die ISR musst Du also nur Deinen Nutzcode einfügen, die Verwaltung
erfolgt per Hardware.
Wie ist Timer1 nun einzustellen?
Da Du 16000 Takte abzählen willst, funktioniert das schon mit Vorteiler
1. Dann gehört der Wert von 16000 (oder 15999 - da streiten sich die
Geister) ins Compare-Register. Bei Vorteiler 8 muss der Timer dann bis
2000 zählen. Ist also auch realisierbar, genauso wie Vorteiler 64 und
250. Um die anderen Dinge einzustellen (auch CTC-Mode) musst Du mal ins
Datenblatt sehen und Dir die Bits in den Steuerregistern TCCR1A und
TCCR1B zusammensuchen und so setzen, dass CTC-Mode 4 oder 12 (gemäß
Tabelle 39) erreicht wird. Im Mode 4 gehört der Zählumfang in das
OCR1A-Doppel-Register, im Mode 12 in das ICR-Register (interessant, wenn
bei begrenztem Zählumfang beide Compare-Interrupts benötigt werden).
Hier sollte Mode 4 ausreichend sein.
Der Aufruf des Handlers muss natürlich auch angepasst werden, siehe
Hilfe zu "on interrupt".
>> Isr_timer0:> Timer0 = Timer0_reload> Rotary0 = Encoder(pinc.0 , Pinc.1 , Links , Rechts , 0)> Return>> jeder einzelne weiss ich was die machen, aber wie eins machen für beide> Funktionen ?
Isr_compare1a:
... 'Code zum Abfragen des Encoders einfügen
incr millisek 'Millisekunden hochzählen, 0 bis 19, 20 = 0
if millisek > 19 then 'Takt für 20 ms erzeugen
millisek=0 'Zählumfang 0 bis 19, 20 = 0
... 'Code für Tastenentprellung einfügen
incr ms20 '20ms-Einheiten hochzählen (50 = 1 Sekunde)
if ms20 > 49 then 'Takt für 1000 ms (1 Sek.) erzeugen
ms20 = 0 'Zählumfang 0 bis 49, 50 = 0
incr sekunde 'Sekunde erhöhen
set merker.0 'Sekundenausgebe für LCD anmelden
endif 'Ende Sekundentakt
endif 'Ende 20ms-Takt
return 'Ende ISR
Die Mainloop enthält nun:
Do
if sekunde > 59 then 'wenn Sekunde überläuft (Minutentakt)
sekunde = sekunde - 60 'eine Minute abziehen
incr minute 'Minute erhöhen
if minute > 59 then 'wenn Munute überläuft (Stundentakt)
minute = minute -60 'eine Stunde abziehen
incr stunde 'Stunde erhöhen
if stunde > 23 then 'wenn Stunde überläuft (Tagestakt)
stunde = 0 'Stunde auf Startwert setzen
... 'bei Kalender weiter fortsetzen
endif 'Ende Tagestakt
endif 'Ende Stundentakt
endif 'Ende Minutentakt
if merker.0 = 1 then 'ist eine weitere Sekunde vergangen?
reset merker.0 'Job-Auftrag entwerten
... 'hier Formatierung und LCD-Ausgabe der Zeit einfügen
... 'hier Vergleichsroutinen mit Weckzeit einfügen
endif 'Ende Sekundentakt
Loop
Natürlich kann man Sekunde und Minute bei Überlauf einfach auf 0 setzen.
Bei Minute ist das egal. Bei Sekunde sollte man das nur tun, wenn man
absolut sicher ist, dass kein Teil des Programms länger als eine knappe
Sekunde dauert. Dies ist jetzt noch der Fall, kann sich aber bei
ungünstiger Programmierung umfangreicher Erweiterung ändern. Das
Subtrahieren einer Einheit ist da fehlertoleranter.
Die LCD-Ausgabe wurde bewusst hinter die Zeitzählung platziert, damit
alle Überläufe behandelt wurden. Das LCD wird auf diese Art nur einmal
pro Sekunde aktualisiert, was für die Zeitanzeige völlig ausreicht.
MfG
Gestern war ich schon mit den Nerven fertig....
was ich nicht verstehe ist
"Wie ist Timer1 nun einzustellen?" die Erklärung..
ich werde nochmal das Kapitel im Buch vom Claus Kühne AVR RISC Timer
nochmal durchlesen
>In dem Scheiss teueren Buch gibt es 2 Seiten über Timer total kacke>eklärt
Volle Zustimmung!
Ein gutes Buch ist das "AVR-Mikrocontroller-Lehrbuch" von R.Walter.
Das kostet zwar auch eine ganze Menge, aber im Gegensatz zu o.g.
Buch ist das gut angelegt.
Ich besitze beide.
MfG Paul
@Thomas
Nein, das Buch verkaufe ich nicht.
>Bin mit dem Nerven am Ende !!
Bleib ruhig! Du kannst nichts erzwingen. Wenn es nicht weitergeht, lasse
es erst mal ruhen und mach etwas Anderes.
Ein paar Stunden spaeter siehst Du den Fehler im Programm auf Anhieb.
Bau Dir einen Adapter fuer die serielle Schnittstelle mit einem MAX232.
Du kannst dann mit dem "Print"-Befehl an einer "verdaechtigen" Stelle
Variablen ueber ein Terminalprogramm auf dem Rechner anzeigen lassen.
MfG Paul
Meine Pollin Board hat eine RS232 Schnittstelle..Ich flasche aber über
ISP.
ich sitze schon seit 3 Tagen dran, das Grundprogramm mit der hr habe ich
bereits gemacht und aufgebaut geht alles, ich wollte nur eine neue
Version machen mit dem Encoder....
Die Erklärung findest Du nur im Datenblatt. Denn nur das ist aus
erster Hand und somit verbindlich.
Um Missverständnisse betreffs Absatz-Nummer, Seite und Tabellen-Nummer
aufgrund unterschiedlicher Datenblatt-Ausgaben zu vermeiden, habe ich
jetzt eben die aktuelle Version des Datenblattes heruntergeladen:
http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf
So, nun zum Timer1:
Zum Konfigurieren des Timer1 gibt es zwei I/O-Register, TCCR1A und
TCCR1B. Jedes dieser beiden Register enthält 8 Bit. Diese Bits sind als
Schalter zu betrachten, mit denen man Funktionen ein- und ausschalten
kann. Diese Bits haben zwar Namen, diese werden anhand der von Atmel zum
AVR-Studio mitgelieferten Portdefinitionsdateien ("m8def.inc") in
Zahlenwerte übersetzt. Inwieweit die Bascom-Dat-Dateien das
berücksichtigen, weiß ich nicht, daher ist es sicher besser (aber
bedeutend unleserlicher!), wenn wir es nicht austesten, sondern gleich
die dahinter stehenden Zahlen verwenden. Man muss sie (die Zahlen) ja
nicht dezimal (0 bis 255) darstellen, es gibt ja schließlich (für solche
Zwecke) auch die Darstellung im Hexformat (&h00 bis &hFF) oder
Binärformat (&b00000000 bis &b11111111). Da uns hier nicht der
Zahlenwert interessiert (der interessiert nur den AVR), sondern die
Stellung der einzelnen Schalter, ist das Binärformat die bessere Wahl.
Schaun wir uns erstmal das Register TCCR1A an (Seite 96 ganz unten):
Da gibt es erstmal Bit 7: COM1A1 und Bit 6: COM1A0
Die gehören zusammen und bilden einen 2-Bit-Schalter, also einen
Schalter mit 4 Stellungen, mit dem das Verhalten der Sonderfunktion des
Pins OC1A gesteuert wird. Diese 4 Stellungen sind für den
Nicht-PWM-Modus in Tabelle 36 auf Seite 97 erklärt. Für die PWM-Modi
gibt es abweichende Funktionen, siehe Tabelle 37 und 38, aber wir
arbeiten ja nicht mit Hardware-PWM. Aus Gründen der Rationalisierung
(und Verwirrung) gelten diese Tabellen aber nicht nur für den Pin OC1A,
sondern auch für den Pin OC1B, die mittels COM1B1 und COM1B0 eingestellt
werden.
Brauchen wir diese Sonderfunktionen der Pins OC1A und OC1B für Dein
Projekt?
Nein?
Nein, die brauchen wir nicht, also stellen wir für beide Pins
"disconnected" ein. Die oberen 4 Bit von TCCR1A müssen also auf 0
gesetzt werden. Der bisherige Steuerwert für TCCR1A ist also:
&b0000xxxx (x steht für "noch unbekannt")
Weiter geht es mit Bit 5: FOC1A und Bit 4: FOC1B. Die genaue Funktion
habe ich auch noch nicht verstanden, aber auch noch nicht gebraucht. Zum
Auslösen eines Compare-Interrupts werden sie glaube nicht gebraucht.
Setzen wir sie auf 00. Der bisherige Steuerwert für TCCR1A ist also:
&b000000xx
Es folgen Bit 1: WGM11 und Bit 0: WGM10.
Hier ist ein Stolperstein, denn diese beiden Bits sind nur die halbe
Miete. Der Rest ist in TCCR1B versteckt: Bit 4: WGM13 und Bit 3: WGM12.
Die 4 WGM-Bits repräsentieren einen Schalter mit 16 Stellungen. Diese
sind in Tabelle 39 auf Seite 98/99 erklärt. Wir entscheiden uns für den
Modus 4, also den CTC-Modus des Compare1A-Interrupts. WGM11 und WGM10
sind deshalb auf 0 zu stellen. Der bisherige Steuerwert für TCCR1A ist
also:
&b00000000
Der Befehl zum Einstellen lautet also:
TCCR1A = 0
Er kann aber weggelassen werden, da dies bereits beim Reset per Hardware
eingestellt wird, siehe die Zeile "Initial Value" direkt unter der
Registerdarstellung, für TCCR1A auf Seite 97 obere Zeile (aufgrund
schlechter Formatierung dieses PDFs).
Nun zu TCCR1B. Auch hier müssen wir uns wieder mühsam die einzelnen Bits
aus dem Datenblatt zusammenklauben.
Bit 7: ICNC1 - Rauschunterdrückung Input-Capture-Interrupt. Brauchen wir
das? - Nein? - Also auf 0...
Bit 6: ICES1 - Flankenauswahl ICP-Interrupt. Brauchen? Nein, auf 0...
Bit 5 ist nicht benutzt, also auf 0...
Bit 4: WGM13 und Bit 3: WGM12 kennen wir schon aus Tabelle 39, sie
brauchen den Wert 01 (also WGM13 auf 0, WGM12 auf 1).
Unser TCCR1B sieht also bisher so aus:
TCCR1B = &b00001xxx
Bit 2, 1 und 0 sind der Schalter für den Vorteiler und zum Starten des
Timers. Die 8 möglichen Stellungen sind in Tabelle auf Seite 100
erklärt. Wir hätten für Deinen Zweck die Wahl zwischen Vorteiler 1, 8
und 64. Wenn Du Dir die letzten beiden Einträge der Tabelle ansiehst,
erkennst Du, dass der Timer nicht nur CPU-Takte zählen kann, sondern
auch externe Takte am Pin T1. Abes das nur am Rande, das brauchen wir
bei Deinem Projekt nicht.
Einigen wir uns auf Voteiler 8 (010), dann sieht TCCR1B so aus:
TCCR1B = &b00001010
Und damit wäre der Timer1 auf Compare1A-Interrupt mit Rücksetzen auf 0
eingestellt.
Doch langsam, zuvor muss das 16-Bit-Register OCR1A auf den
Vergleichswert eingestellt werden. Da der AVR (in seinem Befehlssatz)
nur 8-Bit-Zugriffe kann, ist dieses Register auf 2 8-Bit-Register
aufgeteilt, nämlich OCR1AH (H-Teil, also obere 8 Bit) und OCR1AL
(L-Teil, also untere 8 Bit). Beim Schreiben muss zuerst das H-Register
beschrieben werden, danach das L-Register, beim Lesen ist es umgekehrt,
erst L, dann H. Das ist übrigens bei allen 16-Bit-Registern so.
Normalerweise muss man das beim Benutzen einer Hochsprache nicht wissen,
denn es reicht, wenn der Compiler das weiß. Dumm ist nur, dass ich nicht
weiß, welche Namen der Compiler für den Zugriff auf die 16-Bit-Register
erwartet. Vermutlich ist es OCR1A (ohne H und L), aber ich habe noch
irgendwo im Hinterkopf, dass diese Logik Ausnahmen hat, also nicht immer
stimmt. Um mir Frust zu ersparen, würde ich (persönlich) den Wert
(Timer-Zählumfang) im Vorfeld in zwei 8-Bit-Werte zerlegen und diese
separat (in der richtigen Reihenfolge) schreiben.
Damit der Timer auch Interrupts auslösen kann, muss natürlich auch seine
Interrupt-Freigabe aktiviert werden. Dafür ist das Bit OCIE1A im
Register TIMSK zuständig, siehe Seite 102. Da keine anderen
Timer-Interrupts aktiviert (und berücksichtigt) werden müssen, muss nur
dieses eine Bit gesetzt werden, alle anderen können gelöscht bleiben.
OCIE1A liegt in TIMSk auf Position 4, hätte also bei dezimaler
Schreibweise den Wert 16.
Timsk = 16
würde den Compare1A-Interrupt genauso freigeben wie
TIMSK = &b00010000.
Und natürlich müssen Interrupts auch noch global freigegeben werden,
also das I-Flag im SREG gesetzt werden. Der AVR hat dafür den ASM-Befehl
SEI, in Bascom macht man das ja wohl mit "Enable Interrupt".
Die Initialisierung des Timer1 wäre also:
OCR1A = 2000 '2000 x 8 Takte bis zum Compare-Match
TCCR1B = &b00001010 'CTC-Mode für Compare1A
TIMSK = &b00010000 'Compare1A-Interrupt freigeben
Enable Interrupts 'Interrupts global freigeben
on <frag die Hilfe zu On Interrupt> goto taktms
So, ich hoffe, Du bist nun in der Lage, Dir die benötigten Infos
zukünftig selbst aus dem Datenblatt zusammenzusuchen. Ja, es ist mühsam,
und es ist sehr hilfreich, dabei Papier und Bleistift zu benutzen. Aber
egal, welche integrierte Peripherie-Einheit Du benutzen willst (ADC,
TWI, SPI, UART, ...), die Vorgehensweise ist immer dieselbe. Man sucht
sich die benötigten Register und die darin enthaltenden Bits zusammen
und setzt bzw. löscht die dementsprechend. Hier war es noch einfach, da
keine Rücksicht auf die anderen Bits im jeweiligen Register genommen
werden musste, hier reichten einfache Zuweisungen. Oft muss man aber ein
einzelnes Bit verändern, ohne die anderen Bits zu verändern. Näheres
zazu erfährst Du unter Bitmanipulation.
MfG
Vielen herzlichen Dank für die nette und ausführliche Erklärung...aber
bin glaube zu doof ...ich komme betreffend meine jetzige Kenntnisse
einfach nicht weiter, und deshalb habe langsam keine Lust mehr, es nervt
einfach.
Thomas Kiss schrieb:> Vielen herzlichen Dank für die nette und ausführliche Erklärung...aber> bin glaube zu doof ...
Meinst Du, dass 38 Minuten reichen, den Stoff zu verstehen? Also ich
habe dafür (das erste mal) bedeutend länger gebraucht, aber ich musste
mir auch alles selbst erarbeiten weil keiner da war, den ich fragen
konnte oder wollte.
Wenn Du selbstständig mit AVRs basteln willst, dann ist es unerlässlich,
Dich intensiv damit zu beschäftigen.
> ich komme betreffend meine jetzige Kenntnisse> einfach nicht weiter,
Dann war der Happen vielleicht zu groß?
Vielleicht solltest Du mit kleineren Projekten beginnen und diese selbst
programmieren (wegen des Verstehens) und nicht vom Forum programmieren
lassen bis es funktioniert, ohne dabei selbst zu verstehen, warum es
genau so gemacht wurde und nicht anders.
> und deshalb habe langsam keine Lust mehr, es nervt> einfach.
So schnell gibst Du auf? Gut, ich habe auch keine Lust, alle Hürden zu
nehmen, die nötig sind, das ultimative hocheffiziente Solarkraftwerk zu
bauen, dass auch am Nordpol noch hocheffizient ist, also lasse ich es.
Ich lasse es auch, Romane oder Gedichte schreiben zu wollen, denn dazu
fehlt mir etwas, was auch durch intensives Training nicht zu ersetzen
ist. Genauso geht es mir mit Sprachen, der geringe Erfolg lohnt den
enormen Aufwand nicht. Menschen sind nunmal Individien, nicht jeder kann
alles.
Du solltest aber erstmal ergründen, ob Du es wirklich nicht kannst (weil
das Gen fehlt), oder ob Du nur nicht bereit bist, Dir langsam (und
leider ziemlich mühsam) die Grundlagen zu erarbeiten.
Wenn Du es nicht kannst, dann lass es. Wenn Du es nicht lassen willst,
dann setze Dich auf den Arsch und lerne. Fertig kaufen kannst Du dieses
Wissen nicht, auch das Rowalt-Buch verweist auf fast jeder Seite auf das
betreffende Datenblatt. Du musst es übrigens nicht gleich kaufen, es
steht (hoffentlich noch) zum Online-Lesen auf seiner Homepage.
Egal ob es das Rowalt-Buch ist oder die Beiträge hier im Forum, es geht
darum, dass Du logisches Denken lernen sollst/musst, um Programmieren zu
können. Denn nur damit bist Du in der Lage, Dir selbst die benötigten
Informationen zu erarbeiten und sie anzuwenden. Nur mit
zusammengesammelten Codestücken anderer Leute kommt man nicht weit.
Was meinst Du, warum ich mir die Arbeit gemacht habe, alle Gedankengänge
zur Timer-Initialisierung ausführlich aufzuschreiben? Weil es mit Spaß
macht oder weil ich so gerne schreibe? Falsch. Nur darum, dass Du
verstehst und nachvollziehen kannst, warum ich das so und nicht anders
lösen würde. Es wäre für mich viel einfacher gewesen, Dir die 5 Zeilen
Initialisierung vor die Füße zu werfen und mich zu amüsieren, wie es
weiter geht. Das ist aber nicht mein Ding, auch wenn es mit Dieser oder
Jener gern nachsagen würde.
MfG
Bitte nicht falsch vestehen, ich schätze Deine Arbeit höher ein als Dir
vorstellen kannst, bin nur total enttäuscht von mir selbst !!!
und wenn der Spass frust wird..dann bringt es nichts
Ich werde dieses Projekt fertig machen so, daß es funzt klar schlecht
programmiert, aber nach meine Kenntnissen halt. Bin trotzdem sehr
dankbar an alle die mehr nerven haben wie ich.
Mit neue Kräften ))))
bin noch dabei den Coe zu "verfeinern"..mal ne Grundsätzliche Frage wo
ich noch leider nicht verstanden habe..
Wenn die Alarmzeit erreicht ist, sollte einiges passieren, also LED
blinken
1 Minute lang oder so oder Melodie abspielen,,usw...das ist soweit kein
Problem...
wenn ich in einem Sub mache, klar es wird dort eins nach dem anderen
abgearbeitet, so wird nichts ausgeführt in der main loop...
Wenn ich die Sachen in die do loop packen würde ist ein "durcheinander"
wie am besten vorgehen ?
>Wenn die Alarmzeit erreicht ist
dann Flag setzen
Sub "Melodie und Co" kann nur angesprungen werden, wenn das
Flag gesetzt ist. Und irgendwann Dein Flag löschen.
Aufbauten sehen doch ganz ordentlich aus.
Wigbert
Ja das ist klar, ABER wenn der Sub angesprungen wird und im SUB man
länger bleibt wird in der DO Loop nichts abgearbeitet..
"Aufbauten sehen doch ganz ordentlich aus."
welche meinst ?
richtig,
deshalb musst Du Dein Zeittakt aus dem Timer immer aktuell entnehmen
können. Ich nehme mal an, Du vermisst wärend Deiner Melodie
die Aktualisierung der LCD-Anzeige zB. Gute Frage.
Wigbert
Korrekt....
Zum verrecken kapiere ich nicht wie,,habe schon Stunden verbracht mit
dem Timer
"deshalb musst Du Dein Zeittakt aus dem Timer immer aktuell entnehmen
können."
Thomas Kiss schrieb:> Mit neue Kräften ))))>> bin noch dabei den Coe zu "verfeinern"..mal ne Grundsätzliche Frage wo> ich noch leider nicht verstanden habe..>> Wenn die Alarmzeit erreicht ist, sollte einiges passieren, also LED> blinken> 1 Minute lang oder so oder Melodie abspielen,,usw...das ist soweit kein> Problem...>> wenn ich in einem Sub mache, klar es wird dort eins nach dem anderen> abgearbeitet, so wird nichts ausgeführt in der main loop...
Du solltest nicht in Schleifen denken, sondern in Zuständen und
Ereignissen...
Also nicht in einer Sub, den ganzen Brocken auf einmal (mittels
Schleife) abarbeiten, sondern in der Mainloop einen Zustand prüfen und
wenn dieser zutrifft immer wieder die Sub aufrufen, die dann nur einen
Schritt des Jobs ausführt und danach zur Mainloop zurück kehrt, um
andere Dinge machen zu können. Ist der Job (durch häufiges Aufrufen
dieser Sub) irgendwann erledigt, so wird von der Sub der Zustand
dahingehend verändert, dass die Mainloop die Sub nicht mehr aufruft.
Der "Zustand" kann ein Merker sein, aber auch eine andere Variable.
Beispiel:
Du willst ab Wecktermin 60 Sekunden lang einen Ausgang klappern lassen:
In dem Teil der Mainloop, der einmal pro Sekunde aufgerufen wird, prüfst
Du die Weckzeit (auf die Sekunde genau). Stimmt die Weckzeit (das
passiert nur alle 24 Stunden einmal), dann setzt Du eine Variable
(nennen wir sie "Restzeit" auf 60, also auf den Wert, wie lange der
Portpin an sein soll. Mehr machst Du erstmal nicht.
Die Mainloop prüft im 1Sekunden-Job nun diese Variable auf "nicht 0" und
ruft die Sub auf, solange die Variable nicht 0 ist. Diese Sub vermindert
die Variable "Restzeit". Dann prüft sie, ob sie gerade oder ungerade ist
(erkennbar am Bit 0 der Variable). Ist sie gerade, wird der Ausgang
gelöscht. Ist sie ungerade, wird der Ausgang gesetzt. Danach wird die
Sub sofort beendet, worauf die Mainloop die restlichen Jobs erledigen
kann.
Da sie beim Herunterzählen bei 0 endet und 0 "gerade" ist, endet diese
Sequenz immer mit ausgeschaltetem Port.
Die Sub wird also nicht 1 mal aufgerufen um 1 Minute lang zu blinken,
sondern sie wird 60 mal (im Sekundentakt) aufgerufen, um 30 mal
einzuschalten und 30 mal auszuschalten. Dazwischen kann die Mainloop all
die anderen Dinge erledigen, die Dein Programm noch so tun soll.
Du hast damit also eine Schleife vermieden und die Steuerung anhand
eines Zustandes realisiert. Der Zustand heißt "Restzeit" und dient
einerseits zum Abzählen, wie oft die Sub aufgerufen wird, um nur einen
kleinen Schritt ihrer Arbeit zu erledigen, andererseits zum
Identifizieren, WAS die Sub in diesem Schritt gerade tun soll
(Einschalten bei ungerader Zahl, Ausschalten bei gerader Zahl).
Statt mit
For Restzeit = 1 to 30
wait 1
set blinkport
wait 1
reset blinkport
next Restzeit
die CPU 1 Minute lang zu blockieren, hast Du mit
If restzeit > 0 then
decr Restzeit
blinkport = restzeit.0
endif
auch 30 mal geblinkt, aber mit dem Unterschied, dass das Programm nicht
blockiert wurde, sondern nebenher auch noch alle anderen Jobs erledigen
kann. Wenn der Code überschaubar ist braucht man dafür auch keine Sub.
>> Wenn ich die Sachen in die do loop packen würde ist ein "durcheinander"
Nein, es kann auch in der Mainloop recht übersichtlich sein. Siehe oben.
>> wie am besten vorgehen ?
Da scheiden sich die Geister, es wird immer einen geben, der meint, es
besser zu wissen.
MfG
So etwa ?
If Stunde = A_stunde And Minute = A_minute And Sekunde = A_sekunde Then
Alarmzaehler = 60
End If
If Alarmzaehler > 0 Then
Gosub Alarm
End If
-------------------------------
Alarm:
Toggle Led
Waitms 500
Toggle Led
Alarmzaehler = Alarmzaehler - 1
Return
>"deshalb musst Du Dein Zeittakt aus dem Timer immer aktuell entnehmen>können."
ich versuchs mal mit meinen laienhaften Worten:
Jede Funktion in dem Code benötigt Takte. Also hole ich mir aus dem
Timer die aktuelle Zeit, um kein Timerüberlauf zu verpennen,
denn Dein Code wird seltsamerweise, wie so oft, immer komplexer.
Ich persönlich liebe deshalb DCF-Uhren, dort wird immer aktualisiert.
Ich würde mit ein kleinen AVR eine DCF-Uhr einschliesslich LCD+
Drehencoder realisieren. Dort würde ich ein(ige) Port(s) als Flag
setzen und mit einen 2. AVR mit SD-Card und LED Krams die Musik
machen.
Was besseres fällt mir spontan zur Uhr und Melodie nicht ein.
Ich geb mal das "Mikrofon" an die Profis weiter, die sowas täglich
machen
Schönen Sonntag noch.
Wigbert
Wigpert Idee ist gut, aber
1) Ich habe schon 4 DCf Uhre ( Nachgebaut )
2) Sowas ist noch eine Nummer zu gross
"Also hole ich mir aus dem Timer die aktuelle Zeit"
Du meinst "Sekunde" meine Variable die hochgezählt wird. ?
Wie stelle ich der Main fest Sekunde ist grösser wie "vorher" ?
@Kluchscheisser...ich hoffe ich habe es verstanden, wenn mein Beispiel
das ist was Du gemeint hast...wenn ja..dann geht es weiter..
Wie mache ich, daß Musik (beep )gespielt wird, die länger dauert ?
klar mit led geht weil nur KURZ in den sub gesprungen wird..
gut,
noch eine Idee:
Wenn Du den Beeper an PWM anschliessen möchtest, hol Dir die
Zeiten vom Timer( da ist der schon wieder; Tonlänge) und ändere
in der Hauptschleife oder Sub den PWM Wert.
Also einfach immer wieder abfragen, ist die Zeit um? Dann
PWM Wert ändern.
Wigbert
"hol Dir die
Zeiten vom Timer( da ist der schon wieder; Tonlänge) und ändere
in der Hauptschleife oder Sub den PWM Wert."
ich habe 2 Timer
'System-Timer für periodische Encoder-Abfrage
Config Timer0 = Timer , Prescale = 256
On Timer0 Isr_timer0
Enable Timer0
Const Timer0_reload = 224
Isr_timer0:
Timer0 = Timer0_reload
Rotary0 = Encoder(pinc.0 , Pinc.1 , Links , Rechts , 0)
Return
------------------------------------------------------------
'Timer für Uhr
Config Timer1 = Timer , Prescale = 256
Enable Timer1
On Timer1 Takt
Enable Interrupts
Timer1 = 3036
Takt:
Timer1 = 3036
Incr Sekunde
If Sekunde = 60 Then
Sekunde = 0
Minute = Minute + 1
If Minute = 60 Then
Minute = 0
Stunde = Stunde + 1
If Stunde > 23 Then
Stunde = 0
End If
End If
End If
Return
Ich wollte nicht unbedingt Timer2 für PWM machen,,,
Bei Timer 1 ist die Variable "Sekunde"
Bei Timer0 Variable ??? weiss ich nicht,,,
nehm doch den Sekundentimer(reicht vielleicht für die Melodie)
Sub Rock and Roll
PWMwert = Bla Bla 'Buzzer
Melodietimer = 1 ' Startwert
if Melodietimer = 10 then '10sec
Melodietimer = 1
PWMwert = Heidiho 'neuer Buzzerwert
usw.
Melodietimer = 0 'Rücksetzen
end Sub
#######################
in dem Timer 1 fügst Du hinzu:
If Melodietimer = 1
If Timer 1 = 3063 then ' Beispielzeile
incr Melodietimer
end if
end if
--so in der Art--
Wigbert
Thomas Kiss schrieb:> @Kluchscheisser...ich hoffe ich habe es verstanden, wenn mein Beispiel> das ist was Du gemeint hast...wenn ja..dann geht es weiter..>> Wie mache ich, daß Musik (beep )gespielt wird, die länger dauert ?
Es darf nicht "länger dauern".
Also schaust Du Dir erstmal an, on "Beep" blockierend arbeitet und damit
für diesen Zweck ungeeignet ist. Du weißt es nicht? Ich auch nicht, also
vermeide ich Beep.
Um einen Ton zu erzeugen, muss man einen Pin toggeln. Dies kann man per
Programm tun (brauch viel Rechenzeit und genaues Timing), aber auch per
Hardware. Schau Dir Timer2 an, der hat eine Compare-Einheit mit
CTC-Modus. Diese kann man so einrichten, dass beim Compare-Ereignis
(kein Interrupt, reine Hardware) der OC2-Pin getoggelt wird. Um einen
Ton "einzuschalten", muss man über den Compare-Wert die Frequenz
einstellen. Da das Compare2-Register aber nicht in Notenwerten oder
Hertz geeicht ist, sondern in CPU-Takten (ggf. über Vorteiler), muss man
die Anzahl der CPU-Takte bis zum Toggeln des Pins angeben. Dann muss man
den Timer mit dem entsprechenden Vorteiler einschalten und mit den
Steuerbits den Portpin OC2 toggelnd mit der Compare-Einheit des Timer2
verbinden (Bits in Steuerregister gemäß Tabelle setzen). Dies alles ist
mit wenigen Befehlen möglich und kostet wenig Rechenzeit, kann also
"nebenher" erledigt werden. Der Timer2 wird also nur initialisiert, die
Tonausgabe erfolgt dann per Hardware ohne weiteres Programm, ohne
Interrupts, also ohne Ausbremsen der CPU solange, bis der Timer2 auf
einen anderen Ton initialisiert wird oder über die Steuerbits der
Portpin OC2 von der Compare-Einheit getrennt wird (Pause zwischen den
Tönen, Ende der Musik).
Um nun eine Melodie abzuspielen, legt man sich erstmal eine
Lookup-Tabelle mit den Timerwerten (Frequenzen) zu den einzelnen Tönen
(Noten-Nummer als Index) an. Man kann damit sehr komfortabel über die
Noten-Nummer den zugehörigen Timer-Comparewert ermitteln. Dann baut man
sich eine Funktion oder Sub, der man die Noten-Nummer übergibt und die
anhand der Noten-Nummer die richtige Frequenz einstellt. Diese Funktion
(oder Sub) wird zu jedem Tonbeginn aufgerufen. Es sollte natürlich auch
eine Noten-Nummer für Pause definiert werden, tritt diese auf, wird
Timer2 einfach abgeschaltet und der Pin OC2 von der Logik getrennt.
Nun brauchst Du neben den Noten und der Pause auch noch eine
Noten-Nummer für die Ende-Kennung, damit Du das Ende der Musik erkennst.
Dann wird (im Flash) die Melodie abgelegt. Für jeden Ton braucht es 2
Werte, nämlich die Noten-Nummer (Note, Pause, oder Ende) und die
Spieldauer der Note (Tondauer). Natürlich muss erstmal definiert werden,
in welchem Zeitraster die Tondauer skaliert werden soll. Je feiner das
Zeitraster ist, desto mehr Rechenzeit wird benötigt. Je grober es ist,
desto abgehackter klingt die Musik. 1 Millisekunde ist sicher viel zu
fein, 1 Sekunde ist viel zu grob. Um nicht noch einen neuen Takt dafür
generieren zu müssen, schaun wir uns erstmal die bereits vorhandenen
Takte an. Da gibt es den Tastenentprell-Takt alle 20 ms. In diesem
Raster (20ms je Einheit) lassen sich mit einem Byte Zeiten bis etwa 5
Sekunden darstellen (256 mal 20ms). Das passt. Nun musst Du im
bisherigen Programm erstmal dafür sorgen, dass die Mainloop informiert
wird, wenn jeweils 20ms vergangen sind. Das geht am besten mit einem
Merker (Boolean). Die Timer-ISR setzt diesen alle 20ms, die Mainloop
fragt ihn in jeder Runde ab. Ist er gesetzt, wird der Taster entprellt
(das entlastet die ISR) und die Musikausgabe behandelt.
Die Musikausgabe ist also ein Job der Mainloop, der alle 20ms aufgerufen
wird, solange der Melodie-Merker 1 ist. Der Melodie-Merker wird durch
durch den Vergleich Uhrzeit=Weckzeit eingeschaltet und durch das
Melodie-Ende (Ende-Kennung als Notenwert) ausgeschaltet. Ein
zusätzliches Ausschalten durch Tastendruck ist auch realisierbar. Beim
Einschalten des Merkers muss natürlich der "Notenzähler" (Zeiger auf die
aktuell gespielte Note im Flash-Array) auf Start gesetzt werden und die
Tondauer auf 1 (also 1 vor Ablauf).
Ist nun das Melodie-Bit gesetzt, so wird alle 20ms die Musikausgabe
aufgerufen. Diese vermindert die Tondauer. Ist die 0, werden die Daten
zur Note geholt, auf die der Notenzähler zeigt. Ist das die
Ende-Kennung, wird Timer2 deaktiviert und der Musik-Merker gelöscht.
Dann gehts zur Mainllop zurück. Wurde keine Ende-Kennung gelesen, dann
wird die Tondauer auf die eben geholte neue Tondauer gesetzt, dann wird
der Timer2 auf die neue Note initialisiert, also die Frequenz einstellt,
der Timer2 gestartet und der Portpin im Toggelmode an die
Compare-Einheit gekoppelt. Nun wird noch der Notenzähler erhöht, damit
beim nächsten Ablauf der Tondauer die Daten der nächsten Note gelesen
werden. Dann geht's sofort zurück zur Mainloop, um die anderen
notwendigen Dinge zu erledigen.
Auch dies ist wieder ein Zustandsautomat (State-machine), der, solange
der Melodie-Merker gesetzt ist, alle 20ms die aktuelle Tondauer
herunterzählt, bei Ablauf die nächsten Notendaten holt und Timer2 auf
die neue Frequenz und die Tondauer auf die neue Notendauer
initialisiert, und bei Erreichen der Ende-Kennung den Melodie-Merker
löscht und sich damit für weitere Aufrufe sperrt.
> klar mit led geht weil nur KURZ in den sub gesprungen wird..
Auch bei einer Melodie-Ausgabe genügt es, sehr oft (alle 20ms) nur kurz
einen klitzekleinen Schritt der Arbeit zu erledigen. Das geht aber
vermutlich nicht, wenn man nur Bascom-Bauklötze zusammenschieben will,
anstatt ein Programm hardwarenah selbst zu programmieren.
Mangels Interesse und Notwendigkeit werde ich aber nicht recherchieren,
ob es eine Möglichkeit gibt, die Play-Anweisung nichtblockierend
einzusetzen. Für mich ist es einfacher, ihn zu meiden.
MfG
>If Timer 1 = 3063 then ' Beispielzeile>end if
die beiden Zeilen werden nicht benötigt
>Melodietimer = 1 ' Startwert> if Melodietimer = 10 then '10sec
sind natürlich nur 9 Sec.
Wigbert
Kluchscheisser hast Recht, habe schn getestet, beep blockiert, stimmt..
muss mal überlegen daß ich nur kurz in den Sub springe, ähnlich wie beim
LED...
bin aber noch dabei die Rotary Sace anzusehen,,noch keine Lösung
Ausserdem ist das Problem, wenn die Uhrzeit eingestellt ist sowie Alarm,
wenn neue Alarmzeit eingestellt wird, verstellt sich die Uhrzeit bei
drücken der Taster
Thomas Kiss schrieb:> Kluchscheisser hast Recht, habe schn getestet, beep blockiert, stimmt..
Alles, was "blockiert", ist für ernsthafte Programmierung unbrauchbar.
> muss mal überlegen daß ich nur kurz in den Sub springe, ähnlich wie beim> LED...
Nicht jedes Verzweigen muss zwingend "in eine Sub springen" sein.
Bedingte Verzweigungen als "Jobs" (IF-Abfragen, Select-Käse) können
durchaus Teil der Mainloop bleiben. Subs nimmt man eigentlich nur, wenn
sie von verschiedenen Stellen des Programms (evtl. auch mit
verschiedenen Parametern) aufgerufen werden. Ansonsten lohnt sich der
Verwaltungsaufwand (Rücksprungadresse sichern) nicht.
Einige Programmierer sehen das anders, sie lagern Programmteile wegen
der Übersichtlichkeit und Lesbarkeit auch dann in Subs und Funktionen
aus, wenn sie nur von einer Stelle aus aufgerufen (angesprungen) werden.
Man könnte sich zwar über das Für und Wider streiten, das führt aber zu
nichts.
>> bin aber noch dabei die Rotary Sace anzusehen,,noch keine Lösung
Naja, das ist bei Deinem Gesampkonzept nicht so einfach möglich. Dir
gelingt es (noch) nicht, die einzelnen Abläufe zu einem Gesamtkonzept
zusammenzufassen. Da ich bei diesen Dingen meist ein kleines bisschen
weiter zu denken versuche, als es für den derzeitigen Ausbauzustand
eines Programmes nötig wäre, fällt es Dir (und einigen Anderen) schwer,
meine Gedanken und Hinweise nachzuvollziehen. Ich weiß aber leider nicht
mehr, wie ich Dir verständlich machen soll, was ich meine...
Mein Konzept für Deine Aufgabenstellung wäre:
Um per Drehgeber einen leichten Zugriff auf die Variablen Sekunde,
Minute und Stunde zu haben und auch auf weitere vom Drehgeber
einstellbare Variablen wie Wecksekunde, Weckminute und Weckstunde, ist
es vorteilhaft, alle diese Variablen in einem Array (Feldvariable, siehe
Hilfe zu Dim) zu halten. Wenn das Array den Namen Zeit bekommt ("Dim
Zeit(6) as Byte"), dann könnte Zeit(1) die Sekunde enthalten, Zeit(2)
die Minute und Zeit(3) die Stunde. Zeit(4) wäre dann die Wecksekunde,
Zeit(5) die Weckminute und Zeit(6) die Weckstunde. Das lässt sich bei
Bedarf dann später auch erweitern, ohne die Drehgeber-Routine ändern zu
müssen. Dies nur vorab zum Verständnis, nun zum Programmkonzept:
Timer1: Erzeugung eines Taktes von 1ms per Compare-CTC-Interrupt.
In diesem 1ms-Interrupt wird:
- Der Encoder abgefragt, und zwar mittels 4-Bit-LUT aus den
Pinzuständen Alt und neu, denn das blockiert nicht. Dabei wird nicht
irgendeine Encoder-Variable verändert, sondern gleich der richtige
Parameter, der mittels Menupunkt ausgewählt ist. Der Zugriff erfolgt
also auf die Feldvariable "Zeit(menupunkt)". Falls eine Wertänderung
erfolgte, wird das der Mainloop mit Merker.lcd_update mitgeteilt.
- Ein Takt-Teiler herunter(oder herauf)gezählt, der alle 20 Runden,
also alle 20ms einen Job-Merker der Mainloop (ms20merker) setzt und
einen weiteren Teiler mit Zählumfang 50 zählt, um den Sekundentakt
(50 mal 20ms) zu generieren. Bei Unterlauf dieses Teilers wird die
Sekunde hochgezählt, aber nicht begrenzt, und der Sekunden-Merker
gesetzt.
Der Interrupt des Timer1 liefert also:
- vom Drehgeber ggf. aktualisierte Werte in Zeit(Menupunkt)
- Merker.ms20
- Merker.sekunde
- Sekundenwert
Und mehr erstmal nicht.
Die Mainloop kümmert sich nun (erstmal) um folgende Dinge:
- Ist Sekundenwert > 59, dann wird davon 60 subtrahiert und der
Minutenwert erhöht.
- Ist der Minutenwert > 59, dann wird er gelöscht und der Stundenwert
erhöht.
- Ist der Stundenwert > 23, dann wird er gelöscht.
- Ist Merker.ms20 gesetzt, dann wird (entweder als IF-Block in der
Mainloop oder als Aufruf einer Sub) Merker.ms20 gelöscht (denn der
Job wird ja jetzt abgearbeitet), der Taster entprellt und ggf der
Menüpunkt erhöht, der vom Drehgeber als Index auf das Array Zeit()
genutzt wird. Dazu wird noch ein Merker gesetzt, der der Mainloop
sagt, dass die Menüzeile am LCD aktuelisiert werden muss.
Dann wird der Melodiemerker gefragt, ob zur Zeit eine
Melodieausgabe läuft. Ist das der Fall, wird die Tondauer herunter-
gezählt und ggf. der nächste Ton initialisiert, siehe meinen Beitrag
weiter oben. Und wenn Dir nächstes Jahr ein weiterer Job einfällt, der
im Zeitraster von 20ms ebgearbeitet werden muss, dann erweiterst Du
diesen 20ms-Job einfach durch einen weiteren IF-Block.
- Ist Merker.sekunde gesetzt, dann werden folgende Dinge getan:
Merker.Sekunde löschen, den der Job soll ja nur einmal erledigt
werden. Dann wird der Merker.lcd_update gesetzt.
Und dann kann man die Weckzeit prüfen. Anstatt mehrere
Prüfungen zu einer Zeile zusammenzufassen, ist es günstiger, die
Prüfung auf mehrere geschachtelte IF-Anweisungen zu verteilen:
If Zeit(1) = Zeit(4) Then
If Zeit(2) = (Zeit(5) Then
If Zeit(3) = Zeit(6) Then
Blinkzähler = Startwert
Notenzähler = Startwert
Tonlänge = 1
Set Merker.Melody
(Zünder für Knallfroch unterm Bett starten...)
EndIf
EndIf
EndIf
Es werden also nicht komplette Abläufe abgearbeitet, sondern nur die
Bedingungen (Zustände) gesetzt, anhand der die Mainloop die Dinge
im jeweils richtigen Zeitraster zu Ende bringt.
- Ist Merker.lcd_update gesetzt, so wird die Zeit-Zeile formatiert und
am LCD ausgegeben. Und natürlich muss auch der Merker.lcd_update
wieder gelöscht werden.
- Ist Merker.menu_update gesetzt, so wird die Menüzeile formatiert und
am LCD ausgegeben. Und natürlich muss auch der Merker.menu_update
wieder gelöscht werden. Die Menüzeile enthält einen Hinweis darauf,
welcher Parameter gerade aktiv ist (Menüpunkt-Text).
Und auf diese Art kannst Du viele weitere Tasks in die Mainloop
einbauen, die aber alle nur einen kleinen (schnellen!!!) Schritt machen
dürfen und auf keinen Fall blockieren dürfen. Deshalb wird die
LCD-Ausgabe der Zeit auch nur dann gemacht, wenn es nötig ist, also wenn
sich die Zeit verändert hat (neue Sekunde) oder wenn Du am Rad (des
Drehgebers) gedreht hast. Ebenso wird die Ausgabe des Menütextes auch
nur dann gemacht, wenn sich der Menüpunkt geändert hat.
Kann sein, dass ich jetzt noch was vergessen habe, aber in so einem
kleinen Eingabeformular ist der gesamte Text recht unübersichtlich zu
sehen.
MfG
Allein der Name Nixwisser ist unheimlich UNTERTRIEBEN !!!!
Hast Recht :
"Dir gelingt es (noch) nicht, die einzelnen Abläufe zu einem
Gesamtkonzept
zusammenzufassen." STIMMT
Nun zur meiner Entschuldigung :
Am Anfang habe ich diverse Konzepte angeschaut wie eine Uhr aufgebaut
ist und habe ich auch erfolgreich umgesetzt. Eine "simple"Uhr kann ich
schon alleine machen.
Später dachte ich mir nehme dieses Baustein, und erweitere ich mit einer
Alarmfunktion..soweit so gut ( damals mit 4 Taster - Küchentimer ist
schon im Einsatz )
Dann habe ich entdeckt es gibt ein Encoder..also einbauen..Nun habe ich
bemerkt, wie Du gesagt hast, dass leider vieles nicht in einem
bestehende Konzept passen kann...ob die anderen es vom Anfang an
berücksichtigt haben ist ne Frage.
So bin ich jetzt zum Entschluss gekommen ( ein neuer Thread ? ) eine
Multifunktionsuhr mit Fähigkeit zur Erweiterung vom Anfang an mit guten
Konzept aufzubauen.
"Ich weiß aber leider nicht mehr, wie ich Dir verständlich machen soll"
Kannst echt gut aber Stückweise, weil ich teilweise echt ins Schleudern
komme...
Also Momentan bin ich dafür, dass man SUBS macht wegen der
Übersichtlichkeit.
Mit Array habe ich auch schön überlegt und ich denke das ist eine gute
Methode.
Also "schmeissen wir alles weg" und fangen neu an.
Erstes :
Timer1: Erzeugung eines Taktes von 1ms per Compare-CTC-Interrupt.
Nun schreibt RN-Wissen :
CTC Modus (Clear Timer on Compare Match mode)
Der CTC Modus ist eine Erweiterung des "Output-Compare"-Funktion. Der
CTC Modus eignet sich besonders, um einen mit konstanter Frequenz
wiederkehrenden Interrupt zu erzeugen. Wie im normalen Modus zählt der
Timer hoch. Wenn der Wert im OCRx Register erreicht wird, wird
zusätzlich zum möglichen Interrupt der Zähler wieder auf 0 gesetzt. Es
kann also die maximalen Zählergrenze selber definiert werden.
Bascom hilfe dazu:
'The TIMER also has two compare registers A and B
'When the timer value matches a compare register, an action can be
performed
Config Timer1 = Counter , Edge = Falling , Compare A = Set , Compare B =
Toggle , Clear Timer = 1
'SET , will set the OC1X pin
'CLEAR, will clear the OC1X pin
'TOGGLE, will toggle the OC1X pin
'DISCONNECT, will disconnect the TIMER from output pin OC1X
'CLEAR TIMER will clear the timer on a compare A match
'To read write the compare registers, you can use the COMPARE1A and
COMPARE1B variables
Compare1a = W
W = Compare1a
'And the TIMER can be used in PWM mode
'You have the choice between 8,9 or 10 bit PWM mode
'Also you can specify if the counter must count UP or down after a match
'to the compare registers
'Note that there are two compare registers A and B
Config Timer1 = Pwm , Pwm = 8 , Compare A Pwm = Clear Up , Compare B Pwm
= Clear Down , Prescale = 1
'to set the PWM registers, just assign a value to the compare A and B
registers
Compare1a = 100
Compare1b = 200
'Or for better reading :
Pwm1a = 100
Pwm1b = 200
End
Nun wie weiter ? ausserdem warum ausgerechnet 1 ms erzeugen ? und wie
Konfiguarieren ?
Also mit AVR Calculator habe folgendes ermittelt:
Takt 16 MHz
Interrupttime : 1000us
Interrupt : compare
Timer 16 Bit
Prescale : 128
Compare : 124
Thomas Kiss schrieb:> Allein der Name Nixwisser ist unheimlich UNTERTRIEBEN !!!!
Das sehen Andere anders.
> Nun zur meiner Entschuldigung :
Nix Entschuldigung oder Rechtfertigung, besser...
> Also "schmeissen wir alles weg" und fangen neu an.
Wir? - Du... Aber wirklich von vorn, und den nächsten Schritt erst dann
machen, wenn der vorherige verstanden wurde...
> Erstes :> Timer1: Erzeugung eines Taktes von 1ms per Compare-CTC-Interrupt.>> Nun schreibt RN-Wissen :> CTC Modus (Clear Timer on Compare Match mode)> Der CTC Modus ist eine Erweiterung des "Output-Compare"-Funktion. Der> CTC Modus eignet sich besonders, um einen mit konstanter Frequenz> wiederkehrenden Interrupt zu erzeugen. Wie im normalen Modus zählt der> Timer hoch. Wenn der Wert im OCRx Register erreicht wird, wird> zusätzlich zum möglichen Interrupt der Zähler wieder auf 0 gesetzt. Es> kann also die maximalen Zählergrenze selber definiert werden.
Das ist korrekt...
> Bascom hilfe dazu:
Das Datenblatt ist verbindlich, Bascom kann nicht alles, was die Timer
können. Bascom-Config kann gehen, muss aber nicht...
> 'To read write the compare registers, you can use the COMPARE1A and> COMPARE1B variables
Gut zu wissen (wenn man es braucht). Bei ADCH und ADCL stimmt diese
Regel aber nicht, denn ADC isrt ein reserviertes ASM-Schlüsselwort.
Deshalb tu ich mich etwas schwer mit dem Verallgemeinern von Regeln...
> Compare1a = W>> W = Compare1a
Gut, dann ist der Zugriff auf Compare1a geklärt, das brauchst Du ja nur
ein mal in der Init...
>> 'And the TIMER can be used in PWM mode
Nix PWM, Interrupt...
> 'Note that there are two compare registers A and B
Das weiß das Datenblatt auch. Und das ist verbindlich, weil vom
Hersteller...
>> Config Timer1 = Pwm , Pwm = 8 , Compare A Pwm = Clear Up , Compare B Pwm> = Clear Down , Prescale = 1
Was willst Du nur mit PWM???
> Nun wie weiter ? ausserdem warum ausgerechnet 1 ms erzeugen ?
Weil 1ms das kleinste gemeinsame Vielfache der für Dein Projekt
benötigten Takte ist. Du brauchst:
- 1ms für Drehgeber,
- 20 ms für Entprellung und Tondauerzählung (also jede 20. Runde
des Drehgebertaktes),
- 1000 ms bzw. 1 Sekunde für Zeitzählung der Uhr (also jede 50. Runde
des Entprelltaktes
Nenne mir einen anderen Takt, der dafür besser geeignet ist???
> und wie> Konfiguarieren ?>> Also mit AVR Calculator habe folgendes ermittelt:
Vergiss den Mist und rechne selber, sonst lernst Du es nämlich nie!
> Takt 16 MHz
Ja...
> Interrupttime : 1000us
Ja...
> Interrupt : compare
Ja...
> Timer 16 Bit
Ja...
> Prescale : 128> Compare : 124
Nein!
Denn 128 mal 124 ist nach Adam Ries 2072 Und wenn man mit 125 rechnet,
weil man vermutet, dass der Compare nicht bei Gleichstand, sondern bei
Überschreiten des Vergleichswertes zuschlägt, dann sind es 32000 Takte.
Und wieviel brauchst Du? 16 MHz geteilt durch 1 kHz (Kehrwert von 1 ms)
ist immer noch 16000 und nicht 32000. Dazu braucht man weder ein
Programm wie AVR-Calc noch einen Taschenrechner.
MfG
Schön wieder etwas von Dir zu hören...( Muss mal ein Bier ausgeben ) !!
Okay..
PWM war mist..ich weiss ( Hatte ich mit strg+C mitgenommen aus dem
Lesestoff )
Grübel :
"Denn 128 mal 124 ist nach Adam Ries 2072 Und wenn man mit 125 rechnet,
weil man vermutet, dass der Compare nicht bei Gleichstand, sondern bei
Überschreiten des Vergleichswertes zuschlägt, dann sind es 32000 Takte.
Und wieviel brauchst Du? 16 MHz geteilt durch 1 kHz (Kehrwert von 1 ms)
ist immer noch 16000 und nicht 32000. Dazu braucht man weder ein
Programm wie AVR-Calc noch einen Taschenrechner."
Kann ich auch so rechnen ?
16000000/ 128 ( prescale ) wäre 125000 dann nehme Comparewert 125 und
habe 1000 Hz..Wenn ja, dann verstanden.
dann wäre :
Config Timer1 = Counter , Edge = Falling , Compare A = Set , Compare B =
Toggle , Clear Timer = 1
( Ausgang OC1B wir getogglet also 1 Khz ) aber wenn ich Timer als
counter nehmen wo gebe ich den Parameter prescale an ?
Falsch..timer1 hat Prescale (1,8,64,256,1024)
Also wenn ich 256 nehme dann habe ich 62500 ( komme also nicht auf
1000Hz)
bei 64 wäre 16000000 = 250000 eine Comparewert vom 250.
könnte der Timer also so aussehen ?
Config Timer1=Timer, prescale = 256
On Compare1a Taktgeber
Enable Compera1a
Enable Interrupts
Const Reload 250 ( habe gesehen dies ist der Comparewert )
Blättere mal ein paar Beiträge zurück, dahin, wo ich die
Timereinstellungen anhand des Datenblatts zusammengesucht habe. Ich habe
Dir das da bereits alles haarklein erklärt. Auch wenn Du es da noch
nicht verstanden hast, vielleicht verstehst Du es ja jetzt. Ich muss
auch so manchen Stoff mehrmals lesen um ihn zu verstehen.
MfG
Mein Verständnis zu CTC Mode:
Der Timer1 läuft durch und wenn Timer 1 und Comparewert gleich sind,
wird der Timer gestoppt und ein Interrupt ausgelöst und der Timer neu
gestartet. Da der Timer fixewert ist, kann mit mit verschiedene Compare
Wert auch verschiedene Frequenzen erzeugen.
Ist von der Funktion /Ergebnis das gleiche ?
OCR1A = 2000 '2000 x 8 Takte bis zum Compare-Match
TCCR1B = &b00001010 'CTC-Mode für Compare1A
TIMSK = &b00010000 'Compare1A-Interrupt freigeben
Enable Interrupts 'Interrupts global freigeben
On Goto Taktms
Enable Timer1
Config Timer1=timer,Prescale 256,Compare A=toggle
start Timer 1
Compare1a=250
Nur als Hinweis:
>On Goto Taktms
Das funktioniert nicht, weil GOTO ein reserviertes Wort ist.
Initialisierung:
On Timer1 Taktms
Interruptroutine:
Tamktms
Tralala
Schnulli
Return
Thomas Kiss schrieb:> Ich habe zwar die Definition (wie oben ) noch nicht verdaut muss ich mal> versuchen aus dem Datenblatt die Sachen nachzuvollziehen, ob es mir> gelingt ist die Frage...
Welche Definition?
>> Nun so würde das neue Programm beginnen>> '********************************************************> '* LCD Uhr mit Polin Drehencoder> '* Encoder Routine vom Screwdriver *> '********************************************************>>>> '********************************************************> '* ATMEGA8 *> '********************************************************> ' --------------> ' (Reset) PC6 - | 1 28 | PC5 (ADC5)> ' (RXD) PD0 - | 2 27 | PC4 (ADC4)> ' (TXD) PD1 - | 3 26 | PC3 (ADC3)> ' (INT0) PD2 - | 4 25 | PC2 (ADC2)> ' (INT1) PD3 - | 5 24 | PC1 (ADC1)> ' (XCK) PD4 - | 6 23 | PC0 (ADC0)> ' VCC - | 7 22 | GND> ' GND - | 8 21 | AREF> ' (XTAL1) PB6 - | 9 20 | AVCC> ' (XTAL2) PB7 - | 10 19 | PB5 (SCK)> ' (T1 ) PD5 - | 11 18 | PB4 (MISO)> ' (AIN0) PD6 - | 12 17 | PB3 (OC2)> ' (AIN1) PD7 - | 13 16 | PB2 (OC1B)> ' (ICP1) PB0 - | 14 15 | PB1 (OC1A)> ' --------------
Bis hierher sieht's zwar cool aus, sagt aber absolut nichts darüber aus,
welche Peripherie an welchen Portpin angeschlossen ist. Es ist daher
völlig unnütz und bläht nur den Quelltext auf.
>>> $regfile = "m8def.dat"> $crystal = 16000000> $hwstack = 100> $swstack = 100> $framesize = 100
Du weißt, warum Du diese Werte niimmst und keine anderen?
>> Die Initialisierung des Timer1 wäre also:>> OCR1A = 2000 '2000 x 8 Takte bis zum Compare-Match> TCCR1B = &b00001010 'CTC-Mode für Compare1A> TIMSK = &b00010000 'Compare1A-Interrupt freigeben> Enable Interrupts 'Interrupts global freigeben
Das könnte richtig sein, wenn Du es aus dem Beitrag weiter oben
abgeschrieben hast oder wenn Du es korrekt aus dem Datenblatt
zusammengesucht hast. Ich nehme es einfach mal so hin, ohne es weiter zu
überprüfen.
> On Goto Taktms
Hmmm, dann schau noch mal in die Hilfe zu On Interrupt. Du müsstest dem
Compiler zumindest noch mitteilen ON was er nach Taktms GOTOn soll.
>>>>> Dim Zeit(12) As Byte
Warum 12 Elemente? Bitte aufzählen...
>> Dim Sekunde As Byte> Dim Minute As Byte> Dim Stunde As Byte
Warum doppelt gemoppelt? Wer soll das verwalten? Die "Einzelteile" der
Zeit wurden doch in ein Array gelegt, um (beim Drehgeber-Zugriff) den
Zugriff über Index (Menüpunkt-Nummer) zu ermöglichen. Wozu in Gottes
Namen deklarierst Du diese Variablen nochmal einzeln???
>> Zeit(1) = Sekunde> Zeit(2) = Minute> Zeit(3) = Stunde
Dies interessiert den Compiler nicht, dies muss in Deinen Kopf. Außerdem
ist es programmtechnisch totaler Unsinn, da zu diesem Zeitpunkt "Zeit()"
noch keine Daten enthält.
>>>>> Taktms:>> Return
Schonmal (fast) richtig. Mach' ich auch so. Wenn ich den Kopf eines
Unterprogramms oder einer ISR schreibe, dann schreibe ich auch gleich
den Fuß (den Rücksprung), erst danach fülle ich die Routine mit
Programmcode auf. Allerdings versehe ich den Kopf auch gleich mit einem
Kommentar.
>> Also am Ausgang PB1 würde ich 1 Khz messen ?
Nö, wieso solltest Du? Ich kann nicht sehen, wo Du PB1 "angefasst" hast.
Oder hast Du Timer1 etwa mit Pinklappern initialisiert? Lies nochmal
das, was ich letztens über die Initialisierung des Timer1 geschrieben
habe und beachte dabei, dass das Ziel bei Timer1 nicht das Pinklappern
in Hardware ist, sondern das Auslösen eines Interrupts alle 16000
CPU-Takte.
>> Gibt es irgendwelche Möglichkeit den Timer1 "lesbarer> bzw.verständlicher" zu konfigurieren ?>> Wie hier :> Config Timer1 = Timer , Prescale = 256> Enable Timer1> On Timer1 Takt> Enable Interrupts> Timer1 = 3036
Das musst Du den Bascom-Macher fragen. Leider sind die Timer der
verschiedenen AVR-Typen so unterschiedlich ausgestattet, dass es zuviel
verlangt wäre, wenn Bascom alles Machbare berücksichtigen würde und es
in Config-Blabla übersetzen würde.
Verständlicher finde ich übrigens das Config-Geraffel nicht, denn dabei
muss man ein weiteres mal um die Ecke denken. Der AVR kennt keinen
Config-Befehl, der hat zum Einstellen seiner internen Peripherie-Module
die I/O-Register. Die (verbindliche!!!) Beschreibung findet man im
Datenblatt. Also ist die einfachste und unmissverständlichste Art einen
Timer einzustellen, das Zusammensuchen der Steuerbits aus dem Datenblatt
und Setzen der Steuerregister.
Wenn Du nicht bereit bist, Dich beim Programmieren auf Bitebene
herabzulassen, dann solltest Du Dir einen Mikrocontroller mit
Sprachschnittstelle suchen, den Du dann mit gesprochener Prosa
programmieren kannst. ^^
>> Ganz einfach 1 Hz>> Mir ist zwar nicht 100% klar ( wegen Genaugkeit ?? ) daß man CTC> Modus nehmen sollt ? Also mein 1 Hz Takz ist wirklich ganz genau. Reicht> diese "standard Modus nicht aus um 1000 Hz zu bekommen ?
Dann lies diesen Thread nochmal von vorn. Achte dabei darauf, wie Bascom
bei Aufruf von ISRs Rechenzeit verschwendet. Und denke mal drüber nach,
was passiert, wenn mehrere verschiedene Timer-Interrupts (einer für die
Sekunde, einer für die Drehgeber-Abfrage, einer für die
Tastenentprellung) nebenher laufen und neben ihrer Arbeit noch um die
100 Takte die CPU unnötig blockieren.
Und ja, das Vorladen des Timers in der ISR ist eine Möglichkeit, seinen
Zählumfang zu begrenzen. Bei alten AVRs wie dem AT90S1200 war es sogar
die einzige Möglichkeit. Sie funktioniert aber nur genau, wenn
sichergestellt ist, dass der Timer noch nicht weitergezählt hat, wenn
die ISR dazu kommt, den Zählerstand des Timers zu "fälschen". Da Bascom
den ISR-Aufruf durch Registersicherung (auch der Register, die die ISR
im Einzelfall gar nicht braucht) verzögert, ist das nicht
sichergestellt, erst recht nicht, wenn mehrere Interrupts laufen und sie
im ungünstigen Fall Schlange stehen und sich gegenseitig verzögern.
Deshalb bevorzuge ich es, mit einem Timer-Interrupt auszukommen, wenn
ich mehrere starr aneinander gekoppelte Takte brauche. Das mache ich
sogar in Assembler so, obwohl mich da ein ISR-Aufruf nur etwa 10 Takte
Overhead kostet.
MfG
Thomas Kiss schrieb:> Mein Verständnis zu CTC Mode:>> Der Timer1 läuft durch und wenn Timer 1 und Comparewert gleich sind,> wird der Timer gestoppt
Nein, er wird nicht gestoppt.
> und ein Interrupt ausgelöst und der Timer neu> gestartet.
Nein, er wird nicht neu gestartet.
Er wird lediglich auf 0 gesetzt (gefälscht), und das ohne Abarbeitung
von Programmcode, ganz in Hardware und das auch noch exakt in dem Takt,
in dem der Vergleichswert erreicht wurde.
> Da der Timer fixewert ist, kann mit mit verschiedene Compare> Wert auch verschiedene Frequenzen erzeugen.
Das kann ich nicht nachvollziehen weil ich nicht weiß, was Du in diesem
Zusammenhang mit Fixwert meinst.
>> Ist von der Funktion /Ergebnis das gleiche ?>> OCR1A = 2000 '2000 x 8 Takte bis zum Compare-Match> TCCR1B = &b00001010 'CTC-Mode für Compare1A> TIMSK = &b00010000 'Compare1A-Interrupt freigeben> Enable Interrupts 'Interrupts global freigeben> On Goto Taktms
Lies bitte die Hilfe zu On Interrupt!!!
>>> Enable Timer1> Config Timer1=timer,Prescale 256,Compare A=toggle> start Timer 1>> Compare1a=250
Warum CompareA=toggle? Willst Du Pinklappern oder willst Du Interrupts
generieren? Das ist nämlich Zweierlei, dieser Timer kann Beides...
MfG
@KC
KC schrieb:
> Da Du 16000 Takte abzählen willst, funktioniert das schon mit Vorteiler> 1. Dann gehört der Wert von 16000 (oder 15999 - da streiten sich die> Geister) ins Compare-Register.
Da streiten sich gar keine Geister, mir scheint nur Du weißt es nicht.
Es gibt eine Formel dazu, zu finden im DB des µC unter Fast PWM:
fOCnxPWM = fclk_I/O/(N * (1 + TOP)
Diese Berechnung trifft genauso für CTC zu, z.B bei Prescaler (N) =
1024:
1Hz = 16000000 / (1024 * (1 + 15624)
KC schrieb:
> Das musst Du den Bascom-Macher fragen. Leider sind die Timer der> verschiedenen AVR-Typen so unterschiedlich ausgestattet, dass es zuviel> verlangt wäre, wenn Bascom alles Machbare berücksichtigen würde und es> in Config-Blabla übersetzen würde.
CTC ist gaaanz einfach zu konfigurieren, nur wenn Du Thomas glauben
machst, daß Du Ahnung hast und dann gleichzeitig zur Leserlichkeit des
Codes völlig untaugliche Bitdefinitionen wie hier verwendest, brauchst
Du Dich nicht wundern den Lernenden zu verunsichern:
KC schrieb:
> Inwieweit die Bascom-Dat-Dateien das berücksichtigen, weiß ich nicht,> daher ist es sicher besser (aber bedeutend unleserlicher!), wenn wir es> nicht austesten, sondern gleich die dahinter stehenden Zahlen verwenden
...
> TCCR1B = &b00001010
Ich dachte, Du hast Assembler programmiert ? Auch für AVR Assembler
gibt's symbolische Konstanten als Klarnamen der Register und deren Bits,
damit man nicht nachher an den Bits abzählen muss, was da gemeint war.
Unwissenheit darüber was Bascom kann sollte doch nicht dazu führen einem
Anfänger solchen schlechten Stil beizubringen.
@thomaskiss
Ihr unterhaltet Euch ja gut und ich will die Harmonie ja nicht stören
;-)
Wär' ich allerdings ein Anfänger, dann würde ich nicht viel aus diesem
Thread lernen, zuviel Text und zuwenig Fleisch auf den Knochen. Noch
dazu gibt's ein paar Sachen in diesem Thread, die man so nicht lernen
sollte.
Den CTC Modus schaltet man z.B. so ein:
Guten Morgen...
Definition habe ich gemeint , Timer und seine Betriebsarten. Habe gerade
das Datenblatt von Seite 77 bis 103 ausgedruckt. Nächste Woche,
spätestens bin auf Geschäftsreise, werde ich in alle Ruhe durchlesen (
Naja nächste Monat müssen wir in eine neue Wohnung, es gibt auch dort
viel zu tun )
> $regfile = "m8def.dat" 'Definition des AVR> $crystal = 16000000 'verwendete Quarz> $hwstack = 100 'Hardware Stackgrösse> $swstack = 100 'Software Stack> $framesize = 100 'Framesize
Es sind zwar nicht die standard Werte, aber so hats bissher gefunzt
Ist von Dir ertmal übernommen,
OCR1A = 2000 '2000 x 8 Takte bis zum Compare-Match
TCCR1B = &b00001010 'CTC-Mode für Compare1A
TIMSK = &b00010000 'Compare1A-Interrupt freigeben
'Enable Interrupts 'Interrupts global freigeben
Enable Int0
On Int0 Taktms
Hieer ist Int0 eingeschaltet, wenn interrupt ausgelöst wird, soll in Sub
Taktms springen, etwas ausführen und zurück..so gedacht..
(Wobei generelle Interruptfreigabe sollte man meiden !! )
RN-Wissen sagt :
Man soll darauf achten, dass in der ISR immer nur kurze Anweisungen
abgearbeitet werden und der Hauptteil dann im Hauptprogramm bearbeitet
wird. Sonst kann es sein, dass man den Prozessor damit blockiert.
Insbesondere Befehle wie "Wait" oder "Print" sollte man in der ISR
vermeiden.
Und habe noch dieses gefunden :
http://staff.ltam.lu/feljc/electronics/bascom/BASCOM_Tutorial_2.pdf
Bei dem Array habe ich 12 spalten festgelegt ( 3 erstmal, aber reserve
für andere Variablen )
Habe scon nach Array geschaut, aber auch nichts 100% gefunden ( Buch und
Kugel, und Bascom Hilfe )
Mein Verständnis
Dim Zeit(12) As Byte Array mit 12 Elementen anlegen Name Zeit
Meine Gedanke war :
Dim Sekunde As Byte
Dim Minute As Byte
Dim Stunde As Byte
3 Variablen definieren wie bisher, weil ich die Variablen für
verschiedene Sachen brauchen werde...
Zeit(1) = Sekunde
Zeit(2) = Minute
Zeit(3) = Stunde
Ich sage hier, daß die Variablen in den Array geschrieben werden sollen
"> Also am Ausgang PB1 würde ich 1 Khz messen ?
Nö, wieso solltest Du? Ich kann nicht sehen, wo Du PB1 "angefasst" hast.
Oder hast Du Timer1 etwa mit Pinklappern initialisiert? Lies nochmal
das, was ich letztens über die Initialisierung des Timer1 geschrieben
habe und beachte dabei, dass das Ziel bei Timer1 nicht das Pinklappern
in Hardware ist, sondern das Auslösen eines Interrupts alle 16000
CPU-Takte."
Das stimmt..Interrupt kann man nicht "messen" es sei denn
definirt man den Ausgang als output
"Also ist die einfachste und unmissverständlichste Art einen
Timer einzustellen, das Zusammensuchen der Steuerbits aus dem Datenblatt
und Setzen der Steuerregister."...iiiiiii naja hoffe das ich nach dem
ich die 30 Seiten gelesen habe bzw. noch Beispiele finde wo es
nachvollziehbar ist, dann wirds einfach..
Das ist ja spannend !
> Mein Verständnis zu CTC Mode:>> Der Timer1 läuft durch und wenn Timer 1 und Comparewert gleich sind,> wird der Timer gestoppt
Nein, er wird nicht gestoppt.
> und ein Interrupt ausgelöst und der Timer neu> gestartet.
------- Habe im Buch so gelesen------
AWS : Assembler ? keine Ahnung...ich versuche klar irgendwie das System
zu kapieren, als Anfänger komme sehr oft ins schleudern..
Den CTC Modus schaltet man z.B. so ein:
Config Timer1 = Timer , Prescale = 1024 , Clear Timer = 1
Das hier, so schlicht unslesbar:
TCCR1B = &b00001010
wird so viel lesbarer:TCCR1B = Bits(WGM12, CS11) Lesbarar schon aber was
ist WGM12,cs11 )
> wird so viel lesbarer:TCCR1B = Bits(WGM12, CS11) Lesbarar schon aber> was ist WGM12,cs11 )
Ich hab' mich auf die Direktdefinition der Register wie TCCR1B = ...
bezogen, die Du eigentlich gar nicht benötigst. Es ist sicher nicht
schlecht darum zu wissen, aber im momentanen Stadium scheinst Du mir
doch ein wenig erschlagen von zuviel Information.
Wenn Du den CTC Modus verwenden willst, also als Obergrenze Compare1a
setzen möchtest, dann konfiguriert Bascom mit dieser Zeile:
die Register TCCR1A und TCCR1B für Dich.
Das ist gerade die Stärke von Bascom, daß wenn man Standardfunktionen
benötigt, sich eben nicht in das Registergewurschtel einarbeiten muss.
Aber zu Deiner Frage:
Die Registerbits WGM12, WGM11, WGM10 legen den Modus des Timers fest, es
gibt verschiedene Modi, unter Anderem einen, bei dem der Zähler nach
Erreichen von Compare1A auf 0 zurücksetzt. Das hält ihn nicht an, er
läuft dann weiter und zählt erneut 1,2,3...
Die Registerbits CS12, CS11, CS10 geben an welcher Prescaler verwendet
werden soll, oder ob ein externer Takt verwendet wird.
Man kann unter Bascom entweder Config Timer1 = ... schreiben, oder eben
auch die Prozessorregister selbst setzen mit TCCRA = ..., TCCRB = ...
Wenn Du Letzteres machen willst, so sieh Dir das Datenblatt des ATMega8
an, gibt's bei Atmel, dort sind diese Register alle beschrieben.
Würde aber jetzt darauf noch verzichten, denn das Config = ... macht
alles was Du brauchst.
> Ist sowas hier "brauchbar" ???> http://www.avr-praxis.de/forum/archive/index.php?t-63.html
Da kommt einiges an C vor, das kann Dich eher verwirren, denn helfen.
Such' Dir lieber etwas für Bascom.
Nochmal gelesen..."Die 1ms-ISR behandelt den Encoder und zählt 20 ISRs
für den 20ms-Takt
ab.
Jede 20. ISR wird der Taster abgefragt und entprellt und das Ergebnis
(neuer Tastendruck, langer Tastendruck) dem Hauptprogramm per Merker
mitgeteilt, dann wird 50 Runden abgezählt, was den 1s-Takt ergibt.
Im 1s-Takt wird die Sekunde hochgezählt. Nur hochgezählt, nicht auf
Überlauf überprüft. Das kann die Mainloop machen. Und es wird noch ein
Merker für die nächste LCD-Ausgabe gesetzt. Die Mainloop weiß dann
anhand des Merkers, dass sie die Sekunden (und nur die) neu ausgeben
muss.
"
Taktms:
Load Timer1 , Timer1wert
wie sage hier das gezählt werden soll
so :
Taktms:
Load Timer1 , Timer1wert
incr geber
if geber =20 then
Taster abfrage
if geber =50 then
incr sekunde
if geber >50 then geber=0
....
return
Konfuse ;
Kluchscheisser meinte :
Der Interrupt des Timer1 liefert also:
- vom Drehgeber ggf. aktualisierte Werte in Zeit(Menupunkt)
- Merker.ms20
- Merker.sekunde
- Sekundenwert
Und mehr erstmal nicht.
( und in ein paar anderen Antworten so ähnlich )
oder habe wieder was falsch verstanden ?
Ja freilich hat er das so gemeint. Du hast so in einer
Interruptroutine
alle Zeiten, die Du brauchst auf einen Schlag gewonnen. Und- Keine Zeit
kommt der Anderen in die Quere, weil sie dadurch alle starr aneinander
gekoppelt sind.
Immer Eins nach dem Anderen, wie man die Klöße ißt...
;-)
MfG Paul
Shit kriege ich nicht zusammen ,trotzdem dass ich schon alles zigmal
durchgelesen habe :
$regfile = "m8def.dat"
$crystal = 16000000
$hwstack = 32
$swstack = 10
$framesize = 40
Dim Rotary0 As Byte 'Phasenzustand des Drehencoders
Dim Rotary1 As Byte 'Zähler der Phasenwechsel
Dim Rotary2 As Byte 'Hilfsvariable
Dim Rotary As Byte 'Encoder-Wert
Dim Rotary_last As Byte 'Letzter Encoder-Wert (nur für
Demo)
Dim Sekunde As Byte
Dim Millisekunden As Byte
Dim Ms20 As Byte
Dim Alarm As Bit
Dim Merker As Byte
Config Pind.1 = Input
Taster Alias Pind.1
Portd.1 = 1
' Timer 1 = Zeitbasis
On Timer1 Taktms
Config Timer1 = Timer , Prescale = 1024 , Clear Timer = 1
TCCR1B = Bits(WGM12, CS11)
Enable Timer1
Enable Interrupts
' Hauptprogramm
Do
'Aktuelle Zeit anzeigen
If Rotary_last <> Rotary Then 'Encoder gedreht?
Rotary_last = Rotary 'Neue Stellung merken
Print Rotary 'und Encoder-Wert ausgeben
End If
'Alarmbedingungen prüfen
If Alarm = 1 Then
Gosub Alarm
End If
'Auf Drehgeberknopf reagieren
If Taster = 0 Then
Gosub Menu
End If
Loop
Menu:
Return
Alarm:
Return
Taktms:
Rotary0 = Encoder(pinc.0 , Pinc.1 , Links , Rechts , 0)
Incr Millisekunden 'Millisekunden hochzählen, 0 bis 19, 20 = 0
If Millisekunden > 19 Then 'Takt für 20 ms erzeugen
Millisekunden = 0 'Zählumfang 0 bis 19, 20 = 0
Disable Interrupts 'Routine zur Anpassung des ENCODER-Befehls
Rotary2 = Rotary1
Rotary1 = Rotary1 And 1
push r0
lds r0,{rotary2}
asr r0
sts {rotary2},r0
pop r0
Rotary = Rotary + Rotary2
Enable Interrupts
Incr Ms20 '20ms-Einheiten hochzählen (50 = 1 Sekunde)
If Ms20 > 49 Then 'Takt für 1000 ms (1 Sek.) erzeugen
Ms20 = 0 'Zählumfang 0 bis 49, 50 = 0
Incr Sekunde 'Sekunde erhöhen
set merker.0 'Sekundenausgebe für LCD anmelden
End If 'Ende Sekundentakt
End If 'Ende 20ms-Takt
Return 'Ende ISR
Compiler meckert :
Error 61 Line 110 Label not found und zeigt den Return an...Return
brauche ich aber ( Ende ISR )
Was ist genau mit Set merker.0 gemeint ? chekce nicht
>Was ist genau mit Set merker.0 gemeint ? chekce nicht
Merker.0 ist das unterste Bit eines Bytes mit dem Namen "Merker".
Wenn Du einzelne Bits irgendwo merken lassen willst, dann geht das,
indem
Du ganz oben im Programm einen Merker definierst:
Dim Merker as Byte
Da das Byte aber 8 Bit enthaelt, kannst Du nun 8 Bit einzeln da "hinein-
tun" und aufbewahren. Um wieder dran zu kommen, musst Du nun eben die
Stelle im Byte angeben, wo es sitzt.
Merker.0 oder Merker.3.....Merker.7
"Merker" ist kein Bascom-Schluesselwort, es ist frei gewaehlt. Du
koenntest
ebensogut:
Dim Alfred as Byte
Set alfred.6
schreiben.
MfG Paul
> Kapiert..aber warum meckert der Compiler ?
Das sollte er doch anzeigen, warum er meckert.
Du hast in Encoder 2 Label angegeben, Links, Rechts, diese Label sind
nirgends im Code zu finden.
Bezüglich "merker", das ist eine Möglichkeit genau zu definieren,
welches Bit in welcher "Wirtsvariable" gespeichert wird.
Falls das nicht nötig ist, dann kann man eine Variable einfach als
1
Dim Flag As Bit
definieren. Dann kümmert sich Bascom darum, wo es dieses Bit ablegt.
Ist soweit mein Coce jetzt okay ?
Kluchscheisser meinte :
"In der Mainloop wird die Sekunde auf >59 geprüft. Ist die Bedingung
erfüllt, so wird sie nicht etwa auf 0 gesetzt, sondern es werden 60
Sekunden subtrahiert. Damit erreicht man, dass es auch dann noch stimmt,
wenn die Mainloop aufgrund anderer Jobs mit mehr als 1s Verspätung zum
Zuge kommt. Und hier, also wenn sekunde>59 war, wird die gesamte Uhr mit
Kalender, Mülltermine, Geburtstagsblumenbestelltermine, Weckzeiten usw.
abgearbeitet. Denn dieser Teil der Mainloop wird nur einmal pro Minute
aufgerufen. Und jeder Teil, der sich geändert hat (und wirklich nur das,
was sich geändert hat), wird auch am LCD aktualisiert.
Dies wäre der Grundstein für einen Multitasking-Aufbau Deines
Programmes."
Nun mein Versuch hierzu :
$regfile = "m8def.dat"
$crystal = 16000000
$hwstack = 32
$swstack = 10
$framesize = 40
Dim Rotary0 As Byte
'Phasenzustand des Drehencoders
Dim Rotary1 As Byte 'Zähler der
Phasenwechsel
Dim Rotary2 As Byte
'Hilfsvariable
Dim Rotary As Byte
'Encoder-Wert
Dim Rotary_last As Byte 'Letzter
Encoder-Wert (nur für Demo)
Dim Sekunde As Byte
Dim Minute As Byte
Dim Stunde As Byte
Dim A_sekunde As Byte
Dim A_minute As Byte
Dim A_stunde As Byte
Dim S1 As String * 2 'Sekunde
'
Dim S2 As String * 2 'Minute
Dim S3 As String * 2 'Stunde
Dim S4 As String * 2 'Alarm
Sekunde
Dim S5 As String * 2 'Alarm
Minute
Dim S6 As String * 2 'Alarm
Stunde
Dim Millisekunden As Byte
Dim Ms20 As Byte
Dim Alarm As Bit
Dim Merker As Byte
Dim Menuezaehler As Byte
Config Pind.1 = Input
Taster Alias Pind.1
Portd.1 = 1
' Timer 1 = Zeitbasis
On Timer1 Taktms
Config Timer1 = Timer , Prescale = 1024 , Clear Timer = 1
Tccr1b = Bits(wgm12 , Cs11)
Enable Timer1
Enable Interrupts
Config Lcdpin = Pin , Db7 = Portb.0 , Db6 = Portd.7 , Db5 = Portc.2 , _
Db4 = Portc.3 , E = Portc.4 , Rs = Portc.5
Config Lcd = 16 * 2
Cls
Cursor Off
Stunde = 12
A_minute = 1
' Hauptprogramm
Do
If Sekunde = 60 Then
Sekunde = Sekunde - 60
Minute = Minute + 1
If Minute = 60 Then
Minute = 0
Stunde = Stunde + 1
If Stunde > 23 Then
Stunde = 0
End If
End If
End If
'LCD Ausgabe formattieren
S1 = Str(sekunde) 'Uhr Sekunde
S1 = Format(s1 , "00")
'----------------------------------
S2 = Str(minute) 'Uhr Minute
S2 = Format(s2 , "00")
'------------------------------------
S3 = Str(stunde) 'Uhr Stunde
S3 = Format(s3 , "00")
'--------------------------------------
S4 = Str(a_sekunde) 'Alarm
Sekunde
S4 = Format(s4 , "00")
'----------------------------------
S5 = Str(a_minute) 'Alarm
Minute
S5 = Format(s5 , "00")
'------------------------------------
S6 = Str(a_stunde) 'Alarm
Stunde
S6 = Format(s6 , "00")
'--------------------------------------
Locate 1 , 1
Lcd "Uhr: " ; S3 ; ":" ; S2 ; ":" ; S1
Locate 2 , 1
Lcd "M:" ; Menuezaehler ; " " ; "Al:" ; S6 ; ":" ; S5 ; ":" ; S4
If Rotary_last <> Rotary Then 'Encoder
gedreht?
Rotary_last = Rotary 'Neue
Stellung merken
Print Rotary 'und
Encoder-Wert ausgeben
End If
'Alarmbedingungen prüfen
If Alarm = 1 Then
Gosub Alarm
End If
'Auf Drehgeberknopf reagieren
If Taster = 0 Then
Gosub Menu
End If
Loop
Menu:
Return
Alarm:
Return
Taktms:
Rotary0 = Encoder(pinc.0 , Pinc.1 , Links , Rechts , 0)
Incr Millisekunden
'Millisekunden hochzählen, 0 bis 19, 20 = 0
If Millisekunden > 19 Then 'Takt für 20
ms erzeugen
Millisekunden = 0 'Zählumfang
0 bis 19, 20 = 0
Disable Interrupts 'Routine zur
Anpassung des ENCODER-Befehls
Rotary2 = Rotary1
Rotary1 = Rotary1 And 1
push r0
lds r0,{rotary2}
asr r0
sts {rotary2},r0
pop r0
Rotary = Rotary + Rotary2
Enable Interrupts
Incr Ms20
'20ms-Einheiten hochzählen (50 = 1 Sekunde)
If Ms20 > 49 Then 'Takt für
1000 ms (1 Sek.) erzeugen
Ms20 = 0 'Zählumfang
0 bis 49, 50 = 0
Incr Sekunde 'Sekunde
erhöhen
Set Merker.0
'Sekundenausgebe für LCD anmelden
End If 'Ende
Sekundentakt
End If 'Ende
20ms-Takt
Return 'Ende ISR
Rechts: 'Bei
Rechtsdrehung
Rotary1 = Rotary1 + 1
If Rotary > 59 Then
Rotary = 0
End If
'Zählvariable Phasenwechsel erhöhen
Return
Links: 'Bei
Linksdrehung
Rotary1 = Rotary1 - 1
'Zählvariable Phasenwechsel vermindern
Return
Meine nächste Frage wäre, wie ich folgendes einstellen könnte.
Bisher war es so :
If Taster = 0 Then
Gosub Menue
End If
Menue:
Waitms 50
Incr Menuezaehler_temp
If Menuezaehler_temp = 2 Then Menuezaehler = 1 'Uhr stellen
If Menuezaehler_temp = 4 Then Menuezaehler = 2 'Stunde
stellen
If Menuezaehler_temp = 6 Then Menuezaehler = 3 'Sekunde
stellen
If Menuezaehler_temp = 8 Then Menuezaehler = 4 'Alarm
Stunde stellen
If Menuezaehler_temp = 10 Then Menuezaehler = 5 'Alarm
Minute stellen
If Menuezaehler_temp = 12 Then Menuezaehler = 6 'Alarm
Sekunde stellen
If Menuezaehler_temp > 14 Then Menuezaehler_temp = 0
Return
Select Case Menuezaehler
Case 1 : Gosub Alarm_stunde_stellen
Case 2 : Gosub Alarm_minute_stellen
Case 3 : Gosub Alarm_sekunde_stellen
Case 4 : Gosub Uhr_stellen
Case 5 : Gosub Minute_stellen
Case 6 : Gosub Sekunde_stellen
End Select
Uhr_stellen:
Stunde = Rotary
Return
Minute_stellen:
Minute = Rotary
Return
Sekunde_stellen:
Sekunde = Rotary
Return
Alarm_stunde_stellen:
A_stunde = Rotary
Return
Alarm_minute_stellen:
A_minute = Rotary
Return
Alarm_sekunde_stellen:
A_sekunde = Rotary
Return
Problem ist folgendes:
Der Rotary hat immer ein bestimmte Wert, also wenn ich einen Wert habe
für Alarm und wähle über Menu Uhr Einstellen, dann wird der Wert vom
Alarm auf die Uhr übertragen.
Ich denke, man müßte Rotary nach getaner Arbeit wieder auf Null setzen:
Uhr_stellen:
Stunde = Rotary
Rotary=0
Return
Minute_stellen:
Minute = Rotary
Rotary=0
Return
usw. für alle Unterprogramme.
MfG Paul
Gedanken Fehler ??
Situation : Die Uhr eingestellt :
Uhr : 12:00:00
Alarm 00:01:00
nun wird die Alarmzeiteingestellt. Rotary ist O wenn der Taster gedrückt
wird, ( Incr Menuezaehler_temp) und dann kommt die Select Case
Anweisung,
wird in die Routine gesprungen dann wird die Uhrzeit 00:55:00
Lösung wäre die aktuelle Wert "merken" und dann Rotary dazu
addieren...aber das Problem ist dann wenn der Encoder nach links gedreht
wird...255,254,253...
>das Problem ist dann wenn der Encoder nach links gedreht>wird...255,254,253...
Das kommt dadurch:
Links: 'Bei
Linksdrehung
Rotary1 = Rotary1 - 1
'Zählvariable Phasenwechsel vermindern
Return
Du mußt abfangen, daß Rotary1 nicht kleiner als Null werden kann, denn
Rotary1 ist als Byte angelegt und dann kommt beim Herunterzählen nach
der Null die 255, 254 usw.
MfG Paul
Ich habe gedacht, weil es bei der Erhöhung sauber funzt, müsste ich bei
der Linksdrehung folgendes machen :
Linksdrehung
Rotary1=60
Rotary1 = Rotary1 - 1
Return
geht aber auch nicht, weil bei der 2. Drehung 60-254 kommt...
und als Format kann ich nur byte nehmen oder ? Muss eine andere Logik
hin..habe schon gegoogelt aber rückwärtzählen ist immer kacke..
So müßte das gehen:
Links: 'Bei
Linksdrehung
If Rotary1 > 0 then
Rotary1 = Rotary1 - 1
else
Rotary1=60
end if
'Zählvariable Phasenwechsel vermindern
Return
MfG Paul
Der hat Angst was Falsches zu schreiben.
Andererseits wüsste ich jetzt auch nicht, was da zu antworten wäre:
> aber im Simulator kann ich den Encoder nicht testen.
Ja, und ? Dann test's in HW, die Dir ja zur Verfügung steht.
Ich komme wirklich nicht mehr weiter.
Ein kleines Programm um die Encoder werte zu testen hat mich auch nicht
weitergebracht. Die Werte die im Display ablesen kann, machen mich auch
nicht schlauer..
$regfile = "m8def.dat"
$crystal = 16000000
$hwstack = 100
$swstack = 100
$framesize = 100
Dim Rotary0 As Byte
'Phasenzustand des Drehencoders
Dim Rotary1 As Byte 'Zähler der
Phasenwechsel
Dim Rotary2 As Byte
'Hilfsvariable
Dim Rotary As Byte
'Encoder-Wert
Dim Rotary_last As Byte 'Letzter
Encoder-Wert (nur für Demo)
'
Config Lcdpin = Pin , Db7 = Portb.0 , Db6 = Portd.7 , Db5 = Portc.2 , _
Db4 = Portc.3 , E = Portc.4 , Rs = Portc.5
Config Lcd = 16 * 2
Cls
Cursor Off
'System-Timer für periodische Encoder-Abfrage
Config Timer0 = Timer , Prescale = 256
On Timer0 Isr_timer0
Enable Timer0
Const Timer0_reload = 224
Declare Sub Encoder2() 'Routine zur
Anpassung des ENCODER-Befehls
Enable Interrupts
Config Pind.1 = Input
Taster Alias Pind.1
Portd.1 = 1
Do
Call Encoder2() 'Wird
zyklisch im Hauptprogramm aufgerufen
If Rotary_last <> Rotary Then 'Encoder
gedreht?
Rotary_last = Rotary 'Neue
Stellung merken
Print Rotary 'und
Encoder-Wert ausgeben
End If
Locate 1 , 1
Lcd "R0 " ; Rotary0 ; " " ; "R1: " ; Rotary1
Locate 2 , 1
Lcd "R2 " ; Rotary2 ; " " ; "R-Last:" ; Rotary_last
Loop
End
'***********************************************************************
********
'*** ISR_TIMER0
***
'*** Periodische Auswertung des Dreh-Encoders
***
'***********************************************************************
********
Isr_timer0:
Timer0 = Timer0_reload
Rotary0 = Encoder(pinc.0 , Pinc.1 , Links , Rechts , 0)
Return
'***********************************************************************
********
'*** Unterprogramme
***
'***********************************************************************
********
Rechts: 'Bei
Rechtsdrehung
Rotary1 = Rotary1 + 1
If Rotary > 59 Then
Rotary = 0
End If
'Zählvariable Phasenwechsel erhöhen
Return
Links: 'Bei
Linksdrehung
If Rotary1 > 0 Then
Rotary1 = Rotary1 - 1
Else
Rotary1 = 60
End If
'
Return
'***********************************************************************
********
'*** Routine zur Anpassung des ENCODER-Befehls an POLLIN Drehencoder
***
'***********************************************************************
********
Sub Encoder2()
Disable Interrupts
Rotary2 = Rotary1
'Zählvariable Phasenwechsel kopieren
Rotary1 = Rotary1 And 1
'Ggf.Phasenwechsel zwischen Rastungen stehenlassen
push r0 'BASCOM kann
kein arithmetisches Rechtsschieben
lds r0,{rotary2} 'Aber der
AVR kanns!
asr r0 'ASR=
Rechtsschieben mit Berücksichtigen
sts {rotary2},r0 'des
Vorzeichens, also teilen durch 2
pop r0 'eines
signed byte
Rotary = Rotary + Rotary2
'Encoder-Wert um Anzahl Rastungen erhöhen/vermindern
Enable Interrupts
End Sub
Return
Ich stehe also immernoch da und finde keine brauchbare Lösung ...
Hilfe !!!!
Hallo!
Mach Dir doch mal das Leben einfacher.
Der Encoder macht so glaube ich 24 Rastungen pro Umdr.,d.h. nach 2 1/2
Umdrehungen bist Du wieder am Ausgangspunkt.
Wenn das funktioniert kannst Dir immer noch Gedanken machen wegen
links-drehen.
Hochzählen habe ich schon, sowie die Übernahme der aktuelle Uhrzeit,
also beim drehen wird dazu addiert, das geht schon..Danke..
Bin beim Abwärtszählen ( ist etwas more tricky ))
Komme seit 2 Tagen nicht drauf warum folgendes Problem habe.
Ich habe den Code angehängt, wäre viel zu lang um hier zu porsten.
Also es geht nur um den Prinzip:
( Alles andere tut soweit )
Ich möchte so haben, wenn
Select Case Menuezaehler
Case 4 : Gosub Uhr_stellen
End Select
eintrifft :
Uhr_stellen:
Stunde_temp = Rotary
Return
Der Wert vom Rotary gespeichert wird und auf die Anzeige die Uhrzeit +
den Wert vom Rotary bringt
Stunde = Stunde + Stunde_temp
Die Stelle im Display zählt schnell hoch !!!!
Jetzt kommts, wenn ich aber sage :
Uhr_stellen :
Stunde=Rotary
dann wird sauber hochgezählt, wenn ich am Encoder drehe..