mikrocontroller.net

Forum: Compiler & IDEs debug Problem do-while Schleife


Autor: Andi S. (laserandi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich versuche gerade folgendes Programm mit AVR-Studio 4 zu 
debuggen/simulieren:
/* Zeichen empfangen */
uint8_t uart_getc(void)
{
  while (!(UCSRA & (1<<RXC)));      //warten bis Zeichen verfuegbar
  return UDR;                       //Zeichen aus UDR zurueckgeben
}

int main (void)
{
//Grundeinstellungen

  char Zeichen = '0';              //Puffervariable für empfangene Zeichen
  uint16_t PortAB = 0;             //Ausgabevariable für Port A & B
  uint8_t* Buffer = 0;

//UART-Einstellungen
  UCSRC |= (1<<URSEL)|(3<<UCSZ0);  //Asynchron 8N1, Frameformat 8-Bit
  UBRRH = UBRR_VAL >> 8;           //Baudrate einstellen
  UBRRL = UBRR_VAL & 0xFF;

  UCSRB |= ( 1 << RXEN );          //RX (Empfang) aktivieren

  do
  {                                //Solange kein s empfangen wurde,
    Zeichen = uart_getc;           //Zeichen von RS232 auslesen
  } while (Zeichen != 's');
  do
  {         
    Zeichen = uart_getc;  
    *Buffer++=atoi(Zeichen); 
  } while (Zeichen != 'e');

  return 0;
} 
Problem:
Sobald das Programm bei dem ersten while angekommen ist, läuft es in 
einer Endlosschleife - auch wenn ich RXC auf 1 und UDR auf "s" bzw. 0x73 
setze.
Lässt sich so ein c-Programm grundsätzlich nicht simulieren? Bei 
Assembler hatte ich bis jetzt keine Probleme UART zu simulieren. Oder wo 
ist mein Denkfehler?

Autor: Jan M. (mueschel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lies nochmal die Stelle "Aufrufen von Funktionen" in einem C-Buch deiner 
Wahl. uart_getc(); muss es heißen. - Sollte aber auch eine Warnung im 
Compiler erzeugen!

Speicher für Buffer solltest du natürlich auch noch bereitstellen, so 
schreibst du irgendwo in deinem Adressraum rum bis du was wichtiges 
triffst.

Autor: Andi S. (laserandi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sehr cool, danke für die schnelle Antwort jetzt springt er zu
uart_getc().

>Speicher für Buffer solltest du natürlich auch noch bereitstellen

Ich fange gerade erst wieder mit c an.
In Assembler lässt sich die erste freie ram-Adresse so definieren:
.equ ram = 0x60
und dann z.B. mit
st  X+, temp
beschreiben.
Kannst Du bitte ein kleines c-Beispiel geben.
-DANKE-

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andi S. wrote:

> Kannst Du bitte ein kleines c-Beispiel geben.

Angelehnt an den bisherigen Code:
uint8_t Buffer[10];  // Speicher für 10 Werte
uint8_t* BufferPtr = Buffer;
...
*BufferPtr++ = ...

Ich würde eher mit einem Index arbeiten:
uint8_t Buffer[10];  // Speicher für 10 Werte
uint8_t Index = 0;
...
Buffer[Index++] = ...

*Buffer++=atoi(Zeichen);
Das geht so nicht, denn atoi erwartet einen Pointer auf einen String.

Grundsätzlich sollte man (gerade als Anfänger) die vom Compiler 
ausgespuckten Warnungen ernst nehmen.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert

// Hier fehlen sämtliche Includes (nicht mein Problem)

/* Zeichen empfangen */
uint8_t uart_getc(void)
{
  while (!(UCSRA & (1<<RXC)));      //warten bis Zeichen verfuegbar
  return UDR;                       //Zeichen aus UDR zurueckgeben
}

int main (void)
{
  //Grundeinstellungen
  char Zeichen = '\0';             //Puffervariable für empfangene Zeichen
  uint16_t PortAB = 0;             //Ausgabevariable für Port A & B
  uint16_t Buffer = 0;             //### geändert ###

  //UART-Einstellungen
  UCSRC |= (1<<URSEL)|(3<<UCSZ0);  //Asynchron 8N1, Frameformat 8-Bit
  UBRRH = UBRR_VAL >> 8;           //Baudrate einstellen
  UBRRL = UBRR_VAL & 0xFF;
  UCSRB |= ( 1 << RXEN );          //RX (Empfang) aktivieren

  do
  {                                //Solange kein s empfangen wurde,
    Zeichen = uart_getc();         //Zeichen von RS232 auslesen
  } while (Zeichen != 's');
  
  /*
    Eingabe einer DEZIMALZAHL (max. 16-Bit unsigned: 0..65535)
    Ende der Eingabe mit 'e' oder Nicht-Ziffer
    Keine Prüfung auf Overflow!
  */
  Buffer = 0;
  do
  {         
    Zeichen = uart_getc();
    if (Zeichen >= '0' && Zeichen <= '9') // Ist Ziffer?
    { // JA, umrechnen!
      Buffer *= 10; // Bisheriges Ergebnis eine Dezimalstelle höher
      Buffer += (uint16_t) (Zeichen - '0');  // Ziffer => Zahl => als Einerstelle addieren
    }
    else 
      break; // Keine Ziffer => Raus aus do-while!
  } while (Zeichen != 'e');

  return 0;
} 


Autor: Andi S. (laserandi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Super, ich werde gleich mal ein bisschen testen.
Da ich vorher Assembler programmiert habe, fehlt mir bei c immer der 
Hardwarebezug (auch das GCC-Tutorial bringt hier irgendwie keine näheren 
Infos)
> uint8_t Buffer[10];
Wird damit automatisch der ram angesprochen und die erste freie Adresse 
automatisch auf 0x60 gesetzt?
Wenn ich
uint8_t Index = 0;
schreibe, wird damit automatisch ein freies Register angesprochen (z.B. 
R25)?

> Buffer *= 10; // Bisheriges Ergebnis eine Dezimalstelle höher
> Buffer += (uint16_t) (Zeichen - '0');  // Ziffer => Zahl => als Einerstelle 
addieren
Danke, das ist genau was ich suche. Ich hatte auch schon mal daran 
gedacht, statt "atoi", manuell umzurechnen.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andi S. wrote:

>> uint8_t Buffer[10];
> Wird damit automatisch der ram angesprochen und die erste freie Adresse
> automatisch auf 0x60 gesetzt?

Da es eine lokale Variable ist, liegen diese 10 Bytes auf dem Stack. 
Aber was interessiert es dich, wo genau diese 10 Bytes liegen?

> Wenn ich
> uint8_t Index = 0;
> schreibe, wird damit automatisch ein freies Register angesprochen (z.B.
> R25)?

Der Compiler wird es sehr wahrscheinlich dahingehend optimieren, ist 
aber kein Muss.

Autor: Andi S. (laserandi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aha wieder was dazu gelernt.

> Da es eine lokale Variable ist, liegen diese 10 Bytes auf dem Stack.
> Aber was interessiert es dich, wo genau diese 10 Bytes liegen?

Wenn ich z.B. 500 Bytes speichern möchte wird das, je nach µC, mit dem 
Stack ja schon eng (das ist wahrscheinlich so ein Assemblertick, immer 
wissen zu wollen wie was funktioniert).

Gibt es denn überhaupt eine Möglichkeit den sram gezielt anzusprechen?

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andi S. wrote:
> Aha wieder was dazu gelernt.
>
>> Da es eine lokale Variable ist, liegen diese 10 Bytes auf dem Stack.
>> Aber was interessiert es dich, wo genau diese 10 Bytes liegen?
>
> Wenn ich z.B. 500 Bytes speichern möchte wird das, je nach µC, mit dem
> Stack ja schon eng (das ist wahrscheinlich so ein Assemblertick, immer
> wissen zu wollen wie was funktioniert).

Das muss man auch in C wissen, sonst liegst du früher oder später auf 
der Nase...

> Gibt es denn überhaupt eine Möglichkeit den sram gezielt anzusprechen?

Es gibt unterschiedlliche Speicherklassen in C:

auto (die normalen lokalen Variablen) leben in Registern oder auf dem 
Stack oder sind wegoptimiert, gültig innerhalb des Blocks, in dem sie 
stehen.

static stehen, wie der Name sagt, statisch im RAM. Haben also 
unbegrenzte Gültigkeitsdauer.

extern dito, allerdings mit Sichtbarkeit über Modulgrenzen hinweg.

dynamisch via malloc et al. besorgter Speicher (auf nem kleiner µC 
eher der Overkill)

exoten es gibt auch Mischformen von auto und global, etwa bei lokalen 
Funktionen die über Trampolines betreten werden. Aber recht speziell 
das...

Wenn Du also schreibst
extern int A; // steht üblicherweise im Header (.h)
int A;
static int B;

int * foo (void)
{
    static int c;
    static int e;
    int d;

    return &e;
}

Ist A extern und in anderen Modulen zugreifbar, steht im RAM bzw. kommt 
erstmal in eine bestimmte Section (.text) welche dann im RAM landet.

B ist static (RAM).

c,e sind auch static (überleben verlassen von foo). Ihre Adresse ist 
ausserhalb von foo gültig.

d ist lokal (auto), die Adresse von d ist ausserhalb von foo nicht 
gültig.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wenn ich z.B. 500 Bytes speichern möchte wird das, je nach µC, mit
> dem Stack ja schon eng

Wieso? Der Stack steht auch nur im RAM. Ob die 500 Bytes durch Stack 
oder durch eine statische Variable belegt sind, macht keinen 
Unterschied, außer daß die lokale Variable nur wärend der Ausführung der 
Funktion existiert und nicht über die gesamte Programmlaufzeit hinweg 
500 Bytes Platz verbraucht.

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]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [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.