Author Message
 Buttercup1101
 Posted: May 03, 2012 - 06:04 PM
 Joined: Apr 20, 2012 Posts: 7
 Hello everyone. My problem is simple. I need to get the value from my 16bit counter1 to my LCD. I am programming in AVR Assembler! Lets say my counter has reached a count of 5000 that means that: TCNT1H = 0001 0011 TCNT1L = 1000 1000 The way I was trying to achieve this was by loading each nibble (after conversion) in its own byte like this: High_Byte_High_Nibble = 5 High_Byte_Low_Nibble = 0 Low_Byte_High_Nibble = 0 Low_Byte_Low_Nibble = 0 This will make it easy to print on to the LCD. The biggest problem I am having is that I can't wrap my mind around how to use a 16 Bit number to keep my count. But If anyone can point me in the direction of some example code, I would really appreciate it.

 david.prentice
 Posted: May 03, 2012 - 06:23 PM
 Joined: Feb 12, 2005 Posts: 16324 Location: Wormshill, England
 In the old days, there used to be books published for 6502, 6800, Z80 and other popular chips. If you can find an old book for \$1, it is worth buying. They would show you how to convert numbers to strings, multiply, divide, ... and other common tasks. Nothing has changed. The algorithms are the same. The ASM mnemonics vary slightly. A useful algorithm is to test and subtract 10000, 1000, 100, ... and output the relevant ascii digit. This involves no multiply or divide (and is what I used to do in 6502 ASM). Personally, I think you would be better advised to learn C or some other HLL. Writing whole apps in ASM is not worth the effort. David.

 Kidwidget
 Posted: May 03, 2012 - 06:29 PM
 Joined: May 18, 2004 Posts: 26 Location: Stockbridge, Georgia

 MBedder
 Posted: May 03, 2012 - 06:37 PM
 Joined: Nov 02, 2009 Posts: 3239 Location: Zelenograd, Russia
 Buttercup1101 wrote: The way I was trying to achieve this was by loading each nibble (after conversion) in its own byte like this: High_Byte_High_Nibble = 5 High_Byte_Low_Nibble = 0 Low_Byte_High_Nibble = 0 Low_Byte_Low_Nibble = 0 This will make it easy to print on to the LCD. Wrong idea. You have to convert the integer to ASCIIZ string instead and then just send this string to LCD.

 kk6gm
 Posted: May 03, 2012 - 06:51 PM
 Joined: Sep 12, 2009 Posts: 2406 Location: Sacramento, CA
 david.prentice wrote: A useful algorithm is to test and subtract 10000, 1000, 100, ... and output the relevant ascii digit. This involves no multiply or divide (and is what I used to do in 6502 ASM). I agree this a good approach for devices without hardware mul and div (and AVR has no hardware div)

 MBedder
 Posted: May 03, 2012 - 07:13 PM
 Joined: Nov 02, 2009 Posts: 3239 Location: Zelenograd, Russia
 david.prentice wrote: Nothing has changed. The algorithms are the same. The ASM mnemonics vary slightly. Oh really? How about this then? Code: ;--------------------------------------------------------------------------------------------------- ; Converts an unsigned integer N in W0 to a 5-byte ASCIIZ numerical string [W4] ; using a reciprocal multiplication and fractional conversion techniques ; ; 25 clocks including RETURN (0.625 uS @40 MIPS dsPIC), 16 program words ; Registers trashed: NONE ; ; (C) 2006 MBedder ; uitoa: magic10 = 429497                        ; =~ 2^32/10000         push.s                          ; Save W0..W3, SRL to shadow "stack"         mov     #magic10 >> 16,w1         mul.uu  w1,w0,w2                ; W3:W2 = partial product MSWs         mov     #magic10 & 0xFFFF,w1                  mul.uu  w1,w0,w0                ; W1:W0 = partial product LSWs                                                       add     w1,w2,w0                ; W0 = fract(N%10000)         mov     #'0',w2                 ; W2 = ASCII bit mask         addc.b  w3,w2,[w4++]            ; W3 = N/10000, store an ASCII MS character         inc     w0,w0                   ; Correct a remainder to use 16-bit ops         do      #3,1f                   ; Repeat the block below 4 times:                 mul.uu  w0,#10,w0       ; W1 = next ASCII digit (0..9 range), w0 = fractional remainder 1:      ior.b   w1,w2,[w4++]    ; Store a next ASCII character         clr.b   [w4]                    ; Place a zero string terminator         sub     w4,#5,w4                ; Restore W4         pop.s                           ; Restore W0..W3, SRL         return ;--------------------------------------------------------------------------------------------------- The (X)Mega equivalent would be ~5..8 times slower and ~3..4 times longer due to its poor architecture, lousy instruction set and primitive addressing modes, but anyway this algorithm is at least twice as fast comparing to the degrees of ten subtraction, or at least 5x faster than a popular Gorner algorithm (shift-correction). Last edited by MBedder on May 03, 2012 - 07:22 PM; edited 1 time in total

 david.prentice
 Posted: May 03, 2012 - 07:20 PM
 Joined: Feb 12, 2005 Posts: 16324 Location: Wormshill, England
 The basic algorithm is: Code: uint16_t decades[] = { 1, 10, 100, 1000, 10000 }; void printnum(uint16_t value, uint8_t width) {     uint8_t c;     while (width--) {         decade = decades[width];         c = '0';         while (value >= decade) {             value -= decade;             c++;         }         output(c);     } } You should be able to code that in ASM very easily. The output() subroutine either prints or appends a character to a string. (you need a NUL to terminate) You can access the decades[] array with the X, Y or Z register. The comparison can be a 'test subtraction' and inspect borrow flag. Note that this algorithm is no more than 20 lines of ASM. Heaven knows how anyone can bloat it to pages is a mystery! David.

 MBedder
 Posted: May 03, 2012 - 07:25 PM
 Joined: Nov 02, 2009 Posts: 3239 Location: Zelenograd, Russia
 ~15 lines, but slow enough (~300 clocks): Code: ;------------------------------------------------------------- ; Converts unsigned integer value of r17:r16 to ASCII string x[5] itoa_short:    ldi   zl,low(dectab*2)    ldi   zh,high(dectab*2) itoa_lext:    ldi   r18,'0'-1    lpm   r2,z+    lpm   r3,z+ itoa_lint:    inc   r18    sub   r16,r2    sbc   r17,r3    brsh   itoa_lint    add   r16,r2    adc   r17,r3    st   x+,r18    cpi   zl,low(dectab*2)+1    brne   itoa_lext    ret dectab:   .dw   10000,1000,100,10,1 ;-------------------------------------------------------------

 david.prentice
 Posted: May 03, 2012 - 07:44 PM
 Joined: Feb 12, 2005 Posts: 16324 Location: Wormshill, England
 @MBedder, I like your MIPS algorithm. The AVR algorithm may not be as fast, but it is certainly neat and tidy. Almost as elegant as a 6502 or 68000 solution! Which just goes to show that AVR assembly is not too unpleasant. David.

 MBedder
 Posted: May 03, 2012 - 08:20 PM
 Joined: Nov 02, 2009 Posts: 3239 Location: Zelenograd, Russia
 This is dsPIC, not MIPS. I just mentioned MIPS there as Million Instructions Per Second _________________Warning: Grumpy Old Chuff. Reading this post may severely damage your mental health.

 bobgardner
 Posted: May 03, 2012 - 10:57 PM
 Joined: Sep 04, 2002 Posts: 21272 Location: Orlando Florida
 Dave was just being diplomatic and didn't want to mention The Other Microcontroller company's cpu. _________________Imagecraft compiler user

 Buttercup1101
 Posted: May 04, 2012 - 11:42 AM
 Joined: Apr 20, 2012 Posts: 7
 WoW! Thanx for all the replies... Really helped me to get my code right!! Much appreciated!!

 bobgardner
 Posted: May 04, 2012 - 01:02 PM
 Joined: Sep 04, 2002 Posts: 21272 Location: Orlando Florida
 I'd like to see the Russkie's reciprocal algorithm in c is you please. _________________Imagecraft compiler user

 MBedder
 Posted: May 04, 2012 - 03:48 PM
 Joined: Nov 02, 2009 Posts: 3239 Location: Zelenograd, Russia
 It's almost impossible due to many register oriented tricks and handling the partial multiplication results. You can try reconstructing the algorithm in C using unions and explicit register variables, but I doubt this would be very efficient. _________________Warning: Grumpy Old Chuff. Reading this post may severely damage your mental health.

 sparrow2
 Posted: May 05, 2012 - 12:08 AM
 Joined: Oct 07, 2002 Posts: 2026 Location: Denmark
 If you need speed I have posted a fast (but ugly) ASM program that allways solve it in less than 70 clk. and it does it with div by mul with 1/x , in different ways find first digit div with 100 (result = 2 digit reminder the other two). div result with 10 (result = 2. digit reminder 3.) div reminder with 10 (result=4 and reminder 5.)

 theusch
 Posted: May 06, 2012 - 04:49 PM
 Joined: Feb 19, 2001 Posts: 25923 Location: Wisconsin USA
 Quote: Nothing has changed. Quote: If you need speed I have posted a fast (but ugly) ASM program that allways solve it in less than 70 clk. I thought that we explored every possible AVR approach years ago. http://www.avrfreaks.net/index.php?name ... torder=asc Besides "fastest" and "smallest", consider also "most useful". As I opined in the linked thread and elsewhere, right-justification and leading-zero suppression and insertion of implied decimal point is used with display work.

 Display posts from previous:  All Posts1 Day7 Days2 Weeks1 Month3 Months6 Months1 Year Oldest FirstNewest First
 Jump to: Select a forum Forum index|--[AVR (8-bit) Technical Forums]|   |-- AVR forum|   |-- XMEGA forum|   |-- AVR Wireless forum|   |-- AVR GCC forum|   |-- AVR Studio 5 and Atmel Studio 6 forum|   |-- AVR studio 4 forum|   |-- AVRfreaks Academy forum|   |-- AVR Tutorials|--[AVR Software Framework]|   |-- AVR Software Framework|--[AVR32 (32-bit) Technical Forums]|   |-- AVR32 Linux Forum|   |-- AVR32 General (standalone)|   |-- AVR32 Software Tools|   |-- AVR32 Hardware|--[General Electronics Technical Forums]|   |-- General Electronics|   |-- Atmel Security Products|--[Non-technical forums]|   |-- AVRfreaks.net Housekeeping|--[Non-topical forums]|   |-- Off-topic forum|   |-- AVRfreaks Trading Post
All times are GMT + 1 Hour