One of the target projects I have is to re-implement a door sensor to be wifi enabled. To do that I was going to add an ESP to an Arduino, but thought I could probably squeeze the two digital lines for ‘100% open’ and ‘100% closed’ into something that wouldn’t conflict with the pullup resistors of the ESP-01. Basically something that would read two lines on GPIO0.
This is almost the inverse of reading an analog value on a digital pin (driving a capacitor to charge, then waiting for it to discharge).
I had the idea that if I could encode two analog values into one digital line I might have something. One way to do this is similar to what radio-controlled toys do; they send a series of variable length pulses in between a longer guard timer. With only two values I don’t really need a guard timer, either – I just need to encode the digital-high duration as one value and the digital-low duration as the other value, and then time the two states.
And to do that encoding? How about a bunch of resistors on the two magnetic sensors (for the open and closed states on both) and use those to influence an astable 555.
I’d like to say it worked the first time I wired it up. It didn’t – the breadboard was crappy. As soon as I realized that and moved the project a bit it worked. After some tweaking of the capacitor and resistor values, I had something that was workable. Try this site to see what I mean: http://www.learnabout-electronics.org/Oscillators/osc44.php
To estimate the frequency and components, I used this site: https://www.allaboutcircuits.com/tools/555-timer-astable-circuit/
This is what it looks like:
There is a bit more going on there; from bottom to top:
- A BitScope Micro oscilloscope is below the breadboard
- The 555 and resistors (and tangle of jumpers) are at the bottom-middle.
- There are a couple of buttons on the board which reset the ESP and set flash mode
- The blue PCB in the middle is a 3.3V power supply for the ESP
- The red PCB is a Sparkfun logic level shifter
- The black PCB at the top is the ESP-01
- The FTDI (serial-to-USB board) is at the top to the right of the breadboard.
The output of the 555 circuit looks like this:
If you squint a bit you’ll see it’s running nearly at a 50% duty cycle; just on either side of 150ms for both high and low times.
Now the fun part; with one ISR and micropython, this is what the timings look like, updated once a second on the serial console:
The output in the serial console reads as:
C: Count of seconds out of 5000 (it quits after 5000)
S: Samples taken (also, the number of interrupts)
H: Milliseconds GPIO0 spent at digital HIGH
L: Milliseconds GPIO0 spent at digital LOW
Which matches what the ‘scope is showing; around 150 milliseconds for both readings. It did take a little futzing to select resistors that would balance out like this, and be large enough values to give the system some immunity to noise.
Anyway, once I get the code cleaned up I’ll post it to gitlab. If you’re thirsty, it looks like this:
from machine import Pin import utime tStart = utime.ticks_ms() tHigh = 0.0 tLow = 0.0 count = 0 cmax = 5000 samples = 0 def pinDelta( event ): global tLow global tHigh global tStart global samples if p0.value() == 1: tLow = (tLow * 0.8) + (utime.ticks_diff( utime.ticks_ms() , tStart) * 0.2) else: tHigh = (tHigh * 0.8) + (utime.ticks_diff( utime.ticks_ms() , tStart) * 0.2) tStart = utime.ticks_ms() samples+=1 p0 = Pin(0, Pin.IN) p0.irq(trigger=Pin.IRQ_RISING + Pin.IRQ_FALLING, handler=pinDelta) utime.sleep(5) print('Starting measurement...') alarm = utime.ticks_add(utime.ticks_ms(),1000) while count < cmax: if utime.ticks_diff(alarm, utime.ticks_ms()) < 0: alarm = utime.ticks_add(utime.ticks_ms(),1000) print ("C:",count,"/",cmax," S:",samples," H:", int(round(tHigh)), " L:", int(round(tLow)) ) count += 1
I almost forgot, the magic of reading the two states via the 555 is to use the two separate switches to control the resistance of either side of a voltage divider that controls the timing of the 555 on pin 7. The simple way to do this is to have a resistance when the switch is open, and closing the switch adds another resistor in parallel, on each side. It looks like the drawing below. Ignore the resistance values and use the calculator above.