fastspin Basic CM2302
in Propeller 1
What I am trying to do is create some fastspin Basic code to read a CM2302 temp/humid module.
In my fastspin basic code below, I am trying to get the correct hi/low sequence for the module to send something. I am not having very much success. I am not sure if I am interpreting the Basic output() = 1/0 command correctly. Or is there a better way to do this.
I also have the dht11/22 spin code below as reference material, that code is like Greek to me, but I am trying. Any assistance for solving this would be appreciated.
Thanks
Ray
My basic code
spin code
In my fastspin basic code below, I am trying to get the correct hi/low sequence for the module to send something. I am not having very much success. I am not sure if I am interpreting the Basic output() = 1/0 command correctly. Or is there a better way to do this.
I also have the dht11/22 spin code below as reference material, that code is like Greek to me, but I am trying. Any assistance for solving this would be appreciated.
Thanks
Ray
My basic code
rem test_temp2.bas
'
'
dim indata%
waitcnt(getcnt() + 10_000_000) 'Wait for terminal screen
pausems 2000 'Wait for sensor to stabilize
direction(2) = output
output(2) = 1 'Pull high
pausems 1000
output(2) = 0 'Pull low
pausems 0000_0500 'uS
output(2) = 1 'Pull high
direction(2) = input 'Chnge to input
pausems 1000
output(2) = indata% 'Capture incoming
print "Exp Data! "; indata% 'Print out the data captured
spin code
''******************************************
''* Title: DHTnn_Object *
''* Modified from DHT21_Object - *
''* Walter T. Mosscrop 2016 *
''* Original Author: Gregg Erickson 2012 *
''* See MIT License for Related Copyright *
''* See end of file and objects for . *
''* related copyrights and terms of use *
''* This object draws upon code from other*
''* OBEX objects such as servoinput.spin *
''* and DHT C++ from Adafruit Industries *
''* *
''* This object reads the temperature and *
''* humidity from an DHT11 or DHT22 *
''* using a unique 1-wire serial protocol *
''* with 5 byte packets where 0s are 26uS *
''* long and 1s are 70uS. *
''* *
''* The object automatically returns the *
''* temperature and humidiy to variables *
''* memory every few seconds as Deg C and *
''* relative percent respectively. It also*
''* return an error byte where true means *
''* the data received had correct parity *
''* *
''* The read loop has been reworked to *
''* stabilize the timing and reduce the *
''* number of invalid reads due to timing *
''* issues *
''******************************************
{
Vcc──────────────Red (Power)
│
10K (Pull-Up Resistor)
│
Prop Pin ────────Yellow (Data)
VSS──────────────Black (Ground)
}
CON
MAX_SAMPLES = 40 ' 40 one-bit samples
VAR
long APin,Device
long MeasurementStack[50]
long clkpermicro, clkminpulse
long measurementCog, measuring
long MeasurementValues[MAX_SAMPLES]
long temperaturePtr, humidityPtr, statusPtr
OBJ
f : "FloatMath"
PUB StartDHTnn(devicePin,DeviceModel,TempPtr,HumPtr,StatPtr) : result
APin := devicePin
Device := DeviceModel
measurementCog := -1
{{
This method lauches the Measuring code in a new cog
to read the DHTnn autonomously with variables updated
every few seconds
}}
MeasurementInit(APin, @measuring, @MeasurementValues)
temperaturePtr := TempPtr
humidityPtr := HumPtr
statusPtr := StatPtr
PUB Stop
{{
stop cog if in use
}}
if measurementCog => 0
cogstop(measurementCog)
Pub DHTnn_Read | Data[5], Temp, Humid, ByteCount,BitCount,Pulsewidth,Parity,ptr,tr,hr
{{
This method reads the DHTnn device autonomously with variables located at
the pointers updated every few seconds
}}
'Apin is data line in from DHTnn
'Data[5] bytes received in order from DHTnn
'DATA = upper 8 bits of RH data
' + lower 8 bits of RH data
' + upper 8 bits of temperature data
' + lower 8 bits of temperature data
' + 8 bits check-sum (equals other 4 bytes added)
'ByteCount - Index counter for data Bytes
'BitCount - Index counter for bits within data bytes
'Pulsewidth - Width of bits received from DHTnn, 26uS = 0, 70S=1, in clock ticks
'parity - Boolean - parity for data from DHTnn
'clkpermicro - number of clock ticks per microsecond
'clkminpulse - the number of clock ticks for a pulsewidth value to be considered a 1
clkpermicro := clkfreq / 1_000_000
clkminpulse := clkpermicro * 48 ' Minimum 48 us 'high' pulse
waitcnt(clkfreq*2+cnt) ' Pause to allow DHTnn to stabilize
DIRA[Apin]~~ ' Set selected Pin to output
OUTA[Apin]~~ ' Pull Up selected Pin to start sequence
Repeat ByteCount from 0 to 4
Data[ByteCount]:=0 ' Clear Data of Each Byte Before Input
waitcnt(clkfreq/4+cnt) ' Pause to allow DHTnn to stabilize
' Send a low to the DHTnn to request data
DIRA[Apin]~~ ' Set selected Pin to output
OUTA[Apin]~ ' Pull Down selected Pin for 500 uS to Request Data
if device == 11
waitcnt((clkpermicro * 20_000) + cnt) ' hold 20ms
else
waitcnt(clkfreq / 2000 + cnt) ' Pause for 500uS
OUTA[Apin]~~ ' Return Pin to High
DIRA[Apin]~ ' Set Pin to Input and Release Control to DHTnn
' DHTnn reponds with a ready signal (80uS low, 80uS high, 40 uS low, before data)
waitpne(|<Apin,|<Apin,0) ' Wait for low, high, low sequence
waitpeq(|<Apin,|<Apin,0)
waitpne(|<Apin,|<Apin,0)
MeasurementStart
' DHTnn will send 40 high bits where 0 is 26uS and 1 is 70uS
repeat until measuring == 0
ptr := 0
Repeat ByteCount from 0 to 4 ' Store Data in 5 Bytes
Repeat BitCount from 7 to 0 ' Receive Data by Bit, MSB to LSB
pulsewidth := LONG[@MeasurementValues][ptr++]
if pulsewidth > clkminpulse ' If Pulse > min pulse then bit is 1 else 0
Data[ByteCount]|=|<BitCount ' Store the bit in byte
' Check Parity
parity := ((data[0]+data[1]+data[2]+data[3])& $ff)==(data[4]) 'Last byte equals sum of first four bytes
' Calculate Temperature
if parity
if (Device == 11)
tr := data[2] & $7f ' Pull from data2, mask MSB Bit
else
tr := data[2] ' Pull from data2
tr <<= 8 ' Put into upper byte
tr += data[3] ' Add lower byte
Temp := f.FFloat(tr)
if (Device == 11)
Temp := f.FDiv(Temp, 256.0) ' Convert to DHT11 value
else
Temp := f.FMul(Temp, 0.1) ' Convert to DHT22 value
' Calculate Humidity
if parity
Humid:=data[0] ' Pull from data0
Humid<<=8 ' Put into upper byte
Humid+=data[1] ' Add lower byte
Humid := f.FFloat(Humid)
if (Device == 11)
Humid := f.FDiv(Humid, 256.0) ' Convert to DHT11 value
else
Humid := f.FMul(Humid, 0.1) ' Convert to DHT22 value
' Return values to addresses provided in pointers
if parity
Long[temperaturePtr] := temp ' Temperature
Long[humidityPtr] := humid ' Humidity
Long[statusPtr] := 1 ' Parity ok
else
Long[statusPtr]:= 0 ' Error
' Cog relies on these arguments, do not remove
pub MeasurementInit(pAPin, pMeasuringStatus, pMeasurementValues)
measurementCog := cognew(@MeasureCog, @pAPin)
pub MeasurementStart
Long[statusPtr] := -1 ' We're updating values
LONGFILL(@MeasurementValues, MAX_SAMPLES, 0)
measuring := 1
DAT
ORG 0
MeasureCog
mov p1, par ' Get data pointer
rdlong APinNum, p1 ' Get APin number
add p1, #4 ' Get next pointer
rdlong measuringStatusPtr, p1 ' Get pointer to measuring value
add p1, #4 ' Get next pointer
rdlong arrayPtrSave, p1 ' Get monitor array pointer
mov APinMask, #1 ' Get pin mask
shl APinMask, APinNum
' Used for timing pulses
movi ctra, #%11111 ' Setup counter (always)
mov frqa, #1 ' One count per tick
' Used for timeout in case of device failure
movi ctrb, #%11111 ' Setup counter (always)
mov frqb, #1 ' One count per tick
wait
rdlong t1, measuringStatusPtr wz ' Check "measuring" value
if_z jmp #wait ' Wait until "measuring" value nonzero
' Prepare for measurement
mov arrayPtr, arrayPtrSave ' Set up array pointer
mov t2, #0 ' Reset counter
mov phsb, #0 ' Reset timeout
measure
' Handle low-to-high (pulse gap)
mov t1, #0 wc ' Reset carry for waitpeq
waitpeq APinMask, APinMask ' Wait for high state
mov t1, phsb ' Have we timed out?
cmp t1, timeoutTicks wz, wc
if_a jmp #done ' Yes, set done & start over
mov phsa, #0 ' Reset counter
' Time high-to-low (pulse)
waitpne APinMask, APinMask ' Wait for low state
mov t1, phsa ' Save counter value in t1, can't write directly to hub
wrlong t1, arrayPtr ' Save duration value
add arrayPtr, #4 ' Set up for next array value
mov t1, phsb ' Have we timed out?
cmp t1, timeoutTicks wz, wc
if_a jmp #done ' Yes, set done & start over
add t2, #1 ' Count values
cmp maxSample, t2 wz ' Have we reached the limit?
if_ne jmp #measure ' No, back for more
done mov t1, #0 ' Yes, set status value to zero
wrlong t1, measuringStatusPtr ' Update status value
jmp #wait ' We're done monitoring
APinNum long 0
maxSample long MAX_SAMPLES
measuringStatusPtr long 0
arrayPtr long 0
arrayPtrSave long 0
timeoutTicks long 5 * 80_000_000 ' Assumes 80 MHz clock; 5 seconds
APinMask long 0
p1 long 0
t1 long 0
t2 long 0
{{
┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ TERMS OF USE: MIT License │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │
│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │
│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│
│is furnished to do so, subject to the following conditions: │
│ │
│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│
│ │
│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │
│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │
│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │
│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
}}
Comments
output(2) = indata% 'Capture incoming
does not do what the comment says (capture incoming); instead it outputs a random value (whatever happened to be in the variable "indata%") to pin 2. Did you mean to say:indata% = input(2) ' Capture state of pin 2
In general, if the Spin code you have works correctly then you can just use that directly in the BASIC code by doing something like:
' create a BASIC Object (class) from the Spin object dim dht as class using "DHTnn_Object.spin" ' declare some variables to receive output dim temperature as single dim humidity as single dim status as integer ... ' start the reading process in the background dht.StartDHTnn(devicePin, deviceModel, @temperature, @humidity, @status) ' loop printing temperature and humidity do pausems 1000 if status = 1 print "temperature=", temerature, "humidity=", humidity else print "error? status=", status end if loop
(I haven't checked that code and don't have a device to actually test with, so it probably needs some tweaking, but that's the general idea.)I was curious to see whether the actual Basic code would make the actual program size smaller than what I am getting when using the spin object code. The same experiment could be used to see what the code sizes look like with the dht22 C code, whenever that becomes available.
Since fastspin Basic is using LMM mode, it seems that all the program code has to be as small and compact as possible. I think that it would be easier to tweak Basic code then to tweak the spin objects, before using them in the fastspin Basic. Just my thoughts on this.
Ray
The "in the same way" is an interesting caveat though, because it may be that different languages make slightly different forms of code more "natural". In Spin, for example, it's pretty easy to interface to a PASM driver that runs in another COG, but that's harder in BASIC or C. In BASIC it's easier to use small inline functions than in the other languages. And C code tends not to use objects in the same way as Spin or BASIC.
I think there needs to be an explanation for why/when you would use the optimization option. I noticed that the dhtnn program, when you use 'no optimization', it runs as expected and the values are correct. But when you use 'Default Optimization', the program runs, but the values that you are printing are wrong, although there is quite a substantial reduction in program code size. I guess it would be some what difficult to find out where the problem lies when you do use the optimization option. Maybe a short summary on how the optimization thing works.
Ray
Still need to get a handle on how that Optimization works. With that info I guess you can start writing programs with that protocol in mind, I think. Also, what is the best way to have this program copied to EEPROM, so it starts up on power up?
The next step, I think, will have to be a pair up with a Raspberry Pi, that way I can access a program on the RasPi to get the temperature/humidity readings remotely.
Ray
rem test_temp3.bas ' ' April 21, 2019 rem This uses the CM2302 module for temperature and humidity. /' For this to work, you need access to the following: DHTnn_Object.spin FloatMath.spin FloatString.spin Also, in Options, the selection has to be "No Optimization". Program size is 12704 bytes, ~one third of available memory is used. '/ ' Setup a Spin object for use with Basic dim dht as class using "DHTnn_Object.spin" let dhtpin = 2 ' Pin number. let model = 22 ' Model is dht22. ' Variable types. dim temp as single dim humid as single dim status as integer /' Start the dht object code. Module is set for pin 2, and model 22.'/ dht.StartDHTnn(dhtpin,model,@temp,@humid,@status) ' Hold for terminal screen access. waitcnt(getcnt() + 10_000_000) do dht.DHTnn_Read() ' Read the dht module. if status = 1 then print "Temperature - ";(9.0/5.0)*temp + 32.0;" *F" ;" Humidity - ";humid;" %" else print "error status= "; status end if pausems 3000 ' Need at least two seconds for module stabalization. loop
Well, that's a bug then. Could you describe exactly how it's going wrong? (what kinds of values are being printed, etc.) As I said, I don't have any DHT hardware to test with, but if you could narrow down the problem to which function is producing the wrong result I may be able to figure out what's wrong.
There are a lot of optimizations that fastspin performs. The ones that most reduce the program size are unused method removal (getting rid of methods that are never called) and dead code removal (getting rid of parts of if statements that are always false). I think all of the optimizations in the "default optimization" level are performed within functions. At "full optimization" (-O2) it also does a few things like automatically inlining functions that are only called once.
No Optimization
Temperature : 73.04 *F Humidity : 45.100 %
Default Optimization
Temperature : 107.42 *F Humidity : 1.109E+08
Full Optimization
error status = 0
The values are so far apart, not sure what the heck is going on. But, when you compile with Full Optimization, the program code size is 7932 bytes. That is quite a reduction in program code size.
Ray
$ proploader PropLoader v1.0-41 (2019-04-11 14:50:14 g9192230) usage: proploader [options] [<file>] options: -b <type> select target board and subtype (default is 'default:default') -c display numeric message codes -D var=value define a board configuration variable -e program eeprom (and halt, unless combined with -r) ... many more options available...
The "-e" option allows uploading to the P1 EEPROM.dgately
Another thing that I am noticing is the actual code itself. Of course it is a very simple program, but the fastspin Basic is just as readable as the C code, and vice-versa, in this instance. I know that C code can get very difficult to decipher at times.
I also looked at DHT11_Test.spin, which is similar in function, I sort looked at that code and was scratching my head thinking, what the heck. I am not saying this to start a language war, just my observation.
I am starting to like fastspin Basic, although I must confess, I have written some programs using FreeBasic, so it is starting to become very familiar.
Ray
/* cm2302_test.c September 13, 2018 */ #include "simpletools.h" #include "dht22.h" float temp,humid; // Decimal point precision. int main() { // Add startup code here. while(1) { // Add main loop code here. dht22_read(2); // CM2302 is connected to pin 16. pause(150); temp = dht22_getTemp(0); // (0) Celsius, (1) Fahrenheit, (2) Kelvin. temp = ((temp*.100)-.30); print("%.2f Temperature\n",temp); // Apply decimal point precission. humid = dht22_getHumidity(); humid = (humid*.10); print("%.2f Humidity\n",humid); // Apply decimal point precission. pause(2000); // Pause for two seconds. } }
I thought I would see something like 1.111 2.111 … But what I am seeing is 3F800000 40400000 … So, I must be using math.FFloat() incorrectly, right? I also wanted to see how the optimization would work on a program that had a Spin object attached.
Ray
rem test4.bas dim math as class using "FloatMath.spin" dim i as integer waitcnt(getcnt() + 10_000_000) for i = 1.111 to 10 print math.FFloat(i) pausems 1000 next i
FloatMath.spin''*************************************** ''* Floating-Point Math * ''* Single-precision IEEE-754 * ''* Author: Chip Gracey * ''* Copyright (c) 2006 Parallax, Inc. * ''* See end of file for terms of use. * ''*************************************** PUB FFloat(integer) : single | s, x, m ''Convert integer to float if m := ||integer 'absolutize mantissa, if 0, result 0 s := integer >> 31 'get sign x := >|m - 1 'get exponent m <<= 31 - x 'msb-justify mantissa m >>= 2 'bit29-justify mantissa return Pack(@s) 'pack result PUB FRound(single) : integer ''Convert float to rounded integer return FInteger(single, 1) 'use 1/2 to round PUB FTrunc(single) : integer ''Convert float to truncated integer return FInteger(single, 0) 'use 0 to round PUB FNeg(singleA) : single ''Negate singleA return singleA ^ $8000_0000 'toggle sign bit PUB FAbs(singleA) : single ''Absolute singleA return singleA & $7FFF_FFFF 'clear sign bit PUB FSqr(singleA) : single | s, x, m, root ''Compute square root of singleA if singleA > 0 'if a =< 0, result 0 Unpack(@s, singleA) 'unpack input m >>= !x & 1 'if exponent even, shift mantissa down x ~>= 1 'get root exponent root := $4000_0000 'compute square root of mantissa repeat 31 result |= root if result ** result > m result ^= root root >>= 1 m := result >> 1 return Pack(@s) 'pack result PUB FAdd(singleA, singleB) : single | sa, xa, ma, sb, xb, mb ''Add singleA and singleB Unpack(@sa, singleA) 'unpack inputs Unpack(@sb, singleB) if sa 'handle mantissa negation -ma if sb -mb result := ||(xa - xb) <# 31 'get exponent difference if xa > xb 'shift lower-exponent mantissa down mb ~>= result else ma ~>= result xa := xb ma += mb 'add mantissas sa := ma < 0 'get sign ||ma 'absolutize result return Pack(@sa) 'pack result PUB FSub(singleA, singleB) : single ''Subtract singleB from singleA return FAdd(singleA, FNeg(singleB)) PUB FMul(singleA, singleB) : single | sa, xa, ma, sb, xb, mb ''Multiply singleA by singleB Unpack(@sa, singleA) 'unpack inputs Unpack(@sb, singleB) sa ^= sb 'xor signs xa += xb 'add exponents ma := (ma ** mb) << 3 'multiply mantissas and justify return Pack(@sa) 'pack result PUB FDiv(singleA, singleB) : single | sa, xa, ma, sb, xb, mb ''Divide singleA by singleB Unpack(@sa, singleA) 'unpack inputs Unpack(@sb, singleB) sa ^= sb 'xor signs xa -= xb 'subtract exponents repeat 30 'divide mantissas result <<= 1 if ma => mb ma -= mb result++ ma <<= 1 ma := result return Pack(@sa) 'pack result PRI FInteger(a, r) : integer | s, x, m 'Convert float to rounded/truncated integer Unpack(@s, a) 'unpack input if x => -1 and x =< 30 'if exponent not -1..30, result 0 m <<= 2 'msb-justify mantissa m >>= 30 - x 'shift down to 1/2-lsb m += r 'round (1) or truncate (0) m >>= 1 'shift down to lsb if s 'handle negation -m return m 'return integer PRI Unpack(pointer, single) | s, x, m 'Unpack floating-point into (sign, exponent, mantissa) at pointer s := single >> 31 'unpack sign x := single << 1 >> 24 'unpack exponent m := single & $007F_FFFF 'unpack mantissa if x 'if exponent > 0, m := m << 6 | $2000_0000 '..bit29-justify mantissa with leading 1 else result := >|m - 23 'else, determine first 1 in mantissa x := result '..adjust exponent m <<= 7 - result '..bit29-justify mantissa x -= 127 'unbias exponent longmove(pointer, @s, 3) 'write (s,x,m) structure from locals PRI Pack(pointer) : single | s, x, m 'Pack floating-point from (sign, exponent, mantissa) at pointer longmove(@s, pointer, 3) 'get (s,x,m) structure into locals if m 'if mantissa 0, result 0 result := 33 - >|m 'determine magnitude of mantissa m <<= result 'msb-justify mantissa without leading 1 x += 3 - result 'adjust exponent m += $00000100 'round up mantissa by 1/2 lsb if not m & $FFFFFF00 'if rounding overflow, x++ '..increment exponent x := x + 127 #> -23 <# 255 'bias and limit exponent if x < 1 'if exponent < 1, m := $8000_0000 + m >> 1 '..replace leading 1 m >>= -x '..shift mantissa down by exponent x~ '..exponent is now 0 return s << 31 | x << 23 | m >> 9 'pack result {{ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ TERMS OF USE: MIT License │ ├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │ │files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │ │modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│ │is furnished to do so, subject to the following conditions: │ │ │ │The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│ │ │ │THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │ │WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │ │COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ │ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ }}
Secondly... a For loop would need some form of stepping of non-integers, if it allowed floating point as an index:
For someFloatValue = 1.111 To 20 Step .5 '' if that works at all
Third... I'm not sure that you can print a floating value directly in this BASIC. You probably need a formatted print statement. I'm a bit fuzzy on this BASIC, but if it's like Spin, it will need a formatted print statement.EDIT: Looks like FloatMath.spin uses an integer as basically a pointer to a 32 bit value that it manipulates as if a float. It packs a float into those 32 bits, that would need to be unpacked for use. i.e. you can't just print the integer, as-is.
''Convert integer to float if m := ||integer 'absolutize mantissa, if 0, result 0 s := integer >> 31 'get sign x := >|m - 1 'get exponent m <<= 31 - x 'msb-justify mantissa m >>= 2 'bit29-justify mantissa
dgately
For loops and print will work with floats, so you can do something like:
dim x as single ' declare x as a float for x = 1.11 to 10 print x next x
So there's no need for FloatMath.spin in a BASIC program, and it would actually be confusing to try to mix BASIC floating point and a Spin object.
Ray
I don't think it's a conflict -- you said things work if optimization is disabled, so you've probably encountered a bug in fastspin's optimizer. The Float*.spin files should work, it's just that calling them from BASIC requires some care since Spin does not have floating point as a built in type but BASIC does. (Plus there's not really any need to call them from BASIC, since BASIC has the same functions built in.)
I'd like to figure out what's going wrong, but I don't have DHTnn hardware to test with. Looking at the code I'd guess that if something's going wrong it may be with the data[] array in the DHTnn_Read function in DHTnn_Object.spin. You could try changing that from a local variable to a method variable (in the VAR block) to see if that helps.