Forum: Mikrocontroller und Digitale Elektronik globale variable durch interrupt routine setzen geht nicht


von Tom (Gast)


Lesenswert?

Guten Tag,

ich habe das Problem, dass ich wenn ich eine globale Variable durch eine 
Interrupt Routine setze dies nicht in einer if-Anweisung prüfen kann.

Mein Programm läuft wie folgt ab:
ich starte eine Funktion   -start_measurement();
in dieser Funktion starte ich den ADC   -ADCON1bits.ADON=1;
der ADC deaktiviert sich selbst in seiner Interrupt Routine worauf die 
Funktion "start_measurement" wartet   -while(ADCON1bits.ADON==1){}

nun kommt das Problem:
die Interrupt Routine setzt außerdem noch eine Globale Variable je nach 
dem auf 0 oder 1.
Will ich dies in der Funktion "start_measurement" überprüfen hat die 
Variable den Wert vom vorherigen Durchgang.

Ich habe die globale Variable in der C-Datei mit
volatile int glob_var=0;  definiert
und in der h-Datei mit
extern volatile glob_var; deklariert

Ich benutze die IDE "MPLAB X" von Microchip und deren C-Compiler.

Wenn irgendjemand eine Idee hat wär ich für Hilfe sehr dankbar.
LG Tom

von Tom (Gast)


Lesenswert?

Achja... wo ich grad schon amFragen bin...
Wie würdet ihr das Machen:
Globale Variable mit extern definieren oder nur eine globale Variable 
welche mit einer eigenen Funktion überprüft wird?

Wie könnte man hier diese Globale Variable vermeiden?

von Michael K. (Gast)


Lesenswert?

Warum Polling UND IRQ ?
Der Sinn eines IRQs ist doch das die Bearbeitung bedarfsgerecht 
weitergeht ohne in einer Warteschleife zu verharren.

Sieht für mich danach aus als ob die Funktion eine Kopie der globalen 
Variablen bei Aufruf bekommt, also den letzten Wert.

von Richtigsteller (Gast)


Lesenswert?

Wie wäre es mit dem ganzen Quellcode? Der Fehler liegt natürlich an 
einer Stelle, die du hier nicht zeigt. So wird dir keiner helfen können.

von Tom (Gast)


Lesenswert?

Ich polle ja nicht.
Die Interrupt Routine nimmt nur Werte auf und überprüft sie darauf hin 
ob ein Signal (ein Ultraschall Echo) empfangen wurde oder eben nur 
Rauschen. Ist also nur ein Flag was mir dann am Ende sagen soll ob ein 
Echo empfangen wurde oder eben nicht.

Ja ich denke ich schau jetz noch mal drüber und wenn ich jetz nichts 
finde (hatte gestern ein Tag Pause) lad ich den Code hoch.
Muss den halt erst was aufbereiten weil da viel Funktionen drin sind die 
nicht von interesse sind. Und dann kopier ich die ISR und die andere 
Funktion in eine Datei.

Sieht für mich auch so aus als würd er die globale Variable beim Start 
der Funktion in ein Work-Register laden und eben nicht das "original" 
benutzen.
Aber eigentlich ist doch um das zu verhindern volatile dar oder nicht?

von Richtigsteller (Gast)


Lesenswert?

Aber nicht nur Codefetzen sondern was lauffähiges bitte.

von Tom (Gast)


Angehängte Dateien:

Lesenswert?

So ich habe keine Ahnung. Für mich sieht das so aus als ob der Compiler 
es entweder ignoriert oder ich volatile irgendwie Falsch verwende.

Gesetzt wird die globale Variable jeden falls. Das hab ich überprüft.

Was halt nicht funktionirt ist die Ausgabe in C-File-Finktion.txt ob die 
Messung erfolgreich war.

Gesetzt wird sie in C-File-ADC wo ich die zeile mit XXX kommentiert hab.
Hoffe ihr kommt mit dem Code zurrecht.

Nochmal den Ablauf beschrieben:
start_measurement() startet timer und ADC und wartet auf Beendigung von 
ADC
ADC-ISR setzt measurement_done auf 0 oder 1
start_measurement soll anhand der globalen Variable measurement_done 
eine Ausgabe machen.
measurement_done scheint nicht verändert zu sein.
Wenn ich in meiner main measurement_done überprüfe bekomm ich den 
richtigen Wert.

Danke schon mal für eure Hilfe.

von Bitflüsterer (Gast)


Lesenswert?

Meine Güte. Aber Nase schnauben geht schon alleine, oder? :-)

Jetzt hängst Du mal schon ordentlich ein 'c' und ein 'h' an die Dateien 
und postest die nochmal hier. Vermutlich haben die meisten hier keine 
Lust die Dateien erst auf der Festplatte zu speichern.

von Tom (Gast)


Lesenswert?

Was übrigens auch merkwürdig ist, ist dass er die Ausgabe ob die Messung 
erfolgreich war nicht komplett weg optimiert.

Er kann beide Ausgaben machen nur halt versetzt als würd er die globale 
Variable nicht "updaten" also aus nem Register nehmen.

von Tom (Gast)


Angehängte Dateien:

Lesenswert?

ups wusst nicht das das dann so läuft.

von Bitflüsterer (Gast)


Lesenswert?

Au, Sch... Karl Heinz? Kommst Du mal, bitte?

von Karl H. (kbuchegg)


Lesenswert?

Tom schrieb:

> Er kann beide Ausgaben machen nur halt versetzt als würd er die globale
> Variable nicht "updaten" also aus nem Register nehmen.

Ne. da kann der nichts mit der Variablen optimieren.

Schmeiss halt mal alles aus deiner ISR raus, was nicht notwendig ist.
Da wird halt irgendwas an deiner Logik mit den 85 Flags und 76 Abfragen, 
Min/Max Suche und Wetterprogrnose da drinn nicht stimmen.

von Georg G. (df2au)


Lesenswert?

Sind die ADCCon1Bits auch als "volatile" definiert? Leider fehlt dieser 
Teil deines Programms.

von Karl H. (kbuchegg)


Lesenswert?

Was genau
1
    start_timer_1();          // Timer startet ADC wenn alle Perioden gesendet sind (Funktioniert)
2
3
    while(ADCON1bits.ADON==1){}                   // warte auf das beenden des ADC
macht start_timer?

Kann es sein dass die while Schleife
1
    while(ADCON1bits.ADON==1){}                   // warte auf das beenden des ADC
sofort beendet wird? Nicht, weil der ADC fertig ist, sondern weil der 
noch gar nicht mit seiner Arbeit angefangen hat?
Immerhin liest sich das so, als ob start_timer einen zeitlichen Prozess 
in Gang setzt, an dessen Ende eine Messung des ADC steht.

von Tom (Gast)


Lesenswert?

Das klingt nach einer guten Erklärung Karl Heinz.
Ich probiers mal aus.

von Karl H. (kbuchegg)


Lesenswert?

Tom schrieb:
> Das klingt nach einer guten Erklärung Karl Heinz.
> Ich probiers mal aus.

Ja, tu das.
Mein Bauchgefühl ist sich zu fast 100% sicher, dass du dir da selbst ein 
Ei gelegt hast und das ganze nichts mit der volatile Variablen zu tun 
hat.

von Tom (Gast)


Lesenswert?

So habs ausprobiert indem ich eine weitere globale Variable hinzugefügt 
hab.
ADC_ended
Diese setze ich in der ADC-ISR auf eins an den stellen wo ich auch 
measurement_done auf 0 oder 1 setze.

in start_measurement() setze ich sie zu beginn auf 0 und überprüfe in 
der while-Schleife:
while(ADCON1bits.ADON==1 && ADC_ended==1){}     // wait for ADC

Das Problem besteht weiterhin.
Alle achtung wie schnell ihr durch einen fremden Code gelesen habt.

von Dieter F. (Gast)


Lesenswert?

Du definierst die Variable gleich 2 mal in adc.c (über den Include adc.h 
und im Code) - davon 1 mal (im Include adc.h) als extern.

#include "adc.h"
#include "measurement.h"
#include "timer.h"
//#include "uart.h"
//#include "math.h"
//#include <stdlib.h>

/*** GLOBAL-VAR 
***************************************************************/

int adc_buffer[MEASUREMENTS*8/CHANNELS]={0};
int adc_time[MEASUREMENTS/CHANNELS][1]={{0},{0}};
volatile int measurement_done;

Ist es möglich, dass der Compiler da etwas "verschnupft" reagiert?

von Tom (Gast)


Lesenswert?

Hab ich mir noch ein Ei gelegt mit meiner art das zu überprüfen?

von Tom (Gast)


Lesenswert?

Ne hab doch eine conditional inclusion:

#ifndef adc_h                       // conditional inclusion
#define adc_h

...
extern volatile int measurement_done;
...

#endif

von Tom (Gast)


Lesenswert?

In der c-Datei definiere ich und in der h-Datei deklariere ich.

von Dieter F. (Gast)


Lesenswert?

Tom schrieb:
> Ne hab doch eine conditional inclusion:

... die verhindert, dass das entsprechende Coding in adc.h 2 mal 
includiert wird. Das erste Mal wird aber schon funktionieren - oder?

von Karl H. (kbuchegg)


Lesenswert?

Tom schrieb:


> ADC_ended
> Diese setze ich in der ADC-ISR auf eins an den stellen wo ich auch
> measurement_done auf 0 oder 1 setze.

ok.

> in start_measurement() setze ich sie zu beginn auf 0 und überprüfe in
> der while-Schleife:
> while(ADCON1bits.ADON==1 && ADC_ended==1){}     // wait for ADC

Hier hast du dir ein Ei gelegt. Das muss natürlich
1
   while(ADCON1bits.ADON==1 && ADC_ended==0){}     // wait for ADC
2
                                         ****

lauten. Denn solange dieses Flag auf 0 steht, ist die Messung ja noch 
nicht beendet und du willst weiter warten.

Darf ich dir einen Vorschlag machen:
Benenne deine Variablen so, dass ihr Name den Vorgang beschreibt und 
lass dieses dämliche Vergleichen mit 0 bzw. 1 weg. Du stellst dir damit 
immer nur selbst ein Bein.

Der Name einer Variablen ist eine 'Aussage'. ADC_ended heisst genau das: 
Ist die ADC Messung beendet?

Daher ist
1
  while( ! ADC_ended )
2
    ;
eine perfekte Aussage. Da steht in C Notation mehr oder weniger im 
Klartext: solange es nicht der Fall ist, dass die ADC Messung beendet 
ist.

Oder
1
   if( ADC_ended )

.. "Wenn die ADC Messung beendet ist"

die Abfragen auf 0 bzw. 1 lenken dich viel zu sehr von dem ab, was 
eigentlich gefragt ist. Derartige logische Variablen frägst du 
vorzugsweise nicht extra auf 0 oder 1 ab, sondern du arbeitest mit dem 
(vernünftig gewählten) Variablennamen und gegebenenfalls einem ! als 
Verneinung.
1
   if( isPinHigh )
ist perfekt. Der Name 'isPinHigh' erzählt mir alles, was ich wissen 
will. Da brauch ich nicht noch extra einen Vergleich
1
   if( isPinHigh == 1 )
das ist doppelt gemoppelt und führt nur eine zusätzliche Fehlerquelle 
ein. So wie "Wenn der Schimmel weiß ist". Das brauch ich mich nicht 
fragen. Ein Schimmel ist per Definition ein weißes Pferd. Wäre das Pferd 
nicht weiß, dann wäre es kein Schimmel.


> Das Problem besteht weiterhin.

Natürlich.
Mit der Abfrage hast du ja auch nicht darauf gewartet, dass die ADC 
Messung beendet ist. De Facto hat sich an deiner Programmlogik nichts 
geendert.

von Karl H. (kbuchegg)


Lesenswert?

Dieter Frohnapfel schrieb:

> ... die verhindert, dass das entsprechende Coding in adc.h 2 mal
> includiert wird. Das erste Mal wird aber schon funktionieren - oder?

Vergiss es.
Das passt schon so wie du das gemacht hast.

(der Include Guard ist nicht der Grund. Und Dieter empfehle ich, mal den 
Unterschied zwischen einer Definition und einer Deklaration zu lernen)

von Tom (Gast)


Lesenswert?

Ok das mit das ich auf 0 prüfen muss hab ich grad auch gemerkt.

Verstehe aber nicht warum das Problem weiterhin besteht.

Setze die Variable vor der While-Schleife auf 0.
Dann warte ich bis die ADC-ISR diese auf 1 setzt.
Das tut sie wenn sie beendet ist.
Also müsste das doch gehen oder?

Das mit der 2 fachen definition verstehe ich auch nicht.
In der c-Datei definiere ich:
volatile int Measurement_done;
Und in der h-Datei deklariere ich mit extern:
extern volatile measurement_done;

Hab das öfter so gesehen, dass in der c-Datei auch zu zugehörige h-Datei 
includiert wird. Ist das Falsch?

von Karl H. (kbuchegg)


Lesenswert?

DTom schrieb:
> Ok das mit das ich auf 0 prüfen muss hab ich grad auch gemerkt.
>
> Verstehe aber nicht warum das Problem weiterhin besteht.

Weil deine Codeänderung nichts an der Logik verändert hat.
Du hast vorher nicht auf das Beenden das ADC gewartet und du tust es 
jetzt (mit der Abfrage auf 1) immer noch nicht.


> Setze die Variable vor der While-Schleife auf 0.
> Dann warte ich bis die ADC-ISR diese auf 1 setzt.
> Das tut sie wenn sie beendet ist.
> Also müsste das doch gehen oder?

So rum geht das auch-

> Das mit der 2 fachen definition verstehe ich auch nicht.
> In der c-Datei definiere ich:
> volatile int Measurement_done;
> Und in der h-Datei deklariere ich mit extern:
> extern volatile measurement_done;

Vergiss das. Da hat dir Dieter einen Floh ins Ohr gesetzt, der nicht da 
ist.
Sobald da ein extern steht, ist das keine Definition mehr, sondern eine 
Deklaration.
Das passt schon so.

von Tom (Gast)


Lesenswert?

Nein es geht ja eben nicht.

Ich setze vor der while auf null.
Die While schleife läuft solange diese Var 0 ist.

Da ich sehe das mein prog weiter läuft heist es ja die Variable wird von 
der ADC-ISR auf eins gesetzt und zwar an genau der stalle wo auch 
measurement_done gesetzt wird.

Das kann doch nicht sein?!?!

von Tom (Gast)


Lesenswert?

OK ich brauch Urlaub oder so.
Habs jetzt.

So funktionierts natürlich nicht:
while(ADCON1bits.ADON=1 && ADC_ended==0){}     // wait for ADC

Aber so:
while(ADC_ended==0){}     // wait for ADC

Das && ist der Fehler.

Leute ich danke euch mein Problem ist erledigt.
Da muss ich wohl noch viel üben. Toll wie schnell du dich in ein Problem 
hinen gedacht hast.

von Karl H. (kbuchegg)


Lesenswert?

Tom schrieb:
> OK ich brauch Urlaub oder so.
> Habs jetzt.
>
> So funktionierts natürlich nicht:
> while(ADCON1bits.ADON=1 && ADC_ended==0){}     // wait for ADC
>
> Aber so:
> while(ADC_ended==0){}     // wait for ADC
>
> Das && ist der Fehler.
Mea Culpa.
Hätte ich auch eigentlich sehen müssen.
1
   while( ADCON1bits.ADON || !ADC_ended )

Fehler, die durch && bzw. || bzw. deren falsche Verwendung entstehen 
sind schliesslich legendär. Was auch damit zusammenhängt, dass wir im 
Alltag 'und' bzw. 'oder' unglaublich schlampig verwenden und trotzdem 
damit durchkommen.

von Tom (Gast)


Lesenswert?

Zum glück baue ich keine Flugzeuge, Rakeuten oder Satelliten.

von Dieter F. (Gast)


Lesenswert?

Karl Heinz schrieb:
Und Dieter empfehle ich, mal den Unterschied zwischen einer Definition 
und einer Deklaration zu lernen

Der Unterschied ist mir, denke ich, schon bekannt - nur wäre ich nie auf 
die Idee gekommen eine Variable in einer Code-Strecke als extern zu 
deklarieren und zusätzlich zu definieren.
Ich hätte zumindest einen Hinweis des Prä-Prozessors oder des Linkers 
erwartet ... tut sich aber nichts.
Insofern - vielen Dank, habe etwas gelernt.

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.