Forum: Mikrocontroller und Digitale Elektronik Interrupt - Verständnisproblem


von Rene T. (hifi-freak)


Lesenswert?

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

von Ulrich F. (Gast)


Lesenswert?

>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

von Helmut L. (helmi1)


Lesenswert?

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.

von Rene T. (hifi-freak)


Lesenswert?

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!

von Helmut L. (helmi1)


Lesenswert?

Und warum schmeisst du nicht das ganze Arduino Zeugs raus und nimmst 
einen vernueftigen Compiler und setzt die Controllerregister selber.

von Amateur (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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
von Rene T. (hifi-freak)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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
von Karl H. (kbuchegg)


Lesenswert?

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

von Rene T. (hifi-freak)


Lesenswert?

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 ?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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
von Amateur (Gast)


Lesenswert?

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.

von Tho W. (tommyprog)


Lesenswert?

> 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
von Karl H. (kbuchegg)


Lesenswert?

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.

von Tho W. (tommyprog)


Lesenswert?

>>
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
von Karl H. (kbuchegg)


Lesenswert?

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.

von Rene T. (hifi-freak)


Lesenswert?

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?

von hififreak (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.