Shop OBEX P1 Docs P2 Docs Learn Events
Need to convert user input to multiple word value — Parallax Forums

Need to convert user input to multiple word value

gianallengianallen Posts: 16
edited 2012-09-24 12:20 in BASIC Stamp
Hi,

Along with a separate PIC chip, I am using a BS2pe to accumulate total flow from a flow meter. The BS2pe's role is to calculate an ongoing accumulation of the total pulse count into 2 words, giving a maximum value of 2^32 using Tracy Allen's double precision math routines (http://emesystems.com/BS2math6.htm).

Here's the issue that my feeble brain just can't seem to figure out:
I want a user in the field to be able to set an initial value for the count, as the flow meters we're working with often already have some initial total flow when we install our equipment. I can't figure out how to translate a large number that might be entered by a user (up to 8 digits) into a binary value that spans two 16-bit words.

For instance, if a user enters a value of "12345678", I need that to be stored in two words as $BC $614E. (Note that the user could also enter a small value (even 0) as well)

I have gone down several paths trying to solve this, but haven't gotten there. All I have so far is the user input stored in sequential bytes which I can then convert to decimal values for processing (of course, I could just as easily store the user input as a sequence of bytes in the scratchpad):


char0 VAR Byte
char1 VAR Byte
.
.
.
char7 VAR Byte

SERIN 16,$54,[STR char0\8\CR] <--- if user enter <8 digits, char0(ix) will be set to 0. Can be used to determine number of chars entered by user.

{Convert char0-char7 from ASCII to decimal before processing}

{Move decimal values into 2 words: the part where I can't figure out what to do...}


Any ideas how to get these digits into two words? Thank you.

-Gian

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2012-09-23 07:48
    You need to use the double precision routines to enter the value. To convert an ASCII digit to a number from 0-9, subtract "0". For each digit processed (left to right), multiply your 2-word value by 10, then add the digit. Both the multiply by 10 and the addition need to be done using the multiple precision routines. In each case, the high order word (of the 10 and the digit) would be a zero. In the case of the multiply, you can use the variation where the result is always 32 bits or less since 8 digits will always fit in 32 bits.
  • gianallengianallen Posts: 16
    edited 2012-09-24 00:24
    Thanks for the guidance Mike! I was literally on the verge of banging my head on the wall. I put your suggestions into practice and it looks like I've got it:
    ix VAR Word
    x0 VAR Word
    x1 VAR Word
    y0 VAR Word
    y1 VAR Word
    z0 VAR Word
    z1 VAR Word
    Ww VAR Word
    Wx VAR Word
    char0 VAR x0.BYTE0
    temp VAR Byte
    rm VAR Byte
    
    
    
    
    UserInputTo2Words:
    DO                                                              'loop for this demo
      DEBUG CR,"Enter up TO 8 digits",CR,">"
      SERIN 16,$54,[STR char0\8\CR]                'Accept user input up to 8 chars.  use STR command so we can take advantage of the \terminating char feature
      FOR ix = 0 TO 7                              'move digits entered by user into scratchpad so variable space can be reused
        PUT ix, char0(ix)
        'DEBUG 13,DEC ix,32,DEC char0(ix)
      NEXT
      DEBUG CR
    
    
      x0=0
      x1=0
      z0=0
      z1=0
      y0=0
      y1=0
    
    
      FOR ix = 0 TO 7
        GET ix, x0
        IF x0 = 0 THEN EXIT    'SERIN..[STR...] command fills unused bytes with decimal 0.  Use this as an indicator that all user-entered digits have been addded to total.
        y0= z0 * 10            'multiply result variable, Z, by 10.  Begin with low word, z0, using double precision multiplication
        y1= z0 ** 10
        z0 = y0
        z1 = z1  * 10 + y1     'now multiply the high result word, z1, by ten, and add in the result of the high word of the z0 x 10 calculation
        x0 = x0 - 48           'convert current digit to be added to total from ASCII to decimal
        z0 = z0 + x0           'add low word of result to the current digit being added to the total
        'z1 = z1 + x1          'don't need this step of the double precision addition as x1 is always 0 in this case
        IF z0<x0 THEN          'if addition of z0 + x0 causes z0 to roll over the max value of a word then increment the value of the high result word
          z1=z1+1
        ENDIF
        DEBUG "ix: ",DEC ix, TAB, "z1 z0: ",HEX z1,32,HEX z0,TAB,"x0: ",DEC x0,13
      NEXT
      DEBUG CR,"Final Results: ",13, "Hex (z1 z0): ",HEX z1,32,HEX z0,13, "Decimal: "
      GOSUB showdubdec100    'display decimal version of 2 words 
    LOOP
    
    
    showdubdec100:
      FOR ix=4 TO 0    ' 5 bytes can hold 10 digits
        temp=z1//100   ' high remainder
        z1=z1/100      ' high word of quotient
        rm=((temp*36//100)+(z0//100))  ' remainder calc
        z0=(temp*655)+(temp*36/100)+(z0/100)+(rm/100) 'low word of quotient
        rm=rm//100     ' final remainder
        PUT ix,rm      ' store remainder
      NEXT  ' ix next digits
      ' -- printout routine, digits stored in spRAM
      FOR ix=0 TO 4      ' print digits, most significant first
        GET ix,char0      ' from spRAM
        'GOSUB wratbuff1
        DEBUG DEC2 char0,32  ' includes leading zeros
      NEXT
      DEBUG CR
    RETURN
    
    
    
    
  • Tracy AllenTracy Allen Posts: 6,662
    edited 2012-09-24 11:09
    That looks good. I just hope your head is still okay after all that banging!

    Data entry and accumulation can be done in line with fewer variables and without first PUTting the data in scratchpad RAM.
    [SIZE=1][FONT=courier new]' {$STAMP BS2pe}
    ' {$PBASIC 2.5}
    x0 VAR WORD        ' x1:x0 is double word accumulator
    x1 VAR WORD
    char VAR BYTE
    idx VAR NIB
    
    DO
      DEBUG 13,"Enter a number up to 8 digits: "
      GOSUB enterDigits
      DEBUG 13,"Your number in binary hex is: ", IHEX4 x1, HEX4 x0
    LOOP
      
    
    enterDigits:
      x0 = 0
      x1 = 0
      FOR idx=0 TO 7
        SERIN 16,$54,[char]
        IF char = CR THEN EXIT
        IF char>="0" AND char <="9" THEN
          char = char - "0"
          x1 = (x1 * 10) + (x0 ** 10) ' accumulator*10
          x0 = x0 * 10 
          x0 = x0 + char              ' add user char
          IF x0 < char THEN x1 = x1 + 1   ' carry?!
        ENDIF
      NEXT
      RETURN ' x1:x0 contains the binary value of digits entered.
    [/FONT][/SIZE]
    
  • gianallengianallen Posts: 16
    edited 2012-09-24 12:20
    Thanks Tracy,

    Much more elegant than my clumsy solution, as usual. After we tried this in the field today, it was immediately apparent 8 characters were not going to be enough to cover the existing flow totals on some previously installed flow meters. For instance, a flow meter that's been in the field for some time has already accumulated 570 acre-feet of flow. Given the meter they're using, that translates to 399,323,920 counts! I've expanded the algorithm to accept up to 10 characters, with a warning that the maximum value that can be entered is 4,294,967,295. I tried the algorithm up to that 32 bit max value and it appears to work. In this case it doesn't make sense to allow for values greater than 32-bits since the rest of the BS2pe accumulation program is using a 32-bit value, as is the server we send it to.
Sign In or Register to comment.