Forum: Compiler & IDEs seriell char aus ringpuffer als zeichenkette speichern


von Rene (Gast)


Angehängte Dateien:

Lesenswert?

hallo zusammen,

bin fast am verzweifeln, probiere schon seid 2 tagen an meinem problem 
herum.
bekomme die char seriell aus dem ringpuffer, möchte sie dann aber als 
string á 4 byte groß speichern. habe dafür schonmal das forum 
durchsucht, aber noch keine passende lösung für mein problem 
gefunden.möchte das es auch nur ein gültiger string wird wenn es 
mindestens 4 byte groß ist, ansonsten schon verworfen wird. vom prinzip 
ist mir das schon klar, aber ich weiß nicht wie ich es softwaremässig 
umsetzen soll. meine programmiererfahrung ist leider auch relativ 
gering.

geht das so das ich die 4 byte aus dem ringpuffer hole und dann wieder 
in einen anderen buffer schreibe, und sie dort als kompletten string 
heraus hole?

von Oliver (Gast)


Lesenswert?

>bekomme die char seriell aus dem ringpuffer,

Welchem Ringpuffer?

>möchte das es auch nur ein gültiger string wird wenn es
>mindestens 4 byte groß ist, ansonsten schon verworfen wird. vom prinzip
>ist mir das schon klar, ...

Wohl eher nicht. Was soll wann und warum gültig sein, oder verworfen 
werden?

Prinzipiell ist ein 4-Zeichen-String in C ein char-Array mit fünf 
Werten: Den vier Zeichen, abschliessend eine Null. Also legts du dir 
soch eine Array mit

char myString[5];
myString[5] = 0;

an, und füllst es dann mit den einzelnen Zeichen.

Oliver

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> möchte das es auch nur ein gültiger string wird wenn es
> mindestens 4 byte groß ist, ansonsten schon verworfen wird.
Wie erkennst du, dass es weniger Zeichen sind?
Wie sieht dein Protokoll aus?
Hast du ein Timeout?

von Rene (Gast)


Lesenswert?

den ringpuffer habe ich nicht mit hoch geladen, der ist in dewr uart.c 
enthalten.
ich möchte die Zeichen von:

zeichen = ser_getc();

in ein char-array schreiben lassen, dabei soll das array 4 zeichen 
enthalten. mit welcher routine könnte ich das machen?

timeout gibt es nicht, ich erhalten die daten über die rs232 
schnittstelle (uart)

von Karl H. (kbuchegg)


Lesenswert?

Dachte ichs mir doch (in einem anderen Thread)
1
int main(void)
2
{
3
  unsigned char zeichen;
4
  unsigned char muster;
5
6
  muster='e';
7
8
  ....
9
10
  if(strcmp(zeichen,muster))

Du hast
http://www.mikrocontroller.net/articles/FAQ#Wie_funktioniert_String-Verarbeitung_in_C.3F
immer noch nicht gelesen oder nicht verstanden.
In C ist ein eine Variable, die einen String enthält immer ein 
char-Array. Du hast kein char-Array. Sowohl zeichen als auch muster sind 
bei dir einzelne char. Die wiederrum, werden mit einem gewöhnlichen == 
verglichen. Die str... Funktionen gelten nur für Strings!

von Karl H. (kbuchegg)


Lesenswert?

Rene schrieb:
> den ringpuffer habe ich nicht mit hoch geladen, der ist in dewr uart.c
> enthalten.
> ich möchte die Zeichen von:
>
> zeichen = ser_getc();
>
> in ein char-array schreiben lassen, dabei soll das array 4 zeichen
> enthalten. mit welcher routine könnte ich das machen?
>
> timeout gibt es nicht, ich erhalten die daten über die rs232
> schnittstelle (uart)

Und wie entscheidest du dann, wann etwas verworfen werden soll?

von Oliver (Gast)


Lesenswert?

>der ist in dewr uart.c enthalten.

Tja, dann wollen wir das mal glauben.


>mit welcher routine könnte ich das machen?

mit einer selbstgeschriebenen...
1
char myString[5];
2
myString[4] = 0;
3
4
myString[0] = ser_getc();
5
myString[1] = ser_getc();
6
myString[2] = ser_getc();
7
myString[3] = ser_getc();

und schon hast du einen String mit vier Zeichen.

Oliver

von Karl H. (kbuchegg)


Lesenswert?

Ich denke mal, dass hier sollte dir weiter helfen
1
#include "uart.h"
2
#include <avr/io.h>
3
#include <string.h>
4
5
#define UART_BAUD_RATE 9600
6
7
8
int main(void)
9
{
10
  char empfang[] = "    ";
11
  char zeichen;
12
13
  uart_ini();
14
15
  PORTB=0xff;
16
  DDRB=0xff;
17
  
18
  while (1)
19
  {
20
    
21
    if( UCSRA &= (1<<UDRE) ) 
22
    {
23
      zeichen = ser_getc();
24
      uart_putc(zeichen);
25
26
      empfang[0] = empfang[1];   // aus "abcd" mal "bcdx" machen
27
      empfang[1] = empfang[2];   // wobei x das empfangene Zeichen ist
28
      empfang[2] = empfang[3];
29
      empfang[3] = zeichen;
30
31
32
      if( strcmp( empfang, "toFF" ) == 0 )
33
        PORTB = 0xff;
34
      else if( strcmp( empfang, "to55" ) == 0
35
        PORTB = 0x55;
36
    }  
37
  }
38
39
  return 0;
40
}

Die Abfrage auf UCSRA &= (1<<UDRE) kommt mir allerdings seltsam vor. 
Wenn deine UART Routinen wirklich einen Ringbuffer enthalten, muss es 
eine andere Möglichkeit geben, um rauszufinden ob ein Zeichen 
eingetroffen ist. UDRE wird dir da nicht weiterhelfen, weil die UART 
Routinen sich das Zeichen bereits geschnappt haben, wenn der Ringbuffer 
über Interrupt angekoppelt ist. Wovon ich eigentlich ausgehe, sonst 
macht ein Ringbuffer keinen Sinn

von Rene (Gast)


Angehängte Dateien:

Lesenswert?

Hallo nochmal,

danke erstmal für die Hilfe. Karlheinz ich habe mir das gestern 
durchgelesen, nur hatte ich mich ein bisschen unklar ausgedrück. Habe 
das Beispiel mal eingepflegt und auch mal probiert. Es funzt immer noch 
nicht, die uart.c habe ich nun mal mit darangehangen. Kann da bitte 
nochmal einer drüber schauen!? char habe ich mit 4 byte definiert. Ich 
benutze für die Eingabe HTerm als Terminalprogramm.

von Rene (Gast)


Angehängte Dateien:

Lesenswert?

und nochmal die überarbeitete "main.c" ... der name is a bissl 
irreführend ;)

von Karl H. (kbuchegg)


Lesenswert?

> Es funzt immer noch
> nicht

Dachte ich mir schon.
Der Test ob etwas im Ringbuffer vorliegt, ergibt so wie du ihn hast nie 
wahr. Dein Hauptprogramm wird nie an den UART Registern ablesen können, 
dass ein Zeichen eingetroffen ist.

Allerdings ist die ser_get eine wartende Funktion, dh. die wartet 
sowieso, bis ein Zeichen vorliegt.
1
#include "uart.h"
2
#include <avr/io.h>
3
#include <string.h>
4
5
#define UART_BAUD_RATE 9600
6
7
8
int main(void)
9
{
10
  unsigned char zeichen;
11
  unsigned char empfang[4];  
12
13
  
14
  PORTB=0xff;
15
  DDRB=0xff;
16
    
17
18
  uart_ini();
19
  
20
  while (1)
21
  {
22
    zeichen = ser_getc();
23
    uart_putc(zeichen);
24
  
25
    empfang[0] = empfang[1];
26
    empfang[1] = empfang[2];
27
    empfang[2] = empfang[3];
28
    empfang[3] = zeichen;  
29
30
    if(strcmp( empfang,"toFF")==0)
31
      PORTB = 0xff;
32
  
33
    else if(strcmp( empfang,"to55")==0)
34
      PORTB = 0x55;
35
  }
36
37
  return 0;
38
}

von Stefan E. (sternst)


Lesenswert?

1
if(UCSRA &= (1<<RXC))
Mal davon abgesehen, dass das "&=" hier völlig fehl am Platz ist, 
funktioniert das so sowieso nicht.
Wenn du ein "wenn Zeichen vorhanden" haben willst, musst du das auf der 
Ebene "Ringpuffer" machen, nicht auf der Ebene "Hardware". Z.B. indem du 
rbuffcnt auswertest, oder (sauberer) deinen Ringpuffer um eine 
entsprechende Abfragefunktion erweiterst.

von Karl H. (kbuchegg)


Lesenswert?

Wieso hast du die uart_puts auskommentiert?
Die könnte jetzt nützlich sein
1
#include "uart.h"
2
#include <avr/io.h>
3
#include <string.h>
4
5
#define UART_BAUD_RATE 9600
6
7
8
int main(void)
9
{
10
  unsigned char zeichen;
11
  unsigned char empfang[4];  
12
13
  
14
  PORTB=0xff;
15
  DDRB=0xff;
16
    
17
18
  uart_ini();
19
  
20
  while (1)
21
  {
22
    zeichen = ser_getc();
23
    uart_putc(zeichen);
24
  
25
    empfang[0] = empfang[1];
26
    empfang[1] = empfang[2];
27
    empfang[2] = empfang[3];
28
    empfang[3] = zeichen;  
29
30
    uart_puts( " Kommando: '" );
31
    uart_puts( empfang );
32
    uart_puts( "'\n" );
33
34
    if(strcmp( empfang,"toFF")==0)
35
    {
36
      uart_puts( "->Schalte auf 0xFF\n" );
37
      PORTB = 0xff;
38
    }
39
  
40
    else if(strcmp( empfang,"to55")==0)
41
    {
42
      uart_puts( "->Schalte auf 0x55\n" );
43
      PORTB = 0x55;
44
    }
45
46
    else
47
      uart_puts( "** kein Kommando **\n" );
48
  }
49
50
  return 0;
51
}

von Karl H. (kbuchegg)


Lesenswert?

Das
1
  sei()

in uart_init() ist .... sagen wir mal .... gewagt!

Was, bitte, geht das die uart_init an, wann und wo ich global die 
Interrupts freigeben will. Gar nichts!
Vielleicht muss ich nach der uart_init auch noch ein paar Timer 
konfigurieren. Super, wenn ich dort mal einen Interrupt freigebe, und 
der fängt dann sofort zu feuern an.

Das globale sei() nach den Initialisierungen ist Sache des 
Hauptprogramms und wird erst vor der Hauptschleife gemacht!
1
int main()
2
{
3
  unsigned char zeichen;
4
  unsigned char empfang[4];  
5
6
  
7
  PORTB=0xff;
8
  DDRB=0xff;
9
    
10
  uart_ini();
11
12
  sei();
13
14
  while( 1 )
15
  {
16
    ...
17
  }
18
}

(und aus der uart_init fliegt es raus)

Bei dir macht das im Moment keinen Unterschied. Genausogut könnte ich 
sagen: Es macht auch keinen Unterschied ob ich bei der Tür rausgehe oder 
durchs Fenster springe. Ich wohn ja eh im Erdgeschoss. Nur irgendwann 
ziehst du um, vielleicht in den 3. Stock. Und dann sind alte 
Gewohnheiten kontraproduktiv, weil ....

von Stefan E. (sternst)


Lesenswert?

Ok, ich habe dann auch noch was ähnliches anzumeckern: ;-)

1
UCSRC |= (1<<URSEL)|(3<<UCSZ0);
Das "|=" ist hier eher schlecht, denn konkret steht hier dadurch:
1
UCSRC = UBRRH | ((1<<URSEL)|(3<<UCSZ0));
Gut, es hat im Moment keine Auswirkungen, weil UBRRH 0 enthält, aber 
ändern würde ich es trotzdem (in ein "=").

von Rene (Gast)


Angehängte Dateien:

Lesenswert?

Ich hab alles so eingebunden wie du mir empfohlen hast. Leider kommt in 
meinem Terminal nicht das an was ich möchte (siehe JPG). Die 
Endlosschleife wird abgearbeitet und zwar für jedem einzelnen char des 
arrays den ich eingebe. Es wird nicht als Array betrachet. Aber warum 
gibt es für den Array empfang den character "S" aus? krübel

von Karl H. (kbuchegg)


Lesenswert?

Scheisse

Du hast wieder mal meine Vorgabe verändert (und ich hab sie im weiteren 
dann wieder weiterkopiert, weil ich nicht mehr darauf geachtet habe)

Ich habe im Original nicht ohne Grund
1
int main()
2
{
3
  char empfang[] = "    ";
geschrieben!

Du hast daraus

   char empfang[4];

gemacht.

Erstens: Ist damit das Array um 1 Zeichen zu kurz.
Für einen String der Länge 4 brauchst du ein Array der Länge 5!

Zweitens ist mein String mit Leerzeichen initialisiert und hat am Ende 
automatisch das für einen String notwendige '\0', was dein String  nicht 
hat.

Lass doch den Compiler die Zeichen zählen! Der macht das zuverlässiger 
als du! Ich geb ihm eine Initialisierung mit 4 Leerzeichen vor, der 
Compiler zählt sie und allokiert automatisch ein Array mit der richtigen 
Größe und macht als Zugabe auch noch das obligate '\0' am Ende mit rein.

Ich geb dir nicht ohne Grund den Link in die FAQ. Dort ist jeder 3. 
Satz: "Achte drauf, dass deine Arrays gross genug sind; beachte das 
abschliessende '\0' Zeichen; stell sicher, dass deine Arrays gross genug 
sind; wenn du Längen zählen musst, achte drauf, dass am Ende eines 
Strings immer noch ein '\0' Zeichen steht; wenn du Strings 
zusammenbaust, bedenke das abschliessende '\0' Zeichen" Der ganze 
Artikel wimmelt nur so vor solchen Warnungen.

Mehr Sorgfalt!

von Rene (Gast)


Lesenswert?

Hallo Karl Heinz,

Sry wegen meiner Nachlässigkeit. Wollte dir danken für deine Hilfe! Das 
Proggi läuft jetzt. ich werd auch noch den aktuellen Quelltext 
reinstellen. bin bloß leider ne zu Hause zur Zeit.

Mfg Rene

von René (Gast)


Lesenswert?

Hier also nochmal wie versprochen der Quellcode der funzt! vllt hilft es 
ja jemanden.
1
#include "uart.h"
2
#include <avr/io.h>
3
#include <string.h>
4
5
#define UART_BAUD_RATE 9600
6
7
8
int main(void)
9
{
10
  unsigned char zeichen;
11
  unsigned char empfang[] = "    ";  
12
13
  
14
  PORTB=0xff;
15
  DDRB=0xff;
16
    
17
18
  uart_ini();
19
  
20
  while (1)
21
  {
22
    
23
    for(int i=0;i<=3;i++) 
24
  {  
25
    zeichen = ser_getc();
26
    uart_putc(zeichen);
27
  
28
  empfang[0] = empfang[1];
29
  empfang[1] = empfang[2];
30
  empfang[2] = empfang[3];
31
  empfang[3] = zeichen;  
32
    }
33
  
34
  
35
  uart_puts( " Kommando: '");
36
  uart_puts( empfang );
37
  uart_puts( "'");
38
  
39
  
40
  if(strcmp( empfang,"toFF")==0)
41
    {
42
      uart_puts( "->Schalte auf 0xFF");
43
      PORTB = 0xff;
44
      }
45
    
46
    else if(strcmp( empfang,"to55")==0)
47
    {
48
      uart_puts( "->Schalte auf 0x55");
49
      PORTB = 0x55;
50
    }    
51
            
52
    else 
53
54
      uart_puts( "** kein Kommando **");
55
56
    }
57
58
    return 0;
59
  }

von René (Gast)


Lesenswert?

karl heinz, ich musste die for schleife noch rein machen. sonst funzt es 
nicht! danke hat mir echt weiter geholfen! hab mir auch die artikel alle 
nochmals durchgelesen :)

von Karl H. (kbuchegg)


Lesenswert?

René schrieb:
> karl heinz, ich musste die for schleife noch rein machen. sonst funzt es
> nicht! danke hat mir echt weiter geholfen! hab mir auch die artikel alle
> nochmals durchgelesen :)

Wenn du da eine Schleife reinbaust, dann kannst du dir das komplizierte 
Character-Shifting sparen.
1
  ...
2
  for( int i = 0; i < 4; i++ ) 
3
  {  
4
    empfang[i] = ser_getc();
5
    uart_putc( empfang[i] );
6
  }
7
8
  empfang[4] = '\0';
9
10
  uart_puts( " Kommando: '");
11
  ...

Das Character-Shifting war dazu gedacht, dass sich der Code aus einer 
Eingabe
  abto55jk
das Kommando "to55" rausfischen kann.

Aber auf lange Sicht ist das sowieso keine so gute Idee. Da wirst du dir 
sowieso etwas bauen, was eine komplette Zeile vom Benutzer einliest und 
diese dann nach Wörtern zerlegt, Argumente rausfischt, auf Plausibilität 
prüft und die entsprechende Funktionalität ausführt. Schon alleine der 
Umstand, dass momentan alle Kommandos 4 Zeichen lang sein müssen, ist ja 
eine Annahme, die so nicht so schlau ist. Ausserdem wird dein Benutzer 
rudimentär editieren könnnen müssen (zumindest Backspace sollte man bei 
einem menschlichen Benutzer schon unterstützen) etc. etc.

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.