RST bei Buffernutzung

Gast #1799741
Lesenswert?

Hallo!

ich bekomme immer einen RST, mehr kann mein code nicht...?!?
ATMEGA32 mit WINAVR, AVRStudio 4
1
#define BUFFER_SIZE 70  //buffergröße in Byte
2
volatile unsigned char buffer[BUFFER_SIZE] = "";
3

4
void kill_buffer()
5
{
6
  pread = 0;
7
  pwrite = 0;
8
  for(int ui1=0;ui1<BUFFER_SIZE;ui1++)
9
  {
10
    buffer[ui1]="";
11
    _delay_us(1000);
12
  }
13
}
14

15
int main()
16
{
17
  uart_puts("RST\r\n");
18
  kill_buffer();
19
}
#1799754
Lesenswert?

Floh schrieb:
> Timo P schrieb:
>> int main()
>> {
>>   uart_puts("RST\r\n");
>>   kill_buffer();
>
>   while(1)
>     {
>     }
>
>> }
>
> Da fehlt die abschließende Endlosschleife, da sonst das weitere
> Verhalten des uC nicht definiert ist (Reset, Programmneustart,...)

Im Grunde hast du recht.
Allerdings schickt die gcc-Runtime nach einem return von main() den µC 
in eine Endlosschleife. So gesehen ist das Verhalten (beim gcc) 
definiert.
Gast #1799764
Lesenswert?

Karl heinz Buchegger schrieb:
> Allerdings schickt die gcc-Runtime nach einem return von main() den µC
> in eine Endlosschleife. So gesehen ist das Verhalten (beim gcc)
> definiert.

Wieder was gelernt :-)

Timo P schrieb:
> mein main hat eine for(;;) schleife in der der UART-RX-buffer abgefragt
> wird

davon seh ich nichts im Programmausschnitt??

Wie wärs wenn du mal genau beschreibst, was du erreichen willst, und 
dann, was stattdessen passiert?
Gast #1799771
Lesenswert?

ok....
1
int main( void )
2
{
3
  DDRA |= (1<<PIN);
4
  char s[22];
5
  unsigned char flag1,flag2,flag3,flag4;
6
    DDRC |= 0x01;
7
  PORTC |= 0x01;
8
  DDRB &= ~(1<<1);               // Conf. pin for recv. control signal 
9
  DDRD &= ~(1<<LIMIT_SWITCH_IN_PIN);  // Conf. pin for limit switch
10
  DDRD &= ~(1<<LIMIT_SWITCH_OUT_PIN);  // Conf. pin for limit switch
11
  DDRD |=  (1<<INSERT_PIN);        // Conf. pin for inserting "Falle"
12
  DDRD |=  (1<<RELEASE_PIN);        // Conf. pin for releasing "Falle"
13
    send = 0;
14
    _delay_ms(100);
15
    uart_init(BAUD);
16
  _delay_ms(100);
17
  strcpy(buffer, "");
18
    sei();
19
  uart_puts("RST\r\n");        // Reset of Hardware
20
  sprintf(s,"Buffersize:%d\r\n",BUFFER_SIZE);
21
  uart_puts(s);
22
  kill_buffer();
23
  
24
  unsigned char trigger = 0;
25
  unsigned char tmp = EEPReadByte(IS_CONFIGERD);
26
  //sprintf(s,"IS_CONFIGERD:%X\t\r\n",tmp);     // EEPROM-Wert von Adresse 0x20 lesen 
27
  //uart_puts(s);
28

29
    for(;;)
30
    {
31
    //if(RESET_PORT&(1<<RESET_PIN))EEPWriteByte(IS_CONFIGERD, 0x01);
32
    _delay_ms(10);
33
    sprintf(s,"<%s> \r",buffer);uart_puts(s);
34

35
    
36
     if(strstr(buffer,"\n"))    // command oder command-artiges erhalten
37
     {
38
       cli();
39
      if(strstr(buffer,"config:start\n"))  
40
        {
41
        kill_buffer();
42
        uart_puts("config:start:OK\n");
43
        sei();
44

45
      }
46
      else if(strstr(buffer,"config:end\n"))    // Request Pin switchen
47
        {
48
        kill_buffer();
49
        uart_puts("\t\t\t\tconfig:end:OK\n");
50
        EEPWriteByte(IS_CONFIGERD, 0x01);   // write Flag if configuration ist set
51
        sei();
52
      }      
53
       else if(strstr(buffer,"00T\n"))      // Anfrage Pin switchen
54
        {
55
        kill_buffer();
56
        PORTA ^= (1<<PIN);
57
//*****************************************************************************************************************
58
//PORTD ^= (1<<6);         // Insert "Falle"
59
//*****************************************************************************************************************
60
        if(trigger == 1)trigger = 0;
61
        if(trigger == 0)trigger = 1;
62
        uart_puts("00TOK\n");
63
        
64
      }
65
      else if(strstr(buffer,"00S\n"))      // Statusanfrage
66
        {
67
        kill_buffer();
68
        if(PORTA&(1<<PIN))uart_puts("00S1\n");
69
        if((PORTA&(1<<PIN)) == 0)uart_puts("00S0\n");
70
        
71
      }
72
      else if(strstr(buffer,"PING\n"))
73
        {  
74
        kill_buffer();
75
        uart_puts("PONG\n");      
76
      }
77
      else if(strstr(buffer,"set:ssid\t"))  // set:ssid\ta1b2c3d4\t\n
78
        {  
79
        int i = 9,j = 0;
80
        
81
        while(buffer[i] != '\t')
82
        {
83
          ssid[j] = buffer[i];
84
          i++;
85
          j++;
86
        }
87
        kill_buffer();
88
        sprintf(s,"<%s>",ssid);  uart_puts(s);
89
        uart_puts("set:ssid:OK\n");            
90
      }
91
      else if(strstr(buffer,"set:key\t"))  // set:ssid\ta1b2c3d4\t\n
92
        {  
93
        int i = 8,j = 0;
94
        
95
        while(buffer[i] != '\t')
96
        {
97
          key[j] = buffer[i];
98
          i++;
99
          j++;
100
        }
101
        kill_buffer();
102
        sprintf(s,"<%s>",key);  uart_puts(s);
103
        uart_puts("set:key:OK\n");            
104
      }
105

106
      else kill_buffer();
107
  
108
      sei();  
109
    } //if(strstr(buffer,"\n"))
110

111

112

113

114

115
//*****************************************************************************************************************
116
//* auskommentiert für manuelle Fallenkontrolle in eine Richtung, siehe oben PORT..^=...
117
//*****************************************************************************************************************
118

119
    if(trigger && open_signal == 0)
120
    {
121
      open_signal = 1;   // For remaining control signal
122
      uart_puts("open_signal =1\r\n");
123
      }
124
    if(open_signal && !flag1 && !flag2 && !flag3)
125
    {
126
      PORTD |= (1<<6);         // Insert "Falle"
127
      uart_puts("insert an D6\r\n");
128
      flag1 = 1;
129
    }  
130
    if(open_signal && flag1 && (PIND & (1<<5)))    // reaching limit switch
131
    {
132
      uart_puts("insert stop, release an D7\r\n");
133
      PORTD &= ~(1<<6);      // Einfahrt stoppen
134
      _delay_ms(100);
135
      PORTD |=  (1<<7);      // Ausfahrt starten
136
      flag2 = 1;
137
      flag1 = 0;
138
    }
139

140
    if(open_signal && (PIND & (1<<4)) && flag2)// reaching limit switch
141
    {
142
      PORTD &= ~(1<<RELEASE_PIN);
143
      flag1 = 0;
144
      flag2 = 0;
145
      open_signal = 0;
146
      uart_puts("release_pin aus, open_signal aus\r\n");
147
    }
148

149

150
//*****************************************************************************************************************
151

152
    } // for(;;)
153

154
  return(0);
155
}    // main()
Gast #1799786
Lesenswert?

@ floh:

passiert:
Ständiger Reset! sehe ich an meiner RST\r\n Ausgabe

soll passieren:
µC resettet nicht in einer Tour, ohne überhaupt in meine foreverschleife 
zu gelangen...., da vor dem for(;;) der Code den µC zum Reset zwingt...
#1799791
Lesenswert?

Dein Absturz wird höchst wahrscheinlich hier seinen Ursprung nehmen

    sprintf(s,"<%s> \r",buffer);uart_puts(s);

dein killBuffer hinterlässt nun mal in buffer keinen leeren String. 
Damit knallst du mit Sicherheit zuallererst einmal weit über die Grenzen 
von s drüber.

Das es mit Buffergrößen kleiner 60 scheinbar(*) funktioniert ist Zufall. 
Da erwischt du nur einfach nicht das richtige Byte um das komplette 
System zum Crashen zu bringen.

Um einen Buffer, der sowieso nur einen String aufnehmen kann zu löschen, 
vulgo den String auf einen Leerstring zu setzen, genügt es das erste 
Byte davon auf '\0' zu setzen. Man muss nicht durch das Array durchgehen 
und jedes einzelne Byte auf '\0' setzen.


(*) wie gesagt: scheinbar
Du hast trotzdem einen Fehler. Du siehst ihn nur nicht, weil du zufällig 
die falschen Bytes im Speicher zerstörst.
Gast #1799796
Lesenswert?

weil ich die Interrupts nutzen möchte, aktiviere ich sie auch. Die ISR 
arbeitet wunderbar, wenn ich die Buffersize kleiner als 61 wähle!

Falls es interessiert hier die ISR für den uart-empfang:

ISR (USART_RXC_vect)
{
  buffer[pwrite]=UDR;
  pwrite++;
  if(pwrite >= BUFFER_SIZE) pwrite=0;
}
Gast #1799803
Lesenswert?

Karl heinz Buchegger schrieb:
> Um einen Buffer, der sowieso nur einen String aufnehmen kann zu löschen,
> vulgo den String auf einen Leerstring zu setzen, genügt es das erste
> Byte davon auf '\0' zu setzen. Man muss nicht durch das Array durchgehen
> und jedes einzelne Byte auf '\0' setzen.

ich überprüfe, ob ich ein config:start\n empfangen habe. dazu nutze ich 
strstr(). Wenn ich aber nun den Buffer nur an [0] auf '\0' setze, sind 
die anderen Zeichen nicht automatisch weg oder?

Oder sucht die Funktion strstr() nur bis zum \0 Zeichen?
Dann wäre das eine Lösung, mit kill_buffer nur die erste Stelle auf das 
Stringendezeichen zu setzen...

THX für weitere antwort
#1799814
Lesenswert?

Timo P schrieb:
> Karl heinz Buchegger schrieb:
>> Um einen Buffer, der sowieso nur einen String aufnehmen kann zu löschen,
>> vulgo den String auf einen Leerstring zu setzen, genügt es das erste
>> Byte davon auf '\0' zu setzen. Man muss nicht durch das Array durchgehen
>> und jedes einzelne Byte auf '\0' setzen.
>
> ich überprüfe, ob ich ein config:start\n empfangen habe. dazu nutze ich
> strstr(). Wenn ich aber nun den Buffer nur an [0] auf '\0' setze, sind
> die anderen Zeichen nicht automatisch weg oder?

Richtig - Sind sie nicht.
Aber wen kümmerts?

Ein String ist mit dem ersten '\0' Zeichen zu Ende. Was dann noch 
dahinter kommt interessiert keinen. Auch die str... Funktionen wissen 
das und halten sich daran. So sind Strings in C nun mal definiert.

> Oder sucht die Funktion strstr() nur bis zum \0 Zeichen?

An dieser Stelle ist dann der Hinweis auf ein C-Buch angebracht

> Dann wäre das eine Lösung, mit kill_buffer nur die erste Stelle auf das
> Stringendezeichen zu setzen...

Und mach dein s größer!
Wenn im Extremfall dein Buffer voll ist, dann ist da ein String der 
Länge 70 drinnen. Der wird aber kaum in s (mit 22 Zeichen) reinpassen!
Gast #1799817
Lesenswert?

ok, s ist vergrößert.
ich habe nun in der kill_buffer() nur noch buffer[0] = '\0' gesetzt.

Nun empfange ich nur noch Müll! wenn ich per Terminalprogramm Zeichen 
eintippe, empfange ich sie nur noch einzeln wenn ich mal ein \n drin 
hatte....
Gast #1799825
Lesenswert?

mein Programm hat ja mal gelaufen, als die Buffer kleiner waren!
Ich konnte z.B. erfolgreich eine ssid, die übergeben wurde, 
interpretieren.

denken kann ich mir aber, dass hier gemeint ist, dass ich die 
string-token funktion nutzen soll...

Wo hab ich denn noch Fehler?
#1799826
Lesenswert?

Timo P schrieb:

> ISR (USART_RXC_vect)
> {
>   buffer[pwrite]=UDR;
>   pwrite++;
>   if(pwrite >= BUFFER_SIZE) pwrite=0;
> }

Das ist deine Empfangsfunktion?

Dann kannst du das hier
1
    for(;;)
2
    {
3
    //if(RESET_PORT&(1<<RESET_PIN))EEPWriteByte(IS_CONFIGERD, 0x01);
4
    _delay_ms(10);
5
    sprintf(s,"<%s> \r",buffer);uart_puts(s);

nicht machen. In buffer ist zu diesem Zeitpunkt kein gültiger String.
Gast #1799832
Lesenswert?

Timo P schrieb:
> {
...
>         if(trigger == 1)trigger = 0;
>         if(trigger == 0)trigger = 1;
>         uart_puts("00TOK\n");

Ähm.. ist das so gewollt, das trigger nicht 0 werden kann?

Oder wolltest du vielleicht schreiben

if (trigger == 1) then
  trigger == 0;
else
  trigger == 1;

Oder, kurzform:
trigger = (trigger) ? 0 : 1;
#1799833
Lesenswert?

Als Quick-Fix ändere das mal
1
ISR (USART_RXC_vect)
2
{
3
  buffer[pwrite]=UDR;
4

5
  pwrite++;
6
  if(pwrite >= BUFFER_SIZE)
7
    pwrite=0;
8

9
  buffer[pwrite] = '\0';
10
}

damit hast du zumindest im Input-Buffer ständig einen insofern gültigen 
C-String, als das er nach dem zuletzt empfangenen Zeichen 0-terminiert 
ist.
Gast #1799884
Lesenswert?

Hallo,

Karl heinz Buchegger schrieb:
> damit hast du zumindest im Input-Buffer ständig einen insofern gültigen
> C-String, als das er nach dem zuletzt empfangenen Zeichen 0-terminiert
> ist.

hat er nicht (glaube ich... ;-)

Wenn USART_RXC_vect hier wieder das erste Zeichen des Buffers mit einem 
gültigen Zeichen überschreibt, sieht jede String-Funktion in C wieder 
den gesamten Buffer, plus das was dahinter im Speicher folgt (wenn nicht 
irgendwo im Buffer wieder ein /0 steht).

Wenn man es schon so machen muß wie der TE dann vllt. so:

#define BUFFER_SIZE 70  //buffergröße in Byte
volatile unsigned char buffer[1 + BUFFER_SIZE];
...
buffer[BUFFER_SIZE] == 0;

Damit wäre der Buffer immer NULL-Terminiert.
Gast #1799894
Lesenswert?

hab ich wohl, denn, wenn der RX-Interrupt das erste Zeichen 
überschreibt, hängt er automatisch ein '\0' an dank shiften des writer 
pointers um genu diese Bitbreite, die die Bufferelemente auch 
besitzen.....

so läuft es perfekt!
#1799912
Lesenswert?

Dir ist auch klar, dass der Eingabetext

reset::ssid\t

(für \t drück ich natürlich den Tabulator)

auf diese Abfrage
1
     else if(strstr(buffer,"set:ssid\t"))
passt?

strncmp eignet sich für solche Auswertungen besser als strstr
1
   else if( strncmp( buffer, "set::ssid\t", 10 ) == 0 )
jetzt muss der String mit "set::ssid\t" anfangen, nur dann gilt der Text 
als erkannt. reset::ssid\t passt jetzt nicht mehr.

Vielleicht hängt ja am anderen Ende der Leitung kein Mensch, aber die 
Sache mit dem \t würde ich mir insgesammt nochmal überlegen. Es sei denn 
natürlich, das da ein anderes Programm deinen µC füttert und dort ist 
das schon so festgelegt.
Gast #1799919
Lesenswert?

aus if...if ist längst ein if else geworden.

Mir ist auch bewusst, dass ich ein Bit aus einem 8-Bit char einzeln 
toggeln könnte.

Dann müsste ich aber wieder die Bitmasken nutzen, sowohl bei der 
Zuweisung, als auch bei der Abfrage des Flags...
#1799920
Lesenswert?

Timo P schrieb:
> aus if...if ist längst ein if else geworden.
>
> Mir ist auch bewusst, dass ich ein Bit aus einem 8-Bit char einzeln
> toggeln könnte.

Eine Schreibweise, die mir persönlich gut gefällt

   trigger = 1 - trigger;

keine Ahnung warum, aber ich finde das hat was :-)

> Dann müsste ich aber wieder die Bitmasken nutzen, sowohl bei der
> Zuweisung, als auch bei der Abfrage des Flags...

na, na

    trigger ^= 0x01;

so schlimm ist das auch wieder nicht.
Besser als
        if(trigger == 1)trigger = 0;
        else if(trigger == 0)trigger = 1;
ist es allemal.
Gast #1799926
Lesenswert?

dann frage ich aber auch das "0-te" Bit ab.... Dann gehts....

Oder ich hab mal was von Bitmasken gesehen, ein Strukt, in dem 8 Bits 
sind. Diese kann ich dann über ein define nutzen, quasi ein eigenes sbit 
für die AVRs, die ja keine bitadressierung haben.....
#1799928
Lesenswert?

Timo P schrieb:
> dann frage ich aber auch das "0-te" Bit ab.... Dann gehts....

kannst du natürlich machen.
Aber bei all den Alternativvorschlägen ging es bisher immer nur darum, 
trigger zwischen 0 und 1 hin und her wechseln zu lassen. Das machen alle 
bisher hervorgebrachten Alternativen. Manche der Alternativen haben noch 
einen zuätzlichen Nebeneffekt bzw. zusätzliche Eigenschaften, der/die 
hier bei dir nicht zum tragen kommt, da trigger offenbar sowieso nur 0 
und 1 sein kann und auch das auch so sein soll.
Gast #1799935
Lesenswert?

Hier habe ich genug speicher und nutze ein komplettes byte als flag aus.
Missbrauch?!? ok, soll jeder so sehen, wie er es möchte.

Im übrigen sind alle commands, die hier zum tragen kommen, von einer GUI 
am PC über USB zum µC übertragen.

Daraus erzeuge ich dann andere Commands, die ich an ein WLAN-Modul 
übertrage.
#1799942
Lesenswert?

Timo P schrieb:
> Hier habe ich genug speicher und nutze ein komplettes byte als flag aus.
> Missbrauch?!? ok, soll jeder so sehen, wie er es möchte.

Darum gehts nicht.

Das hier
1
    if(trigger == 1)trigger = 0;
2
    else if(trigger == 0)trigger = 1;
ist für deinen µC so ziemlich die aufwändigste Methode, das Gewünschte 
zu erreichen.

>
> Im übrigen sind alle commands, die hier zum tragen kommen, von einer GUI
> am PC über USB zum µC übertragen.

ok. nehm ich zur Kentniss. Also musst du nicht besondere Sorgfalt in der 
Auswertung walten lassen. Du kannst davon ausgehen, dass der String 
immer vollständig und wohl geformt ist (abgesehen von 
Übertragungsfehlern natürlich)
Gast #1800684
Lesenswert?

ist gemeint, dass die Übertragungsfehler mindestens mit genau der selben 
Entgegnung/Auswertung optimiert werden sollen, wie Fehleingaben?

Oder hieß das, dass ich drauf vertrauen könnte? Wenn die GUI mir

set:ssid\thier_die_ssid\t\n

sendet, ich aber nicht mit einem

set:ssid:OK\n

antworte, weiß die Gui, dass sie erneut senden muss. Selbstverständlich 
versucht sie es nicht hunderte mal....
Gast #1800700
Lesenswert?

Timo P schrieb:
> ist gemeint, dass die Übertragungsfehler mindestens mit genau der selben
> Entgegnung/Auswertung optimiert werden sollen, wie Fehleingaben?

nein, das nicht. Aber dein Programm macht nach den vergessenen tab 
nichts mehr sinnvollens. Du musst also den µC neu starten.
Gast #1800722
Lesenswert?

Das ist doch mal nen Argument...

strstr hätte den vorteil:

&$?=config:start\n wird von mir auch interpretiert, falls sich diese 
Zeichen vor config:start\n einschleichen sollten.

das strncmp klingt auch gut. (Welcher Vorteil ergibt sich praktisch 
durch das n, also die Angabe der Anzahl der zu prüfenden zeichen?)
#1800730
Lesenswert?

Timo P schrieb:
> Das ist doch mal nen Argument...
>
> strstr hätte den vorteil:
>
> &$?=config:start\n wird von mir auch interpretiert, falls sich diese
> Zeichen vor config:start\n einschleichen sollten.

die Frage ist ob du das überhaupt willst.
Falls sich da vor config::start\n ein paar Zeichen eingeschlichen haben, 
die da eigentlich nicht hingehören, woher willst du dann wissen, dass 
dieses config::start nicht eigentlich auch fehlerhaft ist und eigentlich 
gar nicht da hingehört?

> das strncmp klingt auch gut. (Welcher Vorteil ergibt sich praktisch
> durch das n, also die Angabe der Anzahl der zu prüfenden zeichen?)

Ich muss meinen String nicht in Einzelteile zerlegen
Dieser strncmp ist das Equivalent zu: Wenn die ersten n Buchstaben 
(sofern es überhaupt n gibt) diesen Text hier bilden, dann ist alles 
gut.
Gast #1800778
Lesenswert?

Karl heinz Buchegger schrieb:
> dann ist alles
> gut.

klingt doch super ;)

nein im Ernst, Danke für die Anregungen zu meinem code. Sicher, man kann 
leute auf ein C-Buch verweisen. Aber irgendwie schreibt man dann doch 
auch mal mist zusammen. Sehen wir ja hier. Danke für eure Anregungen, 
nur so kann ich mich ja verbessern!

Weiter so im Forum!
#1800789
Lesenswert?

Timo P schrieb:

> auch mal mist zusammen. Sehen wir ja hier. Danke für eure Anregungen,
> nur so kann ich mich ja verbessern!

Das allerwichtigste bei der Arbeit mit Strings in C:

Du musst dir bei jeder Aktion immer im klaren sein, dass es kein 
Fangnetz gibt. Wenn du, aus welchem Grund auch immer, versuchst 20 
Zeichen in ein char-Array der Länge 10 zu quetschen, dann wird das 
grauslich schief gehen. Nicht nur das, es werden unter Umständen 
seltsame Phenomäne in deinem Programm auftauchen, Dinge die bisher schon 
funktioniert haben werden plötzlich nicht mehr funktionieren, 
Berechnungen liefern falsche Ergebnisse, Funktionsreturns landen 
plötzlich nicht mehr an der Stelle an der die Funktion aufgerufen wurde 
etc.

Daher: Bei jeglicher Stringaktion lieber konservativ arbeiten. Was kann 
schief gehen? Wenn du den String von einem Benutzer hast: Nicht darauf 
verlassen, dass der alles richtig eingibt. Wenn Strings über eine 
Leitung übertragen werden: Auch wenn es mitlerweile selten vorkommt, 
aber es gibt sie noch, die Übertragungsfehler.

Das mindeste, was man immer tun sollte, so lange man im Programm nicht 
sicher gestellt hat, das der String nicht zu lang sein kann:
Wenn man einen String (oder Teilstring) in ein anderes Array umkopiert, 
immer die Länge des Zielarrays im Auge behalten und notfalls das 
Umkopieren abwürgen, wenn man das Ziel überläuft!

Nicht wenige der frühen Hacker-Angriffe auf andere Rechner sind genau 
über solche Schlupflöcher gelaufen: Man hat ins Programm einen sehr 
langen String eingespielt, weil man genau wusste das dort und dort in 
der Umkopierschleife keine Sicherung gegen Überlaufen enthalten ist. 
Damit hat das Programm selber den Schadcode an die richtige Stelle im 
Speicher kopiert und das Tor aufgemacht.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren