Do you like my hacking? If so, please consider leaving something in the
Fediverse (Mastodon etc): @Sprite_tm@social. spritesmods.com
Offcourse, a terror-level indicator isn't worth it's salt if it doesn't have a nice sound to go along with the panicked screaming of the people who see the terror-level raise a notch. The toilet terror indicator is no exception. It doesn't seem to have the hardware to do more than a blocky square-wave 'beep', which just doesn't have the cheerful quality we need when we want to indicate the end of the world. So how do we generate that? We have two problems: the first is the generation of the samples for the sound and the second one is getting the analog samples out of the digital pins the microcontroller is connected to.
First of all, how are we going to generate the samples for the the sound we want to have? 2 KB of Flash memory isn't enough to store the samples of a decent `Ping!'. We therefore need to resort to a few tricks to get the required output. If you open a wave file of a `Ping!' sound with a wave editor (in this case: Audacity) and look at its spectrum, you'd see that a major part of the sound is made by two frequencies: 771 Hz and 3136 Hz. It comes in very useful that the higher frequency is about four times the lower one. The sound itself gradually declines in amplitude over time. Using this information we can write a compact program that calculates a sound very similar to the original, analogue ping: The AVR program generates 32 samples for the two sine waves and it outputs these from within a loop. An additional routine uses some clever shift instructions to re-duce the amplitude of the signal in 16 steps in half a second. The resulting output produced by this code is quite pleasing to the ear.
Now, how to get these analog sample-values to the digitally-connected speaker? We can compensate for the lack of a D/A converter via the use of the PWM hardware that resides inside the UC. The PWM frequency is set for several hundred kilohertz; the membrane of the loudspeaker can't move that fast and will therefore take the average of the PWM value. In this way we've implemented a componentless D/A converter.
The rest of the firmware doesn't really do much. The main part consists of a counter that increments once every two seconds when the light is on, or which is decremented every four seconds when the light is off. The times at which the terror level changes from one level to the next are stored as constants in the source code. This makes it very easy to change the behaviour of the circuit to your own preferences. The firmware is GPL-licensed and is downloadable here.