Datum: 15.05.2008 18:57
Hallo Leute,
ich habe Probleme mit folgendem Stück Code:
...
volatile uint16_t zCounter
...
ISR(INT0_vect)
{
if (PINC & (1 << PINC0)) zCounter++;
..
}
..
int main (void)
{
uint16_t Counter;
..
Counter = 300;
zCounter = 0;
sei();
PORTC |= (1 << PC0);
while (zCounter < Counter);
PORTC &= ~(1 << PC0);
cli();
..
}
Die while- Schleife wird einfach übergangen. Wenn ich da "while
(zCounter != Counter);" schreibe, klappt alles. Im INT0-Eingang befindet
sich ein Encoder, dessen Signal ich zählen möchte. An PC0 hängt der
Motor. Ich hoffe, der Code-Auszug reicht, um das Problem darzustellen.
Datum: 15.05.2008 19:40
Sieht so aus, als ob du den Code hier eingetippt hast. Das ist keine gute Idee, poste lieber den echten Code. Da ist vermutlich ein Flüchtigkeitsfehler drin, der hier nicht drin ist.
Datum: 15.05.2008 19:49
das Problem ist, dass ich mit einem anderen Rechner im Netz bin. Hab leider im Moment keine Möglichkeit, den Code zu kopieren.
Datum: 15.05.2008 19:50
Kann es sein, dass der Compiler die While-Schleife einfach mal wegoptimiert? Wobei das "volatile" das je verhindern sollte. Definiere "Counter" doch auch mal volatile.
Datum: 15.05.2008 20:40
Da ist nichts wegzuoptimieren, es muss auch ohne volatile bei Counter funktionieren. Paranoia: du benutzt nicht zufälliger Weise WinAVR-20080402?
Datum: 15.05.2008 20:47
Wie ist der INT0 konfiguriert, als Flanken- oder als Level-Interrupt? Was veranlasst dich zur Vermutung, dass die While-Schleife übersprungen wird? Meine Vermutung: INT0 ist als Level-Interrupt konfiguriert, und der Low-Pegel am Interrupteingang dauert so lange an, dass der Interrupthandler währenddessen mindestens 300mal direkt hintereinander abgearbeitet werden kann. Weil das schneller geht, als dein Auge es erfassen kann, denkst du, die While-Schleife wurde übersprungen. Warum verhält sich das Programm bei "while(zCounter != Counter);" anders? Da zwischen zwei Interrupthandleraufrufen genau eine Instruktion der main-Funktion ausgeführt wird, wird zwischen zwei Prüfungen der While-Bedingung der Counter mehrmals inkrementiert. Je nach Timing kann es deswegen passieren, dass in einem Schleifendurchlauf bspw. der Wert 299 gesehen wird, im nächsten Durchlauf steht er aber schon auf einem Wert >300, so dass die Schleife nicht abbricht. Vielleicht tut sie dies aber, nachdem Counter ein oder mehrere Male bei 65535 überlaufen ist und die While-Abfrage irgendwann doch bei exakt 300 stattfindet. Bis dahin hat sich die Schleife aber zigtausende Male gedreht, so dass dein Auge die Verzögerung tatsächlich wahrnimmt.
Datum: 15.05.2008 20:48
>genau den benutze ich. Gibt es da Probleme?
Wurde wegen Bugs gestrichen.
Nimm erstmal den 200705xx.
Datum: 15.05.2008 20:55
holger wrote: >>genau den benutze ich. Gibt es da Probleme? > > Wurde wegen Bugs gestrichen. > Nimm erstmal den 200705xx. Quatsch. Nimm einfach einen aktuelleren: http://sourceforge.net/project/showfiles.php?group_id=68108 Die neueste Version ist vom 12.5.
Datum: 15.05.2008 21:02
oh Mann, richtig. Ich hab mich beim MCUCR vertan und den Low Level als Interrupt definiert. So ist das, wenn man den nur als Hex-Zahl schreibt. Dann wird die Fehlersuche schwer. Vielen Dank für den Tipp, yalu. Das Kann dann natürlich nichts werden, wenn ich nur den Home-Puls des Encoders nutze und er die meiste Zeit Low ist.
Datum: 15.05.2008 21:11
Upgrade trotzdem das WinAVR. Die Version 20080402 hatte einen richtig üblen Bug. Einer der Patches für den Xmega hatte unbeabsichtigterweise einen Einfluss auf nicht-Xmega-CPUs und hat bei diesen komplett falsche Sprünge generiert.
Datum: 15.05.2008 21:18
Ein Fehler ist noch drin:
while (zCounter < Counter);
|
Das sind 16-Bit-Werte. Da AVR 16 Bits nicht atomar laden kann, kann es sein, daß zwischen dem Einlesen der einzelnen Bytes eine IRQ getriggert wird. Dann würde das eingelesene zCounter aus zwei Teilen bestehen: einem alten Byte von vor Ausführung der ISR, das schon in einem Register steht, und einem neuen Byte, das durch die ISR verändert wurde. Daher muss atomar auf zCounter zugegriffen werden, um sporadische Fehlfunktion zu vermeiden:
uint16_t z; do { cli(); z = zCounter; sei(); } while (z < Counter); |
Datum: 16.05.2008 15:56
@Georg-johann Lay es sind zwar jetzt noch keine Probleme aufgetreten, aber ich werde dies ändern. Klingt auch einleuchtend.
Antwort schreiben
Die Angabe einer Email-Adresse ist freiwillig. Wenn Sie automatisch per Email über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.
Wichtige Regeln - erst lesen, dann posten!
- Suchfunktion und Betreffsuche benutzen - vielleicht gibt es schon einen ähnlichen Beitrag
- Aussagekräftigen Betreff wählen
- Im Betreff angeben um welchen Controllertyp es geht (AVR, PIC, ...)
- Groß- und Kleinschreibung verwenden
- Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang
- JPEG-Dateien (.jpg) nur für Fotos und Scans verwenden
- Schaltpläne, Screenshots usw. als PNG oder GIF anhängen
Formatierung (mehr Informationen...)
- [c]C-Code[/c]
- [avrasm]AVR-Assembler-Code[/avrasm]
- [pre]vorformatierter Text (z.B. Code in anderen Sprachen)[/pre]
- [math]Formel in LaTeX-Syntax[/math]
- [[Titel]] - Link zu Artikel


