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
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?
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.
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.
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?
Aber nicht nur Codefetzen sondern was lauffähiges bitte.
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.
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.
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.
ups wusst nicht das das dann so läuft.
Au, Sch... Karl Heinz? Kommst Du mal, bitte?
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.
Sind die ADCCon1Bits auch als "volatile" definiert? Leider fehlt dieser Teil deines Programms.
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.
Das klingt nach einer guten Erklärung Karl Heinz. Ich probiers mal aus.
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.
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.
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?
Hab ich mir noch ein Ei gelegt mit meiner art das zu überprüfen?
Ne hab doch eine conditional inclusion: #ifndef adc_h // conditional inclusion #define adc_h ... extern volatile int measurement_done; ... #endif
In der c-Datei definiere ich und in der h-Datei deklariere ich.
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?
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.
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)
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?
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.
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?!?!
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.
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.
Zum glück baue ich keine Flugzeuge, Rakeuten oder Satelliten.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.