0

I'm designing a calculator on atmega328p using assembly language, after performing the calculation I need to separate the result into digits to display them on LED matrix. Till now I wrote a code that does that with an 8-bit number (one register) and it's working correctly. However, when I start using two register for the high and low part of the number I'm not able to come up with a code that does the same.

the code for working with 8-bit number is attached below:

ldi r19, 0
HUNDS:
cpi resL, 100    ;compare low part of the result register with 100
brlo TENS
subi resL, 100
inc r19
rjmp HUNDS

TENS:         
st x+, r19    ;store hundreds counter in buffer for screen display (will be displayed on first screen block)
ldi r19, 0    ;reset counter for tens

TENS_Test:
cpi resL, 10
brlo UNITS
subi resL ,10
inc r19
rjmp TENS_Test

UNITS:
st x+, r19     ; store tens counter
st x+, resL    ; store units digit
Majd A.G
  • 3
  • 1
  • Do you know how to use subtract with carry to do 16 bit subtraction? Hint: the instruction set reference for `sbc` even has an example. Given that you can set up a table with powers of 10 that you can subtract in a loop. – Jester Aug 08 '22 at 21:02
  • @Jester I didn't quite understand the approach you mentioned. I'm still very new with assembly language. – Majd A.G Aug 08 '22 at 21:11
  • It's the same approach you used, just subtract 10000 in a loop, then 1000 in a loop, etc. But it's less code duplication if you use a table for the powers. – Jester Aug 08 '22 at 21:40
  • I thought of that but then I got confused with idea that a 16-bit number would be split between two registers, so I would have to work with both of them. can you give me an example of what you mean (e.g. digit for thousands)? – Majd A.G Aug 08 '22 at 22:33
  • 1
    Yes that's why I asked if you knew how to subtract with carry. Since 1000 is 3*256+232 that means high byte 3, low byte 232 (but the assembler will take care of that if you stick that into a table of words). – Jester Aug 08 '22 at 23:09

1 Answers1

0

if you want follow your approach, then one loop looks like this

         ldi zl, low(10000)
         ldi zh,high(10000)

         ldi r19, 0
loop:
         cp  resL, zl
         cpc resH, zh
         brlo endLoop
         sub resL, zl
         sbc resH, zh
         inc r19
         rjmp loop
endLoop:

But this is not good approach. Better is use division by 10 and save remainders in reverse order. You don't need reinvent division routines. You can find it in Atmel application note AVR200: Multiply and Divide Routines.

description is here

source is here

Peter Plesník
  • 524
  • 1
  • 2
  • 7
  • _"But this is not good approach"_: Depends ... the division routine you linked runs in 200+ cycles so this may very well be faster (especially if you remove the comparison from the loop and if your numbers are generally small). Also you get the digits in the proper order so you can ignore leading zeroes easily or you can transmit serially without any storage for reversing. – Jester Aug 10 '22 at 00:24
  • 1
    @Jester and peter thanks a lot for both of you. My confusion was mostly how to deal with 16 bit numbers (256-999), but it turned out I was making it harder than it is. I ended up using the same code by peter and applying it to both 1000s and 100s digits of my result, which worked without any issues. – Majd A.G Aug 10 '22 at 14:02