PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : If-Schleife wird nicht ausgeführt



Knipser-14
06.10.2010, 22:29
Hi Community,

ich habe ein Problem mit einer If-Schleife in meinem Code:

Die Bedingung ist erfüllt, aber der Code der in der If-Schleife steht wird einfach nicht ausgeführt.

Die IF-Schleife ist ganz am Ende des Codes.


/*
* main.c
*
*
*
*/

#include <avr/io.h>
#include <avr/interrupt.h>

#define F_CPU 2048000UL

#define BAUD 9600UL
#define UBRR_BAUD ((F_CPU/(16UL*BAUD))-1)

#define LED_DDR DDRD
#define LED_PORT PORTD
#define LED_PORTPIN PD7

volatile unsigned int Zaehlerstand;

volatile struct sek //vereinbart eine neue struktur vom Typ sek
{
unsigned char bit; //ist entweder 1 oder 0 - Bit für die Sekunde ist gesetzt oder auch nicht
unsigned char wert; //zeigt an welche Information über das Bit verschlüsselt ist
};

volatile struct sek sekunde[60]; //erzeugt ein Feld aus 60 Variablensätzen die wie in sek definiert organisiert sind

volatile unsigned char counter , start; //counter zeigt an welche die aktuelle Sekunde ist


void uart_init(void)
{
// Baudrate einstellen (Normaler Modus)
UBRRH = (uint8_t) (UBRR_BAUD>>8);
UBRRL = (uint8_t) (UBRR_BAUD & 0x0ff);

// Aktivieren von receiver und transmitter
UCSRB = (1<<RXEN)|(1<<TXEN);

// Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}

void struct_init(void)
{
while ( !( UCSRA & (1<<UDRE)) ); // Warten bis der Sendepuffer frei ist
UDR = '!'; // Daten in den Puffer schreiben und damit senden


sekunde[21].wert = 1; //Sekunde 21-27 verschlüsselt die Minute
sekunde[22].wert = 2;
sekunde[23].wert = 4;
sekunde[24].wert = 8;
sekunde[25].wert = 10;
sekunde[26].wert = 20;
sekunde[27].wert = 40; //

sekunde[29].wert = 1; //Sekunde 29-34 verschlüsselt die Stunde
sekunde[30].wert = 2;
sekunde[31].wert = 4;
sekunde[32].wert = 8;
sekunde[33].wert = 10;
sekunde[34].wert = 20; //
}


ISR (INT1_vect)
{
LED_PORT |= (1<<LED_PORTPIN);

Zaehlerstand = TCNT1; //den aktuellen Zaehlerstand auslesen

TCNT1 = 0; //den Zaehlerstand zuruecksetzen

if (Zaehlerstand >= 1000) //die Zeit zwischen zwei Low-Pegeln wurde gemessen
{
if (Zaehlerstand >= 3400) //die Pause vor der nächsten Minute wurde gemessen
{
counter = 0; //counter wird resetet

start++;

while ( !( UCSRA & (1<<UDRE)) ); // Warten bis der Sendepuffer frei ist
UDR = '?'; // Daten in den Puffer schreiben und damit senden

while ( !( UCSRA & (1<<UDRE)) ); // Warten bis der Sendepuffer frei ist
UDR = start; // Daten in den Puffer schreiben und damit senden

while ( !( UCSRA & (1<<UDRE)) ); // Warten bis der Sendepuffer frei ist

UDR = '2'; // Daten in den Puffer schreiben und damit senden
}
}
else //die Zeit eines Low-Pegel wurde gemessen
{
if (Zaehlerstand >= 300) //Low-Pegel > 150ms -> 1
{
sekunde[counter].bit = 1; //setzt in der aktuellen Sekunde das Bit auf 1

counter = counter + 1; //stellt counter auf die nächste Sekunde

while ( !( UCSRA & (1<<UDRE)) ); // Warten bis der Sendepuffer frei ist

UDR = '1'; // Daten in den Puffer schreiben und damit senden
}
else //Low-Pegel < 150ms -> 0
{
sekunde[counter].bit = 0; //setzt in der aktuellen Sekunde das Bit auf 0

counter = counter + 1; //stellt counter auf die nächste sekunde

while ( !( UCSRA & (1<<UDRE)) ); // Warten bis der Sendepuffer frei ist

UDR = '0'; // Daten in den Puffer schreiben und damit senden
}
}
}

void auswertung(void)
{
unsigned char i;
unsigned char minute = 0;
unsigned char stunde = 0;

LED_PORT &= ~ (1<<LED_PORTPIN);

while ( !( UCSRA & (1<<UDRE)) ); // Warten bis der Sendepuffer frei ist
UDR = '3'; // Daten in den Puffer schreiben und damit senden

start = 1; // Flag für Auswertung zurückgesetzt

if ( (sekunde[28].bit == 1) && (sekunde[35].bit == 1) ) //Auswertung nur wenn beide Prüfbits gesetzt
{
for (i = 21 ; i <= 27 ; i++) //Auswertung der Minuten
{
if (sekunde[i].bit == 1) minute = ( minute + sekunde[i].wert );
}
for (i = 29 ; i <= 34 ; i++) //Auswertung der Stunden
{
if (sekunde[i].bit == 1) stunde = ( stunde + sekunde[i].wert );
}

while ( !( UCSRA & (1<<UDRE)) ); // Warten bis der Sendepuffer frei ist
UDR = minute; // Daten in den Puffer schreiben und damit senden

while ( !( UCSRA & (1<<UDRE)) ); // Warten bis der Sendepuffer frei ist
UDR = stunde; // Daten in den Puffer schreiben und damit senden
}
else //Prüfbits nicht gesetzt
{
while ( !( UCSRA & (1<<UDRE)) ); // Warten bis der Sendepuffer frei ist

UDR = '!'; // Daten in den Puffer schreiben und damit senden
}
}



void main(void)
{
uart_init(); //UART initialisieren

struct_init(); //Strukturen initialisieren

counter = 0;

start = 0;

GICR |= (1<<INT1); //externer Interrupt an INT1 (PD3) aktiviert

MCUCR |= (0<<ISC11) | (1<<ISC10); //Interupt bei jeder logische Veränderung an INT1 (PD3)

TCCR1B |= (1<<CS12) | (1<<CS10); // Prescaler auf 1024 -> 2.048MHz/1024 -> 2000Hz

sei(); //Interrupts freischalten

LED_DDR |= (1<<LED_PORTPIN); //LED Port als Ausgang

LED_PORT &= ~ (1<<LED_PORTPIN); //LED Port auf High -> LED leuchtet


while(1);
{
if (2==start) <================================
{
auswertung();
}
}
}


Wie man sieht wird die Variable start im Laufe des Programmes gleich 2.

Das funktioniert auch. Ich habe mir den Wert über RS232 schicken lassen. Aber die IF-Schleife wird nicht ausgeführt.

Hat jemand vielleicht eine Idee woran das liegen könnte?

Ich Programmiere unter Ubuntu mit Eclipse und AVR-Plugin.

Vielen Dank

Knipser

sast
07.10.2010, 00:50
Ich habs jetzt zwar nicht selbst getestet und auch nichts im Internet auf die Schnelle zu volatile gefunden, aber ich habe die Vermutung, das volatile immer nur für die folgende Variable gilt. In allen Beispielen wird jede Variable separat als volatile deklariert. Dann würde das bedeuten, dass start gar nicht von den Registern fern gehalten wird und deshalb im Hauptprogramm der Status nicht aktuell ist. Außerdem sollte eine ISR so kurz wie möglich sein. Besonders UART Sendungen verlängern die ISR Abarbeitung unverhältnismäßig. Rein Interessehalber wäre es interessant, die Variable start einmal so stehen zu lassen, aber dafür die UART Sachen in das Hauptprogramm auszulagern und damit zu sehen, ob sich start verändert. Wenn nicht, dann spendiere der Variable ein eigenes volatile Schlüsselwort.

sast

Knipser-14
07.10.2010, 15:50
hey sast,

erstmal danke für deine Antwort.

Ich habe start jetzt mal als volatile deklariert, aber es funktioniert immer noch nicht.

Ich habe es auch schonmal mit einem Zeiger auf start probiert, aber das funktioniert auch nicht...

Das das UART in der ISR nicht ideal ist weiß ich, aber es soll auch nur zu Testzwecken sein und bis jetzt hat es immer einwandfrei funktioniert. Da der UART nur von diesem mC benutzt wird, ist das UART auch immer frei.

Vielleicht fällt dir ja sonst noch was auf, oder auch jemand anderem.

Danke an alle die sich in meinen Code vertiefen.

mfg Knipser

sast
07.10.2010, 16:27
Wie schnell kommen denn die Interrupts hintereinander?
Versuchs doch mal mit dem Ausgeben der start Werte in der Hauptschleife und nicht in der ISR

sast

TobiKa
07.10.2010, 17:24
Es gibt keine IF-Schleifen!

start=0;
Und dann wunderst du dich das die Bedingung (2==start) nicht erfüllt ist?!
Bevor der Interrupt die Chance bekommt start zu verändern, ist das Programm schon zuende.

BMS
07.10.2010, 18:07
Der Fehler liegt kurz vor dem if:

while(1);
Damit bleibt das Programm an dieser Stelle stehen. Der Strichpunkt muss unbedingt weg! \:D/
Bin schon öfters in diese Falle getappt, deswegen schau ich da genauer hin. :mrgreen:
Grüße
Bernhard

ceekay
07.10.2010, 18:19
Kann es sein das bei

while(1);

das ";" weg muss?

edit: zu langsam =)

sast
07.10.2010, 21:33
Ja das Semikolon ist natürlich tötlich. Aber die Aussage von TobiKa ist nicht richtig, dass das Programm schon vor dem Interrupt zuende ist. Es ist eher so, dass es bis zum Stromausfall oder Reset in der while-Schleife hängt.
Den Interrupt interessiert es nicht, ob das Hauptprogramm im Kreis rennt, der kommt trotzdem.
So etwas wie If-Schleife überlese ich eigentlich, aber wenn man einmal mit der Nase drauf gestoßen wird. Das ist ja nicht nur ein Flüchtigkeitsfehler sondern zieht sich wie ein roter Faden durch den ganzen ersten Beitrag. Es handelt sich hierbei nicht um eine Schleife, sondern um eine bedingte Anweisung.

Jetzt habe ich für mich allerdings immer noch nicht geklärt, ob volatile nun für alle Variablen gilt die dahinter stehen, oder nur für die direkt folgende. Hat da jemand eine belastbare Aussage dazu? Alle Beispiele und Beschreibungen arbeiten immer nur mit einer volatilen Variable oder verwenden pro Variable eine separate Zeile.

sast

Knipser-14
08.10.2010, 01:13
Ja beim nächsten mal schreibe ich If-Anweisung...

Das Semikolon war auf jeden Fall der Fehler!

Danke an alle die geholfen haben.

mfg Knipser

PS das mit dem volatile würde mich auch noch interessieren...

askazo
08.10.2010, 06:31
Jetzt habe ich für mich allerdings immer noch nicht geklärt, ob volatile nun für alle Variablen gilt die dahinter stehen, oder nur für die direkt folgende. Hat da jemand eine belastbare Aussage dazu?

Das volatile gilt für alle dahinter stehenden variablen.
Hab das mit einem relativ einfachen Test verifiziert:


//Test1:
volatile int foo1,foo2;
int *foo3;
foo3 = &foo2;

//Test2:
volatile int foo1,foo2;
volatile int *foo3;
foo3 = &foo2;


Bei Test1 meckert der Compiler:
warning: assignment discards qualifiers from pointer target type
Bei Test2 macht er das nicht. Also ist foo2 auch als volatile deklariert.

Gruß,
askazo

sast
08.10.2010, 07:04
Danke für den Test askazo.

Das ist jetzt zwar nicht das erwartete Zitat aus einer Compileranleitung, aber macht erst einmal einen nachvollziehbaren Eindruck.
Mich hat nur die Aussage stutzig gemacht, dass man das volatile sowohl vor als auch hinter den Typ schreiben kann.

sast

RedBaron
08.10.2010, 12:26
Hi,

das liegt daran, dass der Datentyp "volatile int" ist und nicht die Variable! Der Typ bezieht sich dann auf alle folgenden Variablen in der gleichen Anweisung.

Ist z.B. ganz analog zu "unsigned": unsigned int t1, t2;

Beide(!) Variablen sind vom Typ "unsigned int".

Das ginge auch: volatile unsigned int vui1, vui1;

Wenn dein Compiler "typedef" erlaubt, kannst du schreiben:
typedef volatile unsigned int vui_t;
vui_t foo1, foo2;
vui_t *foo3 = &foo2;
foo3 ist dann ein nicht volatiler Pointer auf eine Variable eines volatilen Datentyps. Das heißt: foo3 kann im Register gehalten werden, aber der referenzierte Variableninhalt (d.h. foo2) muss jedes mal wieder neu gelesen werden.