Naja, weniger...
Code:
main:
	lpm							;Daten laden
   	mov tmp, lpm_reg           ;in temp verschieben
   	adiw ZL, 1                 	;Z um eins erhöhen
   	ldi tmp, LOW  ((daten1 * 2) + daten_laenge)	;vergleiche LOW-Byte
   	cp ZL, tmp
   	ldi tmp, HIGH ((daten1 * 2) + daten_laenge) ;vergleiche HIGH-Byte
   	cpc ZH, tmp
   	breq ende                   ;springe zu ende, wenn letztes Byte ausgelesen
   	rjmp main					;nochmal

ende:							;Endschleif
	rjmp ende
Nach diesem Befehl hier
mov tmp, lpm_reg
erhöhen wir den Zeiger ja um 1, ne? Damit wir das nächste Byte bekommen, also den nächsten Buchstaben. Und dann benutzt du aber wieder das gleich Register, wo wir ja eigentlich das Wort "Hallo!" drinne haben wollten:
ldi tmp, LOW ((daten1 * 2) + daten_laenge)
Da schreiben wir dann in tmp wieder einen völlig anderen Wert.

[EDIT]
Was mir grad auffällt, nach der Zeile hier:
cp ZL, tmp
da werten wir den Vergleich gar nicht aus, sonder nur nach cpc wird ausgewertet. Wieso das denn?