"Innsbruck, Ich muß Dich lassen"...viel schlimmere Barock-musi gibts nicht. Ein guter Grund, das Gedudel als Türglocken-Melodei zu verwurschten. Weil es soll ja nicht gut und wohlig klingen, sondern laut und nervig damit a) ich aufkreuch und zur Tür gehe und b) die Wartenden sich möglichst gleich ohne meine Mithilfe dazu entscheiden daß sie sich schleichen. Weil mei home is mei kastl, da sind nur wenige besondere Leute willkommen. In diesem Sinne also eine perfekte Wahl. Wie ich das verbrochen hab, erzähl ich weiter unten.
We now return to a technical discussion of how I cooked up my hideous "melody" doorbell with a PIC, some trash components and a bit of experimentation.
Recently (well, in March; I've been meaning to write this down since then...) I decided to construct a door bell that plays a melody (sort of) and does not let the person out there cut it short or retrigger it before the melody is finished. I also wanted to build it all by myself, with only my own code and using a PIC microcontroller as an exercise.
Of course other people have done similar things: this project here is about a PIC16F84 doodling "oh when the saints...", this bloke has a doorbell with some triggering gadgetry and so on.
I decided to make do (on purpose) with the absolute minimum processor, a 12F509: 1024 words program flash memory (for a 33-instruction 8bit RISC set that is really RISC, and with a Harvard-architecture: no stack and separate prog/data memories), a whopping 41 bytes of RAM, 6 digital I/O lines and that's about it (well, some watchdogs, timers and counters are even present on the 509 but I didn't use any of these features for this project). The PICs are great beasts, I'm very happy to be learning about them: cheap ($2.50 for the 12f509), sturdy (2V to 5.5V, .350mA at 2V operating, 100nA in sleep mode), tiny (8 pin DIP, 6 of which are usable for I/O), have a 4MHz internal oscillator or use external crystals and so on. The 509 is the absolute lowest end of the offerings, and it is absolutely amazing what you get for $10 in the mid- and upper ranges of Microchip's PIC families (eeprom, i2c bus, usart on board etc etc).
But I wanted to do much with little, also as an exercise to see how much I can conveniently cram in there. The plan was to use a piezo transducer to make noise, with the pic creating square waves of the desired frequencies in software. It was to be battery powered (I hate wall-wart transformers), and when idle, the thing should draw minimum juice. The victi^Wvisitor should have one button to press to Make The Noise Start, and I should be able to terminate the audio pollution with another button before the "melody" runs out (i.e. if and when I happen to want to see the visitor).
So far, so straight-forward. I started coding...delay routines, so that I can produce the correct frequencies. Counting microseconds is a lot of fun! The code side is not very complicated: on connecting the battery the pic starts up and goes to sleep immediately, after having things set up so that it is woken when the go button is pressed. If that happens, it starts making noise: reading the notes one-by-one, it produces square waves of the appropriate frequencies on a pin that is connected to the piezo transducer. When finished it goes to sleep again; when I press the reset button, it resets completely and starts from the power-on scenario again (which means blessed silence and sleeping). Not exactly complicated, but fun to do when you have almost no memory. Here is the main code in assembler (works with gpasm as well as Microchip's mpasm), and reasonably well documented IMHO.
And how did I get the frequencies and the tune into the pic? Quite Easily: I found and downloaded the MIDI file with the tune I wanted, used mftext to dump it textually and used a few lines of perl to convert that into the appropriate assembly statements. The tune info is stored as a pseudo-table: as the pic has 41 bytes of ram and no eeprom (at least this model), I can't store the tune there. The common solution for this is a jump table: you produce the data as return values from a subroutine. The subroutine gets the offset into the table as input, and jumps to the respective instruction which returns the data byte of your choice. Easy, simple, not inelegant and used everywhere on the pics (actually it is mentioned in one of Microchip's application notes). Two such tables is what the perl thing produces, and the main code simply includes that tune file. (If you're interested in the code but can't figure it out, let me know.)
In practice I ran into some minor problems straight away. One was that the piezo sounded weak and, well, awful. No surprise with square waves, but I haven't graduated to designing sine wave generating circuits yet. My electronics knowledge is quite limited, so I decided to stick to what I have, but with a twist: the piezo can be made louder by giving it more voltage. The pic only produces TTL output (5V) and up to 20mA per pin. So I read up on inductors and cooked up a horrible boost stage that raises that to 38V peak-to-peak, which means reasonable volume. The booster also incidentally adds a lot of harmonics to the waveform, and together with a dinky 10pF cap it actually improving the sound a bit. The coil came from a dead compact fluoro that I dismantled and I have no idea what value it is (haven't built me an inductance meter yet).
You can see the resulting waveform on the oscilloscope in this photo:
Of course I can't drive that horror directly from the pic, so there's a garden-variety transistor doing the switching...and a fat diode to protect the battery and the pic. The diode is a 1N4004 -- now, after I had used a signal diode earlier which blew within only half an hour. Somehow it truly didn't like the 38V...
Today I quickly learned to use gschem to produce this circuit diagram.
Building the thing was fun: first I set it up on solderless breadboard, playing around with coil and cap and transistor setups (things like whether I should put the load on the emitter side or on the collector side etc.) until I was happy. Then I plopped the components onto a bit of prototyping board, making up the positioning on the go (I haven't learned PCB well enough yet to use it efficiently). As usually I made things fitting very precisely and closely spaced. Like this.
Way too closely spaced. When it came to mounting the thing, I realised that having the reset button on the board itself is useless; I also realised that I needed a better connector for the battery. As to juice, for that I gutted two old mobile phone Li-Ions: ripped out the protective circuitry and soldered in connecting leads. (One should be Very Careful doing this to Li-Ions, they don't take well to abuse and can go boom if shorted.) The Li-Ions still easily hold enough charge for this purpose, as the pic needs only 100nA during sleep (and about 30mA while squealing). The corresponding phones are long dead, so I change the batteries with my trusty Swallow Advance. Works very well.
The physical installation was fun: I cut a tiny hole in the wall, beneath one of the boards of the shelf/rack thing around the main door, drilled an angled hole through the doorframe, fished for the wires a bit and that's it. The button I also made from scratch: the switch is from a gutted mouse, the rubber dome came from a gutted keyboard and the plastic ring/frame from some electrical leftovers. Add glue, a bit of foam, solder and wire, done. The enclosure box is the only thing besides the pic and the piezo that I bought new. This is how it looks:
This is how it sounds: horrible! Well, actually it sounds a tiny little bit better in reality, but I couldn't be bothered to set up a good microphone to record it.
Overall, a fun project. The next one focused more on the coding side of things and had less active components: I built a persistence-of-vision toy for Cornelia, but that's to be documented another time.