0

I have old speaker which I want to use to play sound. I chose to use PWM mode on ATMega328 (which is in turn on Arduino Uno R3 board) in order to do it.

For signal on the speaker I chose rectangular wave because it does not require any additional setup. To generate this signal I chose timer1 because it is easy to change PWM frequency just by changing ICR1 value. For duty cycle I chose 50%. So my program looks as follows:

#define     CLK_FREQ 16000000   //clock frequency on ATMega328
#define     PRSCLR   1024       //chosen prescaler of timer1

//duration of one note
unsigned int halfDur = 200;
//number of notes in the melody
const int notesSize = 32;
//frequencies of notes in the melody:
unsigned int notes[notesSize] = { 220, 277, 329, 277, 220, 277, 329, 277, 
                                  207, 277, 329, 277, 207, 277, 329, 277,
                                  184, 277, 369, 277, 184, 277, 369, 277,
                                  220, 293, 369, 293, 220, 293, 369, 293 };
//method to play one note
void PlayFreq( unsigned int freq );


void setup()
{
    //PB1 pin in OUTPUT mode
    DDRB |= ( 1 << DDB1 );

    TCCR1A = 0b0;
    //non-inverting mode of PWM
    TCCR1A |= ( 1 << COM1A1 ) | ( 1 << COM1B1 );
    //Fast mode PWM with ICR1 as TOP:
    TCCR1A |= ( 1 << WGM11 );
    TCCR1B = 0b0;
    TCCR1B |= ( 1 << WGM12 ) | ( 1 << WGM13 );
    //prescaler = 1024
    TCCR1B |= ( 1 << CS12 ) | ( 1 << CS10 );
}


void loop()
{
    for ( int i = 0; i < notesSize; i++ )
    {
        PlayFreq( notes[i] );
        delay( halfDur );
    }
}


void PlayFreq( unsigned int freq )
{
    //claclulate TOP according to note frequency
    ICR1 = CLK_FREQ / PRSCLR / freq - 1;
    //50% duty cycle
    OCR1A = ICR1 / 2;
}

Problem is only several first notes are playing and then there is no sound, then again I hear some notes then there is no sound and so on. It seems that tempo is OK. It just skips some notes. What it could be?

  • Why not use the built-in tone() function? – Majenko Apr 9 '18 at 17:24
  • @Majenko, I will try it now. Thx. – LRDPRDX Apr 9 '18 at 17:28
  • Yes, it works perfectly. But what's wrong with my code? – LRDPRDX Apr 9 '18 at 17:41
  • Just a couple of remarks, unrelated to your problem: 1. There is a macro named F_CPU which is already defined and holds the clock frequency. No need to define CLK_FREQ yourself. 2. You would get a better frequency resolution by setting the prescaler to 64. Actually, if your frequencies are always higher than 31 Hz, you could even set the prescaler to 8. – Edgar Bonet Apr 9 '18 at 17:44
  • @EdgarBonet, Thank you for your remarks. Useful. – LRDPRDX Apr 9 '18 at 18:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.