Routinensammlung und Gewusst-wie für Mikrocontroller

Zeichenketten

Zeichenketten (Strings) stellen eine wichtige Datenstruktur in Mikrocontroller-Programmen dar. Oft geht es um deren Ausgabe auf ein Display oder die serielle Schnittstelle. Daher folgen Hinweise für einen effektiven Umgang damit.

Grundlagen

Zeichenketten sollten in Mikrocontrollern nach zwei Kategorien eingeteilt werden: Am häufigsten sind nullterminierte Zeichenketten im Programmspeicher.

Festlegung

Konstante nullterminierte Zeichenketten werden in den verschiedenen Mikrocontroller-Assemblern und C wie folgt abgelegt:
8051-Keil,ASEM518051-WickenhäuserPICATmegaC166C
db "String",0.dc.b "String",0dt "String",0.db "String",0db "String",0"String"
In der Regel benötigt man zum Zugriff auf das erste Byte eine Marke. Der konstante String muss im Kodesegment liegen!

C-Compiler

Ein C-Compiler ermöglicht auch die Ablage konstanter Zeichenketten im Datensegment, erzeugt dafür allerdings unsinnigen Startup-Code! Wie man esordentlich hinbekommt steht in der Beschreibung des C-Compilers, die deswegen unbedingt durchgelesen werden muss. Oft stehen dazu Nicht-ANSI-Schlüsselwörter wie code zur Verfügung:
static const code str[]="String";
Oder aber Ihr C-Compiler wirft static const automatisch ins Kodesegment, dann haben Sie weniger Arbeit. Oder es existiert ein Kommandozeilenschalter dafür usw. usf.: RTFM!
Für die Zeiger-Übergabe gelten ebenfalls gesonderte Regeln. Nur bei Von-Neumann-Prozessoren (bspw. C166) entfällt dieser Ärger.

Zugriff darauf

Angenommen, man hat bereits eine Routine "putchar" zur Zeichenausgabe, dann sieht eine Zeichenkettenausgabe "puts" wie folgt aus:
8051PICATmegaC166C
puts: ;dptr=Str
 clr	a
 movc	a,@a+dptr
 jz	puts_e
 call	putchar
 inc	dptr
 jmp	puts
puts_e:
 ret
puts:	;X=Str
 movfw	X
 movwf	pc,f	;Ansprung
 iorlw	0	;Null-Test
 SKPNZ
  return
 call	putchar
 incf	X,f
 goto	puts
puts: ;Z=Str
 lpm
 adiw	zl,1
 tst	r0
 breq	puts_e
 mov	r16,r0
 rcall	putchar
 rjmp	puts
puts_e:
 ret
puts:	;R8=Str
 mov	rl4,[r8+]
 or	rl4,rl4
 jz	puts_e
 call	putchar	;R4=Zeichen
 jmp	puts
puts_e:
 ret
void puts(const char*str) {
 while (*str) putchar(*str++);
}
ostr:
 pop	dph
 pop	dpl
 call	puts
 jmp	@a+dptr	;Zurück (a=0)
unmöglich
ostr:
 pop	zh
 pop	zl
 add	zl,zl
 adc	zh,zh	;BYTEadresse
 rcall	puts
 adiw	zl,1	;aufrunden
 lsr	zh
 ror	zl	;WORTadresse
 ijmp
nicht möglich
Die dritte Zeile dieser Tabelle enthält Beispielkode für das bequeme Notieren der Zeichenkette hinter dem Funktionsaufruf(!), man braucht durch diese implizite Adressierung keine Marke setzen und Adresse laden.