Hallo it would be fine if somebody could help me on the following problem: I have to send the decimal digits of a 5 Byte Hex value, that is currently stored in an array, via the serial interface. It is no problem to get the digits of a 4 Byte number but Keil or the controller do not allow double integer! any solution????
What you need is a function to divide a 40-bit value by ten. You may be able to adapt the fast_long_divide() function to be found here: http://www.programmersheaven.com/zone5/cat27/32144.htm
OK, just for fun, try this:
#pragma ASM $REGUSE _fast_40_bit_divide( A, B, PSW, R0, R5, R7 ) PUBLIC fast_40_bit_divide #pragma ENDASM unsigned char fast_40_bit_divide( unsigned char data * dividend, unsigned char divisor ) small { dividend = dividend; // Suppress unused variable warning. divisor = divisor; // Suppress unused variable warning. #pragma ASM // pointer to dividend: R7 // divisor in: R5 // uses: // quotient returned in: data memory // remainder returned in: R7 pointer SET R0 ; divisor SET R5 ; ; MOV A,R7 ; MOV pointer,A ; ; fast_40_bit_divide: ; ; MOV A,@R0 ;Get the MS byte of dividend and divide MOV B,divisor ; it by the divisor. DIV AB ; ; MOV @R0,A ;Store result of division as quotient. ; MOV A,B ;Save the remainder (which must be in SWAP A ; the range 0...15) shifted four bits MOV B,A ; to the left. ; INC R0 ; ; MOV loop,#04 ;load loop counter. ; ?fast_40_bit_divide_loop: ; ; MOV A,@pointer ;Get the MS nibble of the SWAP A ; dividend into the accumulator. ANL A,#0x0F ; ORL A,B ; Or in remainder from last iteration. ; MOV B,divisor ;Divide MS nibble by the divisor. DIV AB ; ; SWAP A ;Save partial result (which must be MOV partial,A ; in the range 0...15) shifted 4 bits. ; MOV A,B ;Read remainder (which must be in SWAP A ; the range 0...15) and shift 4 bits left. ; XCHD A,@pointer ;Get next nibble of the dividend into ; the accumulator. MOV B,divisor ;Divide by the divisor. DIV AB ; ; ORL A,partial ;Or in the previously saved partial result. MOV @pointer,A ;Save the MSB of the quotient ready ; to be returned. ; MOV A,B ;Save remainder SWAP A ; shifted 4 bits left MOV B,A ; in B. ; INC pointer ; DJNZ loop,?fast_40_bit_divide_loop SWAP A ;The final remainder is in upper nibble MOV R7,A ; of accumulator. ; RET ; #pragma ENDASM return( dividend ); }
unsigned int loop; unsigned char r; // MSB LSB data unsigned char v[5] = { 0x01, 0xFF, 0xFF, 0xFF, 0xFE }; // == 8589934590 decimal loop = 14; do { r = fast_40_bit_divide( &v, 10 ); }while( --loop != 0 );
Minor update:
#pragma ASM $REGUSE _fast_40_bit_divide( A, B, PSW, R0, R3, R4, R5, R6, R7 ) PUBLIC fast_40_bit_divide #pragma ENDASM unsigned char fast_40_bit_divide( unsigned char data * dividend, unsigned char divisor ) small { dividend = dividend; // Suppress unused variable warning. divisor = divisor; // Suppress unused variable warning. #pragma ASM // pointer to dividend: R7 // divisor in: R5 // uses: R3, R4, R6 // quotient returned in: data memory // remainder returned in: R7 pointer SET R0 ; remainder SET R3 ; partial SET R4 ; divisor SET R5 ; loop SET R6 ; ; MOV A,R7 ; MOV pointer,A ; ; fast_40_bit_divide: ; ; MOV A,@R0 ;Get the MS byte of dividend and divide MOV B,divisor ; it by the divisor. DIV AB ; ; MOV @R0,A ;Store result of division as quotient. ; MOV A,B ;Save the remainder (which must be in SWAP A ; the range 0...15) shifted four bits MOV B,A ; to the left. ; INC R0 ; ; MOV loop,#04 ;load loop counter. ; ?fast_40_bit_divide_loop: ; ; MOV A,@pointer ;Get the MS nibble of the SWAP A ; dividend into the accumulator. ANL A,#0x0F ; ORL A,B ; Or in remainder from last iteration. ; MOV B,divisor ;Divide MS nibble by the divisor. DIV AB ; ; SWAP A ;Save partial result (which must be MOV partial,A ; in the range 0...15) shifted 4 bits. ; MOV A,B ;Read remainder (which must be in SWAP A ; the range 0...15) and shift 4 bits left. ; XCHD A,@pointer ;Get next nibble of the dividend into ; the accumulator. MOV B,divisor ;Divide by the divisor. DIV AB ; ; ORL A,partial ;Or in the previously saved partial result. MOV @pointer,A ;Save the MSB of the quotient ready ; to be returned. ; MOV A,B ;Save remainder SWAP A ; shifted 4 bits left MOV B,A ; in B. ; INC pointer ; DJNZ loop,?fast_40_bit_divide_loop SWAP A ;The final remainder is in upper nibble MOV R7,A ; of accumulator. ; RET ; #pragma ENDASM return( dividend ); }
When you are using printf, you need to use the 'l' prefix to mark a number as a long value. See http://www.keil.com/support/man/docs/c51/c51_printf.htm
"you need to use the 'l' prefix to mark a number as a long value." Yes, but a long is only four bytes: http://www.keil.com/support/man/docs/c51/c51_ap_4bytescalar.htm The OP is using a 5-byte (40-bit) number!
Sorry, I missed the 5-Byte requirement.
Any projected delivery date for "long long" (64 bit) support? (No, it's not a crazy thing to want to do with an 8-bit micro. To cite one example, IEEE 802 requires all statistics / event counters not to roll over for at least 57 minutes while counting their maximum rate. Counters that cannot achieve this duration in 32 bits must be 64 bits wide, per spec. For a Gigabit Ethernet device, that means most of the defined stats. It's not at all out of the scope of an 8051 to be embedded in a NIC card or what-have-you, and 1Gbps is a pretty routine rate these days. Not all long integers show up in astronomy programs and Bill Gate's bank accounts.)
"Any projected delivery date for "long long" (64 bit) support?" And 64 bit doubles please?
View all questions in Keil forum