NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Support Forum » Shuttering when playing sound (piezo buzzer) using interrupts with the Nerdkit

January 28, 2014
by lailai
lailai's Avatar

Hi all,

I'm attempting to play sound (with the piezo buzzer) using the nerdkit. I wanted to play more than one tone at a time, so I used two timers set to interrupt. Each timer manages one pin, both pins are then hooked to a resistor and finally the piezo buzzer.

It works quite well, however there are shuttering present. It always shutters at the same time. The shuttering still happens without LCD updates, but at different times. If I change a little bit, the times when shuttering happens changes again.

Here is my code (with some parts like defining notes to frequencies stripped out):

#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include <avr/pgmspace.h>

#define F_CPU 14745600
#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"

#define DUR 25

#define A5 568
#define B5 506

#define S(s) lcd_write_string(PSTR(s));

void setup_timers (void) {
   sei(); //  Enable global interrupts
   TCCR0A |= (1 << WGM01); // Configure timer 0 for CTC mode
   TIMSK0 |= (1 << OCIE0A); // Enable CTC interrupt
   TCCR0B &= 0; // disable clock

   TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode
   TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt
   TCCR1B &= 0; // disable clock
}

void play_tone(uint16_t delay, uint16_t delay2, uint16_t duration) {
    if(delay != 0){
        OCR0A = delay / 4.31;
        TCCR0B |= ((1 << CS01) | (1 << CS00));
    }
    if(delay2 != 0){
        OCR1A = delay2 / 4.31;
        TCCR1B |= ((1 << CS11) | (1 << CS10) | (1 << WGM12));
    }

    delay_ms(duration*10);
    TCCR0B &= 0;
    TCCR1B &= 0;
}

int main (void) {
    DDRC |= (1 << PC4); // Set Piezo1 as output
    DDRC |= (1 << PC5); // Set Piezo2 as output
    setup_timers();
    lcd_init();

    lcd_clear_and_home();

    S("This "); play_tone(G6, 0, DUR);
    S("was "); play_tone(F6, 0, DUR); 
    S("a "); play_tone(E6, 0, DUR);
    S("tri"); play_tone(E6, 0, DUR);

    S("umph."); play_tone(F6, A4, DUR);
    play_tone(0, D4, DUR); 
    play_tone(0, F4, DUR);
    play_tone(0, D4, DUR);

    play_tone(0, B4, DUR);
    play_tone(0, D4, DUR);
    play_tone(0, F4, DUR);
    play_tone(0, D4, DUR);

    play_tone(0, A4, DUR);
    play_tone(0, D4, DUR);
    play_tone(0, F4, DUR);
    lcd_line_two(); S("I'm "); play_tone(0, D4, DUR);

    S("mak"); play_tone(G6, B4, DUR);
    S("ing "); play_tone(F6, D4, DUR); 
    S("a "); play_tone(E6, F4, DUR); 
    S("note "); play_tone(E6, D4, DUR);

    lcd_line_three(); S("here, "); play_tone(E6, A4, DUR); 
    play_tone(F6, D4, DUR);
    play_tone(0, F4, DUR);
    play_tone(0, D4, DUR);

    S("HUGE "); play_tone(D6, B4, DUR); 
    play_tone(0, D4, DUR);
    S("SUC"); play_tone(E6, F4, DUR); 
    S("CESS. "); play_tone(A6, D4, DUR);

    // etc etc etc
    while(1){

    }
}

ISR(TIMER0_COMPA_vect) {
    PORTC ^= (1 << PC5); // Toggle the buzzer
}
ISR(TIMER1_COMPA_vect) {
    PORTC ^= (1 << PC4); // Toggle the buzzer
}

Can I fix the shuttering? (maybe 0.1 to 0.15 seconds) Or is it interrupt clashes like I suspect?

NOTE: It happens without any LCD updates.

Thanks!

January 28, 2014
by Noter
Noter's Avatar

Possibly you need to set new OCRxA values only when TCCRx < new OCRxA value to prevent overrun. Maybe apply new value in interrupt routine since next TCCRx = 0.

Post a Reply

Please log in to post a reply.

Did you know that an analog comparator can tell when one voltage input crosses another? Learn more...