View Full Version : Display 2 WORDs as a 32bit integer
HenrikOlsson
- 30th November 2024, 14:55
I have two WORD variables representing a 32bit number, lets call them CountH and CountL.
I am displaying these as the two individual variables they are, using HSEROUT with the DEC modifier. (ex: 12, 45234 where 12 is CountH and 45234 is CountL)
Ideally I'd like to display them as the signed 32bit integer that they represent (ex: 831666). I'm at 14.8k on a 16k device, switching to LONGs is not an option, switching device is not an option either since the 18F2431 is the only bloody 8-bitter with the QEI peripheral.
Anyone have a nifty routine to do it?
/Henrik.
richard
- 30th November 2024, 22:38
maybe something like this old gem
Hours VAR WORD[2] ; 32-bit (Dword) Holds up to 99999.9 hoursHoursH VAR Hours(1)
HoursL Var Hours(0)
Result Var Word
Remainder Var Word
;----[Load a 32-bit (Dword) variable into PBP registers, Prior to DIV32]--------
Asm
PutMulResult?D macro Din
MOVE?BB Din, R2
MOVE?BB Din + 1 , R2 + 1
MOVE?BB Din + 2, R0
MOVE?BB Din + 3, R0 + 1
RST?RP
endm
EndAsm
;====[Simple loop to test the HourMeter]========================================
MainLoop:
gosub AddHourTenth
Gosub ShowHourMeter
goto MainLoop ;================================================= ===========
;----[Add 1 tenth of an hour to the hourmeter]----------------------------------
AddHourTenth:
HoursL = HoursL + 1
IF HoursL = 0 then HoursH = HoursH + 1
if (HoursH = $F) and (HoursL = $4240) then ; Roll over at 1,000,000
HoursH = 0 ; 99999.9 + .1
HoursL = 0
endif
return
;----[Display hourmeter using LCDOUT]-------------------------------------------
ShowHourMeter:
@ PutMulResult?D _Hours
Result = DIV32 1000
Remainder = R2
LCDOUT $FE, 2 ; Home Cursor
IF Result > 0 then
LCDOUT Dec Result, DEC2 Remainder/10,".",DEC1 Remainder//10
else
LCDOUT DEC Remainder/10,".",DEC1 Remainder//10
endif
return
the other way is n-bit math
like post #23 here (https://support.melabs.com/forum/picbasic-pro-compiler-3-0-and-later/asm-assembly-language-in-picbasic-pro/972-asm-error-address-label-duplicated-ot-different-in-second-pass/page2)
richard
- 1st December 2024, 10:49
signed 32 bit divide here
(https://forum.microchip.com/s/topic/a5C3l000000LziXEAS/t228973)
or do it the easy way in C where its not an issue
HenrikOlsson
- 1st December 2024, 11:14
Thanks Richard,
I don't need to "do" anything with the value, "all" I need is to display it
ValueH = 12
ValueL = 45234
GOSUB Print32BitValue
Result: 831666
I tried your HourMeter aproach and it works fine with example above. Cool!
Unfortunately it falls appart when the high word is >1000, ie when the Result of DIV32 is >65535.
Without really thinking I changed DIV32 to 10000 and massaged the display code but obviously it only pushes the problem to when the high word is >10000.
I feel daft...
Jerson
- 1st December 2024, 14:04
Many years back, I solved the problem like this.
I have a variable Total defined as 4 bytes
In the routine that increments the total, I did it like this
Total var byte[4] ' packed BCD totalizer upto 99999999
asm
; assembler code embedded into PBP increments Total till 99999999 and then rolls over
incf _Total+3
movlw 100
subwf _Total+3,w
btfss status,c
goto DoneTotal
clrf _Total+3
;
incf _Total+2
movlw 100
subwf _Total+2,w
btfss status,c
goto DoneTotal
clrf _Total+2
;
incf _Total+1
movlw 100
subwf _Total+1,w
btfss status,c
goto DoneTotal
clrf _Total+1
;
incf _Total+0
movlw 100
subwf _Total+0,w
btfss status,c
goto DoneTotal
clrf _Total+0
DoneTotal:
endasm
This allows for a maximum total content of 99,99,99,99 with Total[3] being the lowest byte
Now, in the display routine, I did something like this to show the lower 6 digits. Mind you, this is only for unsigned values.
Dat = Total[2] dig 0
gosub Code2Segment ' convert to 7 segment code
gosub Dsp_Data ' display the 7 segment code
Dat = Total[2] dig 1
gosub Code2Segment
gosub Dsp_Data
Dat = Total[1] dig 0
gosub Code2Segment
gosub Dsp_Data
Dat = Total[1] dig 1
gosub Code2Segment
gosub Dsp_Data
Dat = Total[0] dig 0
gosub Code2Segment
gosub Dsp_Data
Dat = Total[0] dig 1
gosub Code2Segment
gosub Dsp_Data
I hope this will help you find some solution to your stated problem.
Cheers
NickMu
- 1st December 2024, 15:05
Many years ago DT helped me with something similar
https://www.picbasic.co.uk/forum/showthread.php/24-Retrieving-32bit-Multiply-Result (https://www.picbasic.co.uk/forum/showthread.php/24-Retrieving-32bit-Multiply-Result)
Not sure if it might apply to your application.
Nick
richard
- 2nd December 2024, 02:53
Without really thinking I changed DIV32 to 10000 and massaged the display code but obviously it only pushes the problem to when the high word is >10000.
yes biggest num is 655359999
this does a divide by 100000 first in asm and will do rest in pbp to encompass the entire 32 bit signed range
#config CONFIG RETEN=OFF
CONFIG XINST = OFF ;Extended Instruction Set
CONFIG FOSC = INTIO2 ;internal RC oscillator
CONFIG SOSCSEL=DIG
CONFIG FCMEN = OFF ;Fail-Safe Clock Monitor ****
CONFIG IESO = OFF ;Two-Speed Start-up is disabled
CONFIG PLLCFG = OFF ;4x xtal PLL
CONFIG PWRTEN = ON ;Power-up Timer
CONFIG BOREN = SBORDIS ; Brown-out Reset Enabled in hardware, SBOREN disabled
CONFIG BORPWR = HIGH ;BOR MV set to high power level
CONFIG BORV = 2 ; Brown-out Reset 0=3v, 1=2.7v, 2=2v, 3=1.8v
CONFIG WDTEN = SWDTDIS ;ON ;OFF ;WDT enabled in hardware; SWDTEN bit disabled
CONFIG WDTPS = 512 ;WDT 512*4Ms = 2 SECONDS
CONFIG RTCOSC = INTOSCREF ; RTCC uses INTRC
CONFIG MCLRE = ON
CONFIG STVREN = ON ;Stack Full/Underflow Reset
CONFIG DEBUG = OFF ;Background Debugger
CONFIG CP0 = OFF ;code-protected
CONFIG CP1 = OFF
CONFIG CP2 = OFF
CONFIG CP3 = OFF
CONFIG CP4 = OFF
CONFIG CP5 = OFF
CONFIG CP6 = OFF
CONFIG CP7 = OFF
CONFIG CPB = OFF ;Boot Block Code Protection
CONFIG CPD = OFF ;Data EEPROM Code Protection
#endconfig
DEFINE OSC 64
DEFINE DEBUG_REG PORTD
DEFINE DEBUG_BIT 4
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 0 '0=TRUE 1=INVERTER
OSCCON=110100
OSCTUNE.6=1 'Frequency Multiplier PLL Enable bit FOR INIT RC
TRISD=$ed
ANCON0=0 'AN0-AN7 digital port
ANCON1=0 'AN8-AN15 digital port
ANCON2=0 'AN16-AN23 dig
PSPCON.4=0 'General Purpose I/O mode 'PSPMODE: Parallel Slave Port Mode Select bit
Test var byte[3] SYSTEM
Dividend var byte[6] SYSTEM
Remainder var byte[4] SYSTEM ; remainder from 1000000 division
Shift var byte[6] SYSTEM
Counter VAR BYTE SYSTEM
Hours VAR WORD[2] ; 32-bit (Dword) Holds up to 99999.9 hours
HoursH VAR Hours(1)
HoursL Var Hours(0)
QUOTL VAR WORD EXT ; top 5 digits
Result Var Word ; middle 10,000;s single digit
Remains Var Word ; bottom 4 digits
i var byte
goto overasm
Asm
QUOTL=Dividend
PutMulResult?D macro Din
MOVE?BB Din, R2
MOVE?BB Din + 1 , R2 + 1
MOVE?BB Din + 2, R0
MOVE?BB Din + 3, R0 + 1
RST?RP
endm
PutDIV?D macro Din
MOVE?BB Din, Dividend
MOVE?BB Din + 1 , Dividend + 1
MOVE?BB Din + 2, Dividend + 2
MOVE?BB Din + 3, Dividend + 3
MOVE?CB 0 , Dividend + 4
MOVE?CB 0 , Dividend + 5
RST?RP
endm
EndAsm
Remainder[3]=0
overasm:
HoursL=$fff0
HoursH=$7fff
latd=18
debug "ready",13,10
pause 1000
MainLoop:
gosub AddHourTenth
Gosub ShowHourMeter
goto MainLoop ;================================================= ===========
AddHourTenth:
HoursL = HoursL + 1
IF HoursL = 0 then HoursH = HoursH + 1
return
ShowHourMeter:
Test [0]=$a0 ;divisor 100000
Test [1]=$86
Test [2]=1
@ PutDIV?D _Hours
CALL Div4824U ;divide by 100000
debug ,13,10
@ PutMulResult?D Remainder
Result = DIV32 10000
Remains = R2
debug DEC QUOTL, Dec1 Result, ".",DEC4 Remains ,13,10
pause 1000
return
;************************************************* *************************
;Div4824U
;Inputs:
; Dividend - Dividend:6 (0 - least significant!)
; Divisor - Test:3 (0 - least significant!)
;Temporary:
; Counter - Count
; Shift - Shift:6
;Output:
; Quotient - Dividend:6 (0 - least significant!)
; Remainder- Rem:3 (0 - least significant!)
;
;Adaptation of 24x24 division by Tony Nixon with corrections
;by Frank Finster 3/15/2005.
;Code adapted by Andy Lee
;01-Sep-2006 Original version
;************************************************* *************************
Div4824U:
asm
;---------------------------------------------------
; SUBROUTINE - 48 by 24 BIT DIVISION
movlw 48
movwf Counter
movff Dividend+0, Shift+0
movff Dividend+1, Shift+1
movff Dividend+2, Shift+2
movff Dividend+3, Shift+3
movff Dividend+4, Shift+4
movff Dividend+5, Shift+5
clrf Dividend+0
clrf Dividend+1
clrf Dividend+2
clrf Dividend+3
clrf Dividend+4
clrf Dividend+5
clrf Remainder+2
clrf Remainder+1
clrf Remainder+0
dloop
bcf STATUS, C
rlcf Shift+0
rlcf Shift+1
rlcf Shift+2
rlcf Shift+3
rlcf Shift+4
rlcf Shift+5
rlcf Remainder+0
rlcf Remainder+1
rlcf Remainder+2
movf Test+2, w
subwf Remainder+2, w
btfss STATUS, Z
bra nochk
movf Test+1,w
subwf Remainder+1,w
btfss STATUS, Z
bra nochk
movf Test+0,w
subwf Remainder+0,w
nochk
btfss STATUS, C
bra nogo
movf Test+0,w
subwf Remainder+0
btfsc STATUS, C
bra nodec_remainM
decf Remainder+1, f
movf Remainder+1, w
xorlw 0xff
btfsc STATUS, Z
decf Remainder+2, f
nodec_remainM
movf Test+1, w
subwf Remainder+1, f
btfss STATUS, C
decf Remainder+2, f
movf Test+2, w
subwf Remainder+2, f
bsf STATUS, C
nogo
rlcf Dividend+0
rlcf Dividend+1
rlcf Dividend+2
rlcf Dividend+3
rlcf Dividend+4
rlcf Dividend+5
decfsz Counter, f
goto dloop
return
endasm
HenrikOlsson
- 2nd December 2024, 19:28
Thanks Nick,
As far as I can see the examples provided by Darrel in that thread has the same limitation as in "only" going to 655359999 which is "only" ~15% of the 32bit range.
In my case I really do need the full 32bits since the value can and do wrap around. Displaying it signed would be cool but I'll take unsigned over what I have right now any day.
Richard,
Wow, thank you very much indeed!
I have it running on a little dev.board, next is to incorporate it in the actual code, we'll see how that goes.
Thanks again!
/Henrik.
richard
- 2nd December 2024, 23:59
A few tweaks to scrounge some resources back
Test var byte[3] SYSTEM
Dividend var byte[6] SYSTEM
Remainder var byte[3] SYSTEM ; 24 bit remainder from 1000000 division
Shift var byte[6] SYSTEM
Counter VAR BYTE SYSTEM
Hours VAR WORD[2] ; 32-bit
HoursH VAR Hours(1)
HoursL Var Hours(0)
QUOTL VAR WORD EXT ; top 5 digits
Result Var Word ; middle 10,000;s single digit
Remains Var Word ; bottom 4 digits
i var byte
goto overasm
Asm
QUOTL=Dividend
PutMulResult?D macro Din
MOVE?BB Din, R2
MOVE?BB Din + 1 , R2 + 1
MOVE?BB Din + 2, R0
MOVE?BB Din + 3, R0 + 1
RST?RP
endm
PutDIV?D macro Din
MOVE?BB Din, Dividend
MOVE?BB Din + 1 , Dividend + 1
MOVE?BB Din + 2, Dividend + 2
MOVE?BB Din + 3, Dividend + 3
MOVE?CB 0 , Dividend + 4
MOVE?CB 0 , Dividend + 5
RST?RP
endm
PutSH?D macro Din
MOVE?BB Din, Shift
MOVE?BB Din + 1 , Shift + 1
MOVE?BB Din + 2, Shift + 2
MOVE?BB Din + 3, Shift + 3
MOVE?CB 0 , Shift + 4
MOVE?CB 0 , Shift + 5
RST?RP
endm
Put24?D macro Din
MOVE?BB Din, R2
MOVE?BB Din + 1 , R2 + 1
MOVE?BB Din + 2, R0
MOVE?CB 0, R0 + 1
RST?RP
endm
EndAsm
' Remainder[3]=0
overasm:
HoursL=$fff0
HoursH=$7fff
latd=18
debug "ready",13,10
pause 1000
MainLoop:
gosub AddHourTenth
Gosub ShowHourMeter
goto MainLoop ;================================================= ===========
AddHourTenth:
HoursL = HoursL + 1
IF HoursL = 0 then HoursH = HoursH + 1
return
ShowHourMeter:
Test[0]=$a0 ;divisor 100000
Test[1]=$86
Test[2]=1
;@ PutDIV?D _Hours
@ PutSH?D _Hours ; take a shortcut and load shift regs directly
CALL Div4824U ;divide by 100000
debug ,13,10
;@ PutMulResult?D Remainder
@ Put24?D Remainder ; only do a 24 bit load since answer is never bigger than that
Result = DIV32 10000
Remains = R2
debug DEC QUOTL, Dec1 Result, ".",DEC4 Remains ,13,10
pause 1000
return
;************************************************* *************************
;Div4824U
;Inputs:
; Dividend - Dividend:6 (0 - least significant!)
; Divisor - Test:3 (0 - least significant!)
;Temporary:
; Counter - Count
; Shift - Shift:6
;Output:
; Quotient - Dividend:6 (0 - least significant!)
; Remainder- Rem:3 (0 - least significant!)
;
;Adaptation of 24x24 division by Tony Nixon with corrections
;by Frank Finster 3/15/2005.
;Code adapted by Andy Lee
;01-Sep-2006 Original version
;************************************************* *************************
Div4824U:
asm
;---------------------------------------------------
; SUBROUTINE - 48 by 24 BIT DIVISION
movlw 48
movwf Counter
;movff Dividend+0, Shift+0
;movff Dividend+1, Shift+1
;movff Dividend+2, Shift+2
;movff Dividend+3, Shift+3
;movff Dividend+4, Shift+4
;movff Dividend+5, Shift+5
clrf Dividend+0
clrf Dividend+1
clrf Dividend+2
clrf Dividend+3
clrf Dividend+4
clrf Dividend+5
clrf Remainder+2
clrf Remainder+1
clrf Remainder+0
dloop
bcf STATUS, C
rlcf Shift+0
rlcf Shift+1
rlcf Shift+2
rlcf Shift+3
rlcf Shift+4
rlcf Shift+5
rlcf Remainder+0
rlcf Remainder+1
rlcf Remainder+2
movf Test+2, w
subwf Remainder+2, w
btfss STATUS, Z
bra nochk
movf Test+1,w
subwf Remainder+1,w
btfss STATUS, Z
bra nochk
movf Test+0,w
subwf Remainder+0,w
nochk
btfss STATUS, C
bra nogo
movf Test+0,w
subwf Remainder+0
btfsc STATUS, C
bra nodec_remainM
decf Remainder+1, f
movf Remainder+1, w
xorlw 0xff
btfsc STATUS, Z
decf Remainder+2, f
nodec_remainM
movf Test+1, w
subwf Remainder+1, f
btfss STATUS, C
decf Remainder+2, f
movf Test+2, w
subwf Remainder+2, f
bsf STATUS, C
nogo
rlcf Dividend+0
rlcf Dividend+1
rlcf Dividend+2
rlcf Dividend+3
rlcf Dividend+4
rlcf Dividend+5
decfsz Counter, f
goto dloop
return
endasm
HenrikOlsson
- 3rd December 2024, 17:31
Thanks Richard,
I won't pretend to comprehend the assembly voodoo but I think we can shave another BYTE worth of RAM off that thing by declaring Result as a BYTE instead of a WORD. At least it seems to work :-)
/Henrik.
HenrikOlsson
- 7th December 2024, 15:23
Richard,
Just wanted to thank you once again, the code is now incorporated in my project and I can display my two 32bit variables nicely.
I hardcoded the divisor to 100k and got rid of the Divisor variable. It grew the codebase by 230bytes and 34bytes of RAM out of which 11 is an array to which I write the result
DWORDtoString:
CALL DivBy100k
' QUOTL top word, Remainder low word.
' Get Remainder into PBP system variables in preparation for DIV32
ASM
MOVE?BB Remainder, R2
MOVE?BB Remainder + 1 , R2 + 1
MOVE?BB Remainder + 2, R0
MOVE?CB 0, R0 + 1
RST?RP
ENDASM
Result = DIV32 10000
Remains = R2
IF QUOTL THEN
ARRAYWRITE DWordString, [DEC QUOTL, DEC Result, DEC4 Remains, 0]
ELSEIF Result THEN
ARRAYWRITE DWordString, [DEC Result, DEC4 Remains, 0]
ELSE
ARRAYWRITE DWordString, [DEC Remains, 0]
ENDIF
amgen
- 7th December 2024, 22:37
Is it possible to describe the method or algorithm to get the decimal from the possible 8 hexadecimal of 32 bit number.... the conversion itself is pretty straight forward but the 8 bit manipulations are confusing...
.
.9870
richard
- 8th December 2024, 04:35
Just wanted to thank you once again
No problem Henrik glad you could make it work for you. its good to exercise the grey matter occasionally
@amgen
the conversion itself is pretty straight forward but the 8 bit manipulations are confusing...
to which 8bit manipulations do you refer ?
Jerson
- 9th December 2024, 02:23
Is it possible to describe the method or algorithm to get the decimal from the possible 8 hexadecimal of 32 bit number.... the conversion itself is pretty straight forward but the 8 bit manipulations are confusing...
.
.9870
Consider this code.
dim array[8] as byte ' your hex bytes ($00-$0F) are input here from MSN to LSNibble
decimal as long ' 32 bit value
decimal = 0
for i = 0 to 7
decimal = decimal * 16 ' nibble max value is 16, so multiply the existing value by 16 to move decimal value one nibble to the left
decimal = decimal + array[i] ' add in the new nibble
next
' at this point, decimal contains the converted value of the hex digits
Is this what you're looking for?
Powered by vBulletin® Version 4.1.7 Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.