WIe ist es wirklich.
In der Fleury Lib gibt es 3 Mechanismen
uart1_puts
uart1_puts_p (Achtung: kleines p!)
uart1_puts_P (Achtung: grosses P!)
Wann wird welcher eingesetzt?
uart1_puts
**********
Diese Funktion kommt immer dann zum Zug, wenn ich einen String habe, der
im SRAM liegt. Also alles was Variablen sind. Zb
1 | char txt[20];
|
2 | sprintf( txt, "Hallo" );
|
3 | uart1_puts( txt );
|
uart1_puts_p (kleines p)
*************************
Diese Funktion wird immer dann eingesetzt, wenn ich einen
(notwendigerweise konstanten) String habe, der im Flash liegt.
1 | const char FW_variable[] PROGMEM = "Firmware 16.12.2015";
|
2 | uart1_puts_p( FW_variable );
|
uart1_puts_P (grosses P)
*************************
Dieses Makro(!) wird immer dann eingesetzt, wenn ich ebenfalls einen
(notwendigerweise konstanten) String habe, der im Flash liegt.
Huch!
Was ist dann der Unterschied zu der Funktion uart1_puts_p bzw. warum
will ich da noch ein Makro haben?
Ganz einfach.
Wenn ich 'on the fly' einen String im Flash haben will, also zb
1 | uart1_puts_p( "ok" ); // der String "ok" soll im Flash liegen
|
dann geht das klarerweise so nicht. Ich kann den String nicht direkt im
Funtionsaufruf angeben. Ich müsste also schreiben
1 | const char pgmOk[] PROGMEM = "ok";
|
2 | ....
|
3 | uart1_puts_p( pgmOk );
|
und das wird auf Dauer mühsam. Vor allen Dingen dann, wenn ich
zwischendurch immer wieder mal einen neuen Text ins Programm einbauen
möchte. Dann muss ich jedesmal erst mühsam eine entsprechende PROGMEM
Variable anlegen, damit ich mich beim Funktionsaufruf darauf beziehen
kann. Ganz abgesehen davon, dass dann der eigentliche Text von der
Aufrufstelle entfernt wird. Denn woher weiss ich denn schon, was bei
1 | uart1_puts_p( pgmJuhu );
|
wirklich für ein Text ausgegeben wird? Ich müsste mir die Definition von
pgmJuhu suchen
1 | const char pgmJuhu[] PROGMEM = "Ready";
|
um das feststellen zu können.
Und genau da kommt jetzt die Variante von uart1_puts_P (mit grossem P)
ins Spiel. Diese Makroversion macht 2 Dinge. Zum einen verbannt sie den
angegebenen String ins Flash und zum zweiten ruft sie dann mit dem so
ins Flash verbannten String die Funktion uart_puts_p auf.
uart1_puts_P ist also eine Komfortversion, die mir den Tippaufwand von
oben erspart. Anstatt eine extra Variable anlegen zu müssen, auf die ich
mich dann im uart1_puts_p beziehen kann, kann ich gleich einfach
schreiben und das Makro erledigt den Rest. Der String "ok" wird im Flash
angelegt und die Funktion uart1_puts_p wird darauf aufgerufen.
Was ist daher an
1 | const char FW_variable[] PROGMEM = "Firmware 16.12.2015";
|
2 | uart1_puts_P( FW_variable );
|
falsch?
Na ganz einfach. FW_variable liegt ja schon im Flash!
Ich brauch daher nicht die 'gross P' Version, die mir das Argument ins
Flash verschieben würde, sondern ich brauch die Version mit dem 'kleinen
p', welche einen Pointer ins Flash annimmt, den ich mit FW_variable ja
schon habe.
1 | const char FW_variable[] PROGMEM = "Firmware 16.12.2015";
|
2 | uart1_puts_p( FW_variable ); // die Funktion mit dem kleinen p
|
und die Fehlermeldung 'invalid initializer' erklärt sich auch ganz
einfach. Wenn uart1_puts_P eine Hilfsvariable im Flash erzeugt, dann
will sie das Argument als Initialisierung benutzen. Da wird also
versucht eine Hilfsvariable im Flash erzeugt, die mit einer bereits im
Flash liegenden Variablen initialisiert werden soll.
1 | const char strTmp PROGMEM = FW_variable;
|
und das ist in C nun einmal illegal.