It turned out doing software UART was a terrible idea. The processor is way too slow to support a reasonable baud rate. I did figure out how to use a comparator though: the key phrase I was missing was “rail-to-rail.” That means that inputs can be in the full voltage range from ground to Vcc. Another handy phrase is “push-pull,” which means that the comparator can output 0 and 1; in contrast, an “open collector” comparator can only output 0, and needs an external resistor to pull the output to 1.
I bought a rail-to-rail push-pull comparator, the MCP6541, and tried it with the receiver circuit, and sure enough it increased the maximum range significantly. Unfortunately it also increased the minimum range significantly.
The range on the infrared channel, which I discussed in the last entry, is probably enough; but I’d like to increase it a bit. With more range I can space modules farther apart if needed, and hopefully be able to have a wider angle between the transmitter and receiver.
Fortunately the signal output by the Darlington transistor pair on the receiver is a pretty clean digital signal. At full power it ranges from (a little above) 0 V to (a little below) 3.3 V. As the transmitter gets farther away the digital signal remains but the low voltage increases beyond the UART receiver’s ability to read a 0. For example, at a large distance the UART signal might range from 2.5 V (logical 0) to 3.3 V (logical 1).
The receiver circuit completes the modem’s hardware design. It is simply a two-stage amplifier that gives a total gain of about 2000, in series with a band-pass filter.
The acoustic transducer produces a beautiful sine wave with nearly no noise. I found that I could apply a huge gain to its output and the amplifier’s output would still be clean: the raw (unfiltered) output has a 5 V offset, and the signal fits into the 5 V above the offset. In other words, the output is at -5 V when idle and peaks at around 0 V when the receiver receives a signal.
The goal is for the receiver to output a signal that is around -10 V when idle and peaks at -5 V when it receives a signal. These voltages correspond respectively to logic low and high on the microcontroller.
Above you can see the transmitter part of my acoustic modem. From left to right, the components are: the power supply, the acoustic transducer, the amplifier, and the microcontroller.
The problem: I need to send a 40 kHz, 20 V peak-to-peak square wave to the transducer. The circuit has two outputs, + and -, that are connected to the two transducer pins. In other words, each output needs to switch from +10 V to -10 V and back once every 25 microseconds.
As always, there are a few decent solutions, and as always I didn’t implement the best one.
Simulation of a Schmitt trigger. The yellow sine wave is the input, the purple square wave is the output.
I was looking for a way to convert an analogue signal into a digital signal, and came across the Schmitt trigger. This is a great little circuit that you can build with a couple transistors or with an operational amplifier. I tried to build a transistor-based simulation in Simulink, but it didn’t work right away. My op-amp simulation did work, so I stuck with that.
The principle is simple: if the trigger input rises above a certain threshold, then the output saturates to the op-amp’s positive power supply voltage. When the input falls below another threshold, the output saturates to the op-amp’s negative power supply voltage. If the input lies between the thresholds then the output doesn’t change from whatever it was before.
This is incredibly useful. To the left you can see a 0.3 V sine wave being converted into a 5 V binary signal (actually a 4.5 V signal, since I added a diode in series with the output to keep it from going down to -5 V). It also effectively filters out any input jitter that doesn’t cross the threshold needed to change the output state. Microcontrollers have Schmitt triggers on their digital inputs. For example, an AVR microcontroller being powered by 5 V typically considers a 0 logic level to be under 1.5 V and a 1 logic level to be over 3 V. If the input sits between 1.5 V and 3 V then the digital state remains whatever it was before the input entered that region.
Alas, it’s not a perfect circuit. I used an online calculator to figure out what resistances I needed for my project. Configurations that worked in the calculator and in simulation didn’t work in reality, either producing no output or something more like a sawtooth wave than the square wave I expected. It’s probably a limitation in my op-amp—maybe the signal is too high-frequency, I didn’t investigate very deeply.