Shop OBEX P1 Docs P2 Docs Learn Events
Setting the width of a floating point number — Parallax Forums

Setting the width of a floating point number

Hi Everyone,

I'm having a little trouble with a program that involves a rotary encoder and an OLED (SSD1331) that allows the user to select a number displayed on the screen. My issue is that the "print" command that sends that number, as chosen by the rotary encoder, requires the specification of the length of the string being sent (floating point converted to string previous to the command), and my numbers have varying lengths. The minimum length is one character and the max is five. I tried using the simple numbers method that allows the specification of a width that then pads the output with spaces on the OLED screen, but when I used it, it seemed to return the address instead of the value.

Does anyone have any ideas for how I can get the padding/width setting that I need?

{{

*OLED Test 2
*Z. Schulze et. al.
*6/18/21
*

}}

CON

   _clkmode = xtal1 + pll16x
   _xinfreq = 5_000_000


   CLK_FREQ = (_clkmode >> 6) * _xinfreq
   MS_001   = CLK_FREQ / 1_000

   RST          = 15         'OLED pins
   DC           = 16
   CS           = 17
   CLK_oled     = 18
   DIN          = 19

   clk_enc      = 28         'Encoder pins
   dt           = 29
   btn          = 11

   LED0         = 3          'LED pins
   LED1         = 4
   LED2         = 5
   LED3         = 6
   LED4         = 7
   LED5         = 8
   LED6         = 9
   LED7         = 10

   LE           = 2          'latch pin

OBJ

  OLED  :       "OLED_AsmFast v0.5 Driver"
  enk   :       "jm_encoder_1x"
  SPI   :       "SPI_Spin"
  f     :       "Float32"
  fs    :       "FloatString"
  int   :       "string.integer"
  sn    :       "Simple_Numbers"
  n     :       "Numbers"

VAR

  long  Data
  long  Atten
  long  DataX
  long  AttenX

PUB OLED_Test

  OLED.Init(CS,DC,DIN,CLK_oled,RST)
  enk.Start(clk_enc, dt, btn, true, 1, 0, 127)
  SPI.Start(15000, 1)
  f.Start

  dira[LED7..LED0]~~

  wait_for_state(btn, 0, 50)
  OLED.clearDisplay
  OLED.AutoUpdateOff
  OLED.write1x6String(String("Manual"),6,0,0,OLED#Yellow,OLED#BLUE)
  OLED.write1x6String(String("Mode"),4,0,32,OLED#Yellow,OLED#BLUE)
  delay(500)
  repeat
    Data := enk.value   
    Atten := f.FDiv(Data, 4)
    'AttenX := sn.decf(Atten, 5)       issue with this was that it seemed to return the address instead of the value
    AttenX := fs.FloatToString(Atten)   
    ifnot DataX == Data
      OLED.clearDisplay
      OLED.write1x6String(AttenX,5,0,0,OLED#Yellow,OLED#BLUE)
    if ChkBtnPulse(btn, 0, 1)
      LOW1(LE)
      SPI.SHIFTOUT(0, 1, SPI#LSBFIRST, 8, Data)
      HIGH1(LE)
      LOW1(LE)
      outa[LED0] := (Data & %00000001)
      outa[LED1] := (Data & %00000010) >> 1
      outa[LED2] := (Data & %00000100) >> 2
      outa[LED3] := (Data & %00001000) >> 3
      outa[LED4] := (Data & %00010000) >> 4
      outa[LED5] := (Data & %00100000) >> 5
      outa[LED6] := (Data & %01000000) >> 6
      outa[LED7] := (Data & %10000000) >> 7
   DataX := Data



PUB wait_for_state(pin, state, ms) : statems | t

  t := cnt
  repeat                          'enter into infinite repeat loop
    waitcnt(t += MS_001)          'delay for the number of clicks in one millisecond from the current count
    if (ina[pin] == state)        'test to see if the state of pin is equal to the state variable
      if (++statems == ms)        'preincrements variable statems by 1 each pass through and continues to repeat
                                     'until statems reaches the number assigned to ms, and then the return occurs
        return                    'exit repeat loop and method, and go to the next line in "parent method"
    else
      statems := 0                'if state of pin is not equal to state variable, then pin state not equal to state
                                     'variable for specified amount of time, and infinite loop is continued.

PUB delay(ms)
  waitcnt(clkfreq/1000*ms + CNT)

PUB HIGH1(Pin)
    dira[Pin]~~
    outa[Pin]~~

PUB LOW1(Pin)
    dira[Pin]~~
    outa[Pin]~

PUB ChkBtnHoldTime(pin, activeState, mSecDelay, mSecMax) : delta | time1, time2, mSec, waitTicks, maxTicks
{{
This function checks to see if a button is pressed and then times the press to determine how long the
button was held down.  It returns the time in milliseconds.  The time returned INCLUDES the requested
settle delay which must be at least 1ms.  If active state is not held for at least the settle delay
time then the fuction treats it as if no press occured.  It blocks execution until the the button is
released or mSecMax is reached if it is greater than 0.
Parameters:
  pin           - The I/O pin to watch for the button press.
  activeState   - The digital state that is considered a button press [0 or 1].
  mSecDelay     - The debounce or settle time to ignore transitions during, defaults to 1 millisecond.
  mSecMax       - The maximum time to allow the button to be held for.  After that time we force a return.
                  A zero here inidicates no timeout, the function will not return until the button is
                  released.
}}
  if mSecDelay < 1                              'If the delay is less than 1 mSec then increase it to 1.
    mSecDelay := 1

  delta := 0
  mSec := clkfreq/1000                          'Number of clock ticks per millisecond.
  waitTicks := mSec * mSecDelay                 'Number of clock ticks for bounce settleing.
  maxTicks := mSec * mSecMax                    'Number of clock ticks for hold timeout.

  'If a timeout was requested:
  if maxTicks > 0
    time1 := cnt                                      'Record the start time.
    if ina[pin] == activeState                        'If the pin was on when we checked
      waitcnt(waitTicks + cnt)                        '  wait for the requested settle delay
      if ina[pin] <> activeState                      '  Is it still in the requested state?
        return                                        '    If not return while delta is 0
      else
        repeat until cnt > time1 + maxTicks           '  Otherwise loop until the timeout is reached
          if ina[pin] <> activeState                  '    If the button is released first
            time2 := cnt                              '      Record the time.
            delta := ((time2 - time1))/mSec           '      Calculate the delta in milliseconds.
            return                                    '      Return now.

        time2 := cnt                                  '       When the loop exits calculate the delta.
        delta := ((time2 - time1))/mSec
        return

  'If no timeout was requested:
  if maxTicks == 0
    time1 := cnt                                      'Record the start time.
    if ina[pin] == activeState                        'If the pin was on when we checked
      waitcnt(waitTicks + cnt)                        '  wait for the requested settle delay
      if ina[pin] <> activeState                      '  Is it still in the requested state?
        return                                        '    If not exit while delta = 0
      else
        repeat until ina[pin] <> activeState          '    Repeat until the button is released.
        time2 := cnt                                  '    When the loop exits calculate the delta.
        delta := ((time2 - time1))/mSec
        return

PUB ChkBtnPulse(pin, activeState, mSecDelay) : wasPressed | waitTicks, mSec
{{
This function will return true if the button is held active for the designated delay time and then released.
If this is called in a loop it will return a press only when the button has been pressed and released.  Other
execution is blocked while the button is held down so it will not pruduce addtional presses if the user is
holding the button down.
Parameters:
  Pin            - I/O pin to check
  activeState    - The digital state that is considered a button press
  mSecDelay      - The debounce or settle time in milliseconds for a valid press.
}}
  if mSecDelay < 1                              'If the delay is less than 1 millisecond increase it to 1
    mSecDelay := 1

  mSec := clkfreq/1000                          'Clock ticks per millisecond
  waitTicks := mSec * mSecDelay

  if ina[pin] == activeState                    'If the pin is in the desired state.
    waitcnt(waitTicks + cnt)                    'Wait the requested amount of settle time.
    if ina[pin] == activeState                  'Is it still in the desired state?
      repeat while ina[pin] == activeState
      wasPressed := 1

  else
    wasPressed := 0                             'Transient as defined by the request so we won't count it.

Thanks for taking a look.

Zach

Comments

  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2021-06-18 21:39

    Simple_Numbers does not handle floating-point. When you call decf on a floating-point number, it treats the value that it sees as a signed 32-bit integer instead.

    -Phil

  • You can do like this:

    A:=F.FFloat(B)
    C:=(FS.Setprecision(4))
    C:=(FS.FloatoString(F.Fdiv(Data,4)))
    lcd.str(C)

    (I'm using an LCD)

  • Hi @DigitalBob ,

    Thank you for the suggestion. I ended up figuring it out by using the FormatToString method in a different version of the FloatString object. This version that I found on OBEX is different than the one that came with the Propeller Tool's library.

    Thanks,

    Zach

Sign In or Register to comment.