Hallo,
kann man Peter Danneggers Entprellroutine auch in der Arduino IDE und
einem Mega32U4 benutzen?
Wenn ja, gibt es die Komfortversion schon als fertigen Sketch?
Mark Thalle schrieb:> kann man Peter Danneggers Entprellroutine auch in der Arduino IDE und> einem Mega32U4 benutzen?
Ja.
> Wenn ja, gibt es die Komfortversion schon als fertigen Sketch?
Vermutlich nicht.
Mark Thalle schrieb:> Hallo,>> kann man Peter Danneggers Entprellroutine auch in der Arduino IDE und> einem Mega32U4 benutzen?
im Prinzip ja.
Ist ja nichts anderes als ein Timer, der in regelmässigen Abständen
einen Interrupt auslöst und ein wenig Code in der ISR. Der ISR Code ist
da wie dort derselbe, bis auf mglw. den Zugriff auf den Input-Port.
Wie man in der Arduino Umgebung fachgerecht einen Timer samt zugehörigem
Interrupt installiert, solltest du allerdings wissen. Du bist ja
schliesslich der Arduino Programmierer. Aber der ganze Bitpfriemelteil
in der ISR bleibt 100% identisch. Der ist nicht hardwareabhängig.
> Wenn ja, gibt es die Komfortversion schon als fertigen Sketch?
Möglich, dass sich das jemand schon mal gemacht hat. Ich glaubs aber
ehrlich gesagt nicht wirklich.
Karl Heinz schrieb:> Wie man in der Arduino Umgebung fachgerecht einen Timer samt zugehörigem> Interrupt installiert, solltest du allerdings wissen.
Wenn ich nicht irre, dann ist nur der Timer 0 vom Arduino-System belegt.
Konrad S. schrieb:> Karl Heinz schrieb:>> Wie man in der Arduino Umgebung fachgerecht einen Timer samt zugehörigem>> Interrupt installiert, solltest du allerdings wissen.>> Wenn ich nicht irre, dann ist nur der Timer 0 vom Arduino-System belegt.
Keine Ahnung. Irgendeiner muss es sein, denn irgendeiner muss ja die
Systemuhr für millis() implementieren.
Aber wie für fast alles, gibt es auch für die Timer auf den
Arduino-Webseiten zugehörige Doku und Beispiele, die man halt auch als
Ardunio Programmierer mal lesen sollte. Da würde man dann auch was
lernen, was über das Fragen nach fertigen Schketschen hinausgeht.
Darauf wollte ich eigentlich hinaus :-)
http://playground.arduino.cc/Deutsch/HalloWeltMitInterruptUndTimerlibrary
Ah, hier: http://www.gammon.com.au/forum/?id=11488
"One of the internal timers (timer 0) is set up to interrupt roughly
1000 times a second, and increment an internal counter which effectively
becomes the millis() counter."
Karl Heinz schrieb:> was über das Fragen nach fertigen Schketschen hinausgeht.> Darauf wollte ich eigentlich hinaus :-)
Ich höre, was du nicht sagst! ;-)
Mark Thalle schrieb:> kann man Peter Danneggers Entprellroutine auch in der Arduino IDE und> einem Mega32U4 benutzen?
Im Prinzip ja.
Aber wozu soll es gut sein?
Die Arduino-Software stellt Dir in jedem Arduino-Sketch die Funktionen
millis() und micros() als Zeitbasis zur Verfügung.
Alleine bereits mit Hilfe von millis() wird doch jedes softwaremäßige
Entprellen zu einem völlig trivialen Selbstgänger.
So what?
Jürgen S. schrieb:> Alleine bereits mit Hilfe von millis() wird doch jedes softwaremäßige> Entprellen zu einem völlig trivialen Selbstgänger.
Prust, Lach.
Es war gestern wohl schon zu spät und ich war nach der Sucherei bzgl.
der Entprellroutine schon etwas malle. Im Betreff wollte ich nach dem
Arduino gefragt haben.
Karl Heinz schrieb:> Mark Thalle schrieb:>> kann man Peter Danneggers Entprellroutine auch in der Arduino IDE und>> einem Mega32U4 benutzen?>> im Prinzip ja.> Ist ja nichts anderes als ein Timer, der in regelmässigen Abständen> einen Interrupt auslöst und ein wenig Code in der ISR. Der ISR Code ist
So weit hatte ich die Threads und den Artikel hier im Forum auch
verstanden und das leuchtet mir auch ein.
Kleine Teile des C-Codes kann ich auch nachvollziehen, aber es ist zu
viel dabei, was ich nicht verstehe.
> da wie dort derselbe, bis auf mglw. den Zugriff auf den Input-Port.> Wie man in der Arduino Umgebung fachgerecht einen Timer samt zugehörigem> Interrupt installiert, solltest du allerdings wissen. Du bist ja> schliesslich der Arduino Programmierer. Aber der ganze Bitpfriemelteil> in der ISR bleibt 100% identisch. Der ist nicht hardwareabhängig.
Ich fange gerade mit Arduino an und habe "Hallo Welt" erfolgreich
getestet.
Ansonsten habe ich vor vielen Jahren mal ganz oberflächlich was mit PICs
gemacht. Timer und Interrupts habe ich noch nie angefasst.
Mit C hatte ich noch nie etwas zu tun. Ich habe lediglich mal ein klein
wenig mit Borland Pascal und Python gemacht, aber auch höchstens auf dem
Niveau dessen, was man unbedingt während der Schule und des Studiums
braucht.
Ich bin also kein Programmierer.
In meinem ersten Arduino-Projekt wollte ich nur ein paar digitale
Eingänge einlesen und abhängig von deren Kombination ein paar Ausgänge
setzen.
Nachdem, was ich im Arduino-Bereich gelesen habe, traue ich mir auch zu,
selbst irgendwie Tasten zu entprellen. So effizient, wie die
Dannegger-Methode wird das aber garantiert nicht, weshalb ich gerne
darauf zurück greifen würde.
Die Übersetzung von C oder ASM in die Arduino IDE traue ich mir aber
nicht zu.
>> Wenn ja, gibt es die Komfortversion schon als fertigen Sketch?>> Möglich, dass sich das jemand schon mal gemacht hat. Ich glaubs aber> ehrlich gesagt nicht wirklich.
Ich habe auch nach längerer Suche nichts dazu gefunden.
Das finde ich merkwürdig, denn die Dannegger-Methode scheint ziemlich
anerkannt und effizient zu sein. Für einen halbwegs fähigen
Programmierer dürfte es doch nur ein paar Minuten dauern, bis er das für
einen Arduino umgefriemelt hat.
Mark Thalle schrieb:> Für einen halbwegs fähigen> Programmierer dürfte es doch nur ein paar Minuten dauern, bis er das für> einen Arduino umgefriemelt hat.
Aber warum würde ein "halbwegs fähiger Programmierer" sowas tun? Evt.
mit Waffe am Kopf oder nach schwerer Hirnverletzung, aber sonst? Warum
sollte man sich in die Niederungen begeben? Hilft der Adler dem
Regenwurm ein Loch zu buddeln?
Das Hauptproblem dürfte sein, daß die Arduino-Lib über Nummern auf die
Pins zugreift, die sich zufällig aus dem Platinenlayout ergeben haben.
Die Entprellroutine möchte aber über die nativen Portbezeichner
(PINA..L) zugreifen.
Das kann beim Anfänger zur Verwirrung führen, da er nicht weiß, welche
Arduino-Nummer mit welchem Portpin des AVR korrespondiert.
Mark Thalle schrieb:> Ich habe auch nach längerer Suche nichts dazu gefunden.
Beschreibe doch mal konkret, um was es bei Dir genau geht und wo das
Problem liegt?
Also es geht um mehrere Taster/Schalter, das habe ich richtig
verstanden?
Was brauchst Du denn von den Schaltern an Information:
Nur den HIGH/LOW Status?
Oder eine Info, "Taster wechselt den Status" (Flankenwechsel HIGH/LOW),
um genau auf das Drücken oder das Loslassen des Tasters bzw. das Umlegen
des Schalters mit einer Aktion zu reagieren?
Oder möchtest Du bei einem Taster auf unterschiedlich lange Tastendrücke
reagieren, z.B. "kurzer Tastendruck<1s" und "langer Tastendruck>=1s"?
Oder brauchst Du sowas wie zählende Multifunktionsschalter, um mehr als
zwei Funktionen auf einen Taster zu legen, bei dem zum Beispiel "Taster
dreimal schnell nacheinander gedrückt" von "Taster viermal schnell
nacheinander gedrückt" anhand von Timeout-Bedingungen unterschieden
wird, um je nach Anzahl verschiedene Funktionen aufzurufen, gesteuert
über nur einen Taster?
Hast Du Dir schon überlegt, wie die Taster hardwareseitig angeschlossen
werden sollen: Generell mit PullDown-Widerständen? Oder sollen die
internen PullUp-Widerstände des Atmega-Controllers zum Pullen des Inputs
verwendet werden?
Je nachdem ist es dann mit 3 Zeilen Code getan. Oder etwas mehr, je
nachdem was die Schalter an Logik ausspucken sollen.
Der häufigste Anwendungsfall dürfte wohl sein:
a) Du möchtest auf das Drücken (oder Loslassen) eines Tasters reagieren
b) Die Stellung anderer Schalter HIGH/LOW soll dabei berücksichtigt
werden
Kann man das grob so beschreiben, was Du machen möchtest?
Dann könnte ich Dir dafür mal ein paar Zeilen kommentierten Demo-Sketch
schreiben wie es mit der Erfassung und Entprellung in einem
Arduino-Sketch funktioniert, wenn Du möchtest.
Mark Thalle schrieb:> Die Übersetzung von C oder ASM in die Arduino IDE traue ich mir aber> nicht zu.
Die "Arduino IDE" versteht C problemlos, weil dahinter ein gcc die
Arbeit macht.
Mark Thalle schrieb:> So weit hatte ich die Threads und den Artikel hier im Forum auch> verstanden und das leuchtet mir auch ein.> Kleine Teile des C-Codes kann ich auch nachvollziehen, aber es ist zu> viel dabei, was ich nicht verstehe.
Das macht nichts. Selbst gestandene Programmierer brauchen 20 Minuten
oder mehr, bis sie den ISR Code in allen Einzelheiten analysiert haben.
Aber: Den muss man als Anwender auch nicht verstehen. Dazu funktioniert
er einfach zu gut. Du kannst ja wahrscheinlich auch keinen Code
schreiben, der die Wurzel einer Zahl berechnet, hast aber keine
Hemmungen die Funktion sqrt() zu verwenden. Oder: Kannst du eine
dynamische Speicherverwaltung implementieren? Ich denke mal, die Antwort
lautet: nein. Trotzdem benutzt du malloc() oder new ohne mit der Wimper
zu zucken.
Sieh den Code als Baustein an, der dein Problem löst. Mehr ist es nicht.
Ob du die Feinheiten der paar Zeilen Code in der ISR in allen Details
verstehst oder nicht, spielt da keine Rolle.
Wie PeDa schon sagte: Das Hauptpropblem wird wohl sein, dass der Code
die Portpins direkt über das PIN Register abfrägt, während in der
Arduino Welt wohl mehr der Umweg über digitalRead gebräuchlich sein
dürfte.
> Ansonsten habe ich vor vielen Jahren mal ganz oberflächlich was mit PICs> gemacht. Timer und Interrupts habe ich noch nie angefasst.
Dann wird es Zeit das zu lernen.
Ein ordentliches reales Programm (also nicht irgendeine SPielerei) kommt
in den wenigsten Fällen ohne einen Timer bzw. einen Timerinterrupt aus.
> In meinem ersten Arduino-Projekt wollte ich nur ein paar digitale> Eingänge einlesen und abhängig von deren Kombination ein paar Ausgänge> setzen.
Guter Tip.
Dann überleg dir zunächst Aufgabenstellungen, in denen du ohne
Entprellung bzw. Tastenrepeat auskommst. Anstatt eine LED mit nur einem
Taster ein und aus zu schalten, kann man das ja auch mit 2 Tastern
machen. Der eine schaltet ein, der andere schaltet aus. Dazu muss man
nichts entprellen.
> Nachdem, was ich im Arduino-Bereich gelesen habe, traue ich mir auch zu,> selbst irgendwie Tasten zu entprellen.
Lass es.
Wenn schon, dann such nach einem fertigen Enptrellcode, der auch aus der
Arduino Welt stammt. Da gibt es mit Sicherheit etwas.
Das mag zwar nicht so toll und effizient wie der PeDa Code sein und auch
nicht die Möglichkeiten bieten, aber als Anfänger ist deine
Entprelllösung mit Sicherheit schlimmer als alles was du irgendwo als
vorgefertigter Sketch kriegen kannst.
Mark Thalle schrieb:> Das finde ich merkwürdig, denn die Dannegger-Methode scheint ziemlich> anerkannt und effizient zu sein.
Sei versichert, die "Dannegger-Methode" ist ein rein lokales Phaenomaen
dieses Forums. Ausserhalb hat davon noch nie Jemand gehoert und das
Verstaendnis fuer die Huldigung dieses schlecht dokumentierten
Schnipsels Code geht ausserhalb dieses Forums gegen Null.
Ich bezweifle, dass Entprellen das erste wichtige Problem ist, das du
als Arduino-Einsteiger loesen musst. Aber hier gibt es ein Beispiel fuer
Arduino, das hinreichend funktioniert:
http://arduino.cc/en/Tutorial/Debounce
Das ist zwar nicht genial und verehrungswuerdig, aber du kannst dir ja
zum Ziel setzen, eine geniale Alternative fuer Arduino zu schaffen, die
dann allen Nutzern der Arduino-Welt zur Verfuegung steht? Das waere
allemal mehr, als zum Beispiel Lord Maulheld auf die Reihe bekommt...
Peter Dannegger schrieb:> Das Hauptproblem dürfte sein, daß die Arduino-Lib über Nummern auf die> Pins zugreift, die sich zufällig aus dem Platinenlayout ergeben haben.> Die Entprellroutine möchte aber über die nativen Portbezeichner> (PINA..L) zugreifen.> Das kann beim Anfänger zur Verwirrung führen, da er nicht weiß, welche> Arduino-Nummer mit welchem Portpin des AVR korrespondiert.
Das ist zumindest ein Problem.
Ich habe die Komfortroutine aus dem Artikel in Mikrokontroller.net 1:1
in die Arduino-IDE kopiert und kompilieren lassen.
Die erste Fehlermeldung ist:
error: 'PORTA' was not declared in this scope
Die Bezeichnung "PORTA" kommt mir noch aus PIC-Zeiten bekannt vor,
sodass ich mir sicher war zu wissen, was gemeint ist. Die Suche nach
diesem Begriff im Arduino-Bereich war leider nicht erfolgreich.
Hi
>Die Bezeichnung "PORTA" kommt mir noch aus PIC-Zeiten bekannt vor,>sodass ich mir sicher war zu wissen, was gemeint ist. Die Suche nach>diesem Begriff im Arduino-Bereich war leider nicht erfolgreich.
Dann nimm mal das Datenblatt von dem AVR, der auf deinem Arduino verbaut
ist, zur Hand.
MfG Spess
cyblord ---- schrieb:> Mark Thalle schrieb:>> Für einen halbwegs fähigen>> Programmierer dürfte es doch nur ein paar Minuten dauern, bis er das für>> einen Arduino umgefriemelt hat.>> Aber warum würde ein "halbwegs fähiger Programmierer" sowas tun? Evt.
Vielleicht weil er Spaß daran hat und die fertigen und vermutlich
relativ billigen Arduinos auch für sich benutzen kann.
> mit Waffe am Kopf oder nach schwerer Hirnverletzung, aber sonst? Warum> sollte man sich in die Niederungen begeben? Hilft der Adler dem> Regenwurm ein Loch zu buddeln?
Warum veröffentlicht Peter seine Entprellroutine? Ich vermute, dass er
nichts daran verdient und es ihm Freude bereitet.
Quack schrieb:> Mark Thalle schrieb:>> Das finde ich merkwürdig, denn die Dannegger-Methode scheint ziemlich>> anerkannt und effizient zu sein.>> Sei versichert, die "Dannegger-Methode" ist ein rein lokales Phaenomaen> dieses Forums. Ausserhalb hat davon noch nie Jemand gehoert
sagen wir mal: zu wenige
und sagen wir mal: leider
Denn das Ding ist ein echter 'fire and forget' Code. Die paar Zeilen in
die ISR einbauen (die man sowieso als Heartbeat hat) und im Handumdrehen
hat man eine zuverlässige Entprellung für 8 Tasten, die alle Stückeln
spielt, die man braucht.
Mark Thalle schrieb:> Warum veröffentlicht Peter seine Entprellroutine? Ich vermute, dass er> nichts daran verdient und es ihm Freude bereitet.
Es geht auch nicht ums veröffentlichen, sondern um das Anfertigken eines
Arduino-Sketch. Ich habe selbst schon einiges an Code veröffentlicht.
Daran ist ja nichts verwerfliches.
Quack schrieb:
>aber du kannst dir ja>zum Ziel setzen, eine geniale Alternative fuer Arduino zu schaffen, die>dann allen Nutzern der Arduino-Welt zur Verfuegung steht? Das waere>allemal mehr, als zum Beispiel Lord Maulheld auf die Reihe bekommt...
Dem ist nichts hinzuzufügen.
Karl Heinz schrieb:> Mark Thalle schrieb:> Sieh den Code als Baustein an, der dein Problem löst. Mehr ist es nicht.> Ob du die Feinheiten der paar Zeilen Code in der ISR in allen Details> verstehst oder nicht, spielt da keine Rolle.
So wollte ich es auch machen.
Wenn ich den Code aber im Arduino benutzen möchte, muss ich den
umgefriemelt bekommen. Und dazu muss ich wenigstens grob verstehen, was
die einzelnen Befehle machen.
>> Nachdem, was ich im Arduino-Bereich gelesen habe, traue ich mir auch zu,>> selbst irgendwie Tasten zu entprellen.>> Lass es.> Wenn schon, dann such nach einem fertigen Enptrellcode, der auch aus der> Arduino Welt stammt. Da gibt es mit Sicherheit etwas.> Das mag zwar nicht so toll und effizient wie der PeDa Code sein und auch> nicht die Möglichkeiten bieten, aber als Anfänger ist deine> Entprelllösung mit Sicherheit schlimmer als alles was du irgendwo als> vorgefertigter Sketch kriegen kannst.
Das ist wahrscheinlich so.
Dann werde ich das wohl auf die weniger effizienten Sketche
zurückgreifen. Ich bin gespannt, ob das Entprellen damit zuverlässig
funktioniert.
>> Wenn ich den Code aber im Arduino benutzen möchte, muss ich den>> umgefriemelt bekommen. Und dazu muss ich wenigstens grob verstehen, was>> die einzelnen Befehle machen.
Peters Code ist ja ausführlich erklärt. Der Thread zum Thema ist ja mehr
als ein Roman.
Ansonsten schaust du hier...
http://www.compuphase.com/electronics/debouncing.htm
Mark Thalle schrieb:> So wollte ich es auch machen.> Wenn ich den Code aber im Arduino benutzen möchte, muss ich den> umgefriemelt bekommen. Und dazu muss ich wenigstens grob verstehen, was> die einzelnen Befehle machen.
Arduino-Beispielcodes sind oftmals extrem schlechte Beispielcodes.
Bei dem Debounce-Beispiel aus dem Tutorial finde ich es zum Beispiel
gruselig, dass absolut nichts in die Richtung vorgeschlagen wird, mehr
als einen Button auszuwerten.
Als totalen Anfängercode zum Auswerten und Entprellen mit einem
Arduino-Sketch kann ich Dir das anbieten: Entprellen mit delay für
mehrere gleichzeitig ausgewertete Taster. Einmal pro loop-Umlauf wird am
Ende der loop ein kleines delay von einigen Millisekunden eingefügt,
schon tritt kein Tastenprellen mehr auf.
Ich nenne das mal "Entprellen für Arme":
1
#define INPUTMODE INPUT_PULLUP // INPUT oder INPUT_PULLUP
if(INPUTMODE==INPUT_PULLUP)curState=!curState;// Vertauschte Logik bei INPPUT_PULLUP
17
if(curState!=buttonState[i])// Flankenwechsel am Button festgestellt
18
{
19
Serial.print(millis()/1000.0,3);// Zeitstempel mit Millisekundenauflösung
20
Serial.print("\tChange on Pin-");Serial.print(buttonPins[i]);
21
if(curState==true)Serial.println(" PRESSED");
22
elseSerial.println(" RELEASED");
23
}
24
buttonState[i]=curState;
25
}
26
delay(PRELLZEIT);// ==> Zeitliches Entprellen für Arme (mit delay)
27
}
Diese Art des Entprellens ist extrem leicht durchzuführen, sie ist
allerdings nur für recht "langsame" Programme geeignet. Mit fünf
Millisekunden delay in der loop sorgst Du nämlich dafür, dass die
loop-Funktion nur maximal 200 mal pro Sekunde laufen kann. Das reicht
natürlich dicke aus, um eine Modelleisenbahn zu steuern, oder
irgendwelche Lampen und Motoren manuell ein und aus zu schalten. Es
reicht auch aus, um manuell irgendwelche Einstellwert zu erfassen, um
zum Beispiel eine Uhrzeit oder das Datum auf einem LCD-Display zu
stellen oder Konfigurationsdaten zu bearbeiten und speichern.
In vielen Fällen reicht so eine Lösung deshalb locker aus.
Aber wenn Du extrem schnelle Vorgänge messen oder steuern möchtest, wo
die loop-Funktion viele tausende Male pro Sekunde läuft, ist das
Entprellen durch ein (wenn auch kleines) delay völlig ungeeignet.
Was möchtest Du denn mit den Buttons machen?
Quack schrieb:> Sei versichert, die "Dannegger-Methode" ist ein rein lokales Phaenomaen> dieses Forums. Ausserhalb hat davon noch nie Jemand gehoert und das> Verstaendnis fuer die Huldigung dieses schlecht dokumentierten> Schnipsels Code geht ausserhalb dieses Forums gegen Null.
So ist es.
Das Problem ist leider, dass man hier im Forum einen massiven Glaubens-
krieg beginnt, wenn man diesen Code kritisiert.
Dann bilden sich hier immer zwei Lager und durch die Unterstützung
von einem oder mehreren Moderatoren wird fanatisch jede kritische
Meinung
nieder gemacht.
So hatten wir das schon mehrmals hier im Forum bei diesem Thema.
Zum Thema Code:
Das ist das Resultat der Anforderungen die Herr Dannegger sich bei der
Entwicklung des Codes gestellt hat und die (neutral ausgedrückt)
nicht immer mit den eigenen Anforderungen harmonieren.
Ich bin mir auch ganz sicher, dass der Code anders ausgesehen
hätte, wenn Herr Dannagger andere Anforderungen gehabt hätte.
So bleibt am Schluss: Man muss ihn ja nicht einsetzen, wenn es nicht
passt.
spess53 schrieb:> Hi>>>Die Bezeichnung "PORTA" kommt mir noch aus PIC-Zeiten bekannt vor,>>sodass ich mir sicher war zu wissen, was gemeint ist. Die Suche nach>>diesem Begriff im Arduino-Bereich war leider nicht erfolgreich.>> Dann nimm mal das Datenblatt von dem AVR, der auf deinem Arduino verbaut> ist, zur Hand.
Habe ich gemacht. PORTA gibt es beim 32U4 merkwürdigerweise nicht.
Ich habe jetzt einfach PORTB für die Tasten und PORTD für die LEDs
genommen, nur um zu sehen, ob das Programm dann ohne Fehler kompiliert
werden kann.
Das geht.
Dann kommen weitere Fehler:
error: 'TCCR0' was not declared in this scope
error: 'TIMSK' was not declared in this scope
Im Datenblatt finde ich TCCR0A und TCCR0B
Beim Timer Control Register sollte man wohl schon wissen, welches man
nimmt :-)
Ich vermute, dass hier der Timer konfiguriert wird, damit er mit einer
geeigneten Frequenz ausgelöst wird.
TCCR0 = (1<<CS02)|(1<<CS00); // divide by 1024
Die Bitbezeichnung CS00 und CS02 finde ich im Datenblatt bei TCCR0B.
Wenn ich das im Code ändere, ist die entsprechende Fehlermeldung weg.
Merkwürdigerweise gibt es aber auch keine Fehlermeldung, wenn ich TCCR0A
verwende:
TCCR0A = (1<<CS02)|(1<<CS00); // divide by 1024
Das finde ich merkwürdig, weil in TCCR0A die Bits CS00 und CS02 nicht
vorhanden sind - laut Datenblatt.
Bleibt noch:
error: 'TIMSK' was not declared in this scope
TIMSK |= 1<<TOIE0; // enable timer interrupt
Im Datenblatt finde ich TIMSK0..3.
Da das Bit TOIE0 gesetzt wird, welches zum TIMSK0-Register gehört, würde
ich dieses nehmen.
Andererseits könnte gerade das erste Register für interne Zwecke oder
durch irgendwelche anderen Dinge belegt sein.
Wenn ich TIMSK0 verwende kann ich den Code aber schon mal komplett
fehlerfrei kompilieren.
Jetzt habe ich aber Muffen den Code in den Arduino zu laden, denn wenn
der Mist macht, dann knabbert er mir vielleicht am Bootloader und ich
kann den Arduino nicht mehr ansprechen.
Außerdem weiß ich nicht, an welchem Portpin die integrierte LED hängt.
Das ist bei Arduinos wohl nicht so offensichtlich. So einen hier habe
ich:
https://learn.sparkfun.com/tutorials/pro-micro--fio-v3-hookup-guide/hardware-overview-pro-micro
Mark Thalle schrieb:> Dann kommen weitere Fehler:>> error: 'TCCR0' was not declared in this scope> error: 'TIMSK' was not declared in this scope>> Im Datenblatt finde ich TCCR0A und TCCR0B>> Beim Timer Control Register sollte man wohl schon wissen, welches man> nimmt :-)
Möchtest Du für das Board jetzt eigentlich mit "Arduino-like
Programming" eine Firmware schreiben, mit den Arduino-Komfortfunktionen
aus der Arduino-Core Library und dem Programmgrundgerüst aus "setup()"
und "loop()" Funktion?
Oder möchtest Du das Board komplett auf Registerebene programmieren
einschließlich Timer0, ohne die Arduino Konfortfunktionen und mit einer
Progrmmhauptschleife "main()"?
Ich frage nur mal nach, denn: Sobald Du "setup()" und "loop()" als
Programmgrundgerüst verwendest, wird Timer0 von der Arduino Core-Library
bereits dafür aufgebraucht, um die Komfortfunktionen millis(), micros(),
delay() und delayMicroconds() zur Verfügung zu stellen.
Sobald Du selbst an Timer0 rummachst, hast Du danach diese vier
Funktionen aus dem Arduino Core nicht mehr zur Verfügung, bzw. diese
vier (und etliche andere) funktionieren dann nicht mehr.
Wenn Du mit Timer0 in der Arduino-Software selbst rummachen möchtest,
schreibst Du am besten ein Programm mit einer main() Funktion, ohne
setup() und loop(). Dann ist das Arduino Core-Framework komplett außen
vor.
Oder wenn Du die Arduino Core-Funktionen behalten möchtest, nimmst Du
besser einen anderen Timer zum Rummachen, aber nicht Timer0!
Jürgen S. schrieb:> Mark Thalle schrieb:> Arduino-Beispielcodes sind oftmals extrem schlechte Beispielcodes.>> Bei dem Debounce-Beispiel aus dem Tutorial finde ich es zum Beispiel> gruselig, dass absolut nichts in die Richtung vorgeschlagen wird, mehr> als einen Button auszuwerten.
Ich habe bisher auch nur Lösungen für jeweils eine Taste gefunden. Eine
Auswertung für langen Tastendruck oder Doppel-Klick, habe ich auch noch
nicht gesehen.
So etwas habe ich schon mal mit Siemens Logo gebastelt. Das würde ich
wahrscheinlich auch mit dem Arduino hinbekommen.
> Als totalen Anfängercode zum Auswerten und Entprellen mit einem> Arduino-Sketch kann ich Dir das anbieten: Entprellen mit delay für> mehrere gleichzeitig ausgewertete Taster. Einmal pro loop-Umlauf wird am> Ende der loop ein kleines delay von einigen Millisekunden eingefügt,> schon tritt kein Tastenprellen mehr auf.>> Ich nenne das mal "Entprellen für Arme":
:-) Wenn's funktioniert, hätte ich Spaß dran.
Erstmal Danke für den Code.
> Diese Art des Entprellens ist extrem leicht durchzuführen, sie ist> allerdings nur für recht "langsame" Programme geeignet. Mit fünf> Millisekunden delay in der loop sorgst Du nämlich dafür, dass die> loop-Funktion nur maximal 200 mal pro Sekunde laufen kann.
Ich wüsste jetzt nicht, wie ich es umsetzen könnte, aber rein
theoretisch könnte man doch in der Delay-Zeit etwas anderes machen.
Und man könnte auch einen Zähler hochlaufen lassen, der dafür sorgt,
dass nur bei jedem 10. Durchlauf der Tastenzustand überprüft wird. Dann
hätte man nur noch 0,5ms Delay und das restliche Programm würde 10 mal
schneller laufen.
Je nach Anforderungen könnte man das dann ausreizen.
> Was möchtest Du denn mit den Buttons machen?
Ich möchte mit meinem ersten Projekt tatsächlich nur ein paar Relais und
damit Raumbeleuchtung schalten. Das muss also nicht schnell sein.
Prellen sollte es aber auf keinen Fall.
Ich würde aber gerne Doppelklicks und lange Betätigung einer Taste
auswerten.
Das stelle ich mir im Moment so vor:
Pro Taste läuft ein Zähler hoch, solange die Taste ununterbrochen
gedrückt ist.
Wird ein bestimmter Wert erreicht, wird das als "langer Tastendruck"
ausgewertet und ein entsprechendes Bit gesetzt.
Beim Loslassen einer Taste läuft ebenfalls ein Zähler hoch. Wenn
innerhalb einer gewissen Zeit die Taste wieder gedrückt wird, wird das
als Doppel-Klick gewertet.
Ich habe allerdings noch kein Gefühl dafür, wie viele Ressourcen so
etwas verbraucht und ob ich mit der Vorgehensweise auch viel mehr Tasten
auswerten kann. Das wäre nämlich mein Ziel für spätere Projekte.
Bei der Siemens Logo ist man auf relativ wenige Funktionsbausteine
begrenzt. Da bin ich schon bei sehr wenigen Tastenauswertungen mit
Doppelklicks an die Grenzen gestoßen.
Außerdem möchte ich die Ausgänge vor zu häufigem Schalten schützen.
Kurz an und direkt wieder aus, soll beliebig schnell funktionieren. Nach
dem Ausschalten sollen die Ausgänge aber erst nach einer geeigneten
Verzögerung wieder eingeschaltet werden können.
Das ist es, was ich mir bisher so vorgenommen habe.
Mark Thalle schrieb:> :-) Wenn's funktioniert, hätte ich Spaß dran.
Spiel ruhig erst mal mit Jürgens Code, dann merkst du die Schwachstellen
und kannst versuchen den Code zu verbessern. Wenn du davon die Schnauze
voll hast, wendest du dich einfach wieder PeDas Code zu.
Kleiner Merkspruch: delay() löst keine Probleme, es verzögert sie nur!
Konrad S. schrieb:> Mark Thalle schrieb:>> Beim Timer Control Register sollte man wohl schon wissen, welches man>> nimmt :-)>> Konrad S. schrieb:>> Ah, hier: http://www.gammon.com.au/forum/?id=11488>>>> "One of the internal timers (timer 0) is set up to interrupt roughly>> 1000 times a second, and increment an internal counter which effectively>> becomes the millis() counter.">> Wenn du das Arduino-System nicht stören willst, dann lass die Finger vom> Timer 0.
Ich meine, dass ich so etwas in der Art schon mit einem halben Auge
gelesen hatte.
Kann ich an der Stelle dann einfach Timer 1..3 nehmen?
>>> Außerdem weiß ich nicht, an welchem Portpin die integrierte LED hängt.>> Hier> https://learn.sparkfun.com/tutorials/pro-micro--fi...> gibt es einen Link "Fio v3 Schematic" mit dem Schaltplan. Da steht alles> drin.
Danke. Das werde ich mir nachher rauskramen.
Ihr haut mir hier die Antworten schneller um die Ohren, als ich
reagieren kann :-)
Auch dafür vielen Dank.
Ich würde jetzt gerne direkt weiter lesen und Sachen umsetzen, aber
jetzt muss ich mich erst um meine Racker kümmern.
Meine Abwesenheit liegt nicht an Desinteresse.
Karl Heinz schrieb:> Quack schrieb:>> Mark Thalle schrieb:>>> Das finde ich merkwürdig, denn die Dannegger-Methode scheint ziemlich>>> anerkannt und effizient zu sein.>>>> Sei versichert, die "Dannegger-Methode" ist ein rein lokales Phaenomaen>> dieses Forums. Ausserhalb hat davon noch nie Jemand gehoert>> sagen wir mal: zu wenige> und sagen wir mal: leider>> Denn das Ding ist ein echter 'fire and forget' Code. Die paar Zeilen in> die ISR einbauen (die man sowieso als Heartbeat hat) und im Handumdrehen> hat man eine zuverlässige Entprellung für 8 Tasten, die alle Stückeln> spielt, die man braucht.
richtig, die Routine ist jetzt nicht das was ein fähiger Programmierer
auch selbst hinbekommen würde und eine ganz besonders hohen Intellekt
bedarf es auch nicht soetwas zu schreiben. Ich denke Peter ist zwar
stolz auf die Beliebtheit seiner Routine, aber ich denke nicht das er
der Ansicht ist das wäre jetzt DIE geniale Erfindung. Er hats einfach
gebraucht und für alle Anderen zur Verfügung gestellt. So läuft das
richtig. Immerhin hat sie es ja sogar auch als Tasten-Manager-Bibliothek
in Luna geschafft (in Assembler implementiert) und erfreut sich auch da
hoher Beliebtheit.
Jürgen S. schrieb:> um die Komfortfunktionen millis(), micros(),> delay() und delayMicroconds() zur Verfügung zu stellen.
Wenn diese sich in den Timerinterrupt einklinken, dann muß man natürlich
nicht noch einen Timerinterrupt programmieren.
Der Code muß nur etwa alle 10ms ausgeführt werden. Wer das macht, ist
völlig egal.
Mark Thalle schrieb:> Ich habe bisher auch nur Lösungen für jeweils eine Taste gefunden.
Wie ich schon schrieb: Viele Arduino-Beispielcodes sind schlecht gemacht
und orientieren sich nicht an der Praxis.
> Ich wüsste jetzt nicht, wie ich es umsetzen könnte, aber rein> theoretisch könnte man doch in der Delay-Zeit etwas anderes machen.> Und man könnte auch einen Zähler hochlaufen lassen, der dafür sorgt,> dass nur bei jedem 10. Durchlauf der Tastenzustand überprüft wird. Dann> hätte man nur noch 0,5ms Delay und das restliche Programm würde 10 mal> schneller laufen.> Je nach Anforderungen könnte man das dann ausreizen.
Das hast Du vom Prinzip er schon richtig erkannt: In der Zeit, in der
mit delay() die Programmausführung blockiert wird, könnte das Programm
auch viele, viele andere Dinge erledigen. Ein schnell agierendes
Programm muß immer und grundsätzlich auf die Blockierung der
Programmausführung mit delay() verzichten.
In der Praxis kann dazu der Stand des millis()-Zählers verwendet werden:
Du merkst Dir einfach über den Stand des millis()-Zählers, wann die
Taster zuletzt abgefragt wurden. Und dann läßt Du alle Funktionen im
Sketch ablaufen, aber die Taster-Abfrage ist in der loop erst wieder
dran, wenn der millis-Zähler um die Prellzeit weitergezählt hat. So
laufen dann beispielsweise alle Funktionen in der loop() zigtausendmal
pro Sekunde, aber die Taster-Abfrage läuft nur 200 mal pro Sekunde.
Um meinen oben geposteten Code entsprechend anzupassen, wären nur
relativ geringe Änderungen notwendig.
>> Was möchtest Du denn mit den Buttons machen?>> Ich möchte mit meinem ersten Projekt tatsächlich nur ein paar Relais und> damit Raumbeleuchtung schalten. Das muss also nicht schnell sein.> Prellen sollte es aber auf keinen Fall.>> Ich würde aber gerne Doppelklicks und lange Betätigung einer Taste> auswerten.>> Das stelle ich mir im Moment so vor:>> Pro Taste läuft ein Zähler hoch, solange die Taste ununterbrochen> gedrückt ist.> Wird ein bestimmter Wert erreicht, wird das als "langer Tastendruck"> ausgewertet und ein entsprechendes Bit gesetzt.>> Beim Loslassen einer Taste läuft ebenfalls ein Zähler hoch. Wenn> innerhalb einer gewissen Zeit die Taste wieder gedrückt wird, wird das> als Doppel-Klick gewertet.
Hm, das finde ich ungünstig. Den Doppelklick würdest Du erkennen, wenn
der Taster zweimal gedrückt wird. Einen langen Klick würdest Du
erkennen, wenn ein gedrückter Taster nach langer Zeit losgelassen wird.
Das ist ein bisschen überkreuz, denn so kann aus einem Doppelklick ja
auch noch ein anschließender langer Klick werden:
- drücken - loslassen - drücken (Doppelklick komplett) - lange halten -
loslassen
Dann wird am Schluß nach dem Doppelklick noch ein langer Tastendruck
erkannt.
Im Endeffekt kannst Du natürlich jede Programmlogik programmieren, aber
wenn die Logik darauf basiert Low-High Flankenwechsel auszuwerten
(Taster drücken) und auch High-Low Flankenwechsel (Taster loslassen),
dann schleppst Du schon ein paar Statusvariablen durch die Programmlogik
mit durch.
Wesentlich einfacher wäre es zum Beispiel, folgende Logiken zu
implementieren:
1. kurz drücken (<1s), lang drücken (1-2s), superlange drücken (>3s)
oder
2. zählen beim Drücken: x-mal drücken mit nachfolgendem Timeout
Mit 2. könntest Du über einen einzigen Taster locker 10 Funktionen
realisieren, indem Du immer schnell x-mal hintereinander drückst und
dann den Timeout (z.B. 1s) wartest, und 1s nach dem letzten Zählimpuls
wird die Aktion ausgeführt, die x-mal drücken entspricht.
> Ich habe allerdings noch kein Gefühl dafür, wie viele Ressourcen so> etwas verbraucht und ob ich mit der Vorgehensweise auch viel mehr Tasten> auswerten kann. Das wäre nämlich mein Ziel für spätere Projekte.
"Ganz viele Tasten" wirst Du vermutlich nicht mehr an einzelnen
digitalen Inputs auswerten wollen, weil Dir die digitalen Pins sonst
ausgehen. Zum Beispiel kann man mit einer Hilfsbeschaltung aus einigen
Widerständen auch sechs Buttons an einem einzigen Analogeingang
auswerten. Oder eine Tastaturmatrix aus 3*4 = 12 Tasten mit 7 digitalen
Eingängen. Oder, oder, oder.
> Außerdem möchte ich die Ausgänge vor zu häufigem Schalten schützen.> Kurz an und direkt wieder aus, soll beliebig schnell funktionieren. Nach> dem Ausschalten sollen die Ausgänge aber erst nach einer geeigneten> Verzögerung wieder eingeschaltet werden können.
Das wäre dann Sache Deiner Programmlogik. Viele Arduino-Anfänger
scheitern an einer sauberen Programmlogik, weil sie keinerlei
Vorstellung von einer sauber durchführbaren Programmlogik haben.
Zum Beispiel sehe ich immer wieder solche Anfängerprogramme mit einer
Logik, die in Pseudocode irgendwie so aussieht:
1
voidloop()
2
{
3
WennTaste-1gedrueckt==>danntuedies
4
WennTaste-2gedrueckt==>danntuedas
5
WennTaste-3gedrueckt==>danntuejenes
6
}
Das funktioniert genau so lange wie die Tasten und die damit gestuerten
Funktionen absolut nichts miteinander zu tun haben. In der Praxis also
eigentlich nie.
Deshalb müßtest Du darauf achten, eine saubere Programmlogik zu bauen,
und eine sehr einfache Methode dazu ist das "EVA-Prinzip". Du mußt nur
das Programm in drei logische Funktionsbereiche "Eingabe",
"Verarbeitung" und "Ausgabe" aufteilen. Grundschema der Arduino-loop:
1
voidloop()
2
{
3
eingabe();
4
verarbeitung();
5
ausgabe();
6
}
Das bedeutet: In der Funktion "eingabe()" fragst Du nicht einen
einzelnen Taster ab, um ihn zu verarbeiten, sondern Du fragst ALLE
Buttons ab und speicherst den Schaltzustand in Variablen.
Im nachfolgenden Schritt "verarbeitung()" führst Du dann Deine logischen
Operationen zunächst mal virtuell an Zustandsvariablen durch, aber ohne
tatsächlich irgendwelche Ausgänge zu schalten. Dabei kannst Du die
virtuellen Zustandsvariablen auch aufgrund unterschiedlicher Bedingungen
mehrfach ändern, wenn nötig.
Und erst im letzten Schritt, werden die ermittelten Zustände dann an den
Ausgängen oder auf einem Display, auf Serial oder wie auch immer gesetzt
oder angezeigt.
Diese mangelnde Trennung in der loop:
- alle Eingangswerte lesen
- alle Eingangswerte verarbeiten und in Zustände umwandeln
- alle ermittelten Zustände ausgeben
erzeugt bei Anfängern meistens den Knoten im Gehirn für die passende
Programmlogik.
Denn Anfänger denken oft nach dem Schema
- wenn der eine Button so steht, dann mache an den Augängen dies
- wenn der zweite Button so steht, dann mache an den Augängen das
- wenn der dritte Button so steht, dann mache an den Augängen jenes
Und so ist dann keine einwandfreie Programmlogik mehr möglich, wenn
Abhängigkeiten untereinander bestehen.
Konrad S. schrieb:> Mark Thalle schrieb:>> :-) Wenn's funktioniert, hätte ich Spaß dran.>> Spiel ruhig erst mal mit Jürgens Code, dann merkst du die Schwachstellen> und kannst versuchen den Code zu verbessern. Wenn du davon die Schnauze> voll hast, wendest du dich einfach wieder PeDas Code zu.>> Kleiner Merkspruch: delay() löst keine Probleme, es verzögert sie nur!
Warum sollte er von einem kleinen Demo-Code "die Schnauze voll" haben?
Der Code ist zum Ausprobieren für einen Anfänger mit geringen Ansprüchen
an die Ablaufgeschwindigkeit.
Und der Code ist bei weitem nicht ausgereizt und läßt sich für höhere
Ansprüche auch leicht modifizieren.
Okay, hier dann noch einmal eine leicht modifizierte Version des oben
geposteten Codes, ohne delay() zu verwenden und mit einer kleinen
Benchmark-Zeitmessung, die nebenbei läuft:
1
#define INPUTMODE INPUT_PULLUP // INPUT oder INPUT_PULLUP
Der durchschnittliche Zeitbedarf für ein Durchlaufen der loop-Funktion
ändert sich auf einem mit 16 MHz getakteten Controller durch die
Vermeidung des delay() von über 5ms = 5000µs auf durchschnittlich
weniger als 10µs mit dem modifizierten Code.
Jürgen S. schrieb:> Mit fünf> Millisekunden delay in der loop sorgst Du nämlich dafür, dass die> loop-Funktion nur maximal 200 mal pro Sekunde laufen kann.
Einfach keinen delay() nehmen, sondern die Entprellroutine zeitgesteuert
aufrufen. Eine Zeitbasis ist mit millis() ja vorhanden. So kann man
recht trivial verschiedene Tasks zeitgesteuert in loop() abhandeln -
quasi kooperatives Multitasking. :-)
if( millis() - lastCallMillis > DELAY) ...
> Deshalb müßtest Du darauf achten, eine saubere Programmlogik zu> bauen, und eine sehr einfache Methode dazu ist das "EVA-Prinzip".
Was auch eine gute Basis für nächsten Schritt ist, dem
Zustandsautomaten.
Jürgen S. schrieb:> Mark Thalle schrieb:> In der Praxis kann dazu der Stand des millis()-Zählers verwendet werden:> Du merkst Dir einfach über den Stand des millis()-Zählers, wann die> Taster zuletzt abgefragt wurden. Und dann läßt Du alle Funktionen im> Sketch ablaufen, aber die Taster-Abfrage ist in der loop erst wieder> dran, wenn der millis-Zähler um die Prellzeit weitergezählt hat. So> laufen dann beispielsweise alle Funktionen in der loop() zigtausendmal> pro Sekunde, aber die Taster-Abfrage läuft nur 200 mal pro Sekunde.
Einen Sketch, der darauf beruht, meine ich gestern gesehen und
grundsätzlich verstanden zu haben.
>> Ich würde aber gerne Doppelklicks und lange Betätigung einer Taste>> auswerten.>>>> Das stelle ich mir im Moment so vor:>>>> Pro Taste läuft ein Zähler hoch, solange die Taste ununterbrochen>> gedrückt ist.>> Wird ein bestimmter Wert erreicht, wird das als "langer Tastendruck">> ausgewertet und ein entsprechendes Bit gesetzt.>>>> Beim Loslassen einer Taste läuft ebenfalls ein Zähler hoch. Wenn>> innerhalb einer gewissen Zeit die Taste wieder gedrückt wird, wird das>> als Doppel-Klick gewertet.>> Hm, das finde ich ungünstig. Den Doppelklick würdest Du erkennen, wenn> der Taster zweimal gedrückt wird. Einen langen Klick würdest Du> erkennen, wenn ein gedrückter Taster nach langer Zeit losgelassen wird.> Das ist ein bisschen überkreuz, denn so kann aus einem Doppelklick ja> auch noch ein anschließender langer Klick werden:> - drücken - loslassen - drücken (Doppelklick komplett) - lange halten -> loslassen> Dann wird am Schluß nach dem Doppelklick noch ein langer Tastendruck> erkannt.>> Im Endeffekt kannst Du natürlich jede Programmlogik programmieren, aber> wenn die Logik darauf basiert Low-High Flankenwechsel auszuwerten> (Taster drücken) und auch High-Low Flankenwechsel (Taster loslassen),> dann schleppst Du schon ein paar Statusvariablen durch die Programmlogik> mit durch.
Bis ins letzte Detail habe ich mir das noch nicht überlegt, aber wenn
ich so drüber nachdenke, dann müssen doch immer die fallenden Flanken
ausgewertet werden, weil sonst weder ein Doppelklick, noch ein langer
Tastendruck erkannt werden kann, ohne dass vorher die Aktion für
einfaches kurzes Klicken ausgewertet wird.
> Wesentlich einfacher wäre es zum Beispiel, folgende Logiken zu> implementieren:> 1. kurz drücken (<1s), lang drücken (1-2s), superlange drücken (>3s)> oder> 2. zählen beim Drücken: x-mal drücken mit nachfolgendem Timeout>> Mit 2. könntest Du über einen einzigen Taster locker 10 Funktionen> realisieren, indem Du immer schnell x-mal hintereinander drückst und> dann den Timeout (z.B. 1s) wartest, und 1s nach dem letzten Zählimpuls> wird die Aktion ausgeführt, die x-mal drücken entspricht.
Ja genau. So etwas hatte ich für die Rollladenbedienung schon geplant,
wobei ich mich auf maximal 3 oder 4 Funktionen beschränken wollte, weil
es sonst nicht besonders bedienerfreundlich ist.
>> Ich habe allerdings noch kein Gefühl dafür, wie viele Ressourcen so>> etwas verbraucht und ob ich mit der Vorgehensweise auch viel mehr Tasten>> auswerten kann. Das wäre nämlich mein Ziel für spätere Projekte.>> "Ganz viele Tasten" wirst Du vermutlich nicht mehr an einzelnen> digitalen Inputs auswerten wollen, weil Dir die digitalen Pins sonst> ausgehen. Zum Beispiel kann man mit einer Hilfsbeschaltung aus einigen> Widerständen auch sechs Buttons an einem einzigen Analogeingang> auswerten. Oder eine Tastaturmatrix aus 3*4 = 12 Tasten mit 7 digitalen> Eingängen. Oder, oder, oder.
Solche "Spielereien" habe ich in den 90ern theoretisch nachvollzogen.
Damals habe ich auch schon mal ein paar zaghafte Anläufe genommen und
wollte was mit PICs für den Modellbau machen. Das war aber immer sehr
aufwendig und zeitraubend. Es musste immer ein EPROM gebrannt und
gelöscht werden, passende Quarze angebracht werden, der uC musste immer
umgesteckt werden, der Programmer an der seriellen Schnittstelle war
bräsig in der Handhabung und lief nur unter DOS, und in ASM habe ich
immer sehr schnell den Wald vor lauter Bäumen nicht mehr gesehen.
Die Arduinos scheinen ideal für mich zu sein. Da bekomme ich ein
fertiges Modul, welches ich nur noch an USB anschließen muss und schon
loslegen kann.
Mehrere Taster an einem Eingang möchte ich aber möglichst vermeiden.
Das dürfte bei langen Leitungen störanfällig werden. Es ist
wahrscheinlich besser, einen Arduino mit entsprechend vielen Ports zu
nehmen. Ein Arduino Mega hat 54 digitale IO-Pins. Das reicht für mich
locker.
>>> Außerdem möchte ich die Ausgänge vor zu häufigem Schalten schützen.>> Kurz an und direkt wieder aus, soll beliebig schnell funktionieren. Nach>> dem Ausschalten sollen die Ausgänge aber erst nach einer geeigneten>> Verzögerung wieder eingeschaltet werden können.>> Das wäre dann Sache Deiner Programmlogik. Viele Arduino-Anfänger> scheitern an einer sauberen Programmlogik, weil sie keinerlei> Vorstellung von einer sauber durchführbaren Programmlogik haben.
Da verhaspel ich mich auch immer wieder.
> Deshalb müßtest Du darauf achten, eine saubere Programmlogik zu bauen,> und eine sehr einfache Methode dazu ist das "EVA-Prinzip". Du mußt nur> das Programm in drei logische Funktionsbereiche "Eingabe",> "Verarbeitung" und "Ausgabe" aufteilen. Grundschema der Arduino-loop:>
1
>voidloop()
2
>{
3
>eingabe();
4
>verarbeitung();
5
>ausgabe();
6
>}
7
>
Eine ordentliche Struktur ist die halbe Miete. Ich verrenne mich aber
auch immer wieder.
> Und erst im letzten Schritt, werden die ermittelten Zustände dann an den> Ausgängen oder auf einem Display, auf Serial oder wie auch immer gesetzt> oder angezeigt.
So kenne ich es auch von Siemens S7-200. Bei der SPS kann man zwar auch
im Programm jederzeit einen Ausgang setzen, aber es wird letztlich nur
der Zustand am Hardwareausgang eingestellt, der am Ende der
Programmschleife im Prozessabbild gespeichert wurde.
> Diese mangelnde Trennung in der loop:> - alle Eingangswerte lesen> - alle Eingangswerte verarbeiten und in Zustände umwandeln> - alle ermittelten Zustände ausgeben> erzeugt bei Anfängern meistens den Knoten im Gehirn für die passende> Programmlogik.
Jupp, ich weiß, wovon du redest :)
Jürgen S. schrieb:> Mark Thalle schrieb:>> Dann kommen weitere Fehler:>>>> error: 'TCCR0' was not declared in this scope>> error: 'TIMSK' was not declared in this scope>>>> Im Datenblatt finde ich TCCR0A und TCCR0B>>>> Beim Timer Control Register sollte man wohl schon wissen, welches man>> nimmt :-)>> Möchtest Du für das Board jetzt eigentlich mit "Arduino-like> Programming" eine Firmware schreiben, mit den Arduino-Komfortfunktionen> aus der Arduino-Core Library und dem Programmgrundgerüst aus "setup()"> und "loop()" Funktion?>> Oder möchtest Du das Board komplett auf Registerebene programmieren> einschließlich Timer0, ohne die Arduino Konfortfunktionen und mit einer> Progrmmhauptschleife "main()"?
Ich möchte zumindest für den Anfang erst mal in der Arduino-Umgebung
bleiben.
Ob und wenn ja, wie man einen Arduino mit main() programmiert, weiß ich
nicht. Damit möchte ich mich jetzt auch nicht unbedingt aufhalten.
Ich möchte besonders nicht Arduino Bootloader schrotten, denn dann komme
ich nicht mehr an das Teil heran.
Könnte man denn den C-Code problemlos mit Arduino-Code kombinieren, wenn
man die Finger vom Timer0 lässt?
Mark Thalle schrieb:> Könnte man denn den C-Code problemlos mit Arduino-Code kombinieren, wenn> man die Finger vom Timer0 lässt?
Das ist C, bzw C++ und nicht Arduino Magic neue Sprache...
Mark Thalle schrieb:> Ich möchte zumindest für den Anfang erst mal in der Arduino-Umgebung> bleiben.> Ob und wenn ja, wie man einen Arduino mit main() programmiert, weiß ich> nicht. Damit möchte ich mich jetzt auch nicht unbedingt aufhalten.> Ich möchte besonders nicht Arduino Bootloader schrotten, denn dann komme> ich nicht mehr an das Teil heran.>
Was hast Du für ein Board? Mit 32U4 müßte es ein Leonardo oder Micro
sein?
Wenn Du nur ein USB-Kabel hast, um ein 32U4 Board per Bootloader mit
einem Sketch zu versehen, bist Du ständig in höchster Gefahr, Dein Board
zu bricken.
Wenn Du nur mit USB-Kabel und Bootloader arbeiten möchtest, holst Du Dir
besser ein UNO oder MEGA oder NANO Board oder so etwas.
Beim 32U4 läuft nämlich die gesamte serielle Kommunikation per USB über
den 32U4 und keinen gesonderten Chip, und wenn Du einen Arduino-Sketch
hochlädst, der die USB-Schnittstelle außer Gefecht setzt, bekommst Du
über USB-Kabel keinen Sketch mehr hochgeladen.
Und das geht auch mit Arduino Funktionen ganz leicht. Und danach
bekommst Du nur noch mit einem ISP-Programmer einen neuen Sketch
hochgeladen.
Andere Boards haben einen zweiten Chip für die serielle Kommunikation
on-board, so dass die serielle Kommunikation immer erhalten bleibt, egal
was Du auf den Hauptcontroller als Sketch draufgeladen hast. Die 32U4
Boards haben das NICHT.
Also zum Herumspielen mit den 32U4 Boards gehört meines Erachtens auch
immer ein ISP-Programmer zur Grundausstattung. Auch bei Verwendung der
Arduino-Software. Sonst kann der Spaß mit dem Board beim kleinsten
Gedankenfehler vorbei sein und Du bekommst keinen neuen Sketch mehr
drauf.
Wenn Du keinen ISP-Programmer hast: Greife lieber zum UNO, MEGA oder
NANO für erste Anfänger-Experimente!
Ein Board mit 32U4 Controller brauchst Du eigentlich erst dann, wenn Du
das Board als HID-Device programmieren und an Deinen PC als entweder
"Tastatur" oder "Maus" anschließen möchtest, um von Deinem Arduino aus
den PC zu steuern, wie mit einer angeschlossenen Tastatur oder Maus.
Ansonsten hat der 32U4 keinen Vorteil und Du riskierst, das Board zu
bricken und dann bekommst Du nur mit einem ISP Programmer wieder einen
anderen Sketch drauf geladen.
> Könnte man denn den C-Code problemlos mit Arduino-Code kombinieren, wenn> man die Finger vom Timer0 lässt?
Ja, Du kannst jederzeit auf Registerebene programmieren, wenn es Dir
Spaß macht. Du kannst auch jederzeit Arduino-Komfortbefehle und
Programmierung auf Registerebene abwechselnd verwenden. Du kannst sogar
der Arduino-Software im laufenden Betrieb den Timer0 entziehen und in
zweckentfremden, aber dann laufen Befehle wie millis(), delay(),
micros() und delayMicroseconds() nicht mehr.
Aber wie gesagt: Wenn Du ein Board mit 32U4 Controller programmierst,
hast Du besser einen ISP-Programmer in der Hinterhand, um auf ein durch
einen fehlerhaften Sketch gebricktes Board wieder einen neuen Sketch
laden zu können.
Jürgen S. schrieb:> Mark Thalle schrieb:>> Ich möchte zumindest für den Anfang erst mal in der Arduino-Umgebung>> bleiben.>> Ob und wenn ja, wie man einen Arduino mit main() programmiert, weiß ich>> nicht. Damit möchte ich mich jetzt auch nicht unbedingt aufhalten.>> Ich möchte besonders nicht Arduino Bootloader schrotten, denn dann komme>> ich nicht mehr an das Teil heran.>>>> Was hast Du für ein Board? Mit 32U4 müßte es ein Leonardo oder Micro> sein?
Dieser hier ist es:
https://learn.sparkfun.com/tutorials/pro-micro--fio-v3-hookup-guide/hardware-overview-pro-micro
Es schimpft sich "Pro Micro". Wenn ich in der IDE den Leonardo
einstelle, dann kann ich damit auch Programme hochladen. Ich habe mir
aber von Sparkfun das passende Addon besorgt, sodass ich ihn als Pro
Micro ansprechen kann.
> Wenn Du keinen ISP-Programmer hast: Greife lieber zum UNO, MEGA oder> NANO für erste Anfänger-Experimente!
Hm, ich hatte mir die Liste der Arduinos bei Wikipedia angesehen und mir
aus der Tabelle den "Micro" ausgeguckt. In der Bucht habe ich dann den
Pro Micro für kleines Geld gesehen und zugegriffen und dachte, dass es
sogar ein Vorteil wäre, wenn ich keinen Reset-Button zum Programmieren
drücken muss.
Gut, dass du mich vor dem Bricken gewarnt hast.
Ein ISP müsste doch auch über einen Arduino realisiert werden können.
Ein ISP dürfte dann doch nicht teurer als ein kleiner Arduino sein.
>> Könnte man denn den C-Code problemlos mit Arduino-Code kombinieren, wenn>> man die Finger vom Timer0 lässt?>> Ja, Du kannst jederzeit auf Registerebene programmieren, wenn es Dir> Spaß macht. Du kannst auch jederzeit Arduino-Komfortbefehle und> Programmierung auf Registerebene abwechselnd verwenden. Du kannst sogar> der Arduino-Software im laufenden Betrieb den Timer0 entziehen und in> zweckentfremden, aber dann laufen Befehle wie millis(), delay(),> micros() und delayMicroseconds() nicht mehr.
Das hört sich komfortabel an.
> Aber wie gesagt: Wenn Du ein Board mit 32U4 Controller programmierst,> hast Du besser einen ISP-Programmer in der Hinterhand, um auf ein durch> einen fehlerhaften Sketch gebricktes Board wieder einen neuen Sketch> laden zu können.
Ich stehe nun vor der Wahl, mir einen anderen Arduino oder einen ISP zu
besorgen. Ein ISP für Arduinos ist bestimmt kein Hexenwerk und deswegen
denke ich, dass es so etwas auch für kleines Geld geben kann.
Kannst du mir einen ISP empfehlen?
Jürgen S. schrieb:> Konrad S. schrieb:> Okay, hier dann noch einmal eine leicht modifizierte Version des oben> geposteten Codes, ohne delay() zu verwenden und mit einer kleinen> Benchmark-Zeitmessung, die nebenbei läuft:
Ich habe das mal in meinen Arduino geladen und setze und lösche damit
die LED an PIN17.
Dann wollte ich das Programm auch verstehen, aber es hakt gleich am
Anfang.
In loop() deklarierst du 3 Variablen mit static.
Ich habe zu static nur wenig ergoogeln können, was mich weiter bringt.
Wenn ich das richtig verstehe, werden die Variablen nur ein einziges Mal
initialisiert und behalten dann immer ihre Speicheradresse und den
zuletzt zugewiesenen Wert.
Zuerst habe ich mich gefragt, was dieser Aufruf dann in der Schleife zu
suchen hat, wenn man ihn nur einmal machen muss. Das liegt vielleicht
daran, dass man ansonsten die Zugehörigkeit der Variable zur Funktion
nicht hinbekommt.
Dann habe ich mich gefragt, mit welchen Werten die Variablen
initialisiert werden. Ist das definiert, oder kann das ein zufälliger
Wert sein?
Wenn letzteres, dann könnte z.B. lastRunTime einen sehr großen Wert bei
der Initialisierung erhalten.
Damit würde bei der nächsten if-Abfrage erst nach sehr langer Zeit die
Tastenabfrage gestartet und lastRunTime neu gesetzt werden - wenn ich
das richtig verstehe.
>
1
>#defineINPUTMODEINPUT_PULLUP// INPUT oder INPUT_PULLUP
nhvjzrrrft5r schrieb:> Quack schrieb:>> Sei versichert, die "Dannegger-Methode" ist ein rein lokales Phaenomaen>> dieses Forums. Ausserhalb hat davon noch nie Jemand gehoert und das>> Verstaendnis fuer die Huldigung dieses schlecht dokumentierten>> Schnipsels Code geht ausserhalb dieses Forums gegen Null.>>> So ist es.
... sagt der Priester zum Pfaffen.
> Das Problem ist leider, dass man hier im Forum einen massiven Glaubens-> krieg beginnt, wenn man diesen Code kritisiert.
Kritisieren!? - Wenn es denn mal so wäre.
Üblicherweise läuft es so ab, dass der Code nicht verstanden wurde, der
Jenige ihn deswegen doof und sonst noch was findet, um sodann mit
irgendwelchem Gebastel daher zu kommen, was er als das Non-Plus-Ultra
ansieht.
Dann kommen die dazu, die einfach nur GLAUBEN, dass der Dannegger-Code
Scheiße ist, und diese(!) beginnen - von daher hat du (jedoch anders als
beabsichtigt) Recht - ihren GLAUBENskrieg gegen jedwede vernünftigen
Argumente.
> Das ist das Resultat der Anforderungen die Herr Dannegger sich bei der> Entwicklung des Codes gestellt hat und die (neutral ausgedrückt)> nicht immer mit den eigenen Anforderungen harmonieren.
Mag sein. Aber Peter Dannegger hat sich die Anforderungen nicht einfach
vom Baum geschüttelt, sondern diese basieren augenscheinlich auf
praxisorientierten Überlegungen und logischer Herangehensweise, und
werden auch entsprechend begründet.
> Ich bin mir auch ganz sicher, dass der Code anders ausgesehen> hätte, wenn Herr Dannagger andere Anforderungen gehabt hätte.
Hätte hätte Fahrradkette. - Als ob man "irgendwie zusammengeschustert"
eine Anforderung nennen könnte.
> So bleibt am Schluss: Man muss ihn ja nicht einsetzen, wenn es nicht> passt.
Stimmt! Wem der Code auf Grund von was auch immer nicht "gefällt", der
soll halt die Finger davon lassen.
Mark Thalle schrieb:> In loop() deklarierst du 3 Variablen mit static.> Ich habe zu static nur wenig ergoogeln können, was mich weiter bringt.> Wenn ich das richtig verstehe, werden die Variablen nur ein einziges Mal> initialisiert und behalten dann immer ihre Speicheradresse und den> zuletzt zugewiesenen Wert.
Ja, die "static" Variablen behalten zwischen den Funktionsaufrufen ihren
Wert. Man könnte stattdessen auch globale Variablen außerhalb der
Funktion deklarieren.
Aber innerhalb der Funktion deklariert, haben diese Variablen ihren
Gültigkeitsbereich auch nur innerhalb der Funktion.
> Zuerst habe ich mich gefragt, was dieser Aufruf dann in der Schleife zu> suchen hat, wenn man ihn nur einmal machen muss. Das liegt vielleicht> daran, dass man ansonsten die Zugehörigkeit der Variable zur Funktion> nicht hinbekommt.
Die loop-Funktion heißt nur loop (Schleife), aber diese Funktion läuft
immer von Anfang bis Ende durch. Es ist tatsächlich die (unsichtbare)
main()-Funktion der Arduino-Software, die loop() immer wieder aufruft.
Und damit bestimmte Variablen zwischen den Funktionsaufrufen ihre Werte
beibehalten, sind sie innerhalb der Funktion "static" deklariert.
> Dann habe ich mich gefragt, mit welchen Werten die Variablen> initialisiert werden. Ist das definiert, oder kann das ein zufälliger> Wert sein?
Die werden mit null initialisiert. Im Endeffekt wie auch globale
Variablen.
F. Fo schrieb:> Wenn ich das richtig verstanden habe, dann will der TO doch mit Arduino> arbeiten.> Die einfachste Methode, wenn nichts zeitkritisches ansteht:>>
1
>
2
> buttonState = digitalRead(button);
3
> delay(10);
4
> if (button == HIGH) {
5
> digitalWrite(led, HIGH);
6
> ...
7
> }
8
>
9
>
>> Das schlägt Massimo Banzi übrigens in seinem Buch vor und funktioniert.
Bei dem von Dir vorher geposteten Debounce-Beispiel hatte der TO das
Problem, dass er damit nicht MEHRERE BUTTONS gleichzeitig auswerten
konnte. Genau das möchte er aber.
Und bei dem von Dir zuletzt geposteten Minimalbeispiel einer
Buttonabfrage wird nicht einmal mehr ein Flankenwechsel als "Click"
erkannt, sondern nur noch der aktuelle HIGH oder LOW Status.
Falls Du den Thread nicht weiter mitverfolgt hast, der TO möchte:
- MEHRERE BUTTONS ABFRAGEN
- und zwar möglichst auf VERSCHIEDENE AKTIONEN wie "Short Click",
"Double Click" und "Long Click", die unterscheidbar sein sollen und auf
die das Programm mit unterschiedlichen Funktionsaufrufen reagieren kann.
Da war ja bereits mein Posting von heute Vormittag 11:49 Uhr ergibiger,
weil es mehrere Buttons ausgewertet hat.
Hier nun nochmal ein überarbeiteter Code, der mehrere Buttons auf kurze
und lange Tastendrücke abfragen kann. Der Button feuert seine Aktion
dabei beim Loslassen des Schalters, um lange und kurze Tastendrücke zu
unterscheiden.
Den Benchmark lasse ich mal als nebenläufige Funktion nebenbei laufen.
1
#define INPUTMODE INPUT_PULLUP // INPUT oder INPUT_PULLUP
2
#define PRELLZEIT 5 // Prellzeit in Millisekunden
3
#define SHORTCLICKTIME 250 // Längste Zeit für einen SHORTCLICK
4
bytebuttonPins[]={2,3,4,5,6,7,8};// Arduino Pins
5
#define NUMBUTTONS sizeof(buttonPins)
6
bytebuttonState[NUMBUTTONS];// Aktueller Status des Buttons HIGH/LOW
7
enum{NONE,SHORTCLICK,LONGCLICK};
8
bytebuttonResult[NUMBUTTONS];// Aktueller Klickstatus der Buttons NONE/SHORTCLICK/LONGCLICK
@Jürgen S.
Und während du noch an deinem Code rumschraubst - was an und für sich
recht lobenswert ist - läuft PeDas Code seit Jahren problemlos. Dieses
Rad wurde schon erfunden und es läuft schön rund. ;-)
Konrad S. schrieb:> @Jürgen S.> Und während du noch an deinem Code rumschraubst - was an und für sich> recht lobenswert ist - läuft PeDas Code seit Jahren problemlos. *Dieses*> Rad wurde schon erfunden und es läuft schön rund. ;-)
Wo ist denn bei PeDas Code die Auswertung und Unterscheidung von:
- Click
- Double Click
- Long Keypress
???
Der TO wollte nicht nur einen ganzen Schwung Buttons abfragen und darauf
reagieren, sondern er wollte auch möglichst drei verschiedenen Aktionen
pro Taster abfragen können, und zwar kurzen Tastendruck, Doppelklick und
langen Tastendruck mit lange gedrückter Taste.
Wo das in PeDas Code implementiert ist, mußt Du mir zeigen.
Als Arduino-Programmierer sehe ich das leider gerade nicht.
Ich sehe als Arduino-Programmierer momentan nicht mal, dass in PeDas
Code eine flexible Handhabung der Button-Beschaltung mit entweder
PullDown-Widerstand oder mit den internen PullUp-Widerständen im Code
eingebaut wäre.
Jürgen S. schrieb:> Wenn Du nur ein USB-Kabel hast, um ein 32U4 Board per Bootloader mit> einem Sketch zu versehen, bist Du ständig in höchster Gefahr, Dein Board> zu bricken.>> Wenn Du nur mit USB-Kabel und Bootloader arbeiten möchtest, holst Du Dir> besser ein UNO oder MEGA oder NANO Board oder so etwas.>> Beim 32U4 läuft nämlich die gesamte serielle Kommunikation per USB über> den 32U4 und keinen gesonderten Chip, und wenn Du einen Arduino-Sketch> hochlädst, der die USB-Schnittstelle außer Gefecht setzt, bekommst Du> über USB-Kabel keinen Sketch mehr hochgeladen.>> Und das geht auch mit Arduino Funktionen ganz leicht. Und danach> bekommst Du nur noch mit einem ISP-Programmer einen neuen Sketch> hochgeladen.
Aha, der Arduino-Profi spricht.
Seit mehr als zwei Jahren ist auch eine Problemlösung dafür bekannt -
ohne ISP-Programmer.
https://forum.sparkfun.com/viewtopic.php?f=32&t=31518
Und eigentlich müsste klar sein, warum diese Lösung funktionieren muss.
Jürgen S. schrieb:> Beim 32U4 läuft nämlich die gesamte serielle Kommunikation per USB über> den 32U4 und keinen gesonderten Chip, und wenn Du einen Arduino-Sketch> hochlädst, der die USB-Schnittstelle außer Gefecht setzt, bekommst Du> über USB-Kabel keinen Sketch mehr hochgeladen.
Sicher?
Hast Du das selbst getestet?
Ich würde die Arduino-Entwickler mindestens für so intelligent halten,
daß sie den USB-Bootloader in der Bootsektion plazieren.
Damit ist er nach jedem Power-On-Reset erreichbar, völlig schnurz, was
die Applikation macht.
Mir ist zumindest kein Fall bekannt, daß jemand einen Bootloader mit
Selbstzerstörung programmiert hat.
Außer in der Tuning-Szene. Da gibt es Geräte, die genau einmal laufen
sollen, damit nur ein Fahrzeug getunt werden kann.
Eben, dem Bootloader geht es nach wie vor bestens und er kann USB
vollständig von sich aus bedienen. Wie sollte das auch sonst
funktionieren? Durch einen Sketch, der das Arduino-Laufzeitsystem
plattmacht (¨brickt¨), geht die Fähigkeit verloren, aus dem
Normalbetrieb heraus in den Bootloader zu springen und zu einem
beliebigen Zeitpunkt einen Upload einzuleiten. Die im Link genannte
Lösung startet einfach den Upload und löst über einen Reset, z.B. durch
Einstecken des USB-Kabels, den Start des Bootloaders aus.
P.S.: Dieser Beitrag richtet sich nicht an dich, Peter. ;-)
Konrad S. schrieb:> Seit mehr als zwei Jahren ist auch eine Problemlösung dafür bekannt -> ohne ISP-Programmer.> https://forum.sparkfun.com/viewtopic.php?f=32&t=31518> Und eigentlich müsste klar sein, warum diese Lösung funktionieren muss.
Danke für den Hinweis! Das muß ich bei Gelegenheit noch mal intensiver
ausprobieren. Obwohl ich es bereits mal so getestet hatte und dabei mit
einer handvoll Versuchen nicht hinbekommen habe. Vielleicht habe ich zu
früh aufgegeben.
Peter Dannegger schrieb:> Sicher?> Hast Du das selbst getestet?
Nicht besonders intensiv, denn ich habe einen ISP-Programmer.
Das Problem unter Windows mit dem 32U4-Bootloader ist nämlich auch: Der
gebrickte 32U4-Arduino hat keine COM-Schnittstelle mehr, und ohne
existierende COM-Schnittstelle kann die Arduino-Software keinen Upload
auf eine bestimmte COM-Schnittstelle starten. Der Bootloader hat
allerdings nur ein extrem kurzes Timeout, so dass nachdem Windows nach
dem Reset wieder eine COM-Schnittstelle sieht, der Bootloader-Upload
extrem schnell beginnen muss, damit er funktioniert.
Andererseits beginnt der Upload nicht sofort, wenn man in der
Arduino-Software auf "Upload" klickt, sondern dann wird immer erst
nochmal der aktuelle Sketch kompiliert und gelinkt bevor der eigentliche
Bootloader-Upload startet
Vielleicht hatte ich bei meinem Test auch nur das falsche Timing und zu
wenig Geduld, um den richtigen Augenblick für den Bootloader zu treffen.
Wenn es funktioniert, ist es für die 32U4 Arduinos definitiv hakeliger
als bei den Arduino-Boards, die für die USB-Serial Kommunikation einen
eigenen Chip (FTDI, 8U2, 16U2) auf dem Board haben und die deshalb auch
bei einem Controller-Reset ständig den COM-Port im
Windows-Betriebssystem behalten.
In den Arduino-Einstellungen kannst du für den Upload-Vorgang ein
Häkchen für Verbose setzen. Du bekommst dann die beim Upload ablaufenden
Befehle angezeigt. Daraus suchst du dir das eine Kommando raus, das den
eigentlichen Upload macht und rufst es aus einer Konsole heraus auf. So
bekommst du das mit dem Timing besser hin.
Konrad S. schrieb:> In den Arduino-Einstellungen kannst du für den Upload-Vorgang ein> Häkchen für Verbose setzen.
Das ist der TOP-TIP, um wieder einen Sketch ohne ISP-Programmer auf ein
gebricktes 32U4 Arduino-Board zu bekommen!
> Du bekommst dann die beim Upload ablaufenden> Befehle angezeigt. Daraus suchst du dir das eine Kommando raus, das den> eigentlichen Upload macht und rufst es aus einer Konsole heraus auf.
Gerade mal ausprobiert: Leider startet der Upload ja nicht mehr, so dass
das Kommando, das den eigentlichen Upload macht, nicht mehr angezeigt
wird, wenn der Arduino bereits gebrickt ist.
Man müßte sich das Kommando also vorher rausgesucht und gemerkt haben,
bevor man das Board brickt.
Allerdings ist die erweiterte Ausgabe beim Upload trotzdem hilfreich,
weil man beim Timing für das Reset genau im richtigen Moment zuschlagen
kann.
Sobald im Ausgabefenster der COM-Portscan startet:
1
Forcingresetusing1200bpsopen/closeonportCOM15
2
PORTS{COM10,COM15,}/{COM10,COM15,}=>{}
3
PORTS{COM10,COM15,}/{COM10,COM15,}=>{}
4
PORTS{COM10,COM15,}/{COM10,COM15,}=>{}
Macht man dann den Reset, klappt es auch mit dem Upload.
Danke für den Tip!
Ich nehme also alles über gebrickte LEONARDO/MICRO Boards und die
Notwendigkeit von ISP-Programming gesagte zurück und behaupte das
Gegenteil: Man kann gebrickte LEONARDO/MICRO-Boards auch einfach über
den normalen Arduino-Bootloader wieder flottmachen. Einfach die
erweiterte Ausgabe beim Upload aktivieren und dann im genau richtigen
Moment mit dem Reset am Board zuschlagen.
Hallo Jürgen,
ich habe leider erst gerade eben die Zeit dazu gehabt, mit deinen Code
anzusehen und auszuprobieren. Im Vergleich zu dem, wie ich es gebastelt
hätte, sieht das sehr schön aus.
Mit enum und der Zusammenfassung der Eingänge zu einem Array habe ich
nun auch was gelernt, was ich umsetzen kann.
Ich denke, dass ich dein Programm grundsätzlich verstanden habe.
Ich wollte es nun um die Doppelklick-Erkennung erweitern.
Das geht aber leider nicht so einfach :-), denn du setzt den Ausgang
sofort, wenn eine Taste losgelassen wird.
Sehe ich es richtig, dass man die Abfragen komplett anders aufbauen
muss, wenn man auch einen Doubleclick erkennen möchte, ohne vor einem
Doubleclick immer kurz einen Shortclick auszugeben?
Mark Thalle schrieb:> Ich wollte es nun um die Doppelklick-Erkennung erweitern.> Das geht aber leider nicht so einfach :-), denn du setzt den Ausgang> sofort, wenn eine Taste losgelassen wird.
Ja, so ganz einfach ist es nicht.
Aber auch nicht soooo schwierig.
> Sehe ich es richtig, dass man die Abfragen komplett anders aufbauen> muss, wenn man auch einen Doubleclick erkennen möchte, ohne vor einem> Doubleclick immer kurz einen Shortclick auszugeben?
Nein, das kann man erweitern. Aber ich brauche wohl noch einen
Hilfsstatus, um den ersten Klick eine Weile zu speichern, während noch
ein Doppelklick draus werden kann. Und wenn kein Doppelklick innerhalb
einer bestimmten Zeit draus wird, wird es ein Shortklick, beim erneuten
Drücken ein Doppelklick.
Ich lasse mir mal was einfallen und poste es dann.
Jürgen S. schrieb:> Wo ist denn bei PeDas Code die Auswertung und Unterscheidung von:> - Click> - Double Click> - Long Keypress> ???>> Der TO wollte nicht nur einen ganzen Schwung Buttons abfragen und darauf> reagieren, sondern er wollte auch möglichst drei verschiedenen Aktionen> pro Taster abfragen können, und zwar kurzen Tastendruck, Doppelklick und> langen Tastendruck mit lange gedrückter Taste.>> Wo das in PeDas Code implementiert ist, mußt Du mir zeigen.
Doppelklick ist in deinem Code auch nicht drinnen. Also ist das ein
eiher schlechtes Argument. PeDas Code kann Normal-Zeit, Lange Drückzeit
und (was für mich immer besonders für Zahleneingaben wichtig war)
Autorepeat.
> Ich sehe als Arduino-Programmierer momentan nicht mal, dass in PeDas> Code eine flexible Handhabung der Button-Beschaltung mit entweder> PullDown-Widerstand oder mit den internen PullUp-Widerständen im Code> eingebaut wäre.
Ist ganz einfach: Auf einem AVR braucht das tatsächlich keiner wirklich,
weil Tasten sowieso immer gleich angehängt werden: Taster auf Low mit
eingeschaltetem internen Pullup
Das faszinierende an PeDas Code besteht darin, dass diese paar
Anweisungen
1
i=key_state^~KEY_PIN;// key changed ?
2
ct0=~(ct0&i);// reset or count ct0
3
ct1=ct0^(ct1&i);// reset or count ct1
4
i&=ct0&ct1;// count until roll over ?
5
key_state^=i;// then toggle debounced state
6
key_press|=key_state&i;// 0->1: key press detect
7
8
if((key_state&REPEAT_MASK)==0)// check repeat function
9
rpt=REPEAT_START;// start delay
10
if(--rpt==0){
11
rpt=REPEAT_NEXT;// repeat delay
12
key_rpt|=key_state&REPEAT_MASK;
13
}
das Entprellen bzw. die Unterscheidung kurz/lang bzw. den Autorepeat
regeln. Und zwar für 8 Tasten. Brauch ich kurz/lang nicht bzw. brauch
ich keinen Autorepeat, dann sind wir bei
1
i=key_state^~KEY_PIN;// key changed ?
2
ct0=~(ct0&i);// reset or count ct0
3
ct1=ct0^(ct1&i);// reset or count ct1
4
i&=ct0&ct1;// count until roll over ?
5
key_state^=i;// then toggle debounced state
6
key_press|=key_state&i;// 0->1: key press detect
ebenfalls wieder für maximal 8 Tasten. Ich hab nicht nachgesehen, aber
es würde mich sehr wundern, wenn der Compiler da mehr als 20 Taktzklen
dafür verbrutzeln würde. Und nein, ich bin nicht der Meinung von Mike
vom 27.6, wenn er schreibt
> richtig, die Routine ist jetzt nicht das was ein fähiger> Programmierer auch selbst hinbekommen würde und eine ganz besonders> hohen Intellekt bedarf es auch nicht soetwas zu schreiben.
Ganz im Gegenteil finde ich das Codestück als ziemlich trickreich. Das
ist Parallelprozessing durch Vektorbearbeitung in Reinkultur.
In der Arduino Programmierung besteht das 'Problem' mit diesem Code
darin, dass hier mittels
1
........KEY_PIN....
direkt auf einen Port zugegriffen wird um an den aktuellen Zustand der 8
Input Pins zu kommen. Das kann man natürlich auch auf einem Ardunion
machen. Macht man das allerdings Arduino typisch zb mittels
1
.......(digitalRead(2)<<2)+
2
(digitalRead(5)<<1)+
3
(digitalRead(9)
dann ist das insofern ein bischen witzlos, weil die ganze Abfrage
mittels digitalRead ein Vielfaches an Rechenzeit gegenüber der
Entprellung kosten würde.
Machbar wäre es allerdings.
Auf den Interrupt könnte man sogar verzichten, wenn man den ISR Code in
der Form des Zeitvergleichs mittels millis() in loop() einbaut. Da die
Entprellung insofern nicht besonders zeitkritisch ist, als als Zeitbasis
alles von ca. 5ms bis hin zu ca. 40 oder 50ms tauglich ist.
(Ich weiß auch nicht, ob man sich mittels Attach auf einem Arduino noch
zusätzlich an den Timer 0 hängen kann oder nicht. Wenn das möglich ist,
dann wäre natürlich auch das ein gangbarer Weg)
Karl Heinz schrieb:> Und nein, ich bin nicht der Meinung von Mike vom 27.6, wenn er schreibt>> richtig, die Routine ist jetzt nicht das was ein fähiger>> Programmierer auch selbst hinbekommen würde und eine ganz besonders>> hohen Intellekt bedarf es auch nicht soetwas zu schreiben.> Ganz im Gegenteil finde ich das Codestück als ziemlich trickreich.
Ich schließe mich an. Dieser Code ist genial. Und er wird m.E. nur von
denen schlechtgeredet, die ihn nicht verstanden haben. Das ist nämlich
wirklich nicht einfach, obwohl es nur ein paar Zeilen sind...
Als Tipp: alle Variablen als einzelne Bits ansehen. Dann sind ct1 und
ct0 die Bits eines Zwei-Bit-Zählers.
Jürgen S. schrieb:>> Sehe ich es richtig, dass man die Abfragen komplett anders aufbauen>> muss, wenn man auch einen Doubleclick erkennen möchte, ohne vor einem>> Doubleclick immer kurz einen Shortclick auszugeben?>> Nein, das kann man erweitern. Aber ich brauche wohl noch einen> Hilfsstatus, um den ersten Klick eine Weile zu speichern, während noch> ein Doppelklick draus werden kann. Und wenn kein Doppelklick innerhalb> einer bestimmten Zeit draus wird, wird es ein Shortklick, beim erneuten> Drücken ein Doppelklick.>> Ich lasse mir mal was einfallen und poste es dann.
Das ist nett, aber so war das nicht gemeint, besonders dann nicht, wenn
es zeitaufwendig ist.
Ich wollte nur nachgefragt haben, damit ich nicht vielleicht eine sehr
simple Lösung übersehe und mit hier stundenlang den Kopf zerbreche.
An eine Hilfsvariable hatte ich auch schon gedacht und das hätte ich
vermutlich auch selbst in absehbarer Zeit in den innersten Teil deiner
verschachtelten Abfragen implementieren können.
Hier:
1
else// Taster wird losgelassen
2
{
3
if(now-buttonDownTime[i]<=SHORTCLICKTIME)
4
buttonResult[i]=SHORTCLICK;
5
else
6
buttonResult[i]=LONGCLICK;
7
}
Allerdings wird dieser Teil nur durchlaufen, wenn sich der Tastenzustand
geändert hat, und das macht er ja nach dem Timeout nicht mehr, wenn kein
Doppelklick kommt.
Karl Heinz schrieb:> Doppelklick ist in deinem Code auch nicht drinnen.
OK, Tastenauswertung mit Doppelklickerkennung dann in diesem Posting
weiter unten. Ist ja leicht erweiterbar.
Am PeDa Code ist für Arduino-User nur nachteilig, dass standardmäßig der
Timer0 verbraten wird, und Timer0 ist nun ausgerechnet das Grundgerüst,
über das die Arduino-Software dem Programmierer ein Timing-Grundgerüst
für seine Anwendung bereitstellt, mit Funktionen für Millisekundenzähler
"millis()", Mikrosekundenzähler mit 4µs Auflösung "micros()" sowie
Delayroutinen im Millisekundentakt "delay()" und im Mikrosekundentakt
"delayMicroseconds()".
Diese Arduino-Timingroutinen sind für extrem viele Zwecke nutzbar und
längst nicht nur zur Tastaturentprellung und -abfrage nützlich. Wenn ich
mal Zeit und Muße finde, schaue ich mir den PeDa Code mal darauf an, wie
man ihn für Arduino-Programierer nutzbringend umschreiben kann, ohne
dabei Timer0 und die daran hängenden Funktionen komplett stillzulegen
und ohne einen weiteren der wenigen Timer zu verbraten.
Aber die Entprellung von Tastern ist unter Arduino nun wirklich keine
Geheimwissenschaft, egal ob man nun nur auf Tastendruck, kurze und lange
Tastendrücke oder kurze, lange und doppelte Tastendrücke reagieren
möchte.
Bei Bedarf würde ich an meinen unten stehenden Code sogar noch eine
vierte Funktion drauflegen:
- kurzer Tastndruck
- Doppelklick
- langer Tastendruck
- superlanger Tastendruck
Und vor allem sind die reinen Arduino-Funktionen portabel innerhalb der
Arduino-Welt: Derselbe Code mit Hilfe der Arduino Core-Funktionen
programmiert läuft unverändert auf einem 8-Bit Atmega Controller genau
so wie auf einem Atmel SAM3X8E ARM Cortex-M3.
Anyway, hier die Auswertung von Shortklick, Doubleclick und Longclick
mit Arduino, zusammen mit einem kleinen Counter-Benchmark in der loop:
Beim Auswerten sind die Statuswerte NONE, FIRSTDOWN, FIRSTUP zu
ignorieren, und nur auf SHORTCLICK, DOUBLECLICK, LONGCLICK zu prüfen, um
darauf im Programm zu reagieren. Das Beispielprogramm gibt im Klickfall
einfach einen entsprechenden Text auf Serial aus.
Viel Spaß damit, falls es ein Arduino-Programmierer gebrauchen kann!
Und wer nicht, der nutzt eben anderen Code.
Es gibt beim Programmieren ja immer mehrere Möglichkeiten.
Jürgen S. schrieb:> Wenn ich mal Zeit und Muße finde, schaue ich mir den PeDa Code mal> darauf an, wie man ihn für Arduino-Programierer nutzbringend umschreiben> kann, ohne dabei Timer0 und die daran hängenden Funktionen komplett> stillzulegen
Es wäre in 10 Minuten erledigt, wenn man sich in den millis()
Timerinterrupt einhängen könnte.
Und "nutzbringend" ist der Code schon, da musst du nichts mehr
umschreiben...
Lothar Miller schrieb:> Es wäre in 10 Minuten erledigt, wenn man sich in den millis()> Timerinterrupt einhängen könnte.
Kann man. Die relevante Datei ist
hardware/arduino/cores/arduino/wiring.c
im Arduino Verzeichnis.
Jürgen S. schrieb:> Am PeDa Code ist für Arduino-User nur nachteilig, dass standardmäßig der> Timer0 verbraten wird,
Der Timer wird nicht verbraten, er wird benutzt. Ein Timer kann viele
zeitabhängighe Dinge nacheinander erledigen.
Falls schon ein Timer anderweitig benutzt wird, kann man den
Entprelltask einfach mit hineinhängen. Er ist ja nicht in chinesich
geschrieben, man kann ihn ruhig lesen und den Code woanders aufrufen.
Den T0 neu zu laden, ist auch nur bei den allerersten AVRs notwendig (T0
ohne CTC Modus).
Jürgen S. schrieb:> Beim Auswerten sind die Statuswerte NONE, FIRSTDOWN, FIRSTUP zu> ignorieren, und nur auf SHORTCLICK, DOUBLECLICK, LONGCLICK zu prüfen, um> darauf im Programm zu reagieren. Das Beispielprogramm gibt im Klickfall> einfach einen entsprechenden Text auf Serial aus.>> Viel Spaß damit, falls es ein Arduino-Programmierer gebrauchen kann!> Und wer nicht, der nutzt eben anderen Code.> Es gibt beim Programmieren ja immer mehrere Möglichkeiten.
Unter anderem dann auch die, die ich mir zusammen prutscheln würde :-)
Ich hätte nicht gedacht, dass man mit so wenigen Änderungen auch einen
Double-Click integriert bekommt. Ausgehend von deinem Programm hätte ich
die komplette Abfrageverschachtelung umgebaut. Das wäre lange nicht so
kompakt und sehr viel unübersichtlicher geworden.
Alternativ hatte ich mir auch überlegt, deine Abfragen zu lassen, wie
sie sind, und übergeordnet die Shortklicks zu zählen. Damit könnte ich
dann auch einfacher 3x, 4x,..-Klicks realisieren.
Für mich wäre es übersichtlicher und leichter zu ändern, würde aber
wahrscheinlich mehr Programmspeicher in Anspruch nehmen und es wäre
langsamer.
Aber gut, darüber mache ich mir dann Gedanken, wenn ich irgendwas davon
wirklich benötige.
Jürgen S. schrieb:> Deshalb müßtest Du darauf achten, eine saubere Programmlogik zu bauen,> und eine sehr einfache Methode dazu ist das "EVA-Prinzip". Du mußt nur> das Programm in drei logische Funktionsbereiche "Eingabe",> "Verarbeitung" und "Ausgabe" aufteilen. Grundschema der Arduino-loop:
Spricht etwas dagegen, die Ausgänge bei jedem Durchlauf von loop() mit
digitalWrite() neu zu setzen, auch wenn sich das Prozessabbild nichts
geändert hat?
Vom Pic kenne ich es so, dass das kein Problem ist. Bei digitalWrite()
bin ich mir nicht sicher.
Bei allen mir bekannten Controllern passiert nichts, wenn man einen
Ausgang auf den gleichen Pegel setzt, den er schon vorher hatte. Also
keine Spikes beim Umschalten, oder so.
Bedienung mit Multi-Klick ist nicht unbedingt der Hit. Der harmlosere
Punkt ist, dass ein n-Klick erst erkannt wird, wenn der Startzeitpunkt
des n+1-Klicks ereignislos verstrichen ist. Problematischer finde ich,
dass bei zu schnell nacheinander ausgeführten Einzelklicks ein
Doppelklick nicht nur erkannt, sondern auch ausgeführt wird. Beschränkt
man sich auf die Unterscheidung kurzer Klick und langer Klick, so
erreicht man - meiner Meinung nach - eine sicherere Bedienung.
Konrad S. schrieb:> Bedienung mit Multi-Klick ist nicht unbedingt der Hit.
Der Hit wäre dann eher wieder die "OneKey" Eingabe: man morst seinen
Befehl in das Gerät hinein. Das hätte wenigstens den Vorteil, dass ein
weltweit bekanntes Eingabeverfahren verwendet wird...