Table of Contents

 

Sound generator

Required knowledge: [HW]Kasutajaliidese moodul, [AVR]Loendurid/Taimerid,
[AVR]Digitaal-analoogmuundur, [LIB]Heligeneraator

Theory

Piezo sounder
Speaker

One practical use of timers is driving a sounder or a speaker. Sounders are often used in control panels, alarm devices, and elsewhere to make button presses or signal tones audible. Such a sounder is often simply called a speaker, a beeper, or a buzzer. By operating principle, sounders can be divided into piezoelectric and electromagnetic.

A piezoelectric sounder consists of a metal plate with a piezoceramic element attached. The piezoceramic element changes its dimensions according to the applied voltage, causing the metal plate to bend. Applying a square wave or AC signal produces vibration and thus sound.

An electromagnetic sounder is similar in principle to a loudspeaker. A coil is placed in a magnetic field with a metal diaphragm above it. When audio-frequency current flows through the coil, the diaphragm moves due to the magnetic fields of the coil and permanent magnet. Like the piezoelectric sounder, this produces sound.

In general, piezoelectric sounders have higher sound pressure, lower current consumption, and higher possible frequencies compared to electromagnetic ones. The loudest sound with the smallest current occurs when the sounder operates at its resonance frequency, where diaphragm amplitude is highest. The electromagnetic sounder (speaker) has better tonal quality and is suitable not only for simple signal tones but also for music and speech.

To drive speakers, a digital output is usually not enough; you need an analog signal. The easiest way is to use a digital-to-analog converter (DAC). A DAC works opposite to an ADC and allows a microcontroller to generate an analog output. Cheaper and simpler microcontrollers (including ATmega128 and ATmega2560) do not have an integrated DAC. In that case you can use an external chip or generate an analog signal using an RC filter and amplification circuitry. This requires additional components and therefore makes using a speaker with a microcontroller more complex compared to other digital components (switches, LEDs, sensors, etc.).

 

Practice

The HomeLab II User Interface module includes a piezo sounder with an amplifier circuit. The sounder is driven by pin PG5. To use the sounder, the HomeLab library provides the function buzzer_sound, which generates a sound signal with a chosen length and frequency. Frequency is specified in relative units 1-255 and duration in milliseconds.

// Generate a sound signal with selected frequency and length
void buzzer_sound (unsigned char freq, unsigned int length)
{
	// Select the sounder pin
	pin buzzer = PIN(G,5);
 
	// Configure the sounder pin as output
	pin_setup_output(buzzer);
 
	// Timer 0 fast PWM mode with OCR0A and COM0B1 output
	TCCR0A |= (1 << COM0B1);
	TCCR0A |= ((1 << WGM01)|(1 << WGM00));
	TCCR0B |= (1 << WGM02);
	OCR0A = freq;
	// Start Timer 0 with prescaler 1024
	TCCR0B |= ((1 << CS02)|(1 << CS00));
 
	// Sound length
	sw_delay_ms(length);
 
	// Stop timer and sound generation
	timer0_stop();
}

The HomeLab III User Interface module includes a speaker with a simple amplifier connected to controller DAC1 channel 1.

To use the speaker, the HomeLab library function buzzer_sound generates a sound signal with selected length and frequency. Frequency is specified in hertz and duration in milliseconds. In addition, buzzer_volume can be used to change volume in the range 0-4095, implemented by DAC amplitude.

With an Xmega controller, a software PWM signal is generated to drive the DAC module output between 0 V and the voltage level specified by buzzer_volume.

// Timer E0 overflow interrupt
ISR(TCE0_OVF_vect)
{
	static uint8_t CH1_Output = 0;
 
	if( CH1_Output == 1)
	{
		// Set output voltage according to volume = 1
		DAC_Channel_Write( &DACB, volume, CH1);
		CH1_Output = 0;
	}
 
	else
	{
		// Set output voltage to 0 V
		DAC_Channel_Write( &DACB, 0, CH1);
		CH1_Output = 1;
	}
}
 
// Generate sound with frequency freq (8 Hz - 500 kHz) and length length (ms)
// if length = 0, sound is generated continuously
void buzzer_sound (uint16_t freq, unsigned int length)
{
	// DAC setup
	// AVCC as DAC reference
	DACB.CTRLC = ( DACB.CTRLC & ~DAC_REFSEL_gm) | DAC_REFSEL_AVCC_gc;
	// Select channel
	DACB.CTRLB = ( DACB.CTRLB & ~DAC_CHSEL_gm ) | DAC_CHSEL_DUAL_gc;
	// Enable channel 1 and DACB module
	DACB.CTRLA = DAC_CH1EN_bm | DAC_ENABLE_bm;
 
	// Timer E0 setup
	// Enable overflow interrupt with medium priority
	TCE0.INTCTRLA = ( TCE0.INTCTRLA & ~TC0_OVFINTLVL_gm ) | TC_OVFINTLVL_MED_gc;
	// Set Timer E0 frequency to 32 MHz/64 = 500 kHz
	TCE0.CTRLA = ( TCE0.CTRLA & ~TC0_CLKSEL_gm ) | TC_CLKSEL_DIV64_gc;
	// Enable medium-level interrupts
	PMIC.CTRL |= PMIC_MEDLVLEN_bm;
	sei();
 
	// Set timer frequency
	TCE0.PER = (uint32_t)250000/freq;
 
	// Check if timer should be stopped, and wait if needed
	if(length)
	{
		sw_delay_ms(length);
		TCE0.CTRLA = ( TCE0.CTRLA & ~TC0_CLKSEL_gm ) | TC_CLKSEL_OFF_gc;
	}
}

The next example illustrates use of the sounder library. It generates a 500 millisecond beep.

// HomeLab sounder usage example program
// Generate a 500 ms beep
#include <homelab/module/buzzer.h>
 
// Main program 
int main (void)
{
	// Set HomeLab III volume
	buzzer_volume(1000);
 
	// Generate 1 kHz tone for 0.5 s
	buzzer_sound(1000,500);
}