Creating a stand-up countdown buzzer – Pt 2
In part 1 of the article I started out with an idea to make a stand-up countdown buzzer. For this I configured the board, created a Pin class and was able to turn the leds on/off. Here we continue with the remaining functionality and how this is combined into an application.
Connecting the buzzer to a GPIO pin (and another connected to GND) I can create a block wave (toggle the pin on/off) which makes the buzzer beep. Only, it will do so right after starting up the application. In order to allow a person some ‘speaking time’ I need to wait a while before making the buzzer beep. The ST HAL provides a ‘delay’ function, which can be used to ‘wait/stop’ application process for a given amount of milliseconds. Since I can reset the application with a reset button on the board, this will be enough to create delays, for instance to wait 2 minutes before starting with beeps. Once the delay is done I can re-use it for other things, which makes it a handy function. Note: blocking calls prevent the microcontroller from doing ‘other’ work, meaning it is killing for performance and power. Since we use a simple application this is acceptable here.
With the delay I can wait 2 minutes, then use the GPIO pin to make the buzzer beep, this works -kinda-, but I cannot control the frequency easily. Right now I use a small ‘for’ loop, with delays to create the waveform. Fiddling with the delays controls the actual waveform and together they dictate the total length of a single iteration: the frequency. Using PWM (pulse width modulation) this toggling of the pin can be handed over to the microcontroller. This only needs to be setup, then a start and stop command is enough to create the waveform and make the buzzer beep. Doing so will make it a lot easier to create application logic, as I do not need to add those delays and blocking beep loops to make sound. I checked if the microcontroller has support for PWM by looking in the big datasheet. I find it in the (general purpose) timer block, which makes sense as a timer is used to ‘drive’ the PWM pulses: the frequency, on/off time of a pulse.
A timer in a microcontroller is a counter in hardware, which at a given set of conditions (like count N ticks) triggers an event or interrupt. In my case it is used to handle the pulse width of the on/off time and the frequency (or period) of the pulse. I started to look for an example, and found one here, here and here. I noticed one of these has some formulas which I can use to calculate the duty cycle (or ‘on’ time of a pulse) and the frequency of the waveform. This allows a much more convenient way to configure the PWM signal. I made a PWM class and tested this using a logic analyser connected on the output pin. Once I was sure there was a waveform I connected the buzzer and tweaked some settings for the right beep – I wanted this to be loud, and annoying.
With a means to capture a button press as event, turn the leds on/off, wait for various time intervals and a way to sound a buzzer, the building blocks of the application are done, next up: the main logic.
The application runs in 1 big main loop. First it passes an initialization phase in which I configure the HAL, the clock, the pins (leds, button) and the PWM block. Then I create a second loop in which the basic application is running. This loop checks for a flag being set once the user presses a button, after which it executes once. The logic here will do an entire sequence of waiting, starting to beep, then a single loud beep. After this it resets and waits for another button press. The beep logic is the actual application: turn on a led to signal the wait time has started, wait for 2 minutes, then sound a few beeps as warning and a long beep to signal the end. The leds are used to show the application is busy doing something: the waiting, the warning beeps and being idle. By assigning a colour to each such state it makes it visible to the user what is going on.