16 bit (word) binary to 5 digit ASCII characters

Go To Last Post
15 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hello:
I have written code to take a 16 bit number (in bytes nh, nl) & convert to 5 characters of ASCII to send out via the UART. The code shown is not yet fully tested. Is there a simplers/easier/more compact way to do this? I haven't seen any. I looked around a bit (no pun) & only saw a few routines that proided packed BCD. I want separate bytes & a short program. Any thoughts on bettering this are appreciated...note this is untested as my debug session is just starting.

Also, is there a "quicker" way to test a word against a specified value (say $ABCD)...I didn't see anything useful in the AVR. Loved those 8096 days!

Hoyt Clagwell

; 16 bit binary to 5 digit ASCII conversion
; the 16 bit value is in bytes nh & nl
; each of the 5 ascii digits is stored (sent) to a separate memory located (UART xmt buffer)
;NOTE---the data storage is not yet in this code
;NOTE this code has not been fully tested (but is about to be)
; 10000 base 10=$2710, 1000 base 10 =$03E7, 100 base 10=0064, 10 base 10= $000A
; 
			clr temp	;digit count
			ldi temp2, $30 ;ASCII conversion value (number to char)
loop10k:	cpi nh,$27
			brlo end10k	;if too low, <10000
			brpl ok10k  ;if more>10000 do subtract
			cpi nl,$10	;if msd's equal, compare lsd's
			brlo end10k
ok10k:		subi nl, $10	;subtract 10000
			sbci nh,$27
			inc temp	;count up 10k "counts"
			rjmp loop10k
end10k:		add temp,temp2 ;convert to ASCII
			;do store 10k char now

			clr temp	;reset digit  conversion count
loop1k:		cpi nh,$03
			brlo end1k	;if too low, <1000
			brpl ok1k  ;if more>1000 do subtract
			cpi nl,$E8	;if msd's equal, compare lsd's
			brlo end1k
ok1k:		subi nl, $E8	;subtract 1000
			sbci nh,$03
			inc temp	;count up 1k "counts"
			rjmp loop1k
end1k:		add temp,temp2 ;convert to ASCII
			;do store 1k digit

			clr temp	;reset digit  conversion count
loop100:	cpi nh,$00
			brlo end100	;if too low, <100
			brpl ok100  ;if more>100 do subtract
			cpi nl,$64	;if msd's equal, compare lsd's
			brlo end100
ok100:		subi nl, $64	;subtract 100
			sbci nh,$00
			inc temp	;count up 100's "counts"
			rjmp loop100
end100:		add temp,temp2 ;convert to ASCII
			;do store 100's digit

			clr temp	;reset digit  conversion count
loop10:		cpi nh,$00
			brlo end10		;if too low, <10
			brpl ok10  	;if more>10 do subtract
			cpi nl,$0A	;if msd's equal, compare lsd's
			brlo end10
ok10:		subi nl, $0A	;subtract 10
			sbci nh,$00
			inc temp	;count up 10's "counts"
			rjmp loop10
end10:		add temp,temp2 ;convert to ASCII
			;do store 10's digit
			add nl,temp2	;convert 1's digit to ASCII
			;do store 1's digit (value held by nl)
wait4evr:	rjmp wait4evr

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Every AVR-related topic has already been raised, discussed, and concensus reached on this Forum. [Well, there IS one exception--C vs. ASM. :) ]

See this extensive thread:
http://2313.avrfreaks.net/phpBB2...

which includes a reference to the mathematical aspects to kick it off.

The short summary: repeated subtraction of the powers of 10 isn't >>that<< bad of an approach, but it can be shortened.

I'm sure other Forum searches can uncover more discussions.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, I never thought I'd have to correct theusch, but it's conSensus!
Sorry, but you're part of my theory that Good Programmers pay attention to little things like spelling and punctuation. Don't let me down!

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have a look here

http://elm-chan.org/docs/avrlib/...

Other useful routines one level up

Look around his whole site - this guy is a one man wrecking crew!!

Tom

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John_A_Brown wrote:
Well, I never thought I'd have to correct theusch, but it's conSensus!
Sorry, but you're part of my theory that Good Programmers pay attention to little things like spelling and punctuation. Don't let me down!

I >>thought<< of looking it up. I could probably claim typo, but I'd be lying. I couldn't remember; and since "census" is spelled "census", and the English language is always consistent in these respects ... :wink: I should have been thinking of "consent" instead of "census".

It is still true that there has been quite a bit of thrashing about on binary-to-BCD/itoa()/ltoa()/printf() on the Forum in the past. The archives are a treasure trove of information.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And someday he might wonder how the c programmers did it

int mybinarynumber;
char mystring[10];

sprintf(mystring,"%5d",mybinarynumber); //puts it in a string variable

or just

printf("%5d",mybinarynumber); //prints it out

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

update...I tested & fixed my code...now works fine...thanks for the link to a somewhat cryptic solution!

*******
; 16 bit binary to 5 digit ASCII conversion
; the 16 bit value is in bytes nh & nl
; each of the 5 ascii digits is stored (sent) to a separate memory located (UART xmt buffer)
;NOTE---the data storage is not yet in this code
;NOTE this code HAS BEEN tested & seems to work well---NO REFUNDS ARE POSSIBLE
; 10000 base 10=$2710, 1000 base 10 =$03E7, 100 base 10=0064, 10 base 10= $000A
; 
bin2ascii:	clr temp	;digit count
			ldi temp2, $30 ;ASCII conversion value (number to char)
loop10k:	cpi nh,$27
			brlo end10k	;if too low, <10000, move on
			breq lsd10k  
			rjmp ok10k	;if >10000 do subtract
lsd10k:		cpi nl,$10	;if msd's equal, compare lsd's
			brlo end10k
ok10k:		subi nl, $10	;subtract 10000
			sbci nh,$27
			inc temp	;count up 10k "counts"
			rjmp loop10k
end10k:		add temp,temp2 ;convert to ASCII
			;do store 10k char now

			clr temp	;reset digit  conversion count
loop1k:		cpi nh,$03
			brlo end1k	;if too low, <1000, move on
			breq lsd1k 
			rjmp ok1k	;if >1000 do subtract
lsd1k:		cpi nl,$E8	;if msd's equal, compare lsd's
			brlo end1k
ok1k:		subi nl, $E8	;subtract 1000
			sbci nh,$03
			inc temp	;count up 1k "counts"
			rjmp loop1k
end1k:		add temp,temp2 ;convert to ASCII
			;do store 1k digit

			clr temp	;reset digit  conversion count
loop100:	cpi nh,$00
			brlo end100	;if too low, <100, move on
			breq lsd100
			rjmp ok100	;if >100 do subtract
lsd100:		cpi nl,$64	;if msd's equal, compare lsd's
			brlo end100
ok100:		subi nl, $64	;subtract 100
			sbci nh,$00
			inc temp	;count up 100's "counts"
			rjmp loop100
end100:		add temp,temp2 ;convert to ASCII
			;do store 100's digit

			clr temp	;reset digit  conversion count
loop10:		cpi nh,$00
			brlo end10		;if too low, <10, move on
			breq lsd10
			rjmp ok10	;if >10 do subtract
			brpl ok10  
lsd10:		cpi nl,$0A	;if msd's equal, compare lsd's
			brlo end10
ok10:		subi nl, $0A	;subtract 10
			sbci nh,$00
			inc temp	;count up 10's "counts"
			rjmp loop10
end10:		add temp,temp2 ;convert to ASCII
			;do store 10's digit
			add nl,temp2	;convert 1's digit to ASCII
			;do store 1's digit (value held by nl)
wait4evr:	rjmp wait4evr

[/code]

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

now to make it 1/5th the size, make a table of powers of 10 and just go thru the loop 5 times instead of all that inline code... not too many algorithms will compress 500% on the 1st try, but thats what us old guys are good at.... counting bytes and microseconds...

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
It is still true that there has been quite a bit of thrashing about on binary-to-BCD/itoa()/ltoa()/printf() on the Forum in the past. The archives are a treasure trove of information.

I remember reading some of it, I was quite suprised that repeated subtractions method performed so well. Especially after all the time I'd spent writing reverse ordered mod 10 routines!

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have done pretty much what avrcandies has done and it works well. It was pretty much a direct translation from an HC11 routine found in the BUFFALO monitor program. I will think about Bob's suggestion, of course examples are welcomed even in HC11 assembler :D

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I actually timed both routines back in the hc11 days... repeated subtraction of powers of 10 definitely wins when there is no hw divide by 10 instruction! If you imagine the digits to be a 'bell shaped curve', you'll only go thru each loop 5 times... hows that for a rationalization?

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It might have made more sense to do things the other way when different instructions took up significantly more cycle time. I mean if you think about it in order to cause all of your ASM code to become completly obsolute all you have to do is change the length of time it takes a few different instructions to execute. Then you have to completly re-optimize it.

-Curiosity may have killed the cat
-But that's why they have nine lives

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The original routine is sub-optimal. You failed to take advantage of the carry and zero flag propogation during mutli-byte subtracts & compares.

Here is your routine optimised for speed:

*******
; 16 bit binary to 5 digit ASCII conversion
; the 16 bit value is in bytes nh & nl
; each of the 5 ascii digits is stored (sent) to a separate memory located (UART xmt buffer)
;NOTE---the data storage is not yet in this code
;NOTE this code HAS BEEN tested & seems to work well---NO REFUNDS ARE POSSIBLE
; 10000 base 10=$2710, 1000 base 10 =$03E8, 100 base 10=0064, 10 base 10= $000A
;
bin2ascii:
         ldi temp, $2F ;Init ASCII conversion ('0'-1)
loop10k: inc temp      ;count up 10k "counts"
         subi nl, $10
         sbci nh, $27
         brcc loop10k  ;IF >=10000 THEN subtract again
         subi nl, $F0  ;subtract -10000 (add 10000)
         sbci nh, $D8
end10k:  ;do store 10k char now

         ldi temp, $2F ;Init ASCII conversion ('0'-1)
loop1k:  inc temp      ;count up 1k "counts"
         subi nl, $E8
         sbci nh, $03
         brcc loop1k   ;IF >=1000 THEN subtract again
         subi nl, $18  ;subtract -1000 (add 1000)
         sbci nh, $FC
end1k:  ;do store 1k char now

         ldi temp, $2F ;Init ASCII conversion ('0'-1)
loop100: inc temp      ;count up 100 "counts"
         subi nl, $64
         sbci nh, $00
         brcc loop100  ;IF >=100 THEN subtract again
         subi nl, $18  ;subtract -100 (add 100)
         sbci nh, $FC
end100:  ;do store 100 char now

;NB: I know (nh==0) so ignore nh from here

         ldi temp, $2F ;Init ASCII conversion ('0'-1)
loop10:  inc temp      ;count up 10 "counts"
         subi nl, $0A
         brcc loop10   ;IF >=10 THEN subtract again
         subi nl, $F6  ;subtract -10 (add 10)
end10:   ;do store 10's digit

         subi nl, $D0  ;convert 1's digit to ASCII
         ;do store 1's digit (value held by nl)

wait4evr: rjmp wait4evr

I use this method for 32-bit conversions but to keep the size sensible I store the powers of ten values in a table with the subtracting code in a subroutine.

Nigel

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
not too many algorithms will compress 500% on the 1st try, but thats what us old guys are good at.... counting bytes and microseconds...

So that the young guys can then burn them? :)

- John

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks a heap...just what I was looking for...it has been a while & I forgot that you could add via subtracting (too late to think about it)...I can use that method when I want a add immediate.

As you already know, no doubt, the 100's subtract value SHOULD BE $FF9C , but I wanted to mention this for the cut & paste crowd.

I appreciate your help
:P

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!