Source file: /~heha/Mikrocontroller/avr-inc.zip/itoa.i90

;Integer-zu-ASCII-Konvertierung für ATmega
;h#s 01/06
#ifndef ITOA_I90
#define ITOA_I90

;Im Gegensatz zu "itoa()" wird auf die serielle
;Schnittstelle ausgegeben, also eher wie "printf()".
;Ein "richtiges" itoa() entsteht durch Ausgabeumlenkung
;auf einen Speicherbereich innerhalb von putchar().

;Benötigt:
;	putchar(r16)	Zeichen schreiben (blockierend)

;Bietet (r32 bezeichnet r5:r4:r3:r2):
;	neg4(r32)		Negation 32bit
;	zero4(r32)		Ist 32-bit-Register Null
;	divu4u1(r32,r17)	Division 0:32bit/8bit=32bitR8bit
;	SendNumberXxx(r32,...)	Zahlenausgabe (immer 32bit!)
;	Dez		dezimal
;	DezInt		dezimal ohne Komma, vzb.
;	DezIntMin	dezimal ohne Komma, vzb. und minimale Feldbreite

;Gegenüber printf() folgende Einschränkungen:
;	hexadezimale Kleinbuchstaben nur per Kompilierung
;	Nur rechtsbündige Ausgabe
;	Kein Zwangs-Plus, kein abgesetztes Vorzeichen

;Gegenüber printf() folgende Erweiterungen:
;	beliebige Zahlenbasis (auch 2)
;	Festkomma-Ausgabe
;	Festlegbare Zeichen

.include "makros.i90"

#ifndef ITOA_DELIM	;Anwender kann Ausgabezeichen ändern
# define ITOA_DELIM ','	;Komma-Zeichen (ggf. '.')
# define ITOA_MINUS '-'	;Minus-Zeichen (ggf. typografisches Minus)
# define ITOA_PLUS  '+'	;Plus-Zeichen (für Zwangs-Plus)
# define ITOA_SPACE ' '	;führende Leerzeichen (ggf.  )
# define ITOA_DEC_0 '0'	;Ziffern (ggf. Präsentationsformen)
# define ITOA_HEX_A 'A'	;hexadezimales 'A' (ggf. Kleinbuchstabe)
#endif

neg4:
;32-bit-Zahl in R5:R4:R3:R2 negieren
;VR: R2-R5, R16
	neg	r2
	negc	r3
	negc	r4
	negc	r5
	ret

zero4:
;32-bit-Zahl in R5:R4:R3:R2 auf Null testen
;VR: R16
	mov	r16,r2	;Ist da noch ein Bit?
	or	r16,r3
	or	r16,r4
	or	r16,r5
	ret

divu4u1:	;speziell für 32-bit-Zahlenausgabe
;PE: R5:R4:R3:R2 = Zähler vzl.
;    R17 = Nenner, Divisor vzl. (bleibt erhalten)
;PA: R5:R4:R3:R2 = Ergebnis
;    R16 = Rest
;VR: R2-R5,R16
	push	r18
	 clr	r16		;40-bit-Akku
	 ldi	r18,32
div4:	 lslw	r3,r2		;Null einschieben
	 rolw	r5,r4
	 rol	r16
	 brcs	div4sub		;Bei Überlauf immer subtrahieren
	 cp	r16,r17
	 brcs	div4nosub	;Wenn High-Teil < Nenner, dann nicht subtrahieren
div4sub:
	 sub	r16,r17
	 inc	r2		;LSB im Divisionsergebnis setzen
div4nosub:
	 djnz	r18,div4
	pop	r18
	ret
	


SendNumberDezIntMin:
	clr	r19		;minimale Feldbreite (1)
SendNumberDezInt:
	ldi	r18,0x80	;ohne Komma, vzb.
SendNumberDez:
	ldi	r17,10		;dezimal
SendNumber:
;32-bit-Zahl ausgeben
;PE: R5:R4:R3:R2 = Zahl
;    R17 = Zahlenbasis
;    R18 = Low-Nibble: Nachkommastellen (0 = kein Komma); Bit-Flags:
;	7: vorzeichenbehaftet (sonst vorzeichenlos)
;	6: Führende Nullen statt Dezimalstellen erzeugen
;	5: Zwangs-Plus (bei nichtnegativem Ergebnis, auch bei Null)
;	4: reserviert für Gruppierung (3 für dezimal, 4 für hex.)
;    R19 = Feldbreite (0 = minimal)
;PA: R19 = -Anzahl der über die Feldbreite verbrauchten Zeichen
;VR: R0,R2-R5=0, R1,R16,R18,R19
	mov	r1,r18	;Flags retten
	andi	r18,0x0F;Kommastellen im Low-Nibble
	ldi	r16,0x7F
	sbrs	r5,7	;Vorzeichen?
	 and	r1,r16	;Negativ-Merker weg wenn positiv
	clr	r0	;PUSH-Zähler
	sbrc	r1,7	;negativ?
;Argument negieren
	 rcall	neg4
sn4:	rcall	divu4u1
;aus Rest ASCII-Zeichen machen
	addi	r16,ITOA_DEC_0
	cpi	r16,ITOA_DEC_0+10 ;'0'..'9' OK, alles drüber nachbessern
	brlo	sn3		  ;'A' bis 'F' (oder höher) draus machen
	addi	r16,ITOA_HEX_A-ITOA_DEC_0-10
sn3:	;Ziffer wegpushen (LIFO)
	push	r16
	inc	r0	;PUSH-Zähler
	dec	r18	;Dezimalkomma-Zähler
	brne	sn8
	jbrs	r1,6, sn9
	ldi	r16,ITOA_DELIM
	push	r16
	inc	r0	;N-Bit bleibt gelöscht
sn8:	brpl	sn4	;Weitere Ziffern zwangsweise ausgeben
sn9:	rcall	zero4
	brne	sn4	;ja, weiter dividieren
	ldi	r16,ITOA_MINUS
	jbrs	r1,7, sn10
	jbrc	r1,5, sn7
	ldi	r16,ITOA_PLUS
sn10:	push	r16
	inc	r0
;Leerzeichen links ausgeben (immer rechtsbündig)
sn7:	sub	r19,r0	;Noch Platz für Leerzeichen?
	brcs	sn5	;nein, negativ
	breq	sn5	;nein, gerade keins
sn6:	ldi	r16,ITOA_SPACE
	rcall	putchar
	djnz	r19,sn6
;Ziffern ausgeben
sn5:	pop	r16
	rcall	putchar	;Zeichen in umgekehrter Reihenfolge ausgeben
	djnz	r0,sn5
	ret

#endif//ITOA_I90
Detected encoding: UTF-80