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.

Basic Electronics » Shuttering with the Nerdkit & piezo buzzer (Can't post in Support, gives error)

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));

    TCCR0B &= 0;
    TCCR1B &= 0;

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


    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


    PORTC ^= (1 << PC5); // Toggle the buzzer
    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.


January 29, 2014
by BobaMosfet
BobaMosfet's Avatar


Don't use delay_ms().


January 30, 2014
by Ralphxyz
Ralphxyz's Avatar

BobaMosfet, where did you see that delay_ms() was used?

I assume "Stuttering" is meant instead of "shuttering".


January 30, 2014
by Noter
Noter's Avatar

Find it in the play_tone( ) function. I don't think it is related to the problem. Likely the timer is overrunning the OCRxA value when OCRxA is updated to a value smaller then the current TCNTx. I put that suggestion in one of the other threads (3 of them) lailai started on this topic.

January 30, 2014
by BobaMosfet
BobaMosfet's Avatar


Line 38.

I mention it because it could be part of the problem-- anything that affects interrupts can be. Noter's point is also correct. Furthermore, he's enabling and disabling clock which can also cause problems because (per the Datasheet), this can cause a random number of cycles for the chip to sort out and change state.

I would do this differently, with a single interrupt.


Post a Reply

Please log in to post a reply.

Did you know that you can connect to certain car computers via the OBD-II port with a microcontroller? Learn more...