Forum: Mikrocontroller und Digitale Elektronik USART in Funktion


von Markus P. (sebastianwurst)


Angehängte Dateien:

Lesenswert?

Hi,
ich sende auf die USART so eine Zeichenkette + Variableninhalt:
1
usart_writePC("88|01|01|%1i\n",u8SpeicherDimmwert[0]);
Das klappt. Die Ausgabe am Terminal ist 88|01|01|33

Jetzt will ich die Sende-Funktion in eine Funktion setzten, dieses 
versuche ich so:
1
 void Licht (char *String88Ein, uint8_t SpeicherDimmwert)
2
{  
3
  
4
     usart_write_PC(String88Ein);
5
6
}

Dann spuckt er mir einen Fehler aus:

undefined reference to `usart_write_PC'

Aufrufen tue ich die Funktion in der Main so:
1
Licht("88|01|01|%1i\n",u8SpeicherDimmwert[0][0]);

Kann mir einer sagen wie das geht????
Danke

von i2c (Gast)


Lesenswert?

>usart_writePC
vs
>usart_write_PC
            ^

von Markus P. (sebastianwurst)


Lesenswert?

O fuuuuck...manchmal ist es besser mal einfach ne Pause zu machen...
Danke...

von Markus P. (sebastianwurst)


Lesenswert?

Mmmhh...leider hat's doch noch nicht geklappt:
So:
1
 void Licht (char *String88Ein, uint8_t SpeicherDimmwert)
2
{
3
      
4
    
5
    
6
      usart_writePC(String88Ein,SpeicherDimmwert);
7
8
9
}
oder so:
1
 usart_writePC(String88Ein,SpeicherDimmwert);

habe ich diese Fehlermeldung:
main.h:51: error: invalid initializer

Aufgerufen wirds so :
1
Licht ("88|01|01|%1i\n",u8SpeicherDimmwert[0][0]);
Initialisiert ist das Array:
1
 uint8_t u8SpeicherDimmwert[11] [4] ={  {5,5,5,5},
2
                    {5,5,5,5},
3
                    {5,5,5,5},
4
                    {5,5,5,5},
5
                    {5,5,5,5},
6
                    {5,5,5,5},
7
                    {5,5,5,5},
8
                    {5,5,5,5},
9
                    {5,5,5,5},
10
                    {5,5,5,5},
11
                    {5,5,5,5}};


Hast Du vielleicht noch ein Tip?

von Markus P. (sebastianwurst)


Lesenswert?

Also so geht es in der Funktion:
1
  usart_writePC("88|01|01|%1i\n",SpeicherDimmwert);

Ich kriege halt das "88|01|01|%1i\n" nicht in eine variable gepackt und 
übergeben....

von Markus (Gast)


Lesenswert?

Kann es vielleicht auch sein dass das "const" fehlt?

Also so dann:
1
 void Licht (const char *String88Ein, int SpeicherDimmwert)
2
{
3
      
4
    
5
    
6
      usart_writePC(String88Ein,SpeicherDimmwert);
7
8
9
}

Kann es leider nicht testen, aber könnte das mein Fehelr sein?

von Karl H. (kbuchegg)


Lesenswert?

Nein.
Grundsätzlich fehlt der const zwar schon. Genauso wie er hier

void usart_write_str0(char *str)

und hier

void usart_write_str0(char *str)

fehlt. Aber das ist nicht dein Problem. Sieh dir doch einfach mal an, 
was denn eigentlich usart_writePC darstellt. Wenn man fertigen Code von 
anderen übernimmt, ist es durchaus erlaubt (manche würden sogar sagen 
'erwünscht'), wenn man sich die Dinge im Code genauer ansieht.

Was sagt dir
1
  #define usart_writePC(format, args...)   usart_write_P0(PSTR(format) , ## args)

bzw. auch nicht uninteressant: was macht eigentlich macht usart_write_P0 
mit dem Formatstring genau und vor allen Dingen WIE macht es das und was 
folgt daraus.

von Markus (Gast)


Lesenswert?

Ich weiss es nicht,
habe früher immer zwei Variablen (Strings) zusammengefügt um diese als 
Einzelnes per USART zu übertragen, bis ich das irgendwo gesehen habe 
dass das so geht und ich auch in der Libary so drin habe.
Ich vermute das "usart_writePC(format, args...)" aus der stdarg.h kommt:
[c]
void MyPrintf(const char* format, ...)
{
  va_list args;
  char buffer[BUFSIZ];

  va_start(args,format);
  vsprintf (buffer, format, args );
  FlushFunnyStream(buffer);
  va_end(args);
}
[c]

Oder?

Und das PSTR habe ich mal gegoogelt:

PSTR bringt die Zeichenkette "Testnachricht" auch in den Programm-Flash,
das geht logischerweise nur für konstante Werte.

Aber leider hat mir das auch nicht so viel geholfen, ich muss da zu 
Hause noch mal mehr recherchieren...

Aber warum das dann nicht einfach funktioniert wenn ich die Funktion nur 
in einer Funktion aufrufe, weiss ich auch noch nicht...

von Krapao (Gast)


Lesenswert?

> main.h:51: error: invalid initializer
       ^

Vielleicht suchst du an der falschen Stelle. Die Fehlermeldung nennt 
eine Zeilennummer in einem Includefile und nicht in einer 
C-Quelldatei.

>      usart_writePC(String88Ein,SpeicherDimmwert);

usart_writePC() ist ein MAKRO

>> #define usart_writePC(format, args...)   usart_write_P0(PSTR(format) , ## args)

und das funktioniert nur wenn das 1. Argument (format) ein konstanter 
String ist, wil der zur Compilezeit mit PSTR ins Flash geschrieben wird 
und zur Laufzeit in usart_write_P0() aus dem Flash gelesen wird.

Das Funktionsargument String88Ein, der von diesem Aufruf kommt

>> Licht ("88|01|01|%1i\n",u8SpeicherDimmwert[0][0]);

ist aber kein String im Flash, sondern ein String im RAM.

Abhilfe wäre folgender Aufruf:

Licht (PSTR("88|01|01|%1i\n"), u8SpeicherDimmwert[0][0]);

Mit folgender Definition von Licht():

void Licht (const char *String88Ein, uint8_t SpeicherDimmwert)

> uint8_t SpeicherDimmwert

Aufpassen, du hast da drei Varianten!

1/
>>> Licht("88|01|01|%1i\n",u8SpeicherDimmwert[0][0]);
>>> => void Licht (char *String88Ein, uint8_t SpeicherDimmwert)
>>> => usart_write_PC(String88Ein);

2/
>>> Licht("88|01|01|%1i\n",u8SpeicherDimmwert[0][0]);
>>> => void Licht (char *String88Ein, uint8_t SpeicherDimmwert)
>>> => usart_writePC(String88Ein,SpeicherDimmwert);

3/
>>> wie oben?
>>> => void Licht (const char *String88Ein, int SpeicherDimmwert)
>>> => usart_writePC(String88Ein,SpeicherDimmwert);

von Karl H. (kbuchegg)


Lesenswert?

Krapao schrieb:

> Aufpassen, du hast da drei Varianten!
>
> 1/
>>>> Licht("88|01|01|%1i\n",u8SpeicherDimmwert[0][0]);
>>>> => void Licht (char *String88Ein, uint8_t SpeicherDimmwert)
>>>> => usart_write_PC(String88Ein);
>
> 2/
>>>> Licht("88|01|01|%1i\n",u8SpeicherDimmwert[0][0]);
>>>> => void Licht (char *String88Ein, uint8_t SpeicherDimmwert)
>>>> => usart_writePC(String88Ein,SpeicherDimmwert);
>
> 3/
>>>> wie oben?
>>>> => void Licht (const char *String88Ein, int SpeicherDimmwert)
>>>> => usart_writePC(String88Ein,SpeicherDimmwert);

Du kannst an dieser Stelle usart_writePC überhaupt nicht mehr benutzen!
usart_writePC wird auf jeden Fall mit dem ersten Argument einen PSTR 
machen und den String Literal so ins Flash verlagern.
Der String muss aber an dieser Stelle schon im Flash sein, d.h. das PSTR 
muss immer weiter rausgezogen werden. Mit jeder Funktionshhierarchie 
muss das PSTR mitwandern.

Aus der Funktion 'Licht' heraus ist nur noch usart_write_P0 benutzbar, 
wenn das Argument kein String-Literal ist.

von Karl H. (kbuchegg)


Lesenswert?

Markus schrieb:

> Ich vermute das "usart_writePC(format, args...)" aus der stdarg.h kommt:

Ähm.
Hast du dir dein uart.h schon mal angesehen?
Ich (und Krapao ebenfalls) haben dir das hinter usart_writePC stehende 
Makro sogar herauskopiert.

> Aber warum das dann nicht einfach funktioniert wenn ich die Funktion nur
> in einer Funktion aufrufe, weiss ich auch noch nicht...

Weil du, wenn du kein String-Literal hast, usart_writePC überhaupt nicht 
benutzen kannst. Das ist eine Hilfs"funktion", die nur bei 
String-Literalen (als direkt angegebenem String) benutzbar ist. Den Fall 
hast du aber nicht. Also kannst du usart_writePC auch nicht benutzen.

1
 void Licht (const char *String88Ein, uint8_t SpeicherDimmwert)
2
{  
3
  
4
     usart_write_P0( String88Ein, SpeicherDimmwert );
5
6
}

und Aufruf mittels
1
  Licht(PSTR( "88|01|01|%1i\n" ), u8SpeicherDimmwert[0][0]);

Und jetzt kannst du dasselbe Spielchen machen, das auch dein UART Code 
macht. Du kannst dir ein Makro definieren, welches dir das nervtötende 
PSTR einsetzt, so dass du es nicht vergessen kannst. Sozusagen die 
Komfortversion, so wie usart_writePC die Komfortversion von 
usart_write_P0 ist.
1
#define Licht_P(x,y)    Licht( PSTR(x), y )

und damit dann in der Verwendung schreiben:
1
  Licht_P( "88|01|01|%1i\n", u8SpeicherDimmwert[0][0]);


Und es passiert wieder das richtige:
Das PSTR (welches durch das Makro reinkommt), sorgt dafür, dass das 
String-Literal im Flash bleibt und ein entsprechender Pointer durch die 
Funktino Licht durchgeschleust wird, der dann letztendes in der Funktion 
usart_write_P0 ankommt. Denn usart_write_P0 braucht einen Flash Pointer, 
weil es sich den Formatstring mittels pgm_read_byte (das ist die Antwort 
auf meine 2.te Frage von weiter oben) holt. Und dafür muss der String 
nun mal im Flash sein. Ins Flash kannst du den String aber nur bei 
seiner 'Entstehung' verschieben. Also muss das PSTR mit dem 
String-Literal mitwandern. Dort wo das String-Literal ist, muss auch das 
PSTR sein.

von Markus (Gast)


Lesenswert?

Das muss ich mir erstmal zweimal durchlesen, aber danke schonmal für die 
gute Unterstützung!!!

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.