Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 06:50 02 Aug 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Dometic VT2500 Vacuum Toilet -Controller

Author Message
disco4now

Guru

Joined: 18/12/2014
Location: Australia
Posts: 1003
Posted: 01:59pm 27 Jul 2019
Copy link to clipboard 
Print this post

I have a Dometic VT2500 Aviation Style Vacuum Toilet in the caravan. This system allows for much flexibility in layout as the waste cassette can be some distance from the toilet bowl. The system is held permanently in a vacuum until the toilet is 'flushed' where upon the vacuum pump senses the pressure drop and pumps away (quite loudly) until the vacuum is restored.

It is difficult to maintain perfect air tight seals at both the toilet bowl end and the cassette end, so eventually the system will leak enough to cause the pump to spring into action and restore the vacuum. This usually happens in the middle of the night, so most end up switching it off at the circuit breaker before they retire.(if they remember). A google of VT2500 will find several solutions adding switches or timers so it only stays on long enough to allow the vacuum to be restored. If it leaks away you just hit the switch again when needed.

Here is my attempt at a better mouse trap using an MX170 and a few other recent TBS discoveries.
The time for the VT2500 to restore vacuum decreases as the cassette get fuller, until it will no longer attempt to restore the vacuum and it needs to be emptied. An ACS712 current sensor is used to detect when the vacuum pump is running.

The length of time the pump runs(last 16) is displayed as a histogram on this
ST7789 240*240 IPS Display so the decreasing run times can be seen and the emptying time predicted a bit better.

The last 16 runtimes are stored in this little RAM/EEPROM discovered by Lewis and coded by Jim. It ensures that the data is not lost when the power is switched off, and the previous usage is remembered.

47L04 a 4/16 Kbit SRAM with EEPROM backup


An ebay remote control relay is used to control the setup from the ensuite so no wires need to be run.

A short press will start the pump.
5 seconds after the pump stops (when vacuum is reached) the power to the system/pump is removed and the runtime recorded and displayed.
A long press will start the pump, but also clear the stored data.
A short press while the pump is running will stop it immediately. (useful if paper or something is preventing a seal and needs to be cleared)

The remote button


The display


Installed in the cupboard



The hardware at the back of the screen.



FontTweak was used to create a one character 200*200 font to display this splash image at startup.
The splash screen at startup



The code is below. The program is state driven and uses the
state machine from Fruit of the shed as the base for the logic.
Latest F4 Latest H7 FotS
 
disco4now

Guru

Joined: 18/12/2014
Location: Australia
Posts: 1003
Posted: 02:00pm 27 Jul 2019
Copy link to clipboard 
Print this post

  Quote  '================================================================================================
' Program Title Block
'================================================================================================
' Name: VaccuFlush VT2500 Monitor
'
'
' Author: Gerry Allardice
' Runtime is 40 seconds when empty

'



'================================================================================================
' Option settings
'================================================================================================

option explicit
option default NONE
OPTION BASE
0
OPTION AUTORUN ON

DIM string Prog$(3) length 20
Prog$(
0) = "VT2500 Monitor"
Prog$(
1) = "v1.0.0"
Prog$(
2) = "14-Jun-2019"


'================================================================================================
' LCD and Touch Initialisation and Test Commands from command prompt
'================================================================================================
'SPI CLK 25
'SPI MOSI 3
'LCD d/C 9
'LCD RST 7
'LCD CS 10

Sub mm.startup
'MX170 on VT2500 board
ST7789 9,7,10, 2 'DCpin, RESETpin, CSpin, orientation (1-4)
End Sub

'================================================================================================
' 47L04/47C04/47L16/47C16 (47XXX) is a 4/16 Kbit SRAM with EEPROM backup
'================================================================================================
CONST EERAMcr=&h18' address of 47x04/47x16 control register with A0=0 and A1=0
CONST SRAMcb=&h50' address of 47x04/47x16 data register forSRAM with A0=0 and A1=0
'
' these are not I2C device addresses but are sent after the device address
CONST COMMANDreg=&h55 ' address of 47x04/47x16 command register
CONST STATUSreg=&h00 ' address of 47x04/47x16 status register
'
CONST S_store=&h33 ' these are the two command register commands
CONST S_recall=&hdd
CONST SRAMsize =
512 ' size 2048 for 47x16, use 512 for 47x04

if (readstatus() AND &b10) = &b10 then
?
"EEPROM OK"
else
?
"EEPROM Initialised "+setup() ' we only have to do this once for each chip
endif
'
'? setup() ' we only have to do this once for each chip
'? chr$(255),chr$(254)
'z$ = readDATA$(10,8) ' 8 bytes starting at address 10 (any address will do)
'PRINT "Last shutdown occurred at "+readDATA$(0,1)
't$ = TIME$
'PRINT TIME$
'? writeDATA(0,"A")
'
'

'================================================================================================
' Data Variables
'================================================================================================
DIM Integer startup=0,pumpdisable=1,runtime=2,buttonstart=3 ' flag allocation for timers 0-9+10
DIM Integer buttondown=11,buttonup=12,pumpstatechange=13,buttonafter=14 ' other flag allocation
DIM Integer ON=1,true=1,OFF=0,false=0,r,s
DIM INTEGER pumptimemax=15,pumptimeindex=0,thisruntime
DIM INTEGER pumptime(pumptimemax)

DIm String temp$

dim integer laststate =1
dim integer buttontimer


'================================================================================================
'Initialisation DOUT to control pump relay
'================================================================================================
dim integer PumpPin = 22 ' Pin number for the push button input
PIN(PumpPin)=OFF
SetPin PumpPin,DOUT


'================================================================================================
'Initialisation of ACS712 current sensor and array for reading/storing pump current
'================================================================================================
DIM FLOAT pc(10)
DIM INTEGER pumpcurrentindex=0
dim integer VRefPin=24
SetPin VRefPin,AIN

dim integer ACS712Pin=26
DIM INTEGER pumpstate=0
SetPin ACS712Pin,AIN
for r=0 to 9
pc(r)=
5.0
next r

'================================================================================================
'Initialisation and Setup of timers 0-9 (SETTICK) AND PumpCurrent monitoring
'================================================================================================
'Option Base 0
Dim Integer TMRctr(9),TMRini(9),Flags=0
SETTICK
100,CoreTMR,4' service timers every 100mS

'================================================================================================
'Initialisation Button and Polling via (SETTICK)
'================================================================================================
dim integer SwPin = 21 ' Pin number for the push button input
Dim Integer btnUPctr ' counter to hold the shifts
dim integer buttonstate=0,buttoncount=0
SetPin SwPin,DIN,PULLUP
SETTICK
20,ButtonTest,3' check button status every 20mS


'================================================================================================
' Program Initialisation
'================================================================================================

CPU
20
CLS
text
20,20,chr$(1),,7
After
30,startup ' 20*100ms i.e 3 seconds
? pin(ACS712Pin)
? pin(VRefPin)

'================================================================================================
' MAIN LOOP
'================================================================================================
'It is all interupt/timer driven but we need to action any flags that have been
'set here in the main loop so interupts are kept short
do
If FlagTest(startup) Then ' start delay timer expired
FlagRes startup
ShowStartScreen


temp$=readDATA$(
0,17)
pumptimeindex=
ASC(mid$(temp$,17,1))
for r=0 to 15
pumptime(r)=
ASC(mid$(temp$,r+1,1)) '+45*(r+1)
next r
showgraph pumptimeindex
ShowLed(
1,RGB(GREEN))
endif

If FlagTest(pumpdisable) Then '
FlagRes pumpdisable
PumpOff
'disable pump
endif

'If FlagTest(pumpenable) Then ' the start pump delay expired
' FlagRes pumpenable
' ShowLed(2,RGB(GREEN))
' PumpOn
'endif

If FlagTest(pumpstatechange) Then '
FlagRes pumpstatechange
if pumpstate=0 then
ShowLed(
5,RGB(RED))
After
50,pumpdisable ' 50*100ms i.e 5 seconds
thisruntime= 6000-remain(runtime)
thisruntime= max(
3,MIN(4*thisruntime\10,160))

'? thisruntime
pumptimeindex=pumptimeindex-1
if pumptimeindex<0 then pumptimeindex=pumptimemax
pumptime(pumptimeindex)=thisruntime
showgraph pumptimeindex
r= writeDATA(
16,chr$(pumptimeindex))

r= writeDATA(pumptimeindex,chr$(thisruntime))
elseif pumpstate=1 then
ShowLed(
5,RGB(GREEN))
r= remain(pumpdisable)
'stop timer as pump is running
After 6000,runtime ' 600*100ms i.e 600 seconds
else
ShowLed(
5,RGB(YELLOW))

endif

endif

If FlagTest(buttondown) Then '
ShowLed(2,RGB(RED))
ShowLed(
3,RGB(RED))
if FlagTest(buttonafter)=0 then After 2,buttonstart ' 2*100ms
FlagSet buttonafter
FlagRes buttonup
'FlagRes buttondown
endif
If FlagTest(buttonup) Then '
if buttonstate=0 then 'down
'ShowLed(5,RGB(GREEN))

'buttoncount=buttoncount+1
'text 200,10,str$(buttoncount)
elseif buttonstate=1 then 'SHORT PRESS
ShowLed(2,RGB(GREEN))
ShowLed(
3,RGB(YELLOW))
if pumpstate=on then
pumpoff
else
pumpon
After
50,pumpdisable ' 50*100ms i.e 5 seconds
end if
'? pin(ACS712Pin)
'buttoncount=buttoncount+1
'text 200,10,str$(buttoncount)
'? buttoncount
elseif buttonstate=2 then 'LONG PRESS
ShowLed(2,RGB(YELLOW))
ShowLed(
3,RGB(GREEN))
if pumpstate=on then
pumpoff
else
pumpon
After
50,pumpdisable ' 50*100ms i.e 5 seconds
end if
'buttoncount=buttoncount+1
'text 200,10,str$(buttoncount)
pumptimeindex=0
r= writeDATA(
16,chr$(0))
for r=0 to 15
pumptime(r)=
0
s= writeDATA(r,chr$(
0))
next r
endif
'After 3,buttonstart ' 20*100ms i.e 2 seconds
FlagRes buttonup
endif

If FlagTest(buttonstart) Then
FlagRes buttonstart
FlagRes buttondown
FlagRes buttonafter
endif

Loop

'================================================================================================
' Procedures providing program functionality components
'================================================================================================


SUB ShowStartScreen
CLS
BOX
0,0,MM.HRES, MM.VRES,,RGB(GREEN)
TEXT
5, 10, Prog$(0)
TEXT
5, 30, "Software "+Prog$(1)
TEXT
5, 50, "Date "+Prog$(2)
ShowLed(
1,RGB(YELLOW))
ShowLed(
2,RGB(YELLOW))
ShowLed(
3,RGB(YELLOW))
ShowLed(
4,RGB(YELLOW))
ShowLed(
5,RGB(YELLOW))
END SUB
sub showgraph(index as integer)
local integer i,j,k
'cls
box 2,25,237,160,,RGB(black),RGB(black)
for i= 0 to pumptimemax
j=(i+index)
MOD 16
'k=4*pumptime(j)\10
k=pumptime(j)
'k=mIN(k,160)
box 200-12*i,185-k,6,k,,RGB(YELLOW),RGB(YELLOW)


next i

end sub
SUB ShowLed(i as integer, c as integer)
CIRCLE
40*i,205,13,1,1,c,c

END SUB

Sub PumpOn
ShowLed(
4,RGB(GREEN))
pin(PumpPin)=ON
' pumpstate=on


End Sub
Sub PumpOff
ShowLed(
4,RGB(RED))
pin(PumpPin)=OFF
' pumpstate=OFF

End Sub



Sub ButtonTest
'STATIC integer laststate =1
'STATIC integer buttontimer
local integer buttontemp,b

btnUPctr=btnUPctr<<
1 Xor Pin(SwPin) And &h7ff ' sample the input pin and shift the bit into the counter
' If this loop is fast, increase the &h1f so we sample more bits... reduce it if the main loop is slower - tune it for your purposes
' If we shift enough zeroes in, the button has been pressed.
' Any bounce (back to 1) will shift a one in and "spoil" our counter for which will start again.
'If FlagTest(buttonchange)=0 Then
Select Case btnUPctr
Case
0 'button down
If FlagTest(buttondown)=0 Then
buttonstate=
0
if laststate<>buttonstate then
FlagSet(buttondown)
laststate=buttonstate
buttontimer=
timer
endif
endif
'After 2,buttonstart ' 20*100ms i.e 2 seconds
Case &h7ff 'button up
b = TIMER - buttontimer ' this is how long the button was down
IF b < 1500 THEN ' short press
buttontemp=1
else
buttontemp=
2
endif
if laststate=0 then
FlagSet(buttonup)
buttonstate=buttontemp
laststate=buttonstate
endif
'After 2,buttonstart ' 20*100ms i.e 2 seconds
Case Else 'neither up nor down

'buttonstate=2
End Select
' endif
End sub
'

'================================================================================================
' Timer functions
'================================================================================================
'Usage:
' After 10,1 ' 10 seconds using timer 1
' Every 1 ,2 ' count 1 second intervals using timer 2
' Every 2 ,3 ' count 2 second intervals using timer 3
'Variable Descriptions:
'TMRctr() maintains the count for a given timer
'TMRini()holds the timer type and its initialization value.
'- bits 0-61 store the initial value value
'- bits 63&62 store the format of the counter:
'0=disabled
'1=(actually 0x4000000000000000) indicates a one shot "AFTER x" type counter
'2=(actually 0x8000000000000000) indicates a repetitive "EVERY x" type counter

SUB CoreTMR
' needs to run on a ticker at whatever interval is required - this is also the multiple of timer counts
If FlagTest(10) Then Exit Sub
Local Integer n,f,v
For n=0 To 9
f=TMRini(n)
And &hC000000000000000 ' extract the top 2 bits
Select Case f
Case
0,&hC000000000000000 'disabled or invalid
FlagRes(n)
Case
&h4000000000000000' AFTER
If TMRctr(n)>0 then
TMRctr(n)=TMRctr(n)-
1
If TMRctr(n)=0 Then FlagSet(n) ' indicate the timer has expired
EndIf
Case
&h8000000000000000' EVERY
If TMRctr(n)>0 then
TMRctr(n)=TMRctr(n)-
1
If TMRctr(n)=0 Then
FlagSet(n)
' indicate the timer has expired
TMRctr(n)=TMRini(n) And &h3FFFFFFFFFFFFFFF ' reset the timer
EndIf
EndIf
End Select

Next


STATIC Integer lastpumpstate=off
pc(pumpcurrentindex)=pin(ACS712Pin)
pumpcurrentindex=pumpcurrentindex+
1:if pumpcurrentindex=10 then pumpcurrentindex=0
if MIN(pc(0),pc(1),pc(2),pc(3),pc(4),pc(5),pc(6),pc(7),pc(8),pc(9))<2.40 then
'if pin(ACS712Pin)<2.45 then
pumpstate=on
if pumpstate<>lastpumpstate then FlagSet(pumpstatechange)
lastpumpstate=pumpstate
else
pumpstate=off
if pumpstate<>lastpumpstate then FlagSet(pumpstatechange)
lastpumpstate=pumpstate
endif
END SUB


Sub After(Interval As Integer,Tmr As Integer)
' starts a one-shot timer
TMRini(Tmr)=Interval OR &h4000000000000000:TMRctr(Tmr)=Interval And &h3FFFFFFFFFFFFFFF:FlagRes(Tmr)
End Sub

Sub Every(Interval As Integer,Tmr As Integer)
' starts a repetitive timer
TMRini(Tmr)=Interval OR &h8000000000000000:TMRctr(Tmr)=Interval And &h3FFFFFFFFFFFFFFF:FlagRes(Tmr)
End Sub

Sub At(dt$,Tmr As Integer)
' trigger at a specific date/time - assumes the core timer is running in seconds
'dt$ must be a datetime formatted as dd/mm/yyyy hh:mm:ss
Local Integer x
x=
UnixTime(Now())-UnixTime(dt$)
If x<2 then
FlagSet Tmr
' if he difference is less than 2 seconds, trigger the alarm immediately
Else
After x,Tmr
' otherwise set a one-shot for the difference
EndIf
End Sub

Function Remain(Tmr As Integer) As Integer
' stops a timer and returns the remaining whole counts in the counter
TMRini(Tmr)=TMRini(Tmr) And &h3FFFFFFFFFFFFFFF
Remain=TMRctr(Tmr)
End Function

Sub DI
FlagSet
10
End Sub

Sub EI
FlagRes
10
End Sub

'================================================================================================
' Bit manipulation functions
'================================================================================================
'Set a bit
SUB FlagSet(bit AS INTEGER)
FLAGS=FLAGS
OR (2^bit)
END SUB

'Clear a bit
SUB FlagRes(bit AS INTEGER)
FLAGS=(FLAGS
OR (2^bit)) XOR (2^bit)
END SUB

'Set bit equal to value passed
SUB FlagEq(bit As Integer,v as integer)
IF v=0 THEN
FlagRes(bit)
ELSE
FlagSet(bit)
ENDIF
END SUB

'Test if bit is set
FUNCTION FlagTest(bit AS INTEGER) AS INTEGER
FlagTest=
ABS(SGN(FLAGS AND (2^bit)))
END FUNCTION

'================================================================================================
' 47L04/47C04/47L16/47C16 (47XXX) is a 4/16 Kbit SRAM with EEPROM backup
'================================================================================================
FUNCTION setup() as string
local integer x,r
r = readstatus()
' get the current status register
x = x OR &b10 ' set bit 2 leaving the rest alone
PRINT BIN$(x,8)
r= writeCMD(STATUSreg,x)
' set autostore
r = readstatus()
PRINT BIN$(r,8)
END FUNCTION

FUNCTION writeDATA(addr as integer,D$ as string) as integer
' write string D$ to EERAM starting at addr
LOCAL integer L
addr = addr
MOD SRAMsize ' keep address within chip capacity
d$ = CHR$(addr\256)+CHR$(addr MOD 256)+D$
L =
LEN(D$)
ON ERROR SKIP
1
I2C OPEN
400,1000
I2C
WRITE SRAMcb,0,L,D$
I2C CLOSE
END FUNCTION

FUNCTION readDATA$(addr as integer,L as integer) as string
' read string from EERAM starting at addr, L bytes
LOCAL string D$
addr = addr
MOD SRAMsize ' keep address within chip capacity
ON ERROR SKIP 1
I2C OPEN
400,1000
I2C
WRITE SRAMcb,1,2,addr\256,addr MOD 256 'Reset memory pointer to addr
I2C READ SRAMcb,0,L,D$
readDATA$ = D$
END FUNCTION

FUNCTION writeCMD(reg as integer,EERAMcmd as integer) as integer
'write command to the command or status register
ON ERROR SKIP 1
I2C OPEN
400,1000
I2C
WRITE EERAMcr,0,2,reg,EERAMcmd
I2C CLOSE
END FUNCTION

FUNCTION readSTATUS() as integer
'read status register
LOCAL integer status
ON ERROR SKIP
1
I2C OPEN
400,1000
'I2C WRITE EERAMcr,1,2,STATUSreg,0
I2C READ EERAMcr,0,1,status
I2C CLOSE
readSTATUS = status
END FUNCTION

'================================================================================================
' Library code
'================================================================================================

Latest F4 Latest H7 FotS
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 10:21pm 27 Jul 2019
Copy link to clipboard 
Print this post

Now you need a button to call the slave to take the cassette to the dump point for you.

We had a bulk storage tank and if it was too inconvenient to drive to the dump point, it was 3 trips with the tote tank.

Alas, those days are behind us.

It is also good to see the MMEdit code pasting working in the new forum.


Jim
VK7JH
MMedit
 
disco4now

Guru

Joined: 18/12/2014
Location: Australia
Posts: 1003
Posted: 11:25pm 27 Jul 2019
Copy link to clipboard 
Print this post

  TassyJim said  
It is also good to see the MMEdit code pasting working in the new forum.
Jim

Yes, I had a couple of goes posting this item on the old system, but failed to save each time. I am suspicious I may have broken it a couple of times near the end.
Latest F4 Latest H7 FotS
 
BrianP
Senior Member

Joined: 30/03/2017
Location: Australia
Posts: 292
Posted: 03:52am 28 Jul 2019
Copy link to clipboard 
Print this post

disco4now wrote:
  Quote  A short press while the pump is running will stop it immediately. (useful if paper or something is preventing a seal and needs to be cleared)


Just curious - what might the "something else" be??
 
disco4now

Guru

Joined: 18/12/2014
Location: Australia
Posts: 1003
Posted: 05:45am 28 Jul 2019
Copy link to clipboard 
Print this post

  BrianP said  disco4now wrote:

Just curious - what might the "something else" be??

Mostly a few hairs, but not always!
Latest F4 Latest H7 FotS
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025