Forum: Mikrocontroller und Digitale Elektronik Verzweifelt wegen Drehencoder und Interrupt :/


von Wilson W. (wilson)


Angehängte Dateien:

Lesenswert?

Moin zusammen,

ich bin schon ne Weile dabei mir eine 2in1 Lötstation zu bauen, die 
Hardware is fertig und soweit fehlerfrei, nur komme ich mit der Firmware 
nicht weiter. Hatte erst den Drehencoder ohne Library versucht 
auszulesen, was aber nicht geklappt hat, dann habe ich die Methode von 
educ8s, einem YouTuber, dessen Vorschläge immer perfekt funktionieren 
(Bei Interesse verlinke ich das Video) verwendet, das klappt auch, nur 
leider wird dabei die TimerOne Bibliothek verwendet und diese nutzt 
einen Interrupt, genau den Interrupt, an dem mein Summer hängt, den von 
Pin 9, dadurch funktioniert der Encoder nicht mehr sauber und der Summer 
ist extrem leise. Bis auf die analogen Pins 5, 6 und 7 sind alle 
vergeben, 3, 5 und 6 nutzt das PCD8544-Display, 10 und 11 schalten die 
Transistoren für Lötkolben und Heissluft-Lüfter.

Meine Frage ist nun, ob ich einen der anderen Pins für den Interrupt 
nutzen kann, ohne, dass es Probleme gibt? Das könnte ich ja in der 
TimerOne Bibliothek verändern.

Die Lösung wäre es den Drehencoder durch Tasten zu ersetzen, spricht 
nichts dagegen, aber wäre schon schöner den Encoder zu verwenden, daher 
dachte ich lieber nochmal hier zu fragen.

Lieben Gruß,

Willi

PS: Ich hänge mal ein Bildchen dran, wie alle mögen Bilderchen :)

von Peter D. (peda)


Lesenswert?

Wilson W. schrieb:
> wie alle mögen Bilderchen :)

Auf so verkleinerten Bildchen kann man eh nichts erkennen.

Die Angabe bzw. die URL des MCs, der IDE und der Lib wären erheblich 
sinnvoller gewesen.

von asderftttg (Gast)


Lesenswert?

Wilson W. schrieb:
> Ich hänge mal ein Bildchen dran,

Das ist aber zur Beantwortung der Frage nicht hilfreich.
Der Sourcecode würde deutlich sinnvoller sein.

asderftttg

von Yalu X. (yalu) (Moderator)


Lesenswert?

Aus deiner Beschreibung ist kaum zu erkennen, was du da hardware- und
softwareseitig zusammengebastelt hast.

Wenn du den Drehgeber nach althergebrachter Manier einliest, 
brauchst du

- einen Timer, der in regelmäßigen Zeitabständen (in der Größenordnung
  0,1ms bis 10ms) einen (internen) Interrupt auslöst und

- zwei I/O-Pins, die sich als Input konfigurieren lassen (sie müssen
  nicht interruptfähig sein).

Das sollte auf deinem Arduino-Board, das vermutlichen einen ATmega328
o.ä. enthält, überhaupt kein Problem sein, auch wenn da noch ein Display
und ein paar andere Dinge angeschlossen sind.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Wilson W. schrieb:
> wird dabei die TimerOne Bibliothek verwendet und diese nutzt einen
> Interrupt, genau den Interrupt, an dem mein Summer hängt, den von Pin 9,
> dadurch funktioniert der Encoder nicht mehr sauber und der Summer ist
> extrem leise.
Mir wäre der Encoder wichtiger als der Summer...

BTW: es geht auch mit Summer und Encoder auf ein und dem selben 
Timerinterrupt. Da bin ich mir vollkommen sicher.

von Thomas (Gast)


Lesenswert?

Hallo Wilson,

komt darauf an, ob noch ein Interruptfähiger Pin frei ist.
Was das größte Problem macht, ist das Prellen des Encoders.
Kein Mechanischer Schalter geht prellfrei.

Also Entweder gut mit Elektronik entprellen oder mit Software.

Dahin sollte dein Weg dich führen...

Aber wie schon oben genannt   Ohne Schaltplan geht gar nichts.

Gruß Thomas

von Yalu X. (yalu) (Moderator)


Lesenswert?

Thomas schrieb:
> komt darauf an, ob noch ein Interruptfähiger Pin frei ist.

Wozu? Der Timer-Interrupt ist völlig ausreichend und benötigt keinen Pin
nach außen.

Lothar M. schrieb:
> BTW: es geht auch mit Summer und Encoder auf ein und dem selben
> Timerinterrupt. Da bin ich mir vollkommen sicher.

Zudem hat der ATmega328 nicht nur einen, sondern gleich drei Timer, von
denen jeder einzelne auch mehrere Funktionen erfüllen kann. Da sollte
sich durch irgendeine Lösung finden lassen.

von Michael B. (laberkopp)


Lesenswert?

Wilson W. schrieb:
> Die Lösung wäre es den Drehencoder durch Tasten zu ersetzen,

Du musst überhaupt keine Pins mit Timer-Iterrupts belegen, ausser du 
willst einen Ton ausgeben für deinen Summer.

Nimm einfach einen anderen Timer, ordne dem keinen Pin zu, und lass den 
per Interrupt jede Millisekunde void ClickEncoder::service(void) 
aufrufen, fertig. Der Arduino hat 3 Timer.

von Joachim B. (jar)


Lesenswert?

Lothar M. schrieb:
> BTW: es geht auch mit Summer und Encoder auf ein und dem selben
> Timerinterrupt. Da bin ich mir vollkommen sicher.

logisch

Ich hatte mir ja einen 10ms Timer per IRQ gebaut, als ich dann PeDas 
Drehencoder nutzen wollte war 10ms viel zu lang, ergo auf 1ms gesetzt 
und jedes mal bis 10 gezählt um wieder zu meinen 10ms zu kommen.

Genauso kann man Franks (ukw) IR Auswertung machen, dort wird z.B 15000 
Hz abgetastet, also 1/15000s Interrupt, zählt man dort bis 150 hat man 
wieder den 10ms Timer.

von Wilson W. (wilson)


Angehängte Dateien:

Lesenswert?

Hier zunächst der Link zur Bibliothek:
https://github.com/PaulStoffregen/TimerOne?files=1

Ja, es ist ein minimierter ProMini Clone mit nem atmega328.

Mein Sketch ist zur Zeit noch sehr chaotisch, wenn ich den poste fresst 
ihr mich, das garantiere ich xD Will das Projekt aber teilen, wenns 
fertig ist, zwar nicht mit Step-by-Step Bildern und Beschreibung, aber 
schon mit genügend Informationen, dass man es nachbauen kann, es soll 
dabei auch um Kreativität gehen und wie man aus vermeintlichem Müll was 
cooles bauen kann, bis auf den uC sind alle Teile auf der Platine aus 
alter Hardware geerntet hauptsächlich ne Drucker und nem ATX-Netzteil.

Jedenfalls hier der originale Sketch von educ8s, darüber meine 
Pinbelegung, anders genutze klammere ich aus und passe die anderen 
entsprechend an:

Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Genau das ist das Problem, dass kein interruptfähiger Pin mehr frei ist 
und ich die Schaltung auch nicht mehr so verändern kann, dass einer frei 
wird.

Mir ist der Summer schon wichtiger als der Encoder, weil ich diesen eben 
im Fall des Falles durch Taster ersetzen kann, weil ich auch Presets 
eingebaut habe, muss ich nicht ständig an irgendwas drehen, außer dem 
Poti für das Gebläse, auch habe ich eingebaut in welchen Schritten die 
Temperatur eingestellt werden soll.

Einen Schaltplan habe ich nie gemacht, angefangen, aber nicht noch nicht 
zu Ende gemacht, nur entsprechende Berechnungen für den Op-Amp und ein 
Lochmaster Layout, welches aber im Laufe der Zeit stark abgeändert 
werden musste.

Das mit den internen Interrupts ist doch die richtige Richtung, könnt 
ihr mich da noch ein bisschen mehr drüber aufklären? Die TimerOne 
Bibliothek nutzt den Timer1 - OCIE1A Interrupt, der auf Pin 9 liegt, das 
ist dann wohl ein externen, wie ändere ich den zu einem internen? Ist 
mein erstes Mal mit Interrupts  ...außer früher bei den 2-, 386er 
PC's...

--

Code entfernt und als Dateianhang angefügt
-rufus

: Bearbeitet durch User
von Wilson W. (wilson)


Lesenswert?

Mhhh mir kommt da grad so ein Gedanke...

hab ich die Bibliothek nicht richtig verstanden und man kann einfach

Timer1.initialize(1000); und
Timer1.attachInterrupt(timerIsr);

einfach in Timer2 etc. ändern?

von Einer K. (Gast)


Lesenswert?

Wenn du die PWM Fähigkeit des Timer0 nicht brauchst, kannst du dort 
deinen Interrupt einhängen. Denn der Timer läuft auf dem Arduino sowieso 
schon.

Du könntest also
ISR(TIMER0_COMPA_vect)
oder/und
ISR(TIMER0_COMPB_vect)
nutzen

von Guido Körber (Gast)


Lesenswert?

Viel zu umständlich.

Da der Drehgeber ja wohl als User-Interface verwendet wird stört es 
nicht, wenn der mal einen Impuls übersieht. Also einfach in der 
Main-Schleife pollen und fertig.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Wilson W. schrieb:
> else if (page==2 && menuitem == 4)
>   {
>    displayStringMenuPage(menuItem4, difficulty[selectedDifficulty]);
>   }
>   else if (page==2 && menuitem == 4)
>   {
>    displayStringMenuPage(menuItem4, difficulty[selectedDifficulty]);
>   }

Ich sags zweimal und dann ist es wahr? Da hast du wohl irgendwas doppelt 
kopiert :-P
Und wofür ist denn eine 'difficulty' Einstellung in einer Lötstation? 
Für leichte und schwere Lötstellen?

von Yalu X. (yalu) (Moderator)


Lesenswert?

Wilson W. schrieb:
> Genau das ist das Problem, dass kein interruptfähiger Pin mehr frei ist
> und ich die Schaltung auch nicht mehr so verändern kann, dass einer frei
> wird.

Ich sehe nicht, dass in dem geposteten Code ein externer (also ein an
einen Pin gebundener) Interrupt verwendet wird. Der einzige verwendete
Interrupt ist der interne Interrupt von Timer1. Insofern sollte es
diesbezüglich zunächst keine Probleme geben.

Du schriebst aber etwas von einem Summer, der ebenfalls von Timer1
gesteuert wird und deswegen im Konflikt zu dem Encode steht. Wie genau
ist dieses Summen softwareseitig realisiert?

Wilson W. schrieb:
> Timer1.initialize(1000); und
> Timer1.attachInterrupt(timerIsr);
>
> einfach in Timer2 etc. ändern?

Wenn die Arduino-Bibliothek für Timer2 dieselben Funktionen (initialize
und attachInterrupt) bietet, sollte das so funktionieren. Ansonsten
solltest du den Vorschlag vom Arduino Fanboy ausprobieren.

Guido Körber schrieb:
> Da der Drehgeber ja wohl als User-Interface verwendet wird stört es
> nicht, wenn der mal einen Impuls übersieht.

Doch. Wird der Encoder wie hier für die Navigation in einem Auswahlmenü
eingesetzt, hat ein übersehener Impuls eine ähnlich nervige Wirkung wie
verlorengehende Tastendrücke auf einer Tastatur.

> Also einfach in der Main-Schleife pollen und fertig.

Wenn die Main-Schleife kurz genug ist, kann man das so machen. Mit einem
Timer-Interrupt funktioniert der Encoder aber unabhängig davon, was in
der Main-Schleife geschieht, weswegen das die zu bevorzugende Lösung
ist.

von Wilson W. (wilson)


Lesenswert?

Mhh ja, dann war wohl meine eigene Recherche für den Fehler ganz 
daneben, es geht eben darum, dass der Summer extrem leise geworden ist 
und der Encoder Aussetzer hat, wobei ich diesen ohne Summer garnicht 
ausprobiert habe mit der Lib, seit ich die TimeOne.h eingebunden habe. 
Der Summer wird so gesteuert:
1
void beep(unsigned char delayms) {
2
  analogWrite(buzzerPin, 20);  // Any value except of 0 and 255
3
  delay(delayms);      // wait for a delayms ms
4
  analogWrite(9, 0);   // 0 turns it off
5
  delay(delayms);      // wait for a delayms ms
6
}
7
8
// Und so abgerufen(der Begrüßungston aus dem Setup):
9
  beep(50);
10
  beep(50);
11
  beep(80);
12
  delay(300);

Denke so ein paar Delays machen in diesem Fall nichts aus, aber das ist 
wohl der Konflikt zwischen dem erwähnten Interrupt (OCIE1A) und den 
Delay, der das Problem auslöst, oder? Ich habe den Interrupt gegooglet 
und hab gelesen, dass das der Timer1 ist und dieser auf Pin 9 liegt, 
also da, wo mein Summer ist, deswgen bin ich davon ausgegangen, dass es 
kein interner Interrupt ist und das Problem auslöst.

Den Vorschlag von Arduino Fanboy habe ich nachgeschlagen aber nicht 
herausfinden können wie ich das konkret umsetze, schlussendlich sollen 
halt die "up" und "down" bools erhalten bleiben, wenn ich auf eine 
Library verzichten kann ist umso besser, aber ich verstehe nicht wo ich 
diese Zeilen wie verwende.

Ein Dankeschön zwischendurch :-)

von Wilson W. (wilson)


Angehängte Dateien:

Lesenswert?

Auf das Risiko hin, dass der ein oder andere nen Hals kriegt, hänge ich 
mal meinen Sketch dran, der ist halt noch im Aufbau und ich habe keine 
wirkliche Struktur beim Aufbau, bin halt noch Anfänger und baue es nicht 
Funktion für Funktion auf sondern springe hin und her, einiges 
funktioniert noch nicht richtig, das schaffe ich aber alleine zu lösen, 
nur eine Sache der Ordnung. Dass das Setup und der Loop erst am Ende 
auftauchen liegt daran, dass ich den Sketch mit der App ArduinoCode auf 
dem Handy baue und die meckert rum, wenn aufgerufene Funktionen erst 
nach den Aufruf auftauchen.

Und Fotos von der Platine, falls es was bringt, denke eher nicht, der 
Triac für das Heizelement der Heissluft ist auf einer eigenen Platine.

: Bearbeitet durch User
von Oliver R. (superberti)


Lesenswert?

Hi,

ehrlich gesagt würde ich für solche Zwecke heutzutage eher einen 
STM32F103 nehmen. Kost nix, die Abmessungen sind vergleichbar und das 
Ding kann extrem viel mehr.
Unter anderem hat er Hardwareencoder für Drehgeber und außer bei der 
Initialisierung der Hardware hat man gar keine Mühe mehr damit.
Auch damit kann man zwar bei günstigen Drehgebern ein Prellen 
feststellen, in den meisten Fällen stört das aber nicht und Werte lassen 
sich damit wunderbar in einem UI einstellen.

Gruß,
Oliver

von Wilson W. (wilson)


Lesenswert?

Oliver R. schrieb:
> Hi,
>
> ehrlich gesagt würde ich für solche Zwecke heutzutage eher einen
> STM32F103 nehmen. Kost nix, die Abmessungen sind vergleichbar und das
> Ding kann extrem viel mehr.
> Unter anderem hat er Hardwareencoder für Drehgeber und außer bei der
> Initialisierung der Hardware hat man gar keine Mühe mehr damit.
> Auch damit kann man zwar bei günstigen Drehgebern ein Prellen
> feststellen, in den meisten Fällen stört das aber nicht und Werte lassen
> sich damit wunderbar in einem UI einstellen.
>
> Gruß,
> Oliver

Danke für den Tipp, aber das ist ein "very very low to zero 
budget"-Projekt und zu 99% fertig.

von Maxim B. (max182)


Lesenswert?

Wilson W. schrieb:
> Hatte erst den Drehencoder ohne Library versucht
> auszulesen, was aber nicht geklappt hat, dann habe ich die Methode von
> educ8s, einem YouTuber, dessen Vorschläge immer perfekt funktionieren
> (Bei Interesse verlinke ich das Video) verwendet, das klappt auch, nur
> leider wird dabei die TimerOne Bibliothek verwendet und diese nutzt
> einen Interrupt,

Wozu braucht Drehgeber unbedingt Interrupt? Sowieso gibt es bestimmt 
irgendwelche Systemzeit, das reicht.

https://www.mikrocontroller.net/articles/Drehgeber#Beispielcode_in_C

Ich habe die Varianten dort getestet. Da ich billige China-Drehgeber 
eingelötet habe, sollte ich einiges einstimmen. Die Variante mit Tabelle 
in Flash war am besten, zwar sollte ich für sichere Arbeit statt
1
const char table[16] PROGMEM = {0,0,-1,0,0,0,0,1,1,0,0,0,0,-1,0,0};
1
const char table[16] PROGMEM = {0,0,-1,0,0,0,0,1,0,0,0,0,0,0,0,0};
verwenden.
1
volatile signed char enc_delta;
2
3
4
void drehgeber_abfrage(void){  // jede 1 ms gemacht
5
                
6
  static int8_t last=0;           // alten Wert speichern
7
    last = (last << 2)  & 0x0F;
8
    if (PHASE_A) last |=2;
9
    if (PHASE_B) last |=1;
10
    enc_delta += pgm_read_byte(&table[last]);
11
}
12
13
signed char encode_read1( void )         // read single step encoders
14
{
15
  signed char val;
16
  unsigned char tmp_sreg;  // temporaerer Speicher fuer das Statusregister
17
  tmp_sreg = SREG; // Statusregister (also auch das I-Flag darin) sichern
18
  cli();
19
  val = enc_delta;
20
  enc_delta = 0;
21
22
  SREG = tmp_sreg; // Status-Register wieder herstellen
23
  return val;                   // counts since last call
24
}
1
#define PHASE_A (beliebige PINPORT & (1<<beliebige_PIN))
2
#define PHASE_B (beliebige PINPORT & (1<<beliebige_PIN))
Was kann noch einfacher sein?

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Wilson W. schrieb:
> en Vorschlag von Arduino Fanboy habe ich nachgeschlagen aber nicht
> herausfinden können wie ich das konkret umsetze,

Hier ein Blink.ino aus meiner Wühlkiste
1
volatile unsigned int ticks = 0;
2
3
void setup() 
4
{
5
  DDRB |= _BV(PB5);  // pinMode(LED_BUILTIN,OUTPUT);
6
7
  OCR0A   = 42; // Wert ist egal
8
  TIMSK0 |= _BV(OCIE0A);
9
  TIFR0  |= _BV(OCF0A);
10
}
11
12
void loop() {}
13
14
15
ISR(TIMER0_COMPA_vect)
16
{
17
    if(++ticks >= 1000U) // 1000 == 977ms bei 16MHz
18
    {
19
      PINB = _BV(PB5); //digitalWrite(LED_BUILTIN,!digitalRead(LED_BUILTIN));// toggle pin
20
      ticks = 0;
21
    }
22
}

von Wilson W. (wilson)


Lesenswert?

Ich danke euch vielmals, hab aber wohl noch viel zu wenig Ahnung, die 
letzten beiden Beiträge verwirren mich noch mehr, hab mich wrst gefreut, 
weil es eigenständige Funktionen sind, ganz ohne Bibliotheken, aber 
dann... Muss wohl bei diesem Projekt auf den Encoder verzichten und mich 
erstmal ne Weile nur damit auseinander setzen. Kapiere halt bei beiden 
nicht wo ich konkret das "up" und "down", wie im Beispielcode, 
rausziehen kann, klar, irgendwas passiert und dann kann ich enweder 
booleans bestimmen oder einfach Integern 1 oder null zuweisen und statt 
up und down 1 oder 2 nehmen usw., aber was konkret sagt, dass sich der 
Encoder im oder entgegen dem Uhrzeigersinn dreht, das kapiere ich 
einfach nicht und je länger und je mehr ich dazu lese, desto schlimmer 
wird es, Zeichen und undefinierte Zahlen-/Buchstabenkombinationen, wie 
z.B. |=1 oder _BV oder ++ticks oder 1000U machen mich total wirr, | 
kenne ich als oder, ++ kenne ich nach nem Wert, dass sich dieser 
vermehrt und Buchstaben nach der Zahl sind mir völlig neu, gerade 
Zeichen in Suchmaschinen nachzuschlagen ist praktisch unmöglich.

Das ist wohl der Unterschied zwischen richtig lernen und erstmal ewig 
lang garnichts kapieren und zweckgebunden lernen, also immer dann, wenns 
nötig ist sich das beibringen.
Vielleicht leuchtets mir noch plötzlich ein, aber im Moment ist es wenig 
erfreulich.
Will euch auch nicht weiter mit meiner Noobigkeit nerven ;-)

Vielen vielen Dank an alle! Wünsche euch noch einen schönen Abend und 
viel lecker Schaschlik und so :-)

von Einer K. (Gast)


Lesenswert?

Ich schätze mal, dass du dir ein gutes C++ Buch anschaffen solltest!

> ++
> |=
Das Kapitel über Operatoren lesen.


> ++ kenne ich nach nem Wert,
Dann nennt er sich Postincrement
Ich verwende da Preincrement


> _BV()
Ein Macro namens "BitValue"
KA, wo definiert, irgendwo tief im Arduino Core, oder so


TIFR0  |= _BV(OCF0A);
Ist das gleiche wie
TIFR0  |= (1 << OCF0A);


> 1000U
> 1000UL
Das Kapitel über "Konstante Werte" lesen.

von Wilson W. (wilson)


Lesenswert?

Ich glaub auch, denke ich habe auch genug Wissen, dass ich dann nicht 
das Gefühl habe ein Buch in einer fremden Sprache zu lesen, hatte schon 
sowas mal als PDF auf dem Handy und konnte rein garnichts damit 
anfangen, das hatte mich damals sogar davon abgebracht C zu lernen und 
stattdessen VB, was meiner Meinung nach wenig sinnvoll ist.
Danke für die Erklärungen und Stichworte :) Operatoren sind mir nicht 
ganz fremd, aber die "Kapitel" schlage ich gleich nochmal nach und lese 
es mir genauer durch. Vielleicht lasse ich das Projekt auch erstmal 
ruhen.

Danke!

von W.S. (Gast)


Lesenswert?

Maxim B. schrieb:
> Wozu braucht Drehgeber unbedingt Interrupt? Sowieso gibt es bestimmt
> irgendwelche Systemzeit, das reicht....

...eben nicht.

Im Gegensatz zu gewöhnlichen Tasten, die man bequem softwaremäßig 
entprellen kann, weil sie langsam sind und man nur eine Flanke (das 
Gedrücktwerden) auswerten muß, hat man es bei einem Drehgeber mit etwas 
ganz anderem zu tun, denn:

- man hat 2 Signale
- man muß bei einem Signal beide Flanken auswerten
- man muß den Zustand des anderen Signals sehr zeitnah zu den Flanken 
des ersten Signals erfassen.
- man muß mit wesentlich höheren Ereignisraten rechnen als beim Taster. 
Wenn jemand den Knopf mal etwas schnell dreht, dann hat man 9..18 
Ereignisse binnen 200 ms, also manchmal alle 10 ms ein Drehereignis.

Wenn man das pollen will, dann muß man sehr häufig pollen, also etwa 
alle 1 ms oder gar noch schneller. Und das für nen popligen Drehgeber. 
Macht man's langsamer, dann verschluckt er sich. OK, man kann ja an den 
Knopf dranschreiben "bitte nur LANGSAM drehen und den Knopf gut 
festhalten, damit er durch die Rastmechanik nicht mit einem kurzen Knack 
von selbst in die nächste Stellung flutscht".

Deutlich besser ist also ein Interrupt auf beide Flanken des einen 
DG-Signals. Das sollte dasjenige sein, was sich NICHT im Rastpunkt 
ändert. Aber für den Interrupt muß das per HW entprellt werden. 
Normalerweise reicht dafür ein 22nF Kondensator aus.

W.S.

von Joachim B. (jar)


Lesenswert?

W.S. schrieb:
> Wenn man das pollen will, dann muß man sehr häufig pollen, also etwa
> alle 1 ms oder gar noch schneller

das ist ja auch kein Problem,

hatte man für die Tastenauswertung eine ISR mit 10ms dann pollt man eben 
für den Drehgeber alle 1ms das genügt dann und die Tasten werden in der 
ISR danach abgefragt wenn der 1ms ISR Zähler auf 10 steht.

ISR 1ms

lese Drehencoder Ports
zähle den Merker für Tasten hoch
ist dieser 10 (oder 9 weil von 0-9 sind genauso 10 wie von 1-10)
dann lese die Tasten und gebe es an die Tastenentprellung
setze den Merker für Tasten wieder zurück auf 1 (oder 9 weil von 0-9 
sind genauso 10 wie von 1-10)


ISR Ende

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

das Spielchen kann man weitertreiben für IR Dekodierung

ISR 1/15 ms

lese IR Dekoder
zähle den Merker für Drehencoder hoch
ist dieser 15 (oder 14 weil von 0-14 sind genauso 15 wie von 1-15)

lese Drehencoder Ports
setze den Merker für Drehencoder wieder zurück auf 1 (oder 9 weil von 
0-9
zähle den Merker für Tasten hoch
ist dieser 10 (oder 9 weil von 0-9 sind genauso 10 wie von 1-10)

dann lese die Tasten und gebe es an die Tastenentprellung
setze den Merker für Tasten wieder zurück auf 1 (oder 9 weil von 0-9
sind genauso 10 wie von 1-10)

ISR Ende

: Bearbeitet durch User
von Forist (Gast)


Lesenswert?

Wilson W. schrieb:
> Mein Sketch ist zur Zeit noch sehr chaotisch, wenn ich den poste fresst
> ihr mich, das garantiere ich

Das Fressen hat mit dem Chaos im Code erstmal gar nichts zu tun. Es 
reicht schon, dass du seitenlangen Code nicht als ANHANG postest ;-(

von Wolfgang (Gast)


Lesenswert?

Guido Körber schrieb:
> Da der Drehgeber ja wohl als User-Interface verwendet wird stört es
> nicht, wenn der mal einen Impuls übersieht.

Mich würde das bei der Benutzung schon irritieren, wenn ein Auswahlmenü 
beim Drehen ab und zu erratisch hoch und runter springt.

Beitrag #5396906 wurde vom Autor gelöscht.
von Joachim B. (jar)


Lesenswert?

Wolfgang schrieb:
> Mich würde das bei der Benutzung schon irritieren, wenn ein Auswahlmenü
> beim Drehen ab und zu erratisch hoch und runter springt.

das macht man dann mit Überabtastung, ich musste auch erst 
experimentieren, PeDa hat dafür den 4 Impuls ja zur Auswahl gestellt, 
kann sein das ich nun mehr kurbeln muss aber dafür funktioniert es 
sicher mit Einrasten auch in der Menüwahl und nichts zappelt.

https://www.mikrocontroller.net/attachment/highlight/40597
https://www.mikrocontroller.net/articles/Drehgeber#Beispielcode_in_C

: Bearbeitet durch User
von Gerhard O. (gerhard_)


Lesenswert?

Vor ein paar Jahren portierte ich Peters Encoder Code unter anderen uC 
auch auf den Arduino Pro-Mini. Es funktioniert dort genau so einwandfrei 
wie auf allen anderen uC. Abgetastet werden die zwei Pins bei mir in 
einer schon vorhandenen 1ms TIMER2 ISR. Ich bin jetzt gerade nicht in 
der Nähe meines PCs, könnte aber irgendwann später meinen alten Code 
raussuchen wenn es Dir hilft. Die Routine von Peter ist absolut 
empfehlenswert und Goldes wert und es lohnt sich auf alle Fälle sich 
damit zu befassen.

von W.S. (Gast)


Lesenswert?

Gerhard O. schrieb:
> Die Routine von Peter ist absolut
> empfehlenswert und Goldes wert und es lohnt sich auf alle Fälle sich
> damit zu befassen.

nana.

ich bin eher für's Verstehen der zugrundeliegenden Hardware.

Nochwas: Ich nehme für Drehencoder schon seit Jahren nur nen Interrupt - 
und bei mir hat sich das bislang noch nie verzählt, auch dann nicht, 
wenn mal jemand den Knopf mit nem "Ratsch" durchdreht. Da frag ich mich, 
wieso hier so viele Leute immer wieder auf Polling herumreiten. Das 
frißt bloß unnötig Rechenzeit und ist keinen Deut besser.

W.S.

von Der Mann, der zuviel wusste (Gast)


Lesenswert?

W.S. schrieb:
> Da frag ich mich,
> wieso hier so viele Leute immer wieder auf Polling herumreiten. Das
> frißt bloß unnötig Rechenzeit und ist keinen Deut besser.

Teufel, Weihwasser?

von Wilson W. (wilson)


Lesenswert?

@Gerhard

Na klar, sehr gerne, hab zich Tabs geöffnet mit den einzelnen 
Stichworten und springe immer wieder zurück hierher und vielleicht kann 
ich deine Lösung eher nachvollziehen.

Dankeschön!

: Bearbeitet durch User
von Gerhard O. (gerhard_)


Angehängte Dateien:

Lesenswert?

Wilson W. schrieb:
> @Gerhard
>
> Na klar, sehr gerne, hab zich Tabs geöffnet mit den einzelnen
> Stichworten und springe immer wieder zurück hierher und vielleicht kann
> ich deine Lösung eher nachvollziehen.
>
> Dankeschön!

Hallo Wilson,

im Anhang findest Du mein soeben getestetes Demo Programm. Nach dem 
Laden öffne ein Terminal Programm auf 9600, N,8,1 gestellt und drehe am 
Knopf des QE Encoders und die Encoder Schritte werden entsprechend 
seriell angezeigt.

Bei einer ISR Wiederhol-Frequenz von 1ms, kann ich den Decoder so 
schnell wie mit der Hand möglich drehen ohne Schritte zu verlieren.

Es läuft auf einem Pro-Mini Klon mit 16MHz 5V Ausstattung.

Der QE Encoder ist in einer Link im Programm beschrieben und hat 30 
Schritte pro Umdrehung. DA findest Du auch noch eine anderes Demo 
Programm.

Versuchs dann mal und viel Erfolg.


Gerhard

von Gerhard O. (gerhard_)


Lesenswert?

W.S. schrieb:
> Gerhard O. schrieb:
>> Die Routine von Peter ist absolut
>> empfehlenswert und Goldes wert und es lohnt sich auf alle Fälle sich
>> damit zu befassen.
>
> nana.
>
> ich bin eher für's Verstehen der zugrundeliegenden Hardware.
>
> Nochwas: Ich nehme für Drehencoder schon seit Jahren nur nen Interrupt -
> und bei mir hat sich das bislang noch nie verzählt, auch dann nicht,
> wenn mal jemand den Knopf mit nem "Ratsch" durchdreht. Da frag ich mich,
> wieso hier so viele Leute immer wieder auf Polling herumreiten. Das
> frißt bloß unnötig Rechenzeit und ist keinen Deut besser.
>
> W.S.

Das kommt auf die Anwendung an. Meine Programme haben fast immer eine 
Zeitbasis mit Timer ISR und da braucht das Pollen kaum CPU Ressourcen. 
Ich finde diese Methode (für mich) durchaus akzeptabel. Mit ISR kann 
schon so seine Probleme mit Prellen haben und beansprucht dann auch 
entsprechende Abwehrmaßnahmen die auch Code verschlingen. Ich finde 
Peters Algorithmus fuer die Praxis ideal und Ressourcen sparsam.

Für Maschinen Q-Auswertung würde ich nur solche Methoden verwenden 
wollen wie man sie z.B. beim STM32 HW-Counter findet oder die LS7266 
Bausteine um Schrittverluste schon von vornherein ausschließen zu 
können. Software Q- Auswertung hat meiner Meinung nach nur bei langsamen 
mechanischen Anwendungen wie User Interfaces Sinn wo mögliches 
sporadisches Fehlverhalten in der Regel keine schlimme Auswirkung hat.

Aber da viele Wege nach Rom führen, beanspruche ich nur einen davon:-)


Gruß,
Gerhard

von Gerhard O. (gerhard_)


Lesenswert?

Gerhard O. schrieb:
> Der QE Encoder ist in einer Link im Programm beschrieben und hat 30
> Schritte pro Umdrehung. DA findest Du auch noch eine anderes Demo
> Programm.

Ich habe soeben das Demo Programm auf der KY-040 Webseite ausprobiert 
und das funktioniert auch ganz ordentlich. Konnte mit Rumspielen mit dem 
Knopf kein Fehlverhalten erzwingen.

Allerdings verliert es (wie zu erwarten) maechtig Schritte beim 
Schnelldrehen.

: Bearbeitet durch User
von Wilson W. (wilson)


Lesenswert?

Vielen Dank Gerhard. Was interessant ist, der Beispiel-Sketch auf der 
Webseite ist die erste Methode, die ich ausprobiert habe und die ging 
fast garnicht, im Uhrzeigersinn stieg der Wert meist an, sprang aber 
immer wieder zurück und gegen den Uhrzeigersinn ist der Wert hin und her 
gesprungen, meist eher nach oben als nach unten.

Aber cool, hab durch deine Variante auch bei den anderen Versionen 
schonmal verstanden welcher Wert die Drehrichtung ausgibt.

Ich muss das ganze als ein eigenständiges Projekt aufarbeiten und mir 
viel viel Zeit dafür nehmen und denke grad wieder wie praktisch doch ein 
Android Handy wäre, dann müsste ich nicht stundenlang krumm vorm Lappi 
hängen und mich am Kopf kratzen, sondern könnte ständig in jeder 
Situation die Sketche auf den uC laden.

Allen ein schönes Wochenende :)

von Michael B. (laberkopp)


Lesenswert?

W.S. schrieb:
> Da frag ich mich, wieso hier so viele Leute immer wieder auf Polling 
herumreiten.

Das ist einfach: Weil sie mehr wissen als du.

W.S. schrieb:
> Ich nehme für Drehencoder schon seit Jahren nur nen Interrupt

Das kann ja in Ordnung sein - wenn es ein Timer-Interrupt ist. Dass du 
nicht mal diesen wichtigen Unterschied bemerkst, zeigt, WIE wenig Ahnung 
du hast.

von Gerhard O. (gerhard_)


Lesenswert?

Hallo Wilson,

Deinem Bericht nach stimmt höchstwahrscheinlich etwas mit den 
Komponenten, bzw Verdrahtung oder sonst irgendwas nicht. Beide Programme 
funktionieren bei mir absolut einwandfrei wenn man davon absieht, daß 
das Web Demo Programm beim Schnelldrehen Schritte verliert was bei 
Peters Version nicht der Fall ist. Arbeite Dich auch durch den Arikel 
hier im Forum.

Pullups (10k) sind absolut notwendig. Auf die aktivierten internen 
Pullups darfst Du Dich nicht verlassen. Es muß zwecks zuverläßiger 
Funktion durch die Kontakte idealerweise mindestens ein Strom im mA 
Bereich fließen. Besser mit dem Oszi überprüfen was da vor sich geht. 
Der KY-040 hat auf der Bord Pullups die mit der Versorgungsspannung 
verbunden sein müssen. Bei mir verwende ich bequemerweise den auf HIGH 
gesetzten D8 Pin. Auch aufpassen, daß der gemeinsame Pin vom Drehgeber 
nach Masse angeschlossen ist und die Quadraturausgänge tatsächlich zu 
den designierten Eingängen gehen.
Bei mir waren D6 und D7 als Eingänge designiert (Notfalls anpassen). 
Beim Webdemo waren es andere Eingänge. Also alles akribisch nachprüfen.

Bevor Du nicht die Demo Programme so wie angegeben zum Laufen bringst 
nützt es nichts mit Deinen Projekt weiter zu machen. Du mußt methodisch 
vorgehen.

Gerhard

Nachtrag:

Schließ wie im Webartikel vorgeschlagen zwei LEDs an den 
Drehgeberausgängen nach 5V an um die korrekte Sequenz der Ausgänge 
überprüfen zu können.

: Bearbeitet durch User
von Wilson W. (wilson)


Lesenswert?

Ich habe den Pulsgeber bloß gegen Ground auf zwei digitale Pins 
geschaltet. Bin nicht sicher was du mit Demo-Programm meinst, ich meinte 
den kurzen Beispiel-Sketch unten auf der Seite.

Für die Lötstation, zumindest diese Version habe ich mich nun doch für 
Taster entschieden, spricht aktuell mehr dafür als dagegen, es fühlt 
sich seltsam an auf dem kleinen Display mit nem Potiknopf was 
einzustellen, weil für die Wert-Einstellung dreht man den Pulsgeber wie 
nen Poti, aber für die Menü-Bedienung dreht man in Rastern, mir kam 
gleich das Nokia 7110 in Erninnerung mit dem Scrollrad, glaub das wäre 
die Ideallösung. Da ich auch eine Einstellung für die Einstell-Schritte 
der Soll-Temperaturen und der Presets eingebaut habe, kann ich das dann 
bequem für die Taster anpassen, mit den drei Presets werde ich auch 
nicht so viel einstellen müssen, sondern nur auswählen.

Und Pulsgeber ansich zu verstehen und richtig auszuwerten wird ein 
komplett eigenes Projekt, die Dinger sind zu praktisch, als dass man sie 
einfach überspringt und jedes Mal nach Alternativen sucht.

Ein Oszi habe ich leider nicht, bin aber dabei mir eine Hobby-Werkstatt 
für Low- bis Zero-Budget aufzubauen, hab ein altes Pentium III Laptop, 
das maximal 60 Watt verbraucht, welches ich dann so umbauen will, dass 
ich es als Oszi und zum Anzeigen von Schaltplänen nutzen kann, aber da 
hab ich mir noch keine Gedanken drum gemacht, außer, dass eine 
Touchfolie o.Ä. sinnvoll wäre. Im Endeffekt gehts um den Spaß und das 
Lernen beim Aufbau, wirklich brauchen tue ich nichts davon, aber wenn 
ich es habe, kann ich es auch dafür verwenden komplexere Dinge zu machen 
als grobe Elektronik und Elektrik zu reparieren und Komponenten bei 
Handys tauschen.

von Gerhard O. (gerhard_)


Lesenswert?

Wilson W. schrieb:
> Ich habe den Pulsgeber bloß gegen Ground auf zwei digitale Pins
> geschaltet. Bin nicht sicher was du mit Demo-Programm meinst, ich meinte
> den kurzen Beispiel-Sketch unten auf der Seite.

Das ist schon in Ordnung. Nur müssen auch Pullups von 10K von 5V auf die 
Drehgeber Eingänge vorhanden sein. Zumindest sollten die internen 
Pullups des AVRs aktiviert sein. Auch die vorgeschlagenen LEDs wären zum 
Testen ohne Oszi nützlich. Ich würde auf alle Fälle den Problemen auf 
den Grund gehen und zumindestens die Sache zum Laufen zu bringen. Das 
User Interface kannst Du Dir ja noch überlegen.

Also versuch mal die Programme zum richtigen Funktionieren zu bringen.

von Joachim B. (jar)


Lesenswert?

Wilson W. schrieb:
> Und Pulsgeber ansich zu verstehen und richtig auszuwerten wird ein
> komplett eigenes Projekt, die Dinger sind zu praktisch, als dass man sie
> einfach überspringt und jedes Mal nach Alternativen sucht.

nutze die LIB von Dannegger

Wilson W. schrieb:
> Ein Oszi habe ich leider nicht,

ist nicht nötig, ein Nachmittag mit dem Beispiel Code, die verschiedenen 
Varianten probieren 1 -2 -4 Impulse

fertig.

von Maxim B. (max182)


Lesenswert?

Wilson W. schrieb:
> hab ein altes Pentium III Laptop,
> das maximal 60 Watt verbraucht, welches ich dann so umbauen will, dass
> ich es als Oszi und zum Anzeigen von Schaltplänen nutzen kann

Das ist kaum eine gute Idee:
falls etwas mit Oszi kaputt geht, hast du gleich deine Schaltpläne 
verloren! Auch was Frequenzen betrifft, ist ein Laptop-Oszi fragwürdig.

Mein Tipp: überall wo nur möglich Geräte benutzen, die ohne Stromnetz 
arbeiten können. Somit hast du bei Problem mit GND mehr 
Überlebenschancen für deine Technik und auch für dich selbst.

von Wilson W. (wilson)


Lesenswert?

Mhh, es gibt da doch so Oszi-Programme, mit denen man die Soundkarte 
auslesen kann und mit einer Schaltung vor der Soundkarte kann man ja 
Überspannungen etc. verhindern. Der Lappi selbst arbeitet doch mit einem 
Schaltnetzteil, also ist da doch alles sicher und ich würde damit auch 
keine Netzspannung messen.

Ich synchronisiere eh alle meine Datenträger regelmäßig.

Das ist aber auch nur eine Idee, weil ich den Lappi gerne für irgendwas 
verwenden will und die günstigen Oszi-Bausätze haben halt recht kleine 
Bildschirme, vielleicht könnte man die auch auslesen und auf einen 
größeren Schirm übertragen, kein Plan, ich werde mich aber noch genauer 
damit beschäftigen, hat keine Priorität.

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.