Forum: Mikrocontroller und Digitale Elektronik Fehler nach Einfügen einer Else-Anweisung


von Jonas E. (jonas_e43)


Lesenswert?

Hallo,
nachdem ich in meinem Programm eine weitere Else-Anweisung eingefügt 
habe,
funktioniert es nicht mehr vernünftig.

Zum Programm:
Das uart_receive_complete bool wird auf true gesetzt, wenn ein String 
über eine UART-Interruptroutine empfangen wurde. Dann wird damit 
begonnen, den String zu verarbeiten. Das funktioniert auch, solange kein 
weiteres Else verwendet wird.
1
if(uart_receive_complete)
2
    {
3
      lcd_clear();
4
      char cmd = uart_string[0];
5
      if ( cmd == CMD_HEADER )
6
      {
7
        strcpy(g_Header, uart_string+1);
8
      }
9
      else if ( cmd == CMD_TAG )
10
      {
11
        timer1_disable();
12
        timer1_reset();
13
        char accepted = uart_string[1];
14
        
15
        if ( accepted == UART_TRUE )
16
        {
17
          lcd_stringCenter("Welcome", 1);
18
          char* name = ( uart_string + 2);
19
          lcd_stringCenter(name, 2);
20
          led_toggle(LED_ACCEPT);
21
          delay(3000);
22
        }
23
        else if ( accepted == UART_FALSE )
24
        {
25
          lcd_stringCenter("ID unknown.", 1);
26
          lcd_stringCenter("Access denied.", 2);
27
          led_toggle(LED_DENIED);
28
          delay(3000);
29
        }
30
      /*  else
31
        {
32
          lcd_stringCenter("ID transmitted.", 1);
33
          delay(2500);
34
        }
35
      */
36
        rfid_enable();
37
      }
38
      else
39
      {
40
        lcd_stringCenter("Unknown command:", 1);
41
        lcd_stringCenter(uart_string, 2);
42
        led_toggle(LED_ACCEPT);
43
        led_toggle(LED_DENIED);
44
      }
45
46
      free(uart_string);
47
      uart_receive_complete = false;
48
      LED_PORT &= ~(1<<LED_ACCEPT);
49
      LED_PORT &= ~(1<<LED_DENIED);
50
      renderHeader();
51
    }

Wenn ich aber nun die Else-Anweisung ausklammere um eine weitere 
Verarbeitungsmöglichkeit hinzuzufügen, wird g_header nicht mehr 
vollkommen erkannt. Es wird lediglich, der erste Buchstabe kopiert.
Ich flashe mit diesem Programm einen Attiny 4313. Der Flashspeicher ist 
dann zu etwa 95% voll. Woran könnte das Problem liegen.
So langsam bin ich am verzweifeln.
Wenn Jemandem etwas auffällt würde ich mich über Hinweise oder Lösungen 
freuen.
MfG Jonas

von Dr. Sommer (Gast)


Lesenswert?

Jonas E. schrieb:
> free(uart_string);
Du verwendest dynamische Speicherverwaltung auf einem Controller mit 256 
Bytes RAM?! Du verwendest fröhlich ewig lange Delays während derer das 
Programm auf keine Eingaben reagiert? Eventuell klappt das, eventuell 
generiert das aber auch schwierig zu findende Probleme...

von holger (Gast)


Lesenswert?

>Du verwendest dynamische Speicherverwaltung auf einem Controller mit 256
>Bytes RAM?! Du verwendest fröhlich ewig lange Delays

und Strings die vermutlich auch im RAM liegen.

z.B.         lcd_stringCenter("Unknown command:", 1);

Das else

          lcd_stringCenter("ID transmitted.", 1);


hat dem Stack vermutlich nur noch den Rest gegeben. Aus die Maus.

von holger (Gast)


Lesenswert?

>Du verwendest dynamische Speicherverwaltung auf einem Controller mit 256
>Bytes RAM?

Es sind nur 128 Byte;)

von Thomas E. (thomase)


Lesenswert?

holger schrieb:
>>Du verwendest dynamische Speicherverwaltung auf einem Controller mit 256
>>Bytes RAM?
>
> Es sind nur 128 Byte;)
Nee. Das sind 256. Aber trotzdem...

mfg.

von Jonas E. (jonas_e43)


Lesenswert?

Wie kann aus dem Ram die nicht mehr benötigten Strings entfernen, um 
wieder Speicherplatz zu erlangen?
Gruß Jonas

von Dr. Sommer (Gast)


Lesenswert?

Jonas E. schrieb:
> Wie kann aus dem Ram die nicht mehr benötigten Strings entfernen, um
> wieder Speicherplatz zu erlangen?
Gar nicht. Allerdings sollte der GCC clever genug sein, die Strings in 
den Flash zu packen. Mach dich mal schlau wie man Pointer auf 
PROGMEM-Arrays (aka. String-Konstanten) mit dem AVR-GCC an Funktionen 
übergibt. Und nimm alle malloc&free aus dem Programm...

von holger (Gast)


Lesenswert?

>Wie kann aus dem Ram die nicht mehr benötigten Strings entfernen, um
>wieder Speicherplatz zu erlangen?

Überflüssige Ausgaben gar nicht erst machen.

          lcd_stringCenter("ID unknown.", 1);
          lcd_stringCenter("Access denied.", 2);

Da reicht doch auch:

          lcd_stringCenter("ID unknown", 1);
          lcd_stringCenter("Access denied", 2);

Ich hab jetzt mal die beiden '.' weggelassen. Spart zwei Byte.

Oder

          lcd_stringCenter("ID?", 1);
          lcd_stringCenter("Access denied", 2);

Nochmal 7 Byte weniger.

Oder einfach nur

         lcd_stringCenter("Access denied", 1);

Es gibt immer einen Weg RAM zu sparen.

von Dr. Sommer (Gast)


Lesenswert?

holger schrieb:
> Es gibt immer einen Weg RAM zu sparen.
Wieso RAM?! String-Literale gehören in den Flash! Und können auch direkt 
von da byteweise gelesen&verarbeitet werden, braucht 0 Bytes RAM.

von holger (Gast)


Lesenswert?

>> Es gibt immer einen Weg RAM zu sparen.
>Wieso RAM?! String-Literale gehören in den Flash!

Das weiss ich selber, ich bin ja nicht blöd. Im Flash
stehen die sowieso. Woher sollen die sonst ins RAM kommen?

Schreib ihm seine Routine um Daten aus dem Flash zu nehmen
doch einfach. Da hatte ich jetzt im Moment keinen Bock drauf.

Ich hab ihm nur einen Weg gezeigt wie er da ohne grosse
Verrenkungen evtl. noch mal so davonkommt.

von Jonas E. (jonas_e43)


Lesenswert?

Achso jetzt versteh ich das :D.
Würde mich trotzdem über eine Routine freuen.
Gruß Jonas

von holger (Gast)


Lesenswert?

>Achso jetzt versteh ich das :D.
>Würde mich trotzdem über eine Routine freuen.

Dann zeig doch mal deinen Code für lcd_stringCenter().

von Jonas E. (jonas_e43)


Lesenswert?

lcd_StringCenter():
1
void lcd_stringCenter(const char* data, int row)
2
{
3
  if ( sizeof(data) > 0 )
4
  {
5
    int length = strlen(data);
6
    int column = 0;
7
    
8
    if ( length <= LCD_COLOUMS )
9
    {
10
      column = LCD_COLOUMS / 2 - ( length + ( length % 2 ) ) / 2;
11
    }
12
    
13
    lcd_stringAt(data, column, row);
14
  }
15
}
lcd_stringAt(data, column, row):
1
void lcd_stringAt( const char *data, int coloumn, int row )
2
{
3
  lcd_setcursor(coloumn, row);
4
  
5
  while( *data != '\0' )
6
  {
7
    if ( coloumn >= LCD_COLOUMS )
8
    {
9
      coloumn = 0;
10
      row++;
11
      lcd_setcursor(coloumn, row);
12
    }
13
    lcd_data( *data++ );
14
15
    coloumn++;
16
  }
17
}

von holger (Gast)


Lesenswert?

>lcd_StringCenter():

Das jetzt auf PROGMEM umzubauen sieht nicht so einfach aus.

Aber mal ein paar andere Tips vor dem schlafen gehen:

>void lcd_stringCenter(const char* data, int row)

int row? Wozu? Kann row negativ werden? Dein Display hat ja
auch nur zwei Zeilen. Wozu brauchst du da einen 16 Bit Wert?

void lcd_stringCenter(const char* data, uint8_t row)

ist doch besser oder nicht?

Der gleiche Müll:

    int length = strlen(data);
    int column = 0;

Besser

    uint8_t length = strlen(data);
    uint8_t column = 0;

Noch son Ding. Ausser int scheinst du ja nichts anderes zu kennen.

>void lcd_stringAt( const char *data, int coloumn, int row )

void lcd_stringAt( const char *data, uint8_t coloumn, uint8_t row )

Das gleiche vermutlich mit   lcd_setcursor(coloumn, row);

sizeof(data) ist immer grösser 0.

  if ( data != 0 )

usw.

Bring erstmal diesen Unsinn in Ordnung.
Das wird dein Programm schon mal ordentlich eindampfen.

von Jonas E. (jonas_e43)


Lesenswert?

Alles klar.
Ich bin noch an das Programmieren mit C# gewöhnt wo man nicht so auf 
Speicher achten braucht. Nun habe ich alle 16 bit Ints zu uint8_t 
"verwandelt". Spart einen guten Teil an Speicher ein. Nur löst das 
leider nicht mein grundlegendes Problem...
Gruß Jonas

von Jonas E. (jonas_e43)


Lesenswert?

Hallo Holger,
ist es möglich, dass du mir deine E-Mail Adresse per PN schreibst, 
sodass ich dir das komplette Programm mal schicken könnte und du es dann 
einmal ansehen könntest? Was könnte z.B. verbessert werden?
Würde mich echt sehr darüber freuen.
Gruß Jonas

von holger (Gast)


Lesenswert?

>Hallo Holger,
>ist es möglich, dass du mir deine E-Mail Adresse per PN schreibst,

Nö;)

Ich hab mich mal an deiner Funktion vergangen. Nur rein
theoretisch, könnten also noch Fehler drin sein.

So müsste das mit Strings aus dem Flash klappen.
Ohne Gewehr!
1
void lcd_stringCenter_P(const char* data, uint8_t row)
2
{
3
  char c;
4
5
  if ( data > 0 )
6
  {
7
    uint8_t length = strlen_P(data);
8
    uint8_t column = 0;
9
    
10
    if ( length <= LCD_COLOUMS )
11
    {
12
      column = LCD_COLOUMS / 2 - ( length + ( length % 2 ) ) / 2;
13
    }
14
    
15
    lcd_setcursor(coloumn, row);
16
  
17
    while((c = pgm_read_byte(data++)))
18
    {
19
      if ( coloumn >= LCD_COLOUMS )
20
      {
21
        coloumn = 0;
22
        row++;
23
        lcd_setcursor(coloumn, row);
24
      }
25
      lcd_data(c);
26
27
      coloumn++;
28
    }
29
  }
30
}


Du ersetzt jetzt aber nicht deine void lcd_stringCenter() mit dieser
Funktion. Du nimmst dies als eine neue Funktion mit rein.

Da wo du z.B

          lcd_stringCenter("ID unknown.", 1);

schreibst musst du jetzt

          lcd_stringCenter_P((PSTR)"ID unknown.", 1);

draus machen.

Strings aus dem RAM kannst du damit nicht ausgeben! Also

          lcd_stringCenter(name, 2);

bleibt so wie es war.

Viel Spass damit;)

von Jonas E. (jonas_e43)


Lesenswert?

Wenn ich diese Funktion verwende:
1
lcd_stringCenter_P((PSTR)"ID unknown.", 1);

Er schmeißt dann aber bei mir einen Feher raus:
Error  6  too few arguments to function 'lcd_stringCenter_P'

von Fabian O. (xfr)


Lesenswert?

Es muss heißen:
1
lcd_stringCenter_P(PSTR("ID unknown."), 1);

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.