Forum: Mikrocontroller und Digitale Elektronik WinAvr - Variable wird nicht von einer *.c in die andere übernommen


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Markus W. (kornbanane)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich programmiere meinen Atmega16 in C mit WinAvr und stehe gerade voll 
auf dem Schlauch.

Also nur kurz zum Programm

Es geht einfach nur darum ein Telegramm über die UART0 Schnittstelle was 
vom PC an den µC empfangen wird solange in einen Empfangsbuffer zu 
schreiben, bis das Telegrammendezeichen (CR) empfangen wird.
Wenn das Telegramm fertig empfangen ist wird die Variable 
uart0_rxd_complete auf 1 gesetzt und das nachfolgende Programm kann 
irgendwas machen.

Ich habe 4 Dateien: main.c main.h uart.c uart.h

Hier jetzt nur mal die für mein Problem relevanten Codeausschnitte

uart.c:
1
//---------------------------------------------------------------------------
2
// ISR(USART_TXC_vect)
3
//
4
// functiondescription:  Interrupt für USART0 recieve. Schreibt die empfangenen Zeichen in einen Empfangsbuffer bis das Endezeichen (CR=0x0D) erkannt wurde
5
//
6
// hand over:
7
//  - input parameters: nothing
8
// returns:
9
//  - return parameter: nothing
10
//---------------------------------------------------------------------------
11
ISR(USART_RXC_vect)
12
{
13
  if(UDR!=0x0D)     // Kein Endezeichen empfangen ?
14
  {
15
    uart0_rx_buffer[uart0_rx_buffer_pointer]=UDR;
16
    uart0_rx_buffer_pointer++;
17
    if(uart0_rx_buffer_pointer>255) uart0_rx_buffer_pointer=0;    // Zur Sicherheit, kann hier aber nicht passieren, da unsigned char sowieso überläuft 
18
  }
19
  else        // Wenn ein Endezeichen empfangen wurde
20
  {
21
    uart0_rx_buffer[uart0_rx_buffer_pointer]=UDR;          // Das Endezeichen (CR=0xOD) wird als letztes in den Empfangsbuffer geschrieben
22
    uart0_rx_buffer_pointer=0;
23
    uart0_rxd_complete=1;
24
    PORTC=0x0A;
25
  }
26
}

main.h
1
//-------------------
2
// begin extern vars 
3
//-------------------
4
5
extern unsigned char uart0_rxd_complete;
6
7
//-----------------
8
// end extern vars 
9
//-----------------


main.c
1
while (1)
2
  {
3
  
4
      if(uart0_rxd_complete==1)
5
    {
6
    
7
      PORTC=0xFF;
8
      uart0_rxd_complete=0;
9
      putstring("\nFolgende Daten wurden empfangen: \n",0);
10
      
11
      while(uart0_rx_buffer[i]!=0x0D)
12
      {
13
        putch(uart0_rx_buffer[i],0);
14
      }
15
      
16
      putch('\n',0);
17
    }
18
    
19
  }


So also nun zum Problem. In der uart.c steckt der empfangsinterrupt. Das 
ganze funktioniert auch, das sehe ich an meinen LED's die ich am PortC 
angeschlossen habe. Wenn das Telegrammendezeichen empfangen wurde wird 
Portc auf 0x0A gesetzt. Gleichzeitig setze ich uart0_rxd_complete=1;.

Jetzt müsste in der main.c die Abfrage if(uart0_rxd_complete==1) true 
ergeben, aber nix da. Für die main.c ist uart0_rxd_complete immer 0 !
Es liegt auch nicht an der Abfrage die Variable ist dort wirklich immer 
0 aber wieso ? Ich habe sie doch in main.h "eingebungen" und main.c ruft 
main.h auf.

Ich dachte das aus irgendeinen Grund generell keine Variable von der 
uart.c in die main.c übertragen werden kann. Hab ich überprüft und es 
geht. Aber wieso dort nicht ? Das Programm ist sehr klein. Die Variable 
wird 100%ig nirgendswo auf 0 gesetzt.

Jetzt hab ich echt kein Plan mehr :(

von Achim K. (aks)


Bewertung
0 lesenswert
nicht lesenswert
Versuchs mal mit
1
extern volatile unsigned char uart0_rxd_complete;

von Markus W. (kornbanane)


Bewertung
0 lesenswert
nicht lesenswert
Danke, man wie blöd ....

Sag mal versteh ich das richtig, dass das jetzt nur eine 
Optimierungssache war die halt in meinem Fall daneben ging. Mit anderen 
Worten bei einem anderem Compiler oder auch bei WinAvr mit anderen 
Einstellungen hätte es auch ohne volatile funktioniert ?

von Thomas M. (langhaarrocker)


Bewertung
0 lesenswert
nicht lesenswert
Naja, ob die Optimierung nun 'daneben' ging, ist Ansichtssache. Es ist 
ja durchaus gut und richtig, wenn ein Compiler nicht unnötig Variablen 
mit vergleichsweise teuren Ram Zugriffen nochmal holt, wenn sie ohnehin 
schon gerade in einem flotten Register gepuffert sind. Nur wenn dann 
durch einen Interrupt diese Pufferung unterwandert wird, gibt's 
Probleme. Genau das zu vermeiden, dafür ist so ein volatile halt gut. 
Die Alternative wäre ja auf Optimierungen zu verzichten.

Man könnte auch auf die Idee kommen dem Compiler die Pufferung zu 
verbieten indem man ihn anweist ein Register für solch eine Variable zu 
reservieren:
register unsigned char uart0_rxd_complete asm("r2");
Aber das ist nicht zu empfehlen, da der Compiler sich durchaus auch 
erlaubt trotzdem das Register für andere Zwecke zu verwenden, wenn ihm 
freie Register ausgehen. Wenn dann ein Interrupt stattfindet und völlig 
andere Werte überschreibt ... viel Spaß bei der Fehlersuche. :)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.