Forum: Mikrocontroller und Digitale Elektronik LCD Uhr mit Alarmfunktion mit Drehencoder in BASCOM (Ein kleines Projekt für BASCOM Änfänger Vol3)


von Thomas Kiss (Gast)


Lesenswert?

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

von Paul Baumann (Gast)


Lesenswert?

Guck mal hierhin:
http://www.rn-wissen.de/index.php/Drehencoder#Bascom_ENCODER-Befehl_mit_Anpassung

Da hat einer den Encoder-Befehl von Bascom benutzt und ihn im Timer-
interrupt aufgerufen.

MfG Paul

von Thomas Kiss (Gast)


Lesenswert?

Bei der Analyse von den Beispielcodes habe ich als Anfänger folgendes 
Bemerkt : Der Anschluss vom Encoder fehlt im Code ?

Ist so richtig ?

Config Portc.0 =Input
Portc.0=1
Config Portc.1 =Input
Portc.1=1

#####################################################
'*********************************************************************** 
********
'***   Testprogramm für POLLIN Dreh-Encoder PANASONIC EVEQDBRL416B 
***
'***   Best.Nr. 240 313 
***
'*********************************************************************** 
********
'***   Algorithmus: BASCOM ENCODER-Befehl mit Anpassungsroutine 
***
'*********************************************************************** 
********
'***   Author: Screwdriver 
***
'***   Datum:  29.08.2009 
***
'*********************************************************************** 
********

'*********************************************************************** 
********
'***   Konfiguration 
***
'*********************************************************************** 
********
'AVR
$regfile = "m16def.dat"
$crystal = 8e6
$baud = 9600

'System-Timer für periodische Encoder-Abfrage
Config Timer0 = Timer , Prescale = 256
On Timer0 Isr_timer0
Enable Timer0
Const Timer0_reload = 224                                   'Wert für 
1ms

'*********************************************************************** 
********
'***   Variablen 
***
'*********************************************************************** 
********
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)

'*********************************************************************** 
********
'***   Deklaration Unterprogramme 
***
'*********************************************************************** 
********
Declare Sub Encoder2()                                      'Routine zur 
Anpassung des ENCODER-Befehls

'*********************************************************************** 
********
'***   HAUPTPROGRAMM 
***
'*********************************************************************** 
********
Enable Interrupts

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
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 
'Zählvariable Phasenwechsel erhöhen
Return

Links:                                                      'Bei 
Linksdrehung
   Rotary1 = Rotary1 - 1 
'Zählvariable Phasenwechsel vermindern
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

von Paul B. (paul_baumann)


Lesenswert?

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

von Avr N. (avrnix) Benutzerseite


Lesenswert?

Verschiede Versionen zum Abfragen von Drehgebern:

http://comwebnet.weimars.net/forum/showthread.php?tid=40

ggf mal Beitrag #7 lesen , das der Panasonic Drehgeber nicht so sauber 
ist.


http://www.comwebnet.de

von Thomas Kiss (Gast)


Lesenswert?

Schon wieder was neues gelernt !..spitze

von Kluchscheißernder N. (kluchscheisser)


Angehängte Dateien:

Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

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...

von Karl H. (kbuchegg)


Lesenswert?

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.

von Thomas Kiss (Gast)


Lesenswert?

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 !!

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

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..

von Karl H. (kbuchegg)


Lesenswert?

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.

von Thomas Kiss (Gast)


Lesenswert?

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 ?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

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...

von Thomas Kiss (Gast)


Lesenswert?

Beispiel vom Screwdriver

http://www.rn-wissen.de/index.php/Drehencoder#Hannes-Lux-Methode_als_Alternative_zum_ENCODER-Befehl

beinhaltet den Panasonoc Encoder

Testprogramm für POLLIN Dreh-Encoder PANASONIC EVEQDBRL416B

wäre es okay ? für meine Anwendung..denke schon

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

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...

von Thomas Kiss (Gast)


Lesenswert?

Mod Läubi..Titel wäre hier :

LCD Uhr mit Alarmfunktion mit Drehencoder in BASCOM

von Thomas Kiss (Gast)


Lesenswert?

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..

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

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 !!!

von Paul B. (paul_baumann)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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-Tutorial
AVR-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.

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

hmmm....werde mal probieren, was ich kann..

von Paul B. (paul_baumann)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

Ich glaube ic werde es nie lernen (((( traurig...

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

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 ?

von Karl H. (kbuchegg)


Lesenswert?

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?

von Thomas Kiss (Gast)


Lesenswert?

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...

von Karl H. (kbuchegg)


Lesenswert?

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.

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

> 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

von Thomas Kiss (Gast)


Lesenswert?

"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)

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von MWS (Gast)


Lesenswert?

> 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.

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

> 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

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

> 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

von MWS (Gast)


Lesenswert?

> 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.

von Thomas Kiss (Gast)


Lesenswert?

Bin auf der suche nach : "asynchronen Modus des Timer2."


Die Seite ist recht interessant:

http://www.rn-wissen.de/index.php/Timer/Counter_%28Avr%29

steht aber nicht, wonach ist suche..

Im Datenblatt habe aich nach Asyncron Mode Timer2 gesucht auch nichts 
brauchbares for Beginners gefuden

http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf

teilweise habe ich das Problem, dass die Codes in Asm oder C sind..hmm

von Thomas Kiss (Gast)


Lesenswert?

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 !! )

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

> 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

von MWS (Gast)


Lesenswert?

> 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

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

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 ?

von Thomas Kiss (Gast)


Lesenswert?

Nun ich bin jetzt soweit, daß die Uhrroutine drin habe und der Encoder
(50% Fertig )

'********************************************************
'* 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)
'                --------------


$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)
Dim Menuezaehler As Byte
Dim Sekunde As Byte
Dim Minute As Byte
Dim Stunde As Byte
Dim S1 As String * 2                        'Sekunde
Dim S2 As String * 2                        'Minute
Dim S3 As String * 2                        'Stunde


Config Lcdpin = Pin , Db7 = Portb.0 , Db6 = Portb.1 , Db5 = Portb.2 , _
      Db4 = Portb.3 , E = Portb.4 , Rs = Portb.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                           'Wert für 1ms

Config Timer1 = Timer , Prescale = 256              'Timer für Uhr
Enable Timer1
On Timer1 Takt
Enable Interrupts
Timer1 = 3036




Declare Sub Encoder2()         'Routine zur Anpassung des 
ENCODER-Befehls
Enable Interrupts

'Taster
Config Pind.1 = Input
Portd.1 = 1
Taster Alias Pind.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

S1 = Str(sekunde)                            'Uhr Stunde
S1 = Format(s1 , "00")
'----------------------------------
S2 = Str(minute)                             'Uhr Minute
S2 = Format(s2 , "00")
'------------------------------------
S3 = Str(stunde)                             'Uhr Sekunde
S3 = Format(s3 , "00")
'--------------------------------------




Locate 1 , 1
Lcd "Uhr:    " ; S3 ; ":" ; S2 ; ":" ; S1        'Stunde-Minute-Sekunden
Locate 2 , 1
Lcd "Encoderwert:" ; Rotary




Loop
End

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


'*********************************************************************** 
********
'***   ISR_TIMER0 
***
'***   Periodische Auswertung des DrehEncoders 
***
'*********************************************************************** 
********
Isr_timer0:
   Timer0 = Timer0_reload
   Rotary0 = Encoder(pinc.0 , Pinc.1 , Links , Rechts , 0)
Return

'*********************************************************************** 
********
'***   Unterprogramme 
***
'*********************************************************************** 
********
Rechts:                                'Bei Rechtsdrehung
   Rotary1 = Rotary1 + 1               'Zählvariable Phasenwechsel 
erhöhen
Return

Links:                                'Bei Linksdrehung
   Rotary1 = Rotary1 - 1             'Zählvariable Phasenwechsel 
vermindern
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

von Falk B. (falk)


Lesenswert?

@  Thomas Kiss (thomaskiss)

Lies mal was über Netiquette. Lange Quelltexte gehören in den 
Anhang.
Danke.

MFG
Falk

von MWS (Gast)


Lesenswert?

> 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.

von Thomas Kiss (Gast)


Lesenswert?

MWS : um was gehts denn hier ?????

von MWS (Gast)


Lesenswert?

> MWS : um was gehts denn hier ?????
Um die Antwort von KC von 17:28

von Thomas Kiss (Gast)


Lesenswert?

MWS : Sorry aber "irgendwie" gehört es nicht zu diesem Thread oder ?

von MWS (Gast)


Lesenswert?

> 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.

von Thomas Kiss (Gast)


Lesenswert?

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

von MWS (Gast)


Lesenswert?

> 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 ;-)

von Thomas Kiss (Gast)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

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" ??

von Paul B. (paul_baumann)


Lesenswert?

"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

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

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:?

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

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...

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

Hmm..nicht klar...

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

-----------------------------------------------

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....

von MWS (Gast)


Lesenswert?

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.

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

ja...habe ich ( einige lesen ich sogar mehrmals durch..stehe aber auf m 
schlauch

von MWS (Gast)


Lesenswert?

> 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.

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

Grrrrrrrrrrrrrrr............

Ich finde ein bisschen Kacke, daß hier immerwieder "Krieg" gibt...

von MWS (Gast)


Lesenswert?

> 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

von Thomas Kiss (Gast)


Lesenswert?

vergessen wir es..okay..wer kann mir der Config vo Timer noch helfen ? 
stehe echt auch dem schlauch..noch...

von MWS (Gast)


Lesenswert?

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.

von Thomas Kiss (Gast)


Lesenswert?

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 ?

von MWS (Gast)


Lesenswert?

> 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:
1
Incr ms_Ctr
2
  If ms_Ctr = 1000 Then
3
    Incr Sekunde
4
      ms_Ctr = 0
5
  End If

von MWS (Gast)


Lesenswert?

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.

von Picht (Gast)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

Also ich denke die erste und zweite Uhr Variante habe ich geschrieben, 
daß es komplett ferig ist ...

Bin gerade dabei Variante 3 zu coden..

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

Sorry, ist zu hoch für mich..Werd doch nie lernen..(((

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

Thomas Kiss schrieb:
> Sorry, ist zu hoch für mich..Werd doch nie lernen..(((

Was genau verstehst Du nicht?

MfG

von Thomas Kiss (Gast)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

In dem Scheiss teueren Buch gibt es 2 Seiten über Timer total kacke 
eklärt

Beim Halvar.at

http://halvar.at/elektronik/kleiner_bascom_avr_kurs/timer_counter/
http://halvar.at/elektronik/kleiner_bascom_avr_kurs/timer0_als_timer/

ist etwas mehr aber bringt mich nicht weiter.....ich finde nichts mit 
ausführliche UND einfache Erklärung...

von Paul B. (paul_baumann)


Lesenswert?

>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

von Thomas Kiss (Gast)


Lesenswert?

Was ich überhaupt nicht verstehe ( braucht nicht sagen, habe keine 
Ahnung ich weiss es,,shit )

mein jetziger Code :

'********************************************************
'* 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)
'                --------------


$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)
Dim Menuezaehler As Byte
Dim Menuezaehler_temp As Byte
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 X As Byte                                               'Blinkzähler


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                                   'Wert für 
1ms

Config Timer1 = Timer , Prescale = 256                      'Timer für 
Uhr
Enable Timer1
On Timer1 Takt
Enable Interrupts
Timer1 = 3036




Declare Sub Encoder2()                                      'Routine zur 
Anpassung des ENCODER-Befehls
Enable Interrupts

'Taster
Config Pind.1 = Input
Portd.1 = 1
Taster Alias Pind.1

'LED an PD0
Led Alias Portd.0
Portd.0 = 1
Config Led = Output

Stunde = 12
A_minute = 1

Do

Led = 0

   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

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 
'Stunde-Minute-Sekunden
Locate 2 , 1
Lcd "M:" ; Menuezaehler ; "  " ; "Al:" ; S6 ; ":" ; S5 ; ":" ; S4 
'Alarm Stunde-Minute-Sekunden

If Taster = 0 Then
Gosub Menue
End If


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



Loop
End

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 = 1

Return

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

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


'*********************************************************************** 
********
'***   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 
'Zählvariable Phasenwechsel erhöhen
Return

Links:                                                      'Bei 
Linksdrehung
   Rotary1 = Rotary1 - 1 
'Zählvariable Phasenwechsel vermindern
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

Nach dem Einschalten, kann ich mit Taster Mode durchtippen, sehe ich 
Display und kann ich Uhr und alarm einstellen.

Aber, wenn die Zeiten eingestellt sind, wird die Uhrzeit hochgezählt 
aber es reagiert nichtmehr auf dem Taster steht immernoch Mode 1 ( 
nachdem ich durchgetippt habe ( also Mode 1,2,3,4,5,6)

Ich gehe davon aus, daß nur die Zeiten gesetzt werden, wenn der Taster 
gedrückt wird.Bin mit dem Nerven am Ende !!

von Thomas Kiss (Gast)


Lesenswert?

@Paul und Du möchtest das Buch nicht verkaufen ?

Ich werde das Buch vom Claus im Bucht verticken

von Paul B. (paul_baumann)


Lesenswert?

@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

von Thomas Kiss (Gast)


Lesenswert?

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....

von Thomas Kiss (Gast)


Lesenswert?

So sieht schon besser aus...also funzen tut es..

'********************************************************
'* 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)
'                --------------


$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)
Dim Menuezaehler As Byte
Dim Menuezaehler_temp As Byte
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 X As Byte                                               'Blinkzähler


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                                   'Wert für 
1ms

Config Timer1 = Timer , Prescale = 256                      'Timer für 
Uhr
Enable Timer1
On Timer1 Takt
Enable Interrupts
Timer1 = 3036




Declare Sub Encoder2()                                      'Routine zur 
Anpassung des ENCODER-Befehls
Enable Interrupts

'Taster
Config Pind.1 = Input
Portd.1 = 1
Taster Alias Pind.1

'LED an PD0
Led Alias Portd.0
Portd.0 = 1
Config Led = Output

Stunde = 12
A_minute = 1

Do

Led = 0

   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

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 
'Stunde-Minute-Sekunden
Locate 2 , 1
Lcd "M:" ; Menuezaehler ; "  " ; "Al:" ; S6 ; ":" ; S5 ; ":" ; S4 
'Alarm Stunde-Minute-Sekunden

If Taster = 0 Then
Gosub Menue
End If


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



Loop
End

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

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

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


'*********************************************************************** 
********
'***   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 
'Zählvariable Phasenwechsel erhöhen
Return

Links:                                                      'Bei 
Linksdrehung
   Rotary1 = Rotary1 - 1 
'Zählvariable Phasenwechsel vermindern
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

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

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.

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

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.

von Thomas Kiss (Gast)


Lesenswert?

Nun ist die Uhr fertig...Es sollte doch kein Beispiel sein, weil , 
wahrscheinlich schlecht gecoded ist, aber es funktioniert so, daß es das 
macht was ich wollte. Alarm und Uhrzeit sind sauber einstellbar und 
Alarm wird ausgelöst mit LED und Buzzer.

Ich sehe es so, daß die eine bessere Version ist wie Vol 2. Ob jemand 
einen Fortschritt darin sieht, mag ich bezeifeln aber für mich war 
einer.

Es wird wahrscheinlich noch eine weitere "saubere" Version geben, 
aberjetzt bin ich mit den Nerven ferig.

Es gibt auch Eagle Plan und Platine, wenn jemand haben will, kann ich 
posten.

'********************************************************
'* 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)
'                --------------


$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)
Dim Menuezaehler As Byte
Dim Menuezaehler_temp As Byte
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 X As Byte                                               'Blinkzähler


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                                   'Wert für 
1ms

Config Timer1 = Timer , Prescale = 256                      'Timer für 
Uhr
Enable Timer1
On Timer1 Takt
Enable Interrupts
Timer1 = 3036




Declare Sub Encoder2()                                      'Routine zur 
Anpassung des ENCODER-Befehls
Enable Interrupts

'Speaker an PD2
Speaker Alias Portd.2
Portd.2 = 1
Config Speaker = Output

'Taster
Config Pind.1 = Input
Portd.1 = 1
Taster Alias Pind.1

'LED an PD0
Led Alias Portd.0
Portd.0 = 1
Config Led = Output

Stunde = 12
A_minute = 1


Do

Led = 0

   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

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 
'Stunde-Minute-Sekunden
Locate 2 , 1
Lcd "M:" ; Menuezaehler ; "  " ; "Al:" ; S6 ; ":" ; S5 ; ":" ; S4 
'Alarm Stunde-Minute-Sekunden

If Taster = 0 Then
Gosub Menue
End If


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

If Stunde = A_stunde And Minute = A_minute And Sekunde = A_sekunde Then
Do
  Waitms 500
  Toggle Led
  Waitms 500
  Toggle Led
  Incr X
Loop Until X = 25

Sound Speaker , 50 , 1000                                'Länge Tonhöhe
      Wait 1
   Sound Speaker , 50 , 1000
      Wait 1
   Sound Speaker , 50 , 1000
      Wait 1
   Sound Speaker , 50 , 1000
      Wait 1
   Sound Speaker , 50 , 1000
      Wait 1
   Sound Speaker , 50 , 1000
      Wait 1
   Sound Speaker , 100 , 1500
   Sound Speaker , 100 , 1000
   Sound Speaker , 100 , 1500

End If

Loop
End

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

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

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


'*********************************************************************** 
********
'***   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 
'Zählvariable Phasenwechsel erhöhen
Return

Links:                                                      'Bei 
Linksdrehung
   Rotary1 = Rotary1 - 1 
'Zählvariable Phasenwechsel vermindern
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

von me (Gast)


Lesenswert?

If Stunde = A_stunde And Minute = A_minute And Sekunde = A_sekunde Then
    X = 0  ' muss hier noch rein, sonst blinkt er nur EINMAL 25mal :-)
    Do

von Thomas Kiss (Gast)


Lesenswert?

LED blinkt einmalig 25 mal..so wollte ich, danach Buzzt..

von Thomas Kiss (Gast)


Lesenswert?

Noch etwas, einige Sachen, die bereits fertig sind :

Beitrag "Re: Zeigt her Eure Kunstwerke !"

von Thomas Kiss (Gast)


Angehängte Dateien:

Lesenswert?

Anbei noch die Eagle Plane

von Thomas Kiss (Gast)


Lesenswert?

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 ?

von Wigbert P. (wigbert) Benutzerseite


Lesenswert?

>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

von Thomas Kiss (Gast)


Lesenswert?

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 ?

von Falk B. (falk)


Lesenswert?


von Wigbert P. (wigbert) Benutzerseite


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

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."

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

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

von Wigbert P. (wigbert) Benutzerseite


Lesenswert?

>"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

von Thomas Kiss (Gast)


Lesenswert?

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" ?

von Thomas Kiss (Gast)


Lesenswert?

@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..

von Wigbert P. (wigbert) Benutzerseite


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

"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,,,

von Wigbert P. (wigbert) Benutzerseite


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

Moment muss mal was probieren,,

von Thomas Kiss (Gast)


Lesenswert?

So in der Verion funzt LED ertsmal perfekt :

'********************************************************
'* 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)
'                --------------


$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)
Dim Menuezaehler As Byte
Dim Menuezaehler_temp As Byte
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 X As Byte                                               'Blinkzähler

Dim Alarmzaehler As Byte

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


'Timer für Uhr
Config Timer1 = Timer , Prescale = 256
Enable Timer1
On Timer1 Takt
Enable Interrupts
Timer1 = 3036




Declare Sub Encoder2()                                      'Routine zur 
Anpassung des ENCODER-Befehls
Enable Interrupts


'LED an PD0
Led Alias Portd.0
Portd.0 = 1
Config Led = Output

Config Pind.1 = Input
Taster Alias Pind.1
Portd.1 = 1

'Speaker an PD2
Speaker Alias Portd.2
Portd.2 = 1
Config Speaker = Output






Stunde = 12
A_minute = 1


Do

Led = 0

   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

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 
'Stunde-Minute-Sekunden
Locate 2 , 1
Lcd "M:" ; Menuezaehler ; "  " ; "Al:" ; S6 ; ":" ; S5 ; ":" ; S4 
'Alarm Stunde-Minute-Sekunden

If Taster = 0 Then
Gosub Menue
End If


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

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

Loop
End

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

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

Alarm:
  Toggle Led
  Waitms 500
  Alarmzaehler = Alarmzaehler - 1
Return


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


'*********************************************************************** 
********
'***   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
   Rotary1 = Rotary1 - 1
   If Rotary > 59 Then
   Rotary = 0
   End If 
'Zählvariable Phasenwechsel vermindern
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

Aber folgendes muss perfektioniert werden:

Wenn ich z.B Menue 3 habe (Einstellung Sekunden ) und drücke den Taster 
am Encoder - Menü 4 (Alarmstunde einstellen ) wird die aktuelle Zahl 
Sekuden übernommen. Kann ich einstellen, aber müsste anders gehen

Monentan ist so :

Minute_stellen:
Minute = Rotary
Return

Welche Wert hat Rotary wann ?

Es müsste von der Logik her sein :
Aktuelle Minute + Rotary aber rotary muss solange 0 sein bich ich drehe 
aber wie umsetzen ?

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Wigbert P. (wigbert) Benutzerseite


Lesenswert?

>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

von Thomas Kiss (Gast)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

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

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

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

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

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 ?

von Thomas Kiss (Gast)


Lesenswert?

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 )

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

Ja habe gefunden, muss ich den Stoff nochmal durchkauen...bis morggen 
vielen Dank !! Gute Nacht !!

von Thomas Kiss (Gast)


Lesenswert?

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...

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)
'                --------------


$regfile = "m8def.dat"
$crystal = 16000000
$hwstack = 100
$swstack = 100
$framesize = 100

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 Goto Taktms




Dim Zeit(12) As Byte

Dim Sekunde As Byte
Dim Minute As Byte
Dim Stunde As Byte

Zeit(1) = Sekunde
Zeit(2) = Minute
Zeit(3) = Stunde




Taktms:

Return

Also am Ausgang PB1 würde ich 1 Khz messen ?

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

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 ?

von Thomas Kiss (Gast)


Lesenswert?

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

von Paul Baumann (Gast)


Lesenswert?

Nur als Hinweis:

>On Goto Taktms

Das funktioniert nicht, weil GOTO ein reserviertes Wort ist.

Initialisierung:
On Timer1 Taktms

Interruptroutine:
Tamktms
   Tralala
   Schnulli
Return

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

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

von MWS (Gast)


Lesenswert?

@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:
1
Config Timer1 = Timer , Prescale = 1024 , Clear Timer = 1

Das hier, so schlicht unslesbar:
1
TCCR1B = &b00001010

wird so viel lesbarer:
1
TCCR1B = Bits(WGM12, CS11)

Dann weißt Du auch später noch, was Du einmal programmiert hast, 
außerdem zählen potentielle Helfer nicht gerne Bits ab.

von Thomas Kiss (Gast)


Lesenswert?

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..

von Thomas Kiss (Gast)


Lesenswert?

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 )

von Thomas Kiss (Gast)


Lesenswert?


von MWS (Gast)


Lesenswert?

> 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:
1
Config Timer1 = Timer , Prescale = 1024 , Clear Timer = 1
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.

von Thomas Kiss (Gast)


Lesenswert?

Diese Variante ? ( Grundidee )

$regfile = "m8def.dat"
$crystal = 16000000
$hwstack = 32
$swstack = 10
$framesize = 40

Dim Sekunde As Byte

Const Timer1wert = 250           '1000 Hz bei 16000000 Hz / 64  (250000)
Const Timer2wert = 250000        '1 Hz


' Timer 1 = Zeitbasis
On Timer1 Taktms
Config Timer1 = Timer , Prescale = 64
Enable Timer1
Enable Interrupts

' Hauptprogramm

Do

'Aktuelle Zeit anzeigen
Gosub

'Alarmbedingungen prüfen
If Alarm = Ein Then Gosub Alarm

'Auf Drehgeberknopf reagieren
If Taster = 0 Then
Gosub

Loop


Taktms:
Load Timer1 , Timer1wert              'Timer-Voreinstellung laden
...encoder Auswertung
Return

Taktsec:
Load Timer1 , Timer2wert
Incr Sekunde
If Sekunde > 59 Then
   Sekunde = 0

Return

von Thomas Kiss (Gast)


Lesenswert?

So funzt nicht..es gibt bei Timer1 nur ein sub...


$regfile = "m8def.dat"
$crystal = 16000000
$hwstack = 32
$swstack = 10
$framesize = 40

Dim Sekunde As Byte

Const Timer1wert = 250          '1000 Hz bei 16000000 Hz / 64  (250000)
Const Timer2wert = 250000       '1 Hz


' Timer 1 = Zeitbasis
Config Timer1 = Timer , Prescale = 64
On Timer1 Taktms
Enable Timer1
Enable Interrupts

' Hauptprogramm

Do

'Aktuelle Zeit anzeigen
Gosub

'Alarmbedingungen prüfen
If Alarm = Ein Then Gosub Alarm

'Auf Drehgeberknopf reagieren
If Taster = 0 Then
Gosub

Loop


Taktms:
Load Timer1 , Timer1wert
...encoder Auswertung

Load Timer1 , Timer2wert
Incr Sekunde
Return

geht es so ?

von Thomas Kiss (Gast)


Lesenswert?

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

von MWS (Gast)


Lesenswert?

1
if geber =20 then
2
if geber =50 then
Du kannst mit einer einzelnen Zählvariablen nicht beide, das 20ms und 
das 50 x 20ms Ereignis zählen, Du brauchst 2 Zähler.

von Thomas Kiss (Gast)


Lesenswert?

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 ?

von Thomas Kiss (Gast)


Lesenswert?

Ich denke sowas eher, was Kluscheisser gemeint hat

'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

von Paul Baumann (Gast)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

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

von Paul Baumann (Gast)


Lesenswert?

>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

von Thomas Kiss (Gast)


Lesenswert?

Kapiert..aber warum meckert der Compiler ?

von MWS (Gast)


Lesenswert?

> 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.

von Paul Baumann (Gast)


Lesenswert?

Kann ich jetzt nicht gucken, ich muss Etwas tun, sonst gibt's Mecker vom
Meister oder von Eckhart...
;-)
MfG Paul

von Thomas Kiss (Gast)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

Nun der Code ist etwas weiter entwickelt, auch länger..könntet mal 
gucken ob okay ist ( redesign )
$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
Dim Alarmflag As Byte

Config Pind.1 = Input
Taster Alias Pind.1
Portd.1 = 1

'LED an PD0
Led Alias Portd.0
Portd.0 = 1
Config Led = Output

' 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

If Stunde = A_stunde And Minute = A_minute And Sekunde = A_sekunde Then 
Alarmflag = 60

If Alarmflag > 0 Then
Gosub Alarm
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:
  Toggle Led
  Waitms 500
  Alarmflag = Alarmflag - 1
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

von Thomas Kiss (Gast)


Lesenswert?

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.

von Paul Baumann (Gast)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

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...

von Paul Baumann (Gast)


Lesenswert?

>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

von Thomas Kiss (Gast)


Lesenswert?

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..

von Paul B. (paul_baumann)


Lesenswert?

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

von Thomas Kiss (Gast)


Lesenswert?

Um den Encoder genau anzusehen, habe mal den Code umgestrickt, aber im 
Simulator kann ich den Encoder nicht testen ( pinc.0 und pinc.1)

$sim
$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
   Rotary1 = Rotary1 - 1 
'Zählvariable Phasenwechsel vermindern
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

von Thomas Kiss (Gast)


Lesenswert?

Hat niemand Ratschläge mehr für mich ?

Klugscheisser ? wo ist er `?

von MWS (Gast)


Lesenswert?

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.

von Thomas Kiss (Gast)


Angehängte Dateien:

Lesenswert?

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 !!!!

von dietmar (Gast)


Lesenswert?

' 
------------------------------------------------------------------------ 
------
' Author :     Dietmar Steiner
' Projekt:     Temperaturmessung und Regelung mit Dallas DS1820
'              für Aquarien mit Boden und/oder Wasser(Stab)heizer.
'              Mit LCD - Anzeige und Tastatur
' Hier:        Test einer Encoder-Steuerung
' Version:     0.9
' Datum:       05.06.05
' Controller:  Atmel Atmega8, interner 8MHZ RC Oszillator
'              CKSEL=0100 SUT=10
' Portbelegungen:
'
' PORTB                       PORTC                      PORTD
' 
------------------------------------------------------------------------ 
------
' Portb.0 = 1wire (DS1820)    Portc.0 = Enable (LCD)     Portd.0 =
' Portb.1 = Boden (Heizer)    Portc.1 = RS     (LCD)     Portd.1 =
' Portb.2 = Wasser(Heizer)    Portc.2 = Db4    (LCD)     Portd.2 = Int0 
von SQW
' Portb.3 = T_set(Taste)      Portc.3 = Db5    (LCD)     Portd.3 =
' Portb.4 = T_plus(Taste)     Portc.4 = Db6    (LCD)     Portd.4 =
' Portb.5 = T_minus(Taste)    Portc.5 = Db7    (LCD)     Portd.5 = Sda 
(DS1307)
' Portb.6 = im STK500 nicht ! Portc.6 =                  Portd.6 =
' Portb.7 = im STK500 nicht ! Portc.7 =                  Portd.7 = Scl 
(DS1307)
'
' Portb.6 und Portb.7 sind beim STK500 und Verendung des Atmega 8 nicht
' verwendbar !! Die Pind sind nicht auf die Sockelleisten geführt (Xt1 
Xt2),
' jedoch an die "Expand 1 un 0 Leiste.
' Also vorsicht, wenn mit internem Taktgeber gearbeitet wird und die 
freiwerdenden
' PB6(pin9) und PB7(pin10) verwendet werden sollen.....
' 
------------------------------------------------------------------------ 
------
$regfile = "M8DEF.DAT"
$baud = 38400
$crystal = 8000000
Config Lcd = 20 * 4
Config Lcdpin = Pin , Db4 = Portc.2 , Db5 = Portc.3 , Db6 = Portc.4 , 
Db7 = Portc.5 , E = Portc.1 , Rs = Portc.0






Dim Wert As Integer
  Wert = 0
  Config Portd = Input
  Portd = 255
  Enc_a Alias Pind.3
  Enc_b Alias Pind.2
  Mcucr = &B00001111
  On Int0 Encoder0
  On Int1 Encoder1
  Enable Int0
  Enable Int1
  Enable Interrupts

  Do
    Upperline
  Lcd "Zaehler: " ; Wert ; "     "
  Loop

  End

  Encoder1:
  Disable Interrupts
  Waitms 5
  If Enc_a <> Enc_b Then
    Decr Wert
  Else
    Incr Wert
  End If
  Enable Interrupts
  Return

  Encoder0:
  Disable Interrupts
  Waitms 5
  If Enc_a = Enc_b Then
    Decr Wert
  Else
    Incr Wert
  End If
  Enable Interrupts
  Return

von GK (Gast)


Lesenswert?

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.

von Thomas Kiss (Gast)


Lesenswert?

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 ))

von dietmar (Gast)


Lesenswert?

ja is klar , subtrahieren ist immer sehr viel schwieriger als 
addieren...

uahhhhhhhhhhhhhh

von Thomas Kiss (Gast)


Angehängte Dateien:

Lesenswert?

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..

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.