If you need a way to make some noise, the buzzer is one of the simplest ways. In this article we will use a timer to ‘semi asynchronously’ play sound.
In the ATMega328p (Arduino Uno and Nano) there are 3 timers, Timer 0 and 2 are both 8bit and Timer 1 is 16bit, it does not make sense to waste the higher precison timer in such a simple task, and Timer 0 is usually used to keep track of timer, so we will use Timer 2.
Note: Timer 2’s OCRA port uses the same pin as SPI’s MOSI (D11), so if you want to use both SPI and Timer 2’s pwm output, you need to use OCRB (D3).
To follow this article you only need two things, an Arduino Uno (buy here) or Nano (buy here) and a buzzer (buy here).
1 - Code
The first thing we need is to create an ‘init’ function. In this function we set Timer 2’s OCRB pin to output (D3). Then we need to set a duty cycle, you can test various values to see which one sounds better.
One important step is to set the timer mode to Fast PWM, we do that by setting bits WGM21 and WGM20 in the register TCCR2A and, lastly, we need to set a prescaler, 128 sounded nice to me so thats what i used, bits CS22 and CS20 in register TCCR2B):
void buzzer_init()
{
// Set D3 as output
DDRD |= (1 << PD3);
// Duty cycle 0x00 - 0xFF, changes the tone
OCR2B = 0x64;
// Mode 3, fast PWM
TCCR2A |= (1 << WGM21) | (1 << WGM20);
// Prescaler, also changes the tone, set to 128
TCCR2B |= (1 << CS22) | (1 << CS20);
}
For the buzzer to start making noise, you need to set the bit ‘COM2B1’ in register TCCR2A:
void buzzer_play()
{
// Enable timer output, plays sound
TCCR2A |= (1 << COM2B1);
}
To stop the buzzer, you need to clear the bit ‘COM2B1’, that returns the pin to ‘normal port operation’ and then, just to be sure it isn’t being left high, we set D3 to low:
void buzzer_stop()
{
// Disable timer output, stops sound
TCCR2A &= ~(1 << COM2B1);
// Set D3 to low, as continuous current can damage the buzzer
PORTD &= ~(1 << PD3);
}
Finally, on main, init the buzzer and, in a loop, play the sound for 100 milliseconds and wait 900 milliseconds:
int main()
{
buzzer_init();
while (1)
{
buzzer_play();
_delay_ms(100);
buzzer_stop();
_delay_ms(900);
}
return 0;
}
And that’s it. Thanks for reading and stay tuned for more tech insights and tutorials. Until next time, and keep exploring the world of tech!