Sonsivri
 
*
Welcome, Guest. Please login or register.
Did you miss your activation email?
April 19, 2024, 06:23:22 06:23


Login with username, password and session length


Pages: [1]
Print
Author Topic: How to sense water level with a microcontroller I/O and three passive components  (Read 3051 times)
0 Members and 1 Guest are viewing this topic.
PeterMcMonty
Junior Member
**
Offline Offline

Posts: 99

Thank You
-Given: 154
-Receive: 119



« on: April 12, 2015, 01:26:01 13:26 »

Hi everybody,

here I describe a very simple method to implement a water level sensor.
The idea is to charge a capacitor and discharge it through the liquid itself, if the electrodes are immersed in it.
This can be done with an I/O pin, three external passive components and few firmware instructions.

Referring to schematics in figure 1, a PIC16F818 is used to control a tank for ultrasonic cleaning: set temperature, set timer and water level control, output readout by some leds. Just the water level control circuit is shown, using RB7 I/O as sensor input and outputting a led indication on RB6.

Here the assembly code:
Code:
                      00442 ;======== input / output routines ===========================
                      00443 ; switch reading (port B)
                      00444 ; ******** level sensor read (RB7) and led low level output (RB6) ******
                      00445 ; Time and Temp leds toggle and output (port B)
                      00446 ; port A output
                      00447 ; switch debounce routine
                      00448
0086                  00449 read_switches
.................... omissis ..............................................
                      00471 ;************ Reading of water level
0096   3014           00472         movlw   20      ; init timeoutcounter
0097   00CA           00473         movwf   CNT2
0098   3000           00474         movlw   B_TRIS_lout     ; set RB0,..,RB7 as outputs (not affecting Z flag)
0099   1683           00475         bsf     STATUS,RP0      ; bank 1
009A   0086           00476         movwf   TRISB
009B   1283           00477         bcf     STATUS,RP0      ; bank 0
009C   1786           00478         bsf     PORTB,7         ; charge level capacitor
009D   0BCA           00479         decfsz  CNT2,f          ; charge timeout RB7: 20x3=60 Tcyc
009E   289D           00480         goto    $-1
009F   3080           00481         movlw   B_TRIS_levrd    ; set RB0,..,RB6 as outputs (not affecting Z flag)
00A0   1683           00482         bsf     STATUS,RP0      ; bank 1
00A1   0086           00483         movwf   TRISB
00A2   1781           00484         bsf     OPTION_REG,NOT_RBPU     ; disable pull-ups
00A3   1283           00485         bcf     STATUS,RP0      ; bank 0
00A4   0806           00486         movf    PORTB,w         ; lettura port B reading
00A5   3980           00487         andlw   h'80'           ; mask bit 7
00A6   1903           00488         btfsc   STATUS,Z        ; if RB7 = 1 then continue
00A7   28B0           00489         goto    levshort        ; else if RB7 = 0 then skip to RB6=1 (capacitor discharged by a short circuit)
00A8   3064           00490         movlw   100             ; RB7 = 1 wait for capacitor discharge
00A9   00CA           00491         movwf   CNT2            ; init timeout counter
00AA   0BCA           00492         decfsz  CNT2,f          ; timeout to read RB7: 100x3=300 Tcyc
00AB   28AA           00493         goto    $-1
00AC   0806           00494         movf    PORTB,w         ; port B reading
00AD   3980           00495         andlw   h'80'           ; mask bit 7
00AE   1306           00496         bcf     PORTB,6         ; preset RB6=0
00AF   1D03           00497         btfss   STATUS,Z        ; if RB7 = 0 then skip with RB6=0 (capacitor discharged by water)
00B0                  00498 levshort
00B0   1706           00499         bsf     PORTB,6         ; else if RB7 = 1 then set RB6 (capacitor charged: no water)
00B1   1386           00500         bcf     PORTB,7         ; keep output RB7=0 (read-modify-write instruction)
                      00501 ;************
                      00502
00B2   3000           00503         movlw   B_TRIS_lout     ; set RB0,..RB3 as outputs (not affecting Z flag)
00B3   1683           00504         bsf     STATUS,RP0      ; bank 1
00B4   0086           00505         movwf   TRISB
                      00506 ;************
00B5   1381           00507         bcf     OPTION_REG,NOT_RBPU     ; enable pull-ups
                      00508 ;************
00B6   1283           00509         bcf     STATUS,RP0      ; bank 0
00B7   0008           00510         return
.................... omissis ..............................................

Two words about the phisical implementation of the sensor itself: since the tank was an AISI 315 medical grade stainless steel, it was used as ground reference, while the sensor was a M3 stainless steel screw fixed to the tank wall and insulated by the very same plastic insulators that are commonly used to mount TO220 devices on heatsinks with mica or SilPad. A mounting sketch is shown in figure 2.

Of course, you can shape the sensor in many other ways, depending on your application. This is just an hint.

In figure 3 another way to do the job, with three sensors, the same of figure 2: one is mounted at the bottom of the tank (tank empty) and the remaining two are mounted on the side of the tank, some 2 cm spaced in height (tank full and tank overfull).
The sensors (LEV0, LEV1 and LEV2) are read by RE0, RE1 and RE2 I/Os of PIC16F877.

This time, the hardware is made with two capacitors and one resistor for each sensor input. The capacitors forms three 9:10 voltage dividers, connected to ground through the water resistance. C6, C7 and C8 are connected toghether to RC2 I/O of PIC16F877, that provides to discharge them.
The whole system has been tailored to work with a broad range of water EC (EC = Electro Conductivity, from 10 uS/cm up to 10 mS/cm).

The reading sequence is as follows:
- initially all capacitors are kept discharged by RE0,..,RE2 and RC2 all outputting 0 level;
- RE0,..,RE2 are raised to high level (Vcc) for 6 us;
- RE0,..,RE2 are switched to inputs;
- Common RC2 to C6, C7 and C8 is raised to high level (Vcc) for 2 us, letting capacitors start to be charged through C9, C10 and C11 and water resistance;
- First read of PORT E: RE0,..,RE2 inputs are swapped in POE4,..,POE6 register bits;
Please note: readings should be high level unless a sensor is short circuited or liquid EC is too high (more than 10 mS/cm);
- wait for 2001 us, to allow C6,..,C8 to be charged through C9,..,C11 and water resistance;
- second read of PORT E: RE0,..,RE2 inputs are stored in POE0,..,POE2 register bits. A low level indicates the presence of water, even with very low EC (about 10 uS/cm: R.O. water);
- discharge capacitors, by setting RE0,..,RE2 and RC2 outputs at low level;
- perform other read operations (read RC1 input and store in POE3 register bit);
- debounce inputs, update level indicator leds LevLD0..2 and returns, leaving decisions to other parts of program.

Here the assembly code:
Code:
; Some I/O definitions:
; PORTC bit assignement, TRIS I/O direction controls and defines
                      00027 ; PORTC: COVER input, LCD control lines D/C and R/W,
                      00028 ;        Lev0..3 capacitors charge output, serial communications
                      00029 ; RC0 = RTS (RS232 control line O),
                      00030 ; RC1 = COVER (I),
                      00031 ; RC1 = R/W (LCD control line O),
                      00032 ; RC2/CCP1 = Lev0..2 capacitors charge output (O),
                      00033 ; RC2/CCP1 = LevLD0..2, CovLD led disable output (O),
                      00034 ; RC2/CCP1 = D/C (LCD control line O),
                      00035 ; RC3/SCL = I2C communication (I),
                      00036 ; RC4/SDA = I2C communication (I),
                      00037 ; RC5/SDO = CTS (RS232 control line I),
                      00038 ; RC6/TX = RS232 communication (O),
                      00039 ; RC7/RX = RS232 communication (I).
  000000B8            00040 C_TRIS_init     equ     h'B8'   ; control direction (PORTC)
  000000B8            00041 C_TRIS_i2c      equ     h'B8'   ; data direction for I2C (PORTC)
  000000BA            00042 C_TRIS_rdCv     equ     h'BA'   ; read Cover input (PORTC)
                      00043
  000000E7            00044 PORTC_init      equ     h'E7'   ; SCL and SDA init mask
  00000001            00045 Cover           equ     1       ; cover bit
  00000002            00046 Cov_led_dis     equ     2       ; covLD disable output bit
  00000002            00047 Lev_charge      equ     2       ; Level capacitors charge bit
  00000003            00048 SCL             equ     3       ; i2c SCL
  00000004            00049 SDA             equ     4       ; i2c SDA
  00000005            00050 CTS             equ     5       ; Clear To Send
  00000020            00051 CTS_msk         equ     h'20'   ; Clear To Send read mask
                      00052         #define Cover_bit PORTC,Cover
                      00053         #define Cov_led_dis_bit PORTC,Cov_led_dis
                      00054         #define Lev_charge_bit PORTC,Lev_charge

; PORTE bit assignement, TRIS I/O direction controls and defines
                      00089
                      00090 ; PORTE: Level inputsLCD control lines, outputs
                      00091 ; RE0 = LEV0 (I/O), RE1 = LEV1 (I/O), RE2 = LEV2 (I/O),
  00000000            00092 E_TRIS_init     equ     h'00'   ; control direction (PORTE)
  00000007            00093 E_TRIS_levr     equ     h'07'   ; read levels direction (PORTE)

                      00074 ;*********************************************************************
                      00075 ; inputs reading (Cover bit and level sensors Lev0, Lev1, Lev2)      *
                      00076 ;*********************************************************************
108D                  00077 rd_inputs                       ; level sensor and cover bit inputs reading
108D   0858           00078         movf    POE,w           ; debounce
108E   00D7           00079         movwf   OLD_POE
108F   30FF           00080         movlw   h'ff'
1090   0089           00081         movwf   PORTE           ; 6uS: LEV0, LEV1, LEV2 output high
1091   3009           00082         movlw   PORTE
1092   0084           00083         movwf   FSR
1093   3007           00084         movlw   E_TRIS_levr     ; set RE0, RE1, RE2 inputs
1094   1507           00085         bsf     Lev_charge_bit  ; 2 uS charge input capacitors
1095   1683           00086         bsf     STATUS,RP0      ; bank 1
1096   0089           00087         movwf   TRISE
1097   0E00           00088         swapf   INDF,w          ; 1uS: read PORTE
1098   1283           00089         bcf     STATUS,RP0      ; bank 0
1099   00D8           00090         movwf   POE             ; copy: POE4 <- RE0, POE5 <- RE1, POE6 <- RE2
109A   30FA           00091         movlw   250             ; delay 250x8 + 1 = 2001uS
109B   00C5           00092         movwf   cont
109C   0000           00093         nop
109D   0000           00094         nop
109E   0000           00095         nop
109F   0000           00096         nop
10A0   0000           00097         nop
10A1   0BC5           00098         decfsz  cont,f
10A2   289C           00099         goto    $-6
10A3   0809           00100         movf    PORTE,w         ; read PORTE
10A4   04D8           00101         iorwf   POE,f           ; copy: POE0 <- RE0, POE1 <- RE1, POE2 <- RE2
10A5   3000           00102         movlw   E_TRIS_init     ; set RE0, RE1, RE2 outputs (high)
10A6   0189           00103         clrf    PORTE           ; LEV0, LEV1, LEV2 output low
10A7   1107           00104         bcf     Lev_charge_bit  ; discharge input capacitors
10A8   1683           00105         bsf     STATUS,RP0      ; bank 1
10A9   0089           00106         movwf   TRISE
10AA   30BA           00107         movlw   C_TRIS_rdCv     ; set RC2 input
10AB   0087           00108         movwf   TRISC
10AC   1283           00109         bcf     STATUS,RP0      ; bank 0
10AD   1887           00110         btfsc   Cover_bit       ; read Cover bit in POE3
10AE   15D8           00111         bsf     POE,3
10AF   30B8           00112         movlw   C_TRIS_i2c      ; set RC2 output
10B0   1683           00113         bsf     STATUS,RP0      ; bank 1
10B1   0087           00114         movwf   TRISC
10B2   1283           00115         bcf     STATUS,RP0      ; bank 0
10B3   0857           00116         movf    OLD_POE,w       ; debounce: update levels only if POE = OLD_POE
10B4   0658           00117         xorwf   POE,w
10B5   1D03           00118         btfss   STATUS,Z
10B6   0008           00119         return
10B7   085A           00120         movf    Levls,w         ; debounce
10B8   00D9           00121         movwf   OLD_Levls
10B9   307F           00122         movlw   h'7f'           ; invert levels
10BA   0658           00123         xorwf   POE,w
10BB   00DA           00124         movwf   Levls
10BC   0E5A           00125         swapf   Levls,w         ; update level indicator leds LevLD0..2
10BD   065A           00126         xorwf   Levls,w
10BE   39F0           00127         andlw   h'f0'
10BF   00D5           00128         movwf   POB
10C0   0008           00129         return

Advantages of this system:
- extreme simplicity in making sensors,
- small size of sensors,
- very simple hardware,
- very simple firmware.

Disadvantages of this system:
- electric circuit is connected to water, in particular water is at ground potential: this could impair other sensor readout, such as pH sensors,
- the same could concern electric safety issues.

Some other further possible developements:
By measuring the time of discharge or by convert the input voltage (into an analog input with an embedded ADC) after a given discharge time, one could think to perform:
- EC readout and measurement, but beware to water polarization phenomena: usually this measure is performed using an AC signal,
- continous level monitoring: making sensor made of two stainless steel bars, from bottom to top of the tank, one can imagine to have a sort of potentiometer where the cursor is water level. But the readout is also EC dependent.

Conclusions:
This is just an hint, a starting point, that everyone can elaborate and adapt to his own application.
The two examples are part of real devices that were in production in the firm I was worrking in at that time.

Regards,
PeterMcMonty
Logged

That\'s not a bug, it\'s a feature!
Pages: [1]
Print
Jump to:  


DISCLAIMER
WE DONT HOST ANY ILLEGAL FILES ON THE SERVER
USE CONTACT US TO REPORT ILLEGAL FILES
ADMINISTRATORS CANNOT BE HELD RESPONSIBLE FOR USERS POSTS AND LINKS

... Copyright © 2003-2999 Sonsivri.to ...
Powered by SMF 1.1.18 | SMF © 2006-2009, Simple Machines LLC | HarzeM Dilber MC