Shop OBEX P1 Docs P2 Docs Learn Events
Decimal to Binary Conversion to then print to Parallax Serial Terminal — Parallax Forums

Decimal to Binary Conversion to then print to Parallax Serial Terminal

Hello,

I am trying to run a simple program in Propeller Tool using Spin. The program utilizes the Parallax Serial Terminal to allow a user to enter a decimal number that is multiplied to create a new variable, and then that new variable is converted into binary and printed to the Parallax Serial Terminal. I am having trouble with the the decimal to binary conversion. For the spin code I have, when I try to run it I get an "Expected Expression Form" error with the i after repeat highlighted. Can anyone see a mistake I am making or a way to put that i in "expression form"? Also, if anyone has a simpler way of converting a decimal to binary, please let me know.

Thanks for the help,

Zach

CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000

VAR
Byte Data
word atten
word decimal
word bin

OBJ
SPI : "SPI_Spin" ''The Standalone SPI Spin engine
pst : "Parallax Serial Terminal"
f : "Float32"
fs : "FloatString"

PUB DSA_CONTROL|SERIN,CLK,LE,ClockDelay,ClockState

pst.Start(115200)
f.Start
SPI.Start(15000, 1)

pst.Str(String("Attentuation Control ", pst#NL))
repeat
pst.Str(String(pst#NL, "Enter desired level of attenuation: "))
atten := pst.DecIn
decimal := f.FMul(atten, 4)
bin := string("00000000")
repeat i from 0 to strsize(bin)-1
byte[bin][i] := (((|<(strsize(bin)-1-i))&decimal)>>(strsize(bin)-1-i))+48
Data := byte[bin][i]
pst.Str(String("Data = "))
pst.Str(fs.FloatToString(Data))

Comments

  • The Propeller uses binary internally. Decimal, hexadecimal and binary are just alternate ways to display the data to us humans.

    Try this code.

    CON
    _clkmode = xtal1 + pll16x
    _xinfreq = 5_000_000
    
    VAR
    
      long atten
    
    
    OBJ
    
      pst : "Parallax Serial Terminal"
    
    PUB DSA_CONTROL
    
      pst.Start(115200)
    
      repeat
        result := pst.RxCount
        pst.Str(String(11, 13, "Press Any Key to Start"))
        waitcnt(clkfreq / 2 + cnt)
      until result
    
      pst.RxFlush
    
      pst.Str(String(11, 13, 11, 13, "Attentuation Control "))
      repeat
        pst.Str(String(11, 13, "Enter desired level of attenuation: "))
        atten := pst.DecIn
    
        pst.Str(String(11, 13, "Data = "))
        pst.Dec(atten)
        pst.Str(String(" = %"))
        pst.Bin(atten, 16)  ' Change digits to desired value. Up to 32 allowed.
    
    
  • Thank you so much Duane Degn and DigitalBob. The code worked very well in my program.

    Cheers!

  • @ZachS said:
    Thank you so much Duane Degn and DigitalBob. The code worked very well in my program.

    Cheers!

    Make sure you don't wait too long before asking for help.

    I remember trying to figure out the same sort of stuff when I first started using microcontrollers 13 years ago. I somehow thought I needed a separate variable for binary and decimal.

    The one time you will need a separate variable is when using floating point numbers. Floating point numbers are encoded differently than the integer values we normally use. Mathematical manipulation of Floating point numbers need to floating point specific code. But as a former boss of @"Heater." used to say, if you need to use floating point, you don't understand the problem. I've come to learn Heater's boss was a wise man.

  • I'm having another issue with decimal to binary conversion. But this one has to do with using the conversion from the Simple_Numbers library. When I implement the following code,

    CON
    _clkmode = xtal1 + pll16x
    _xinfreq = 5_000_000

    VAR
    byte Data
    long atten
    long decimal
    long dec
    long SERIN
    long CLK
    long LE

    OBJ
    SPI : "SPI_Spin" ''The Standalone SPI Spin engine
    pst : "Parallax Serial Terminal"
    f : "Float32"
    fs : "FloatString"
    sn : "Simple_Numbers"

    PUB Test_Conversion

    SPI.Start(15000, 1)
    pst.Start(115200)

    decimal := 4
    Data := sn.Bin(decimal, 8)
    pst.Dec(Data)

    I'm expecting the variable "decimal", defined as 4, to be converted into 00000100 and "Data" to be a variable defined as that binary number. Then to double check that I'm getting the correct binary number, I convert it back to decimal and send it to the Parallax Serial Terminal to check it. When I do this, the number that results is 192. Any ideas on where that number is coming from? Am I misusing the sn.Bin(decimal, 8) function? Also, something curious happens when I change the variable designation for "Data" in the VAR section. If I switch it from a byte to a long, without changing anything else, 6076 results instead of the 192. I'm not sure if this is a clue.

    Thanks,

    Zach

    P.s. Sorry about the formatting of my code when the comment is posted

  • Duane DegnDuane Degn Posts: 10,588
    edited 2021-05-21 21:40

    The variable "decimal" is stored in the Propeller in binary. The "Bin" method is just used to convert this to characters to display on the screen. The returned value of "Bin" is the location in memory where these characters are stored.

    If you change "pst.Dec(Data)" to "pst.Str(Data)" you'd see the characters stored in the memory located held by "Data".

    "Data" in your example hold the memory location of the ASCII characters used to display the binary value. If you don't know what ASCII characters are, look it up on Wikipedia. Understanding the difference between values stored in memory and characters to display these values is an important concept.

    Edit: The code "pst.Dec(Data)" displayed memory address where the binary characters are stored in RAM. The buffer "nstr" is used in Simple_Numbers to hold these characters.

    Simple_Numbers is likely not needed for what you're trying to do. Propeller Serial Terminal.spin can already display values in binary notation.

  • P.s. Sorry about the formatting of my code when the comment is posted

    Put three back-ticks (on the tilde key) on the lines before and after your code -- that will cause the forum to format it like code.

  • Hi JonnyMac and DigitalBob,

    So I'm working with a Propeller 1 Development Board. What I'm trying to do with it is have a user enter a desired level of attenuation using the Parallax Serial Terminal object, preferably I would like to have them enter a floating point number but I can't seem to find that in the PST object library, have that number be converted to binary and then have that binary be passed to the microcontroller to be outputted using the SPI object.

    My strategy has been to try and make the converted binary number, converted using PST, into a variable, I call it Data, and then use that variable with the SPI object. But I'm having trouble getting that to work. Any thoughts?

    I'll keep looking into how I can get the user to be able to enter a floating point number into PST and have PST recognize it, but do either of you have any suggestions for that as well? Currently when 31.75 is entered, it is read as 3175. I've temporarily gotten around this by using an if/else statement to get the desired number.

    Thanks,

    Zach

  • There are likely better floating point input methods out there but this is one made for a project.

    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
      NOT_A_NUMBER = $7FFF_FFFF
    
    VAR
    
      long attenuation
    
    
    OBJ
    
      Pst : "Parallax Serial Terminal"
      F32 : "F32_160222a"                        ' uses one cog
      FMath : "FloatString160226a" ' Needed for floating point input and output.
    
    PUB Init
    
      F32.Start
      Pst.Start(115200)
    
      repeat
        result := Pst.RxCount
        Pst.Str(String(11, 13, "Press Any Key to Start"))
        waitcnt(clkfreq / 2 + cnt)
      until result
    
      Pst.RxFlush
    
      MainLoop
    
    PUB MainLoop
    
    
      repeat
        Pst.Str(String(11, 13, 11, 13, "Attentuation Control "))
        Pst.Str(String(11, 13, "Enter desired level of attenuation: "))
        attenuation := GetFloatInput
    
        Pst.Str(String(11, 13, "attenuation = "))
        Pst.Str(FMath.FloatToString(attenuation))
    
    
    PUB GetFloatInput | leftOfDec, rightOfDec, inputCharacter, sideOfDecimal, {
    } negativeFlag, rightSideDivisor, exponentFlag, exponent, parameterReceivedFlag, timeout
    
      negativeFlag := 0
      exponentFlag := 0
      rightSideDivisor := 1
      sideOfDecimal := 0 ' zero for left and one for right
      ' use trick leftOfDec[1] is the same variable as rightOfDec
      leftOfDec := 0
      leftOfDec[1] := 0 ' same as rightOfDec := 0
      repeat
    
        inputCharacter := Pst.CharIn
    
        if inputCharacter => "0" and inputCharacter =< "9"    'Checking for numbers 0-9 extract and parameters values
          leftOfDec[sideOfDecimal] *= 10                                      'to shift over one digiit
          leftOfDec[sideOfDecimal] += inputCharacter - "0"                       'this converts from ASCII to numeric..
          parameterReceivedFlag := 1                        ' now we have a number so set flag
          if sideOfDecimal ' if on the right side of decimal keep track of size
            rightSideDivisor *= 10
        elseif inputCharacter == "-"                        ' check for neg flag to make a neg number later if we need
          negativeFlag := 1                                 'a negative sign anywhere in string will set flag
        elseif inputCharacter == "."
          sideOfDecimal := 1
        if inputCharacter == "e" or inputCharacter == "E"
          exponentFlag := 1
    
      while inputCharacter <> 13 and exponentFlag == 0
    
      if negativeFlag
        -leftOfDec
        -rightOfDec
    
      if leftOfDec
        result := F32.FFloat(leftOfDec)
      else
        result := 0.0
    
      if rightSideDivisor > 1
        rightOfDec := F32.FFloat(rightOfDec)
        rightSideDivisor := F32.FFloat(rightSideDivisor)
        rightOfDec := F32.FDiv(rightOfDec, rightSideDivisor)
        result := F32.FAdd(result, rightOfDec)
    
      if exponentFlag
        exponent := Pst.DecIn
        if exponent == NOT_A_NUMBER
          result := NOT_A_NUMBER
    
        else
          exponent := F32.FFloat(exponent)
          exponent := F32.Pow(10.0, exponent)
          result := F32.FMul(result, exponent)
    
    

    @ZachS said:
    use that variable with the SPI object.

    What sort of SPI devices using floating point input?

    All the SPI devices I've used require integer values as input.

  • Hi Duane,

    I've gotten around the floating point number issue by asking the user some extra questions about the level of attenuation. If it's a fraction, then I treat the number a little differently to get the correct binary number.

    You're correct, the SPI is using an integer or binary value. The floating point is geared towards the attenuator logic that will be used.

    My main issue now is just trying to pass the binary number derived in the Parallax Serial Terminal object into the SPI object. Below is my code for trying to do this.

    PUB DSA_CONTROL|SERIN,CLK,LE,ClockDelay,ClockState
    
      SPI.Start(15000, 1)
      pst.Start(115200)
      f.Start
    
        pst.Str(String("Attentuation Control ", pst#NL))
        pst.Str(String("Is attenuation a fraction? (enter 1 for yes or 2 for no)", pst#NL))
        Response := pst.DecIn
          if Response == 1
            pst.Str(String(pst#NL, "Enter desired level of attenuation to two decimal places (Ex/ for 0.5 dB, enter 0.50): "))
              atten := pst.DecIn
              decimal := atten / 25
          if Response == 2
            pst.Str(String(pst#NL, "Enter desired level of attenuation: "))
              atten := pst.DecIn
              decimal := atten * 4
    
          Data := sn.Bin(decimal, 8)
          pst.Dec(Data)    
          'pst.Str(String(pst#NL, "Decimal = "))
          'pst.Dec(decimal)
          'pst.Str(String(" = "))
          'pst.Bin(decimal, 8)
          'Data := result   '(pst.Bin(decimal, 8))
    
        'Data :=  0
    
        SERIN     := 0                                            '' Data Pin
        CLK       := 1                                            '' Clock Pin
        LE        := 2                                            '' Latch Enable Pin
    
        LOW(LE)                                                  '' Send High Out on Latch Pin
        SPI.SHIFTOUT(SERIN, CLK, SPI#LSBFIRST , 8, Data)          '' SEND OUT THE 7-BITS OF DATA
        HIGH(LE)                                                   '' release the DS1620
        LOW(LE)
    
        repeat                                                  'Pause the Program
    
    PUB HIGH(Pin)
        dira[Pin]~~
        outa[Pin]~~
    
    PUB LOW(Pin)
        dira[Pin]~~
        outa[Pin]~
    

    So everything seems to work well leading up to the defining of the variable decimal, both cases of fraction and integer work. The trouble comes in when I try to define the variable Data. I'm using the simple_numbers object to convert the integer stored in the variable decimal into a binary number, and then defining that as Data. (the pst.Dec(Data) is there so I can verify that the correct binary number is being stored in Data by converting it back to a decimal number and printing it to the terminal). Then that Data variable is used in the SPI object to send the binary number to the microcontroller; where LED lights blink out the binary number. Unfortunately, no matter what integer the variable decimal is it gets converted into the binary number for 200. I know that the SPI object is working as it is supposed to because I get 200 blinked out with the LED's on the microcontroller. So the issue seems to be with Data := sn.Bin(decimal, 8). Any thoughts on why that would not yield the correct decimal to binary conversion? And why it would yield the binary equivalent of 200 no matter what number the decimal variable is?

    Thanks for all of the help!

  • Duane DegnDuane Degn Posts: 10,588
    edited 2021-05-25 16:24

    @ZachS said:
    why it would yield the binary equivalent of 200 no matter what number the decimal variable is?

    Because the buffer "nstr" is located in RAM at memory position 200. I tried to explain this in an earlier post.

    An integer in the Propeller is already encoded in binary. You don't need to convert. You only "convert to binary" if you want to display the number using the character "0" and the character "1". Make sure you read about ASCII characters.

  • Thank you for your patience Duane. I now understand what you were trying to explain. You are correct, I don't need the simple_numbers object to convert that number into binary. I was able to redefine Data and easily pass it to the SPI.

    Thank you!

  • Ok, try this I gave an example of a float string etc. Your Attentuation fraction enter a number higher than 25 like 50 or a 100, or else you'll get "0" option 2 is ok, it just multiplies the interger. You can use the float to convert the pst.DecIn to a float etc. I don't have a DS1620 or else I would post a working code (too lazy to look at the data sheet)

  • Here is an old JonnyMac DS1620 Demo if that helps

Sign In or Register to comment.