Forum: Compiler & IDEs debug Problem do-while Schleife


von Andi S. (laserandi)


Lesenswert?

Hallo,
ich versuche gerade folgendes Programm mit AVR-Studio 4 zu 
debuggen/simulieren:
1
/* Zeichen empfangen */
2
uint8_t uart_getc(void)
3
{
4
  while (!(UCSRA & (1<<RXC)));      //warten bis Zeichen verfuegbar
5
  return UDR;                       //Zeichen aus UDR zurueckgeben
6
}
7
8
int main (void)
9
{
10
//Grundeinstellungen
11
12
  char Zeichen = '0';              //Puffervariable für empfangene Zeichen
13
  uint16_t PortAB = 0;             //Ausgabevariable für Port A & B
14
  uint8_t* Buffer = 0;
15
16
//UART-Einstellungen
17
  UCSRC |= (1<<URSEL)|(3<<UCSZ0);  //Asynchron 8N1, Frameformat 8-Bit
18
  UBRRH = UBRR_VAL >> 8;           //Baudrate einstellen
19
  UBRRL = UBRR_VAL & 0xFF;
20
21
  UCSRB |= ( 1 << RXEN );          //RX (Empfang) aktivieren
22
23
  do
24
  {                                //Solange kein s empfangen wurde,
25
    Zeichen = uart_getc;           //Zeichen von RS232 auslesen
26
  } while (Zeichen != 's');
27
  do
28
  {         
29
    Zeichen = uart_getc;  
30
    *Buffer++=atoi(Zeichen); 
31
  } while (Zeichen != 'e');
32
33
  return 0;
34
}
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?

von Jan M. (mueschel)


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.

von Andi S. (laserandi)


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:
1
.equ ram = 0x60
und dann z.B. mit
1
st  X+, temp
beschreiben.
Kannst Du bitte ein kleines c-Beispiel geben.
-DANKE-

von Stefan E. (sternst)


Lesenswert?

Andi S. wrote:

> Kannst Du bitte ein kleines c-Beispiel geben.

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

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

1
*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.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

1
// Hier fehlen sämtliche Includes (nicht mein Problem)
2
3
/* Zeichen empfangen */
4
uint8_t uart_getc(void)
5
{
6
  while (!(UCSRA & (1<<RXC)));      //warten bis Zeichen verfuegbar
7
  return UDR;                       //Zeichen aus UDR zurueckgeben
8
}
9
10
int main (void)
11
{
12
  //Grundeinstellungen
13
  char Zeichen = '\0';             //Puffervariable für empfangene Zeichen
14
  uint16_t PortAB = 0;             //Ausgabevariable für Port A & B
15
  uint16_t Buffer = 0;             //### geändert ###
16
17
  //UART-Einstellungen
18
  UCSRC |= (1<<URSEL)|(3<<UCSZ0);  //Asynchron 8N1, Frameformat 8-Bit
19
  UBRRH = UBRR_VAL >> 8;           //Baudrate einstellen
20
  UBRRL = UBRR_VAL & 0xFF;
21
  UCSRB |= ( 1 << RXEN );          //RX (Empfang) aktivieren
22
23
  do
24
  {                                //Solange kein s empfangen wurde,
25
    Zeichen = uart_getc();         //Zeichen von RS232 auslesen
26
  } while (Zeichen != 's');
27
  
28
  /*
29
    Eingabe einer DEZIMALZAHL (max. 16-Bit unsigned: 0..65535)
30
    Ende der Eingabe mit 'e' oder Nicht-Ziffer
31
    Keine Prüfung auf Overflow!
32
  */
33
  Buffer = 0;
34
  do
35
  {         
36
    Zeichen = uart_getc();
37
    if (Zeichen >= '0' && Zeichen <= '9') // Ist Ziffer?
38
    { // JA, umrechnen!
39
      Buffer *= 10; // Bisheriges Ergebnis eine Dezimalstelle höher
40
      Buffer += (uint16_t) (Zeichen - '0');  // Ziffer => Zahl => als Einerstelle addieren
41
    }
42
    else 
43
      break; // Keine Ziffer => Raus aus do-while!
44
  } while (Zeichen != 'e');
45
46
  return 0;
47
}

von Andi S. (laserandi)


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
1
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.

von Stefan E. (sternst)


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
1
> 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.

von Andi S. (laserandi)


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?

von Johann L. (gjlayde) Benutzerseite


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
1
extern int A; // steht üblicherweise im Header (.h)
2
int A;
3
static int B;
4
5
int * foo (void)
6
{
7
    static int c;
8
    static int e;
9
    int d;
10
11
    return &e;
12
}

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.

von Rolf Magnus (Gast)


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.

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
Noch kein Account? Hier anmelden.