Jo, war wohl ungeschickt da zu annotieren.

Wenn du so was machst wie
Code:
blah()
{
   char str1[] = "...";
}
Dann ist das nicht sonderlich effizient. Die Variable wird erst bei der Benutzung initialisiert, also ist das langsam.

Besser ist dann schon so was wie
Code:
blah()
{
   static char str1[] = "...";
}
Hier wird beim Verwenden nur die Anfangsadresse des Strings zugewiesen, die eigentliche Initialisierung erfolt im Startup-Code aus der crt*.o

Für unveränderliche Strings ist das auch nicht so toll, weil das sowohl Platz im RAM (da lebt der String) und im Flash (von da aus wird er initialisiert) belegt.

Besser lässt man des String im Flash. Da AVRs aber eine Harvard-Architektur haben, kann man anhand der Adresse des Strings nicht mehr entsceiden, woher er kommt. Das allerdings muss man zur korrekten Behandlung wissen.

Du bräuchtest dann neben uart_send_string(char*) eine uart_send_string_P (prog_char*)

Code:
#include <avr/pgmspace.h>

void uart_send_char (const char);

void uart_send_string_P (const prog_char* pstr)
{
   while (1)
   {
      char c = (char) pgm_read_byte (pstr);
      if ('\0' == c)
         break;
      pstr++;
      uart_send_char (c);
   }
}

// Lokatiert den String ins Flash
const prog_char str2[] = "...";
//oder
const char str3[] PROGMEM = "...";

blah()
{
   uart_send_string_P (str2);
   // Schneller geschrieben ist folgendes, aber schlechter,
   // wenn öfter der gleiche String ausgegeben werden soll
   uart_send_string_P (PSTR ("..."));
}