Skip to content

Instantly share code, notes, and snippets.

@TG9541 TG9541/ntctheta
Last active Mar 17, 2019

Embed
What would you like to do?
Solar water heater control with transmission of collector and storage temperature via nRF24L01+
\ W1209 temperature measurement with filter and noise suppression
\ © 2017 TG9541, refer to https://github.com/TG9541/W1209/blob/master/LICENSE
\ Note: W1209 thermostats may require adjustment,
\ especially when used outside the range of -5C to +20C
\ Refer to https://github.com/TG9541/W1209/wiki/W1209-Sensor
RAM
900 CONSTANT USENSMAX \ max temperature
NVM
#require @inter
$8000 CONSTANT DEFAULT \ Default value indicator (-32768)
\ note: adjust to specific sensor here if accuracy is required!
\ note: @inter accepts 2..n value pairs
\ interpolation table ADC digits * 32 -> temperature * 10
CREATE dig2tem 14 , \ number of value pairs
1216 , 1100 , \ 1 1216 -> 11.0 C
1534 , 1000 , \ 2
1982 , 900 , \ 3
2560 , 800 , \ 4
3296 , 700 , \ 5
4320 , 600 , \ 6
5634 , 500 , \ 7
7370 , 400 , \ 8
9632 , 300 , \ 9
12382 , 200 , \ 10
15522 , 100 , \ 11
19012 , 0 , \ 12
20768 , -50 , \ 13
22466 , -100 , \ 14 22466 digits -> -10.0 C
: lpf32 ( n1 alpf -- n2 )
\ low pass filter, multiplies n1 by 32, uses a as LPF memory
( alpf ) DUP >R @ DUP 32 / - + DUP R> !
;
: unchatter ( n1 ahy -- n2 )
\ remove chatter (+/- 0.5 digit window), divides n1 by 32
\ ahy: hysteresis storage call address
SWAP 16 / OVER @ OVER SWAP - ABS 2-
0< IF DROP @ ELSE DUP ROT ! THEN
2/
;
: ntctheta ( adc astr -- theta )
\ filter noisy W1209 sensor input, result in astr @
SWAP DUP USENSMAX < IF
OVER 2+ lpf32 \ low pass filter, "noise to digits", 32*ADC
dig2tem @inter \ interpolation: lpf32 digits to temperature
OVER 2+ 2+ lpf32 \ low pass filter, "smoothen", 32*theta
OVER 2+ 2+ 2+ unchatter \ remove chatter, divides by 32
ELSE
DROP DEFAULT \ sensor error - default
THEN
SWAP ! \ store theta in astr
;
RAM
\ changed $HW to erase buffer with spaces so that the count and
\ retries saved into mybuff typed correctly at RX end
#require ntctheta
\res MCU: STM8S103
\res export BIT0 BIT1 BIT2 BIT3 BIT4 BIT5 BIT6 BIT7
\res export INT_EXTI2
\res export PA_ODR PA_DDR PA_CR1
\res export PC_DDR PC_CR1
\res MCU: nRF24L01
\res export R.SETUP_RETR R.STATUS R.OBSERVE_TX R.DYNPD R.FEATURE
1 CONSTANT _COL \ PA1 low side KTY10 solar collector
2 CONSTANT _STO \ PA2 low side KTY10 storage tank
3 CONSTANT _REL \ PA3 Relais
4 CONSTANT _AIN \ PC4/AIN2 ref=2000R to VCC
800 CONSTANT MAXTEMP \ safe storage temp
\ helper word: create BSET/BRES instructions
#require ]B!
#require BL
NVM
VARIABLE VALCOL 6 ALLOT \ collector temperature struct
\ theta \ temperature [0.1°C]
\ adc.lpf \ LPF memory for ADC value
\ tem.lpf \ LPF memory for temperature
\ hyst.lpf \ unchatter memory
VARIABLE VALSTO 6 ALLOT \ storage temperature struct
\ theta \ temperature [0.1°C]
\ adc.lpf \ LPF memory for ADC value
\ tem.lpf \ LPF memory for temperature
\ hyst.lpf \ unchatter memory
VARIABLE CSDIFF \ collector-storage diff (>0: col is warmer)
VARIABLE PUMPON \ current pump activation state
VARIABLE THRESH \ threshold value
VARIABLE HYSTER \ hysteresis value
VARIABLE LIMIT \ temperature Limit (with hysteresis)
: REL.on ( -- )
[ 1 PA_ODR _REL ]B!
;
: GetAin ( -- n )
2 ADC! ADC@
;
: REL.off ( -- )
[ 0 PA_ODR _REL ]B!
;
: SetCol ( -- )
[ 1 PA_DDR _COL ]B! [ 0 PA_DDR _STO ]B!
;
: SetSto ( -- )
[ 0 PA_DDR _COL ]B! [ 1 PA_DDR _STO ]B!
;
: measure ( -- ) \ background task
\ get collector an storage in odd and even cycles
GetAin ( ain ) TIM 1 AND 0= IF
SetSto \ switch to storage sensor
VALCOL ntctheta
ELSE
SetCol \ switch to collector sensor
VALSTO ntctheta
THEN
VALCOL @ VALSTO @ - CSDIFF !
;
: $HW ( -- )
mybuff P0_width $20 FILL \ erase buffer
$" Solar" COUNT ( --- a1 n1 )
mybuff SWAP CMOVE
;
: @retries ( --- n1 )
R.OBSERVE_TX nRF@1 \ get count of lost packets:retries
$0F AND \ mask off lost packets
;
: n>str ( n1 --- a1 n2 ) <# BL HOLD #S #> ;
: n>buff ( a1 n1 --- ) \ store n1 as a string at offset a1 in mybuff
n>str \ a1 a2 n2
ROT mybuff +
SWAP
CMOVE
;
VARIABLE STATUS \ nRF24 STATUS from IRQ
\ interrupt service routine
HERE ] \ headerless code (keep xt on stack)
SAVEC
\ R@STATUS ( s )
R.STATUS nRF@1 ( s )
DUP STATUS @ OR STATUS ! ( s )
DUP BIT4 AND IF
FlushTx \ FlushRx
THEN
\ DUP BIT5 AND IF
\ DEB.On \ Tx data sent
\ THEN
( s ) BIT6 AND IF
LED.On \ Rx data ready
\ RXBUFF 4 R_RX_PAYLOAD nrf>b DROP
RXBUFF 4 rx>b DROP
THEN
$70 R.STATUS nRF!1
IRET
[ OVERT ( xt ) INT_EXTI2 ! \ set Port C int vector
: PAYLOAD.TX ( -- ) \ send n bytes as set by P0_width
mybuff P0_WIDTH b>tx DROP
_CE.HD _CE.LOW \ 10us minimum, using 130uS
;
HERE $05A3 , $B4C5 , $D6E7 , ( myP0Addr )
: TxInit ( -- ) \ setup as primary transmitter
nRF24Init \ general setup
IrqInit \ enable nRF24 IRQ interrupt of PC.4
\ set pipe0 RX/TX to same address
( myP0Addr ) LITERAL COUNT b>p0addr
\ configure ACK payload mode
( DPL_P0 ) $01 R.DYNPD nRF!1
( EN_ACK_PAY ) $02 R.FEATURE nRF!1 \ see footnote ^d
4 SetPL_width \ make it work for SI24R1
\ set TX power to 0dBm output, modulation to 250kbps
[ $0 BIT5 >HIGH BIT2 >HIGH BIT1 >HIGH ] LITERAL RfSetup
\ ARD: retransmit delay, ARC: retries
[ ( ARD: 250us* ) $80 ( ARC: n* ) 3 + ] LITERAL R.SETUP_RETR nRF!1
$70 SetRF_CH
>Standby1
Set.TX \ enter TX mode
." Device reset" cr
;
: sol.init ( -- )
[ 0 PA_ODR _COL ]B! \ open drain output
[ 1 PA_DDR _COL ]B!
[ 0 PA_CR1 _COL ]B!
[ 0 PA_ODR _STO ]B! \ open drain output
[ 1 PA_DDR _STO ]B!
[ 0 PA_CR1 _STO ]B!
[ 1 PA_DDR _REL ]B! \ PA RELais output
[ 1 PA_CR1 _REL ]B! \ push-pull output
[ 0 PC_DDR _AIN ]B! \ PC4 AIN2 as input
[ 0 PC_CR1 _AIN ]B! \ no pull-up
0 PUMPON !
50 THRESH !
30 HYSTER !
MAXTEMP LIMIT !
[ ' measure ] LITERAL BG !
;
: sol.act
VALCOL ?
VALSTO ?
CSDIFF @ DUP . CR
( cs-diff ) THRESH @ - \ apply activation threshold
( diff ) PUMPON @ 0= IF
HYSTER @ - THEN \ apply hysteresis if pump is off
MAXTEMP VALSTO @ < IF
( diff ) DROP -1 THEN \ limit storage temperature
( limdiff ) 0< IF
REL.off 0 PUMPON !
ELSE
REL.on 1 PUMPON ! THEN
;
: Solar ( -- )
TxInit
0 STATUS !
sol.init
$HW BEGIN
8 VALCOL @ n>buff 16 VALSTO @ n>buff
PAYLOAD.TX
@retries DUP 27 SWAP n>buff DROP
100 ms
STATUS @ 0 STATUS !
DUP BIT4 AND IF ." Max retries cleared" CR THEN
\ DUP BIT5 AND IF ." Tx data sent" CR THEN
DUP BIT6 AND IF ." Rx data ready" CR THEN
( s ) . SPACE RXBUFF 4 TYPE SPACE
LED.Off \ DEB.Off
sol.act
900 ms
?RX \ input on serial line
IF 32 = ELSE 0 THEN \ only if it is a space char do we exit
UNTIL
DROP
;
' Solar 'Boot !
RAM
@TG9541

This comment has been minimized.

Copy link
Owner Author

commented Sep 24, 2018

This is in extension of solar.fs using stm8ef-nRF24L01 (using additional code from PingInt). PongInt works as a simple receiver. Note that in order to free up an analog input PC3 instead of PC4 was used for the nRF24L01+ interrupt.

There is a project on Hack-A-Day to track the progress.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.