Below is a test program where I am trying to use the familiar high() and low() commands. The program compiles without any errors, but there is no flashing of the LED on pin 26.
If Eric does not mind, I am calling this BASIC, pBas or pBAS.
Will pBas provide an #include provision? I am thinking that, as an example, the high, low, and pausems commands could be placed in a lib, so you only code it once, and have it called within your program.
Ray
rem test2.bas
let mscycles = clkfreq / 1000
'*******************************
'Main
print "This is the test2.bas program"
do
high 26
pausems 500
low 26
pausems 26
loop
'*******************************
sub high(pin)
dim pin%
direction(pin) = output
end sub
sub low(pin)
dim pin%
direction(pin) = input
end sub
sub pausems(ms)
waitcnt(getcnt() + ms * mscycles)
end sub
Below is a test program where I am trying to use the familiar high() and low() commands. The program compiles without any errors, but there is no flashing of the LED on pin 26.
The second pausems is for only 26 ms. Is that what you intended?
Also, your high() and low() functions are changing the direction, not the output value. They really should be something like:
sub high(pin)
output(pin) = 1
end sub
sub low(pin)
output(pin) = 0
end sub
And then in your main code do
direction(pin) = output
once to set the pin as an output.
If Eric does not mind, I am calling this BASIC, pBas or pBAS.
Probably "fBas" would be a better abbreviation, to avoid confusion with PropBasic.
Will pBas provide an #include provision?
It already does, actually. I need to write documentation for the preprocessor, but it supports #include, #define, #ifdef, #elseifdef, and #endif.
Besides #include (which just literally includes one file into another) there is also "class using filename", which lets you include files as objects, similar to the OBJ statement in Spin. "class using" works with both Spin and BASIC files.
I get a compile error. I tried adding 'dim pin%', but that did not work.
Ray
rem test2.bas
let mscycles = clkfreq / 1000
direction(pin) = output
'*******************************
'Main
print "This is the test2.bas program"
do
high 26
pausems 500
low 26
pausems 500
loop
'*******************************
sub high(pin)
output(pin) = 1
end sub
sub low(pin)
output(pin) = 0
end sub
sub pausems(ms)
waitcnt(getcnt() + ms * mscycles)
end sub
G:/fastspin/spin2gui/bin/fastspin -l -O1 -L ./lib G:/fastspin/programs/test2/test2.bas
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2018 Total Spectrum Software Inc.
Version 3.9.5-beta Compiled on: Oct 11 2018
test2.bas
G:/fastspin/programs/test2/test2.bas(5) error: Unknown symbol pin
child process exited abnormally
Thanks for testing it Ray. It sounds like I need to find a newer version of propeller-load that can handle WiFi.
proploader knows how to do wifi downloads. However, it doesn't handle XMM programs. I suspect that won't be a problem for you though.
Thanks David! I'll switch to proploader for the next version.
proploader defaults to trying to do a wifi load. You have to specify -s on the command line to get it to do serial loads. In retrospect, that might not have been the best default but proploader was written for the WX wifi module originally and later expanded to include serial support.
I get a compile error. I tried adding 'dim pin%', but that did not work.
Use "direction(26) = output". Or you could add
const ledpin = 26
at the beginning of your code so that it's easy to change the pin. For example:
rem blinker: blink an led
const ledpin = 16
' set the led pin as an output
direction(ledpin) = output
print "This is the LED blink test program"
' loop blinking the led
do
high ledpin
pausems 500
low ledpin
pausems 500
loop
sub high(pin)
output(pin) = 1
end sub
sub low(pin)
output(pin) = 0
end sub
The most recent version of fastspin has pausems as a builtin function so you probably don't need to define that, but your definition looked OK and you can use it if you like
Also note that 'dim pin%' declares a variable called 'pin%' and is different from 'dim pin'. I think that may be an area where fastspin differs from qbasic and freebasic.
I was trying to get around the use of 'const ' . The way it is now, you have to pre-define the pins that you will be using. In some ways this is like working with spin, where you deal with the pin defs up front. I was thinking along the lines of PropGCC, where you have pre-definitions under the hood, so all you do is high(26) or low(26), and it works.
I am liking the spin2gui program, although some improvements would be nice. One would be, a Load command, where it writes the program to the EEPROM. The other is, you do not have any support for .bas in terms of creating a or saving a .bas file.
I was trying to get around the use of 'const ' . The way it is now, you have to pre-define the pins that you will be using. In some ways this is like working with spin, where you deal with the pin defs up front. I was thinking along the lines of PropGCC, where you have pre-definitions under the hood, so all you do is high(26) or low(26), and it works.
Well, you could put a 'direction(pin) = output' line in both high() and low(), before setting the value of output(pin). I think that may be what the PropGCC functions do. It's a little less efficient, because it means you're constantly setting the direction when it's only necessary to set it once.
I am liking the spin2gui program, although some improvements would be nice. One would be, a Load command, where it writes the program to the EEPROM. The other is, you do not have any support for .bas in terms of creating a or saving a .bas file.
The program below compiles and runs as expected. The next program, I will try to have pin 27 LED blinking in the Main, and I will try to get pin 26 LED to blink in a cpu(COG).
I noticed that pBas does not have any break or exit commands. What would be the method for getting out of a while loop.
Ray
rem test2.bas
' October 12, 2018
' General use of pBas compiler
' Define clock freq
let mscycles = clkfreq / 1000
' Variables
dim pin
'*** Subs & Functions ***
sub high(pin)
direction(pin) = output
output(pin) = 1 ' LED is on
end sub
sub low(pin)
direction(pin) = output
output(pin) = 0 ' LED is off
end sub
sub pausems(ms)
waitcnt(getcnt() + ms * mscycles)
end sub
'*******************************
'Main
print "This is the test2.bas program"
do
high 27 ' Pin 27 on
pausems 500
low 27 ' Pin 27 off
pausems 500
loop
'*******************************
The program below compiles and runs as expected. Not sure as to how to use the stack, I dim it one size and the usage is of a different size, but it works.
Does, or will, pBas have inline pasm? I am wondering as to the best way for pBas to utilize all the Spin driver code that is available. I think JonnyMac had written quite a few drivers in pasm, but there also is quite a few drivers that are written in Spin. One large driver, that could be of great use, is the SD driver, which is in Spin.
Since Parallax has the Activity Board WX, and the FLiP module, maybe there should be an effort made to start trying to create some usage of the different items for the these platforms. For the Activity Board WX: the SD, WiFi, ADC, sound, motor driver, …, etc. Other items of interest could be the RTC, Temp/humidity module and others.
Ray
rem test3.bas
' October 12, 2018
' pBas cpu(COG) usage.
' Are these declarations all Global?
' Define clock freq
let mscycles = clkfreq / 1000
' Variables
dim pin
'*** Subs & Functions ***
sub high(pin)
direction(pin) = output
output(pin) = 1 ' LED is on
end sub
sub low(pin)
direction(pin) = output
output(pin) = 0 ' LED is off
end sub
sub pausems(ms)
waitcnt(getcnt() + ms * mscycles)
end sub
'*******************************
'Main
dim stack(4) 'This is the minimal to run the cpu job1
' Start the cpu(COG)
var a = cpu(job1(26), @stack(1)) ' Not sure what size @stack(1) is
do
high 27 ' Pin 27 on
pausems 500
low 27 ' Pin 27 off
pausems 500
loop
'*******************************
' This is the cpu(COG) job.
sub job1(pin)
do
high pin ' Pin 27 on
pausems 300
low pin ' Pin 27 off
pausems 300
loop
end sub
'*******************************
I noticed that pBas does not have any break or exit commands. What would be the method for getting out of a while loop.
The usual way would be to have the while loop test for a variable, and to set that inside the loop. For example, an (ugly) way to print some integers is:
var done = 0 ' indicates loop is finished
var i = 1
do
print i
i = i + 1
if (i > 4) done = 1
print "still looping"
loop until done <> 0
You could also use a goto:
var i = 1
do
print i
i = i + 1
if (i > 4) goto out
print "still looping"
loop
out:
The program below compiles and runs as expected. Not sure as to how to use the stack, I dim it one size and the usage is of a different size, but it works.
The @stack(1) just returns a pointer to the first element of the stack array (remember that in fastspin BASIC array indices start at 1, not 0).
Does, or will, pBas have inline pasm? I am wondering as to the best way for pBas to utilize all the Spin driver code that is available.
fastspin supports inline assembly between "asm" and "endasm". But if you want to use Spin, you can import it directly with "class using". (The compiler is called "fastspin" after all, and that was the first language it supported -- the BASIC is a new addon!)
For example, to use the FullDuplexSerial.spin driver from a BASIC program you can do:
' create a FullDuplexSerial object named fds
' this is just like the Spin command OBJ fds : "FullDuplexSerial.spin"
dim fds as class using "FullDuplexSerial.spin"
' initialize the fds object
' WARNING: we're choosing to use pins 31 and 30 here, which
' will conflict with the built-in print commands. Don't try to
' use print after the fds.start. If we used other pins (to communicate
' with some device, for example) then this wouldn't be an issue
fds.start(31, 30, 0, 115_200)
do
fds.str("hello, world!")
fds.tx(13)
fds.tx(10)
loop
"class using" accepts either a BASIC or Spin file.
I think I read somewhere that pBas will be able to be used with the P2 chip. I also think I read that pBas, at the moment is set up to run in LMM. What is available now is COG Ram, HUB Ram, and for the P2, HUB Execute. How will pBas be able to use these specific Ram areas? Will you have something like a setting in pBas:
TMM = Cog Ram
LMM = Hub Ram
XMM = P2 Hub Execute
fastspin defaults to hubexec in P2 mode (if the -2 switch is given) and LMM in P1 mode. If you use the --code=cog option then it will compile the code to run in COG memory in both cases.
I think I read somewhere that pBas will be able to be used with the P2 chip. I also think I read that pBas, at the moment is set up to run in LMM. What is available now is COG Ram, HUB Ram, and for the P2, HUB Execute. How will pBas be able to use these specific Ram areas? Will you have something like a setting in pBas:
TMM = Cog Ram
LMM = Hub Ram
XMM = P2 Hub Execute
Ray
Ahem....'t ain't called "pBas", it's called fastspin(BASIC).
OK fastspin(BASIC), it is, until Eric gives it an official name.
Since I have a WX Activity Board with DS1302 module installed, I thought I would try doing a real use program with fastspin(BASIC).
The program below compiles without complaints, but the value is showing up as 0, it should be 13, todays date. I believe that in the Spin program, the value(s) is presented as a byte. So, I am not sure if fastspin(BASIC) is doing a correct print of the day1 variable. Have not done anything in Spin, in the last ten years, so I could be wrong with my interpretation.
I attached the DS1302.spin program, for easy referencing.
Ray
test_rtc.bas
rem test_rtc.bas
' October 13, 2018
' Test of the RTC on the WX Activity Board
dim rtc as class using "DS1302_full.spin"
let mscycles = clkfreq / 1000
sub pausems(ms)
waitcnt(getcnt() + ms * mscycles)
end sub
dim day1 as byte
dim month1 as byte
dim year1 as byte
dim dow1 as byte
dim day
dim month
dim year
dim dow
rtc.init(10,11,9)
rtc.readDate(day1, month1, year1, dow1)
'day1 = day
do
print "day", day1
pausems 3000
loop
ds1302_full.spin
{{ DS1302_full.spin
┌─────────────────────────────────────┬────────────────┬─────────────────────┬───────────────┐
│ DS1302 driver v1.3 │ BR │ (C)2010 │ 8Jul2010 │
├─────────────────────────────────────┴────────────────┴─────────────────────┴───────────────┤
│ │
│ A full-featured DS1302 timekeeping chip driver. Based on the original object by │
│ Daniel Robert. │
│ │
│ Notes: │
│ •Original object here: http://obex.parallax.com/objects/89/ │
│ •12 hour mode is not supported in this object. The reason is that it would add │
│ significant complexity to this object for minimal benefit. A better solution is │
│ to handle the 12/24 hour conversion in software outside of this object if needed. │
│ Okay. So it is nearly full-featured. │
│ •The DS1302 data sheet specs the maximum frequency on the clk pin as: │
│ 0.5MHz@2V, 2MHz@5V --> 1.5MHz@3.3V (1.5 uS per clock, 120 ticks@clkfreq=80MHz) │
│ Original object had a 2 uS pause between clock pin transitions. However, it seems to │
│ work fine with no wait @ clkfreq=80MHz...apparently spin can't outrun the DS1302. │
│ Not tested at clkfreq=100MHz. │
│ •Experimented with trickle charger using 1 diode+2K resistor setting. 10µF │
│ electrolytic cap kept DS1302 powered up for >10 minutes. Implies a 1000µF should be good │
│ for ~16 hrs of backup power...enough to last through a typical brown-out or black-out │
│ (if leakage current and wide tolerance band of electrolytics doesn't kill it first) │
│ •Note that this device needs to have a 32.768KHz crystal with 6pF capacitance in order to │
│ keep accurate time: http://forums.parallax.com/forums/default.aspx?f=25&m=467246 │
│ │
│ See end of file for terms of use. │
└────────────────────────────────────────────────────────────────────────────────────────────┘
DEVICE PINOUT & REFERENCE CIRCUIT
┌────┐ 1000µF
3.3V │ │ backup_Vin ── to gnd
xtal xi │DS1302│ clk ─── to prop pin
32.768 KHz xo │ │ io ─ 1KΩ resistor to prop pin
┌│ │ ce ─── to prop pin
GND └──────┘
TRICKLE CHARGER NOTES
'Trickle charger setup tc_enable diodeSel resistSel
' | | |
' write(command(clock,tc,w),(%1010 << 4) + (2 << 2)+ ( 3 ))
Diode select register bits: 00 = trickle charger disabled
01 = 1 diode enabled
10 = 2 diodes connected in series (more voltage drop when in charging mode)
11 = trickle charger disabled
Resistor select bits: 00 = no resistor 0Ω
01 = R1 2KΩ
10 = R2 4KΩ
11 = R3 8KΩ
'Examples of other useful config and control commands
'write(command(clock,sec,w),read(command(clock,sec,r))&%1000_0000) 'set clock halt bit
'write(command(clock,ctrl,w),%1000_0000) 'set write-protect bit
'write(command(clock,hr,w),read(command(clock,hr,r))&%1000_0000) 'set 12h mode
V1.1 - 27Oct09 fixed mis-labeled pins in docs (clk and io were swapped in 1.0)
V1.2 - 28Mar10 fixed bug in config method that caused seconds to be reset (thanks, Doug!)
v1.3 - 26Jun10 cleanup and additional documentation
}}
CON
'command byte options
#0, clock,ram
#0, sec, mi, hr, day, mo, dow, yr, ctrl, tc, #31, burst
#0, w,r
VAR
byte clk 'clock
byte io 'data io
byte ce 'chip enable
byte datar
PUB command(clock_or_ram, register, r_or_w)
''Returns a DS1302 command byte
''clock_or_ram : select clock or ram (allowed values: clock, ram)
''register : register name (allowed values: 0-30, sec, mi, hr, day, mo, dow, yr, ctrl, tc, burst)
''r_or_w : read or write (allowed values: w, r)
''Usage : cmd:=command(rtc#ram, 21, rtc#w) --> write to RAM byte 21
'' cmd:=command(rtc#clock, rtc#min, rtc#r) --> read minute register
return (1<<7) + (clock_or_ram<<6) + (register<<1) + r_or_w
PUB init( inClk, inIo, inCe )
''Initialize propeller serial com channel with DS1302. Call once after prop power-up.
''Usage: rtc.init(clk_pin, io_pin, chipEnable_pin)
clk := inClk 'save pin numbers
io := inIo
ce := inCe
dira[ce]~~ 'configure chip enable pin
outa[ce]~
dira[clk]~~ 'configure clock pin
outa[clk]~
PUB config
''Config DS1302. Call once after DS1302 power-up.
''Usage: rtc.config
write(command(clock,ctrl,w),0) 'clear write-protect bit
write(command(clock,sec,w),read(command(clock,sec,r)) & %0111_1111) 'clear halt bit
write(command(clock,hr,w),read(command(clock,hr,r)) & %0111_1111) 'set 24hr mode
write(command(clock,tc,w),0) 'disable trickle charger
PUB setDatetime( _mth, _day, _year, _dow, _hr, _min, _sec )
''Set date and time
write($8c, bin2bcd( _year ) )
write($8a, _dow )
write($88, bin2bcd( _mth ) )
write($86, bin2bcd( _day ) )
write($84, bin2bcd( _hr ) )
write($82, bin2bcd( _min ) )
write($80, bin2bcd( _sec ) )
PUB readDate( _day, _mth, _year, _dow )
''Read current date (day, month, year, day-of-week)
''Usage: rtc.readDate( @day, @month, @year, @dow )
byte[_year] := bcd2bin( read($8d) )
byte[_mth] := bcd2bin( read($89) )
byte[_day] := bcd2bin( read($87) )
byte[_dow] := bcd2bin( read($8b) )
PUB readTime( _hr, _min, _sec ) | tmp1, tmp2
''Read current hour, minute, second
''Usage: rtc.readTime( @hour, @minute, @second )
byte[_hr] := bcd2bin( read($85) )
byte[_min] := bcd2bin( read($83) )
byte[_sec] := bcd2bin( read($81) )
Pub read( cmd ) | i
''Read a byte of data per command byte
outa[ce]~~
writeByte( cmd )
dira[io]~ 'set to input
readByte
outa[ce]~
return(datar)
Pub write( cmd, data )
''Write a byte of data per cmd byte
outa[ce]~~
writeByte( cmd )
writeByte( data )
outa[ce]~
PUB writeN(cmd, dataPtr, n)|i
''Write a stream of n bytes from byte array pointed to by dataPtr
outa[ce]~~
writeByte( cmd )
repeat i from 0 to n
writeByte(byte[dataPtr][i])
outa[ce]~
Pub readN(cmd, dataPtr, n)|i
''Read a stream of n bytes of data and put in byte array pointed
''to by dataPtr
outa[ce]~~
writeByte( cmd )
dira[io]~ 'set to input
repeat i from 0 to n
readByte
byte[dataPtr][i]:=datar
outa[ce]~
PRI readByte|i
datar~
repeat i from 0 to 7
if ina[io] == 1
datar |= |< i ' set bit
outa[clk]~~
outa[clk]~
PRI writeByte( cmd ) | i
dira[io]~~ 'set to output
repeat i from 0 to 7
outa[io] := cmd
outa[clk]~~
cmd >>= 1
outa[clk]~
PRI bin2bcd(dataIn) | tmp
'Convert a byte of binary data to binary coded decimal
tmp:= dataIn/10
result := dataIn - ( tmp * 10 ) + ( tmp << 4 )
PRI bcd2bin(dataIn)
'Convert a byte of binary coded decimal data to binary
result := (dataIn & %00001111) + ((dataIn >> 4) & %00001111)*10
DAT
{{
┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ 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. │
└─────────────────────────────────────────────────────────────────────────────────────────────────────┘
}}
You're right that the day, month, year, etc. have to be bytes. You missed the comment in the Spin file that the readDate and readTime functions want the addresses of the bytes:
Adding the "@" did the trick, now the program runs as expected. This fastspin(BASIC) is starting to really grow on me.
I also did a program code size comparison, fastspin(BASIC) - 6616; SimpleIDE PropGCC - 6576. The PropGCC version was derived from DS1302_full.spin.
The next thing that I will try is CM2302 module, the Spin code for that looks a little more confusing. It works best with float variables, which fastspin(BASIC) can handle.
The next thing up would be to write the date/time and the temp/humidity to the SD card. But, I noticed that the open command and some sort of read/write to the SD card or file, are not available. So, this just might have to wait.
Ray
rem test_rtc.bas
' October 13, 2018
' Test of the RTC on the WX Activity Board
dim rtc as class using "DS1302_full.spin"
let mscycles = clkfreq / 1000
sub pausems(ms)
waitcnt(getcnt() + ms * mscycles)
end sub
dim day1 as byte
dim month1 as byte
dim year1 as byte
dim dow1 as byte
dim minutes as byte
dim hour as byte
dim seconds as byte
dim dow
rtc.init(10,11,9)
do
rtc.readDate(@day1, @month1, @year1, @dow1)
rtc.readTime(@hour,@minutes,@seconds)
print month1;"/";day1;"/";"20";year1;" ";hour;":";minutes;":";seconds
pausems 3000
loop
This one is a little more confusing. I think the DHTnn_Object.spin starts a COG, so I am not sure what happens within fastspin(BASIC). I think the starting of the COG is essential for the program to show the correct results. Right now the test_temp.bas compiles and runs, but it is showing 0.000 for the temp. Not sure what is going on.
Yep, fastspin(BASIC) ROCKS!
Ray
test_temp.bas
rem test_temp.bas
' October 13, 2018
' Test of the CM2302 module on the WX Activity Board
dim cm2302 as class using "DHTnn_Object.spin"
'dim f as class using "FloatMath.spin"
'dim fp as class using "FloatString.spin"
let mscycles = clkfreq / 1000
sub pausems(ms)
waitcnt(getcnt() + ms * mscycles)
end sub
dim temp#,humid#,misc#
cm2302.StartDHTnn(8,22,@temp#,@humid#,@misc#)
do
print "Temp ";temp#
pausems 3000
loop
DHTnn_Object.spin
''******************************************
''* 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. │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
}}
I got the program to run, it works as expected. The program provides the temp in C degrees, so I will have to figure out how to convert tp F degrees. The problem I see is with the humidity read out, not what it is supposed to be. I tried changing the variable from float to integer, but that did not help.
Ray
rem test_temp.bas
' October 13, 2018
' Test of the CM2302 module on the WX Activity Board
dim cm2302 as class using "DHTnn_Object.spin"
'dim f as class using "FloatMath.spin"
'dim fp as class using "FloatString.spin"
let mscycles = clkfreq / 1000
sub pausems(ms)
waitcnt(getcnt() + ms * mscycles)
end sub
dim temp#,humid#,misc#
dim humid1
cm2302.StartDHTnn(8,22,@temp#,@humid#,@misc#)
do
cm2302.DHTnn_Read()
print "Temp ";temp#;" Humid ";humid#
pausems 3000
loop
Propeller Version 1 on COM4
Loading G:/fastspin/programs/test_temp/test_temp.binary to hub memory
8676 bytes sent
Verifying RAM ... OK
[ Entering terminal mode. Type ESC or Control-C to exit. ]
Temp 24.500 Humid 1.1034E+09
Temp 24.600 Humid 1.1034E+09
Temp 24.600 Humid 1.1034E+09
I tried to compiler the code snippet and got the following errors
class fullduplex using "FullDuplexSerial.spin"
class Sd using "fsrw.spin" 'dowloaded from OBEX
dim ser as fullduplex
dim sd as fsrw
' test typewriter here
dim chr as ubyte
ser.start(31, 30, 0, 115200)
pausems(1000)
do
chr = ser.rx()
ser.tx(chr)
if chr = 13 then
ser.tx(10)
' handle SDcard commands here...but not ready yet
end if
loop
Results of compiler, fastspin
line 246 return @buf2 + (byteloc & constant(SECTORSIZE - 1))
line 483 floc := filesize & constant(!(SECTORSIZE - 1))
line 485 bufat := frem & constant(SECTORSIZE - 1)
fsrw.spin(246) error: Cannot handle expression yet
fsrw.spin(483) error: Cannot handle expression yet
fsrw.spin(485) error: Cannot handle expression yet
Not sure why the humidity is coming out wrong; the code looks OK to me. You could trying to compile with optimization turned off (-O0) just in case there may be a fastspin optimizer bug.
@Mickster : fastspin is an optimizing compiler, so the output is a little harder to read than PropBasic's. If you give it the -l switch it'll add the original code to the listing file as comments.
@rsut : thanks for trying that! I think the problem is the constant(x) expression. I hope to fix that soon.
It's a great piece of code on your part. I was trying port the sd code to pbasic but I could not fit the fast_spi_engine into one cog. (it's all inline pasm !!!)
I decided not to try and re-invent the wheel and give your fastspin basic a try.
I am using spin2gui, and I chose, from the Options - No Optimizations, that seemed to have done the job. Before I was using, Default Optimizations, which produced the weird humidity# values. I also tried the Full Optimizations, it showed the first five lines of information, and it froze, never got to running the program. So, it might be something in your spin2gui Options, that might be causing a problem.
The program below is outputting the correct values now, using-No Optimizations.
Now that this is working, I would like to tackle the ADC component that is on the WX Activity Board. I know that there is PropGCC function for that, but that is in C. In the OBEX, the only thing that is available is for a different kind of ADC chip. Now if you have a C2fastspin(BASIC) conversion program, and the C source for the ADC , then I guess we could accomplish something.
Now, in the mean time, I will have to try my hand at fsrw26, and see if I can make some progress. That looks like a fairly complicated Spin program.
Ray
rem test_temp.bas
' October 13, 2018
' Test of the CM2302 module on the WX Activity Board
dim cm2302 as class using "DHTnn_Object.spin"
let mscycles = clkfreq / 1000
sub pausems(ms)
waitcnt(getcnt() + ms * mscycles)
end sub
dim temp#,humid#,misc#
cm2302.StartDHTnn(8,22,@temp#,@humid#,@misc#)
do
cm2302.DHTnn_Read()
print "Temp ";(9.0/5.0)*temp# + 32.0;" Humid ";humid#
pausems 3000
loop
Propeller Version 1 on COM4
Loading G:/fastspin/programs/test_temp/test_temp.binary to hub memory
12840 bytes sent
Verifying RAM ... OK
[ Entering terminal mode. Type ESC or Control-C to exit. ]
Temp 73.040 Humid 55.500
Temp 73.220 Humid 55.100
Temp 73.220 Humid 55.100
Temp 73.220 Humid 55.000
Comments
If Eric does not mind, I am calling this BASIC, pBas or pBAS.
Will pBas provide an #include provision? I am thinking that, as an example, the high, low, and pausems commands could be placed in a lib, so you only code it once, and have it called within your program.
Ray
The second pausems is for only 26 ms. Is that what you intended?
Also, your high() and low() functions are changing the direction, not the output value. They really should be something like: And then in your main code do once to set the pin as an output.
Probably "fBas" would be a better abbreviation, to avoid confusion with PropBasic.
It already does, actually. I need to write documentation for the preprocessor, but it supports #include, #define, #ifdef, #elseifdef, and #endif.
Besides #include (which just literally includes one file into another) there is also "class using filename", which lets you include files as objects, similar to the OBJ statement in Spin. "class using" works with both Spin and BASIC files.
Eric
Thanks David! I'll switch to proploader for the next version.
Ray
Use "direction(26) = output". Or you could add at the beginning of your code so that it's easy to change the pin. For example:
The most recent version of fastspin has pausems as a builtin function so you probably don't need to define that, but your definition looked OK and you can use it if you like
Also note that 'dim pin%' declares a variable called 'pin%' and is different from 'dim pin'. I think that may be an area where fastspin differs from qbasic and freebasic.
Eric
I am liking the spin2gui program, although some improvements would be nice. One would be, a Load command, where it writes the program to the EEPROM. The other is, you do not have any support for .bas in terms of creating a or saving a .bas file.
Ray
Thanks for the suggestions!
I noticed that pBas does not have any break or exit commands. What would be the method for getting out of a while loop.
Ray
Does, or will, pBas have inline pasm? I am wondering as to the best way for pBas to utilize all the Spin driver code that is available. I think JonnyMac had written quite a few drivers in pasm, but there also is quite a few drivers that are written in Spin. One large driver, that could be of great use, is the SD driver, which is in Spin.
Since Parallax has the Activity Board WX, and the FLiP module, maybe there should be an effort made to start trying to create some usage of the different items for the these platforms. For the Activity Board WX: the SD, WiFi, ADC, sound, motor driver, …, etc. Other items of interest could be the RTC, Temp/humidity module and others.
Ray
The usual way would be to have the while loop test for a variable, and to set that inside the loop. For example, an (ugly) way to print some integers is: You could also use a goto:
fastspin supports inline assembly between "asm" and "endasm". But if you want to use Spin, you can import it directly with "class using". (The compiler is called "fastspin" after all, and that was the first language it supported -- the BASIC is a new addon!)
For example, to use the FullDuplexSerial.spin driver from a BASIC program you can do:
"class using" accepts either a BASIC or Spin file.
TMM = Cog Ram
LMM = Hub Ram
XMM = P2 Hub Execute
Ray
Ahem....'t ain't called "pBas", it's called fastspin(BASIC).
Other readers are going to be confused 😕
Since I have a WX Activity Board with DS1302 module installed, I thought I would try doing a real use program with fastspin(BASIC).
The program below compiles without complaints, but the value is showing up as 0, it should be 13, todays date. I believe that in the Spin program, the value(s) is presented as a byte. So, I am not sure if fastspin(BASIC) is doing a correct print of the day1 variable. Have not done anything in Spin, in the last ten years, so I could be wrong with my interpretation.
I attached the DS1302.spin program, for easy referencing.
Ray
test_rtc.bas ds1302_full.spin
You're right that the day, month, year, etc. have to be bytes. You missed the comment in the Spin file that the readDate and readTime functions want the addresses of the bytes: so if you change the line in your BASIC program from to then it may work. (I don't have hardware to test it myself.)
I also did a program code size comparison, fastspin(BASIC) - 6616; SimpleIDE PropGCC - 6576. The PropGCC version was derived from DS1302_full.spin.
The next thing that I will try is CM2302 module, the Spin code for that looks a little more confusing. It works best with float variables, which fastspin(BASIC) can handle.
The next thing up would be to write the date/time and the temp/humidity to the SD card. But, I noticed that the open command and some sort of read/write to the SD card or file, are not available. So, this just might have to wait.
Ray
Yep, fastspin(BASIC) ROCKS!
Ray
test_temp.bas DHTnn_Object.spin
I don't see anything obviously wrong with the code. Does the Spin object work as you expect it to when you use it in a Spin project?
Ray
What does the fastspin(BASIC) PASM code look like (assuming it does similar to PropBasic)?
Ray
I tried to compiler the code snippet and got the following errors
Posted in the hope that it is helpful.
Ron
@Mickster : fastspin is an optimizing compiler, so the output is a little harder to read than PropBasic's. If you give it the -l switch it'll add the original code to the listing file as comments.
@rsut : thanks for trying that! I think the problem is the constant(x) expression. I hope to fix that soon.
It's a great piece of code on your part. I was trying port the sd code to pbasic but I could not fit the fast_spi_engine into one cog. (it's all inline pasm !!!)
I decided not to try and re-invent the wheel and give your fastspin basic a try.
Love it
Ron
The program below is outputting the correct values now, using-No Optimizations.
Now that this is working, I would like to tackle the ADC component that is on the WX Activity Board. I know that there is PropGCC function for that, but that is in C. In the OBEX, the only thing that is available is for a different kind of ADC chip. Now if you have a C2fastspin(BASIC) conversion program, and the C source for the ADC , then I guess we could accomplish something.
Now, in the mean time, I will have to try my hand at fsrw26, and see if I can make some progress. That looks like a fairly complicated Spin program.
Ray