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
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