Guten Tag, allerseits! Bin scheinbar seeeeehr schwer von Begriff! aktuelles Projekt mittels Arduino Software und Sainsmart 2560 Board Ich habe bereits ein Programm geschrieben, in dem ich Drehzahlwerte mit pulseIn einlese (zuvor sauber von Sinus auf Rechteck gewandelt mit Komparator - klar) ich hatte das Problem, dass mir pulseIn das Programm bei Drehzahl 0 nahezu zum Stillstand bringt...draufgekommen bin ich schon, warum! also -> mit Interrupts umsetzen! ich habe schon einige Wochen versucht, es zu verstehen...keine Chance! also, kann mir wer nen anschaulichen, verständlichen Code reinschreiben? ich will also eine Drehzahlmessung (max 2kHz) haben, benötige regelmässig diese Drehzahlwerte, um sie dann weiter verarbeiten zu können! Bei Drehzahl 0 soll nur die Loop laufen wie gesagt, ich versteh die ganze Syntax zum Interrupt nicht so wirklich, ebenso nicht die Syntax von den Prescalern!! wäre sehr dankbar für Erklärung bzw. Pseudo-Code für einen Clown, wie mich
>pulseIn
Ich kenne dein pulseIn nicht....
Deiner Beschreibung nach arbeitet die Funktion "blockierend".
Kein Puls, keine Rückkehr.
Dann haben die anderen Aufgaben natürlich keinen Spass ;-)
Warum bastelst du dir nicht eine ISR, welche einfach nur eine Variable
hoch zählt?
Und die eigentlichen Berechnungen machst du dann alle im loop().
Die Arduino Umgebung stellt dir alles nötige zur Verführung.
Und Beispiele gibts wie Sand am Meer.
----
Meine Erinnerung sagt, dass der 2560 einen Zählereingang hat.
Damit könntest du ganz auf die ISR verzichten.
ungeprüft
Wenn man eine Drehzahlmessung ueber eine Zeitmessung macht dann braucht die Routine eine Timeoutfunktion. Drehzahl 0 gibt es in dem Fall nicht denn das waere eine Periodendauer von unendlich. Besser ist es du sagst alles was unter z.B. 5 Upm ist, ist 0. Also wenn die Periodendauer des Messimpules zu lange dauert wird abgebrochen und als Ergebnis 0 zurueck gegeben.
hmmmmm....mir ist die grundprinzipielle Sache klar....es scheitert halt an der Umsetzung!! habe nun das hier geschrieben----> könnte klappen ? void value_l_f() { detachInterrupt (3); //Interrupt 3 ausschalten unsigned long m=micros(); //Auslesen der Mikrosekunden unsigned long v=m-last_v_l; //Differenz von letzter ISR und jetzt dauer_v_l=v; //Wert in andere Variable schreiben last_v_l=m; //Wert "merken" attachInterrupt(3, value_l_f, RISING); //Interrupt einschalten } ...und nur in der void Setup() rufe ich den Interrupt auf ?!?! die Umrechnung erfolgt in der Loop bin mir da beim Code nicht sicher.... Das beabsichtigte Programm könnte auch erst bei 10km/h (ungefähr 100 Impulse/sec) eingreifen..drunter macht es keinen Sinn für meine Anwendung! Holzweg? btw: pulseIn wartet BIS ein Signal kommt, max. aber etwa 1sec...solang steht das Programm.....unlustig!! und: ich hab noch einen Taster, womit ich zwischen Display-Infos umschalten will....mit IF-Schleife bremse ich doch wieder massiv ein (T-Flip-Flop)....auch mit Interrupt ansteuern?! leider hab ich nur Datenblätter zum Arduino 2560 gefunden, was aber nicht heisst, dass die Interrupts an den selben DIs sind, wie beim Sainsmart!
Und warum schmeisst du nicht das ganze Arduino Zeugs raus und nimmst einen vernueftigen Compiler und setzt die Controllerregister selber.
Je nach Elektronik, gibt es die Möglichkeit, dass im Stillstand, dauernd Null oder dauernd High/Aktiv an deinem µC anliegt. Möglicherweise bekommt Deine Auswertung damit Verdauungsstörungen. Je nach µC gibt es die Möglichkeit, die Unterbrechungen an ihren Flanken zu erkennen. Ansteigende oder abfallende Flanke. Diese Einstellung würde dafür sorgen, dass beim Stillstand der letzte Status nur eine Unterbrechung auslöst und keine Dauerunterbrechungen.
Rene Trattner schrieb: > ...und nur in der void Setup() rufe ich den Interrupt auf ?!?! Einen Interrupt 'rufst' du überhaupt nicht auf. Das ist ja der ganze Witz an einem 'Interrupt'! Interrupt bedeutet 'Unterbrechung'. Einen Interrupt installierst du im System und 'verbindest' ihn mit einem Ereignis. Tritt das Ereignis auf, dann wird der normale Progammablauf unterbrochen und die Hardware führt ganz eigenständig und ohne dein weiteres Zutun, die angegebene Interrupt Funktion auf. Ist die Funktion abgearbeitet, dann springt die Hardware wieder zurück zu der Stelle an der das Programm durch das Interrupt Ereignis unterbrochen wurde und macht weiter als sie nie irgendetwas geschehen. Auch wenn Interrupt letzten Endes der Schlüssel zum Erfolg sein wird, solltest du dir meiner Meinung nach erst mal ohne Interrupt darüber klar werden, wie du eine Puklszählung machen kannst. Die erste Technik, die man auf einem Arduino lernt ist diese hier
1 | unsigned long lastTime; |
2 | |
3 | ...
|
4 | |
5 | void loop() |
6 | {
|
7 | unsigned long now = millis(); |
8 | |
9 | if( now - lastTime >= 1000 ) { |
10 | lastTime = now; |
11 | |
12 | .... mach was |
13 | }
|
14 | }
|
mit der man auf einfache Weise alle 1000 Sekunden Code ausführen lässt. Das Prinzip ist ein einfacher Zeitvergleich: wann hat man zuletzt diese Aktion gemacht und wieviel Zeit ist in der Zwischenzeit vergangen. Ist diese Differenz gleich dem gewünschten Zeitintervall, dann steht die Aktion erneut zur Ausführung an. Man vermerkt den Zeitpunkt an dem die Aktion gemacht wird (weil man diese Zeit ja braucht um damit den nächsten Zeitpunkt für das nächste mal festzulegen) und macht die Aktion. Auf die Art hast du also eine Möglichkeit, wie du jede Sekunde eine Aktion machen kannst. Was könnte bei dir die Aktion sein? Na zum Beispiel, dass du auswertest, wieviele Pulse du in dieser 1 Sekunde gezählt hast. D.h. du brauchst jetzt noch einen Pulszähler, der einfach bei jedem Puls um 1 weiter gezählt wird. Und nach jeweils 1 Sekunde wertest du den aus, indem du aus der Anzahl der Pulse auf die Geschwindigkeit umrechnest und den Zähler wieder auf 0 setzt. Das ist eine Möglichkeit. Leider hat das Verfahren ein Problem: Je kleiner die Pulszahl in der 1 Sekunde wird, desto ungenauer wird es. Daher dreht man das um: Jedes mal, wenn man den Beginn eines Pulses feststellt, stellt man einen Zeitvergleich mit dem vorhergehenden Puls an. Auf die Art stellt man fest, wie lange ein Puls gedauert hat und errechnet daraus dann die Drehzahl/Geschwindigkeit. Was auch immer. Der springende Punkt ist, dass du dazu überhaupt noch gar keinen Interrupt gebraucht hast. Solange du mit millis(), also Millisekunden, arbeiten kannst, ist alles gut. Kritisch wirds erst, wenn Millisekunden nicht mehr ausreichen, weil der Fehler zu gross wird. Aber auch dann kann man immer noch, je nach Vormessung zum Beispiel zwischen den Verfahren hin und her schalten. Bei kleinen Drehzahlen misst man die Pulsdauer, bei größeren Drehzahlen misst man die Anzahl Pulse in einem Zeitfenster. Wenn du das gemeistert hast, dann kann man immer noch überlegen, ob man auf Interrupts geht. Aber erst mal ist es meiner Meinung nach wichtig, dass du grundlegende Programmiertechniken lernst. Denn auch das Stichwort 'Interrupt' ist kein Allheilmittel, wenn man schon grundsätzliche Probleme hat und sich nicht von vorgefertigten Funktionen anderer lösen kann, weil man dann eben doch ausser vorgefertigen Teilen in 'Malen nach Zahlen' Manier nichts anderes kann. Da beginnt dann richtiges Programmieren.
:
Bearbeitet durch User
vielen Dank für diese Ausführung! also, ich verarbeite Pulse zwischen 0 (oder auch z.B. 29) bis etwa 1400 ergo, Millisekunden reichen da nicht mehr! um einen Interrupt werde ich nicht herumkommen, da die Loop so klein und simple sein soll, wie nur irgendwie möglich, damit auf das Messergebnis SCHNELL "reagiert" werden kann! ich lese 3 Drehzahlwerte ein, will diese vergleichen...weicht einer der Werte um einen gewissen Wert ab, soll ein Stellglied mittels PWM betätigt werden! und sollte KEINE Drehzahl der Sensoren kommen, sollte man trotzdem noch über eine weitere analoge Grösse das Stellglied ansteuern können! der Komparator liefert bei Stillstand des Sensors logisch 0....ich habe die Empfindlichkeit etwas abgesenkt, denn es muss nicht schon bei 29 Pulsen/sec was getan werden (29, weil der Sensor pro Radumdrehung 29 Impulse macht) oben angeführte Loop versteh ich nicht 100%, nimm sie nur so hin!! vl sollte ich mal Pause machen...es dreht sich alles g
Rene Trattner schrieb: > vl sollte ich mal Pause machen... vielleicht solltest du erst mal mit kleinen Brötchen anfangen, anstatt die Welt in 5 Minuten einreissen zu wollen. > oben angeführte Loop versteh ich nicht 100%, nimm sie nur so hin!! Das ist schlecht. Denn das ist so ziemlich das einfachste, was man mit einem Arduino aus dem Stand heraus machen kann. Wenn du schon diese Technik nicht kennst bzw. verstehst, dann schwant mir da nichts gutes. Noch einfacher geht fast nicht mehr. Komplexer (mit höherer Genauigkeit) allerdings geht immer. Aber wie das eben im Leben so ist: Von nichts kommt nichts und erst mal sollte man die einfachen Techniken beherrschen, auch wenn die vielleicht nicht ganz die Genauigkeit erreichen, die einem vorschwebt. (Im übrigen hast du anscheinend nicht gesehen, dass ich eigentlich 2 Techniken vorgeschlagen habe, die die nette Eigenschaft haben, komplementär zu sein: dort wo das eine eine schlechte Genauigkeit hat, hat das andere eine gute und umgekehrt.)
:
Bearbeitet durch User
> um einen Interrupt werde ich nicht herumkommen, da die Loop > so klein und simple sein soll, wie nur irgendwie möglich, damit > auf das Messergebnis SCHNELL "reagiert" werden kann! Diese Aussage ist Quatsch. Denn dein µC ist viele Zehntausend mal schneller, als es minimal notwendig wäre um diese Drehzahlen bei einer normalen Anzahl Pulse pro Umdrehung zu messen.
unsigned long lastTime; ... void loop() { unsigned long now = millis(); if( now - lastTime >= 1000 ) { lastTime = now; .... mach was } } NOW muss ich irgendwo mal im Wert festlegen, oder ? (Startwert) die Schleife würde nur einmal durchlaufen... z.B. now=1000000, lastTime=1000 if-Bedingung erfüllt...dann wird danach lastTime zu 1000000....FERTIG 1000 sind Millisekunden, also Programm wird JEDE SEKUNDE neu ausgeführt, nicht alle 1000sec ?
Rene Trattner schrieb: > unsigned long lastTime; > > ... > > void loop() > { > unsigned long now = millis(); > > if( now - lastTime >= 1000 ) > { > lastTime = now; > > .... mach was > } > } > > NOW muss ich irgendwo mal im Wert festlegen, oder ? (Startwert) passuert doch. Hier
1 | unsigned long now = millis(); |
> die Schleife würde nur einmal durchlaufen...
Nö. da ist überhaupt keine Schleife.
Ein if ist keine Schleife. Ein if ist eine Abfrage.
Die Arduino typische Schleife ist ausserhalb, in dem loop immer wieder
aufgerufen wird.
Karl Heinz schrieb: > Die Arduino typische Schleife ist ausserhalb, in dem loop immer wieder > aufgerufen wird. Mir scheint dir ist noch überhaupt nicht klar, wie das Arduino typische 'Framework' überhaupt funktioniert. Es gibt 2 Funktionen. Die eine, setup(), wird einmalig am Anfang des Programms aufgerufen und dort machst du deine Initialisierungen. Die andere, loop(), wird laufend immer wieder aufgerufen. Das Prinzip dahinter ist: loop sieht sich nacheinander alle möglichen Dinge an, ob es etwas zu tun gibt. Gibt es etwas zu tun, dann wird das erledigt, wenn nicht, dann eben nicht. Danach ist die Funktion loop() beendet und es geht wieder zurück zum Aufrufer. Kurze Zeit später wird loop() erneut aufgerufen und wieder dasselbe Spielchen: gibt es etwas zu tun, dann bearbeite das. loop() ist so gesehen also wie ein Nachtwächter, der regelmässig von einem Wecker geweckt wird. Er sieht sich um, kontrolliert die Anzeigen und wenn ihm dabei was auffällt, dann macht er eine Schaltung. Hat er seine Kontrollen alle durchgesehen, dann legt er sich wieder schlafen. Bis dann das nächste mal der Wecker klingelt. Aber eins tut er nicht: er wartet nicht darauf, dass irgendetwas fertig ist. Vor allen Dingen dann nicht, wenn dieses 'irgendetwas' lange dauert. Einzige UNterschied: der WEcker im Arduino klingelt nicht alle halbe Stunde sondern ein paar Zehn- bis Hundert-tausend mal in der Sekunde. Die Uhrzeit aber, die der Nachtwächter von seinem Wecker abliest, die ist im Arduino die Funktion millis(). So realisiert eine Uhr, die in Millisekunden seit dem Einschalten des Arduino zählt. Und genauso wie der Wecker des Nachtwächters unabhängig von den Aktionen (oder dem Schlafen) weiterläuft, genauso läuft auch die durch millis() realisierte Uhr weiter.
:
Bearbeitet durch User
Praktisch alle mechanischen Geräte sind träge. Warum also nicht, je nach Messwert, die Torzeiten bzw. Auflösungen anpassen. So sind immer, optimal angepasste Arbeitsbereiche, Verfügbar.
> Interrupt bedeutet 'Unterbrechung'. > Einen Interrupt installierst du im System und 'verbindest' ihn mit einem > Ereignis. Tritt das Ereignis auf, dann wird der normale Progammablauf > unterbrochen und die Hardware führt ganz eigenständig und ohne dein > weiteres Zutun, die angegebene Interrupt Funktion auf. Ist die Funktion > abgearbeitet, dann springt die Hardware wieder zurück zu der Stelle an > der das Programm durch das Interrupt Ereignis unterbrochen wurde und > macht weiter als sie nie irgendetwas geschehen. Karl Heinz, vor einigen Tagen hab ich mal gelesen, dass es Interrupts in Interrupts geben sollte. Kann es sein, dass dann das Programm, wenn es in ein interrupt kommt, etwas tut, was wiederrum ein Interrupt ausübt? Die Notation hierfür wäre
1 | ISR(Vect_0,XYZ){} |
Gibt es das wirklich? Und könntest du das bitte kurz erklären, wie das geht? Mfg, tommyProg
:
Bearbeitet durch User
Tho Wes schrieb: > Karl Heinz, > > vor einigen Tagen hab ich mal gelesen, dass es Interrupts in Interrupts > geben sollte. Das ist eine Möglichkeit. Auf einem AVR ist es aber so, dass automatisch weitere Interruptabarbeitung gesperrt ist, solange ein Interrupt Handler arbeitet. > Kann es sein, dass dann das Programm, wenn es in ein interrupt kommt, > etwas tut, was wiederrum ein Interrupt ausübt? Auch das kommt auf den Prozessor an, bzw. was es tut. > > Die Notation hierfür wäre > >
1 | ISR(Vect_0,XYZ){} |
Nope. Wo hast du das her? > Gibt es das wirklich? Und könntest du das bitte kurz erklären, wie das > geht? Die Abarbeitung eines Interrupts ist grundsätzlich vergleichbar mit einem Funktionsaufruf. Nur dass eben nicht dein Programm die Funktion aufruft, sondern die Hardware den Funktionsaufruf auslöst.
>>
1 | ISR(Vect_0,XYZ){} |
> > Nope. > Wo hast du das her? ..und stimmt, da stehts andersrum^^ steht bei Unterbrechbare Interruptroutinen ""Faustregel": im Zweifel ISR. Die nachfolgend beschriebene Methode nur dann verwenden, wenn man sich über die unterschiedliche Funktionsweise im Klaren ist. #include <avr/interrupt.h> ISR(XXX,ISR_NOBLOCK" -> Vielleicht habe ich da was falsch verstanden <- >> Gibt es das wirklich? Und könntest du das bitte kurz erklären, wie das >> geht? > > Die Abarbeitung eines Interrupts ist grundsätzlich vergleichbar mit > einem Funktionsaufruf. Nur dass eben nicht dein Programm die Funktion > aufruft, sondern die Hardware den Funktionsaufruf auslöst. Danke.
:
Bearbeitet durch User
Tho Wes schrieb: > -> Vielleicht habe ich da was falsch verstanden <- Sieht wohl so aus. Der Standardfall ist, dass eine ISR nicht durch eine andere ISR unterbrochen werden kann. Will man das nicht, dann muss man das extra anfordern. Im Regelfall will man genau das nicht, d.h. die Nichtunterbrechbarkeit ist schon gut so, wie sie ist. Es gibt Ausnahmefälle, zweifellos, aber das sind Ausnahmen und wer so etwas braucht, hat auch genug Erfahrung um zu wissen was er tut und was ihn da alles erwarten kann.
Guten Morgen! gut, millis() hatte ich völlig falsch interpretiert (jaja, besser lesen) folgenden Code für meine Zählung...könnte das klappen?? ----> T=pulseIn(wheel_r_f, HIGH,1000)+pulseIn(wheel_r_f, LOW,1000); if (T==0) {lcd.setCursor(9,1);lcd(print("000");} else{f=1/(double)T; {lcd.setCursor(9,1);lcd.print(f*1e6);} T...unsigned Long f...double also mess ich hier ein HIGH und ein LOW, zähl zusammen (1 Schwingung sozusagen) der dritte Parameter ist eine Wartezeit, bis der Impuls kommt in Mikrosekunden dann Umrechnung in eine Frequenz und Ausgabe in Hz könnte das klappen ? das Ganze müsste ich 3 mal machen, also für 3 Sensoren....dies geschieht alles in der Loop! (so nebenbei : pro Sensor max 1400Hz min 58Hz..sind 2 U/sec in meinem Fall, das Programm muss SCHNELLSTMÖGLICH mit den 3 Werten eine Stellgrösse bewegen mittels PWM) bin ich immer noch am Holzweg?
will hier noch mal nachhaken habe heute einen Zähler oben angeführter Art eingefügt....im Endeffekt keine spürbare Einbuße der Geschwindigkeit im Programm! sieht allerdings ganz anders aus, wenn ich diese pulseIN 3 mal reinsetze in die Loop! dann wird das Servo schon eckig in seiner Bewegung...das kann ich nicht brauchen! wenigstens lauft inzwischen eine andere Abfrage recht sauber... könnte ich den Interrupt nun so auslösen? ----> void Setup() {. . . attachInterrupt (pin, zähler, CHANGE???);} void Loop () {Umrechnung des Wertes, den ich via Interrupt bekomme} void zähler() { Zählung von Impulsen (HIGH to LOW) dabei läuft micros() und zählt die Zeit vom Beginn der Routine bis zum Auslösen des nächsten Interrupt "attachInterrupt(..) } ist das so richtig?! wenn ja, was erhalte ich dann von dem Interrupt genau?! irgendwie muss ich schnell den Schmarrn zusammenstopseln, dass es mal funktioniert, auf der anderen Seite kann ich tun, was ich will....da geht nix weiter....auch vom Verständnis her! }
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.