3 #include <avr/interrupt.h>
6 #ifdef __AVR_ATmega32U4__
9 #define BUZZER_DDR DDRD
10 #define BUZZER (1 << PORTD7)
12 #define TIMER4_CLK_8 0x4 // 2 MHz
14 #define ENABLE_TIMER_INTERRUPT() TIMSK4 = (1 << TOIE4)
15 #define DISABLE_TIMER_INTERRUPT() TIMSK4 = 0
20 #define BUZZER_DDR DDRD
21 #define BUZZER (1 << PORTD3)
23 #define TIMER2_CLK_32 0x3 // 500 kHz
25 static const unsigned int cs2_divider[] = {0, 1, 8, 32, 64, 128, 256, 1024};
27 #define ENABLE_TIMER_INTERRUPT() TIMSK2 = (1 << TOIE2)
28 #define DISABLE_TIMER_INTERRUPT() TIMSK2 = 0
32 unsigned char buzzerInitialized = 0;
33 volatile unsigned char buzzerFinished = 1;
34 const char *
volatile buzzerSequence = 0;
38 static volatile unsigned int buzzerTimeout = 0;
41 extern volatile unsigned char buzzerFinished;
42 extern const char *
volatile buzzerSequence;
45 static volatile unsigned char use_program_space;
49 static volatile unsigned char octave = 4;
50 static volatile unsigned int whole_note_duration = 2000;
51 static volatile unsigned int note_type = 4;
52 static volatile unsigned int duration = 500;
53 static volatile unsigned int volume = 15;
54 static volatile unsigned char staccato = 0;
57 static volatile unsigned char staccato_rest_duration;
60 static void nextNote();
62 #ifdef __AVR_ATmega32U4__
67 if (buzzerTimeout-- == 0)
69 DISABLE_TIMER_INTERRUPT();
71 TCCR4B = (TCCR4B & 0xF0) | TIMER4_CLK_8;
72 unsigned int top = (F_CPU/16) / 1000;
88 if (buzzerTimeout-- == 0)
90 DISABLE_TIMER_INTERRUPT();
92 TCCR2B = (TCCR2B & 0xF8) | TIMER2_CLK_32;
93 OCR2A = (F_CPU/64) / 1000;
104 inline void PololuBuzzer::init()
106 if (!buzzerInitialized)
108 buzzerInitialized = 1;
114 void PololuBuzzer::init2()
116 DISABLE_TIMER_INTERRUPT();
118 #ifdef __AVR_ATmega32U4__
153 unsigned int top = (F_CPU/16) / 1000;
182 OCR2A = (F_CPU/64) / 1000;
186 BUZZER_DDR |= BUZZER;
200 unsigned char volume)
205 unsigned int timeout;
206 unsigned char multiplier = 1;
214 unsigned char min = 40 * multiplier;
217 if (multiplier == 1 && freq > 10000)
220 #ifdef __AVR_ATmega32U4__
222 unsigned char dividerExponent = 0;
225 top = (
unsigned int)(((F_CPU/2 * multiplier) + (freq >> 1))/ freq);
230 top = (
unsigned int)((((F_CPU/2 >> (dividerExponent)) * multiplier) + (freq >> 1))/ freq);
234 unsigned char newCS2 = 2;
235 unsigned int divider = cs2_divider[newCS2];
238 top = (
unsigned int)(((F_CPU/16 * multiplier) + (freq >> 1))/ freq);
242 divider = cs2_divider[++newCS2];
243 top = (
unsigned int)(((F_CPU/2/divider * multiplier) + (freq >> 1))/ freq);
248 if (multiplier == 10)
249 freq = (freq + 5) / 10;
254 timeout = (
unsigned int)((
long)dur * freq / 1000);
259 DISABLE_TIMER_INTERRUPT();
261 #ifdef __AVR_ATmega32U4__
262 TCCR4B = (TCCR4B & 0xF0) | (dividerExponent + 1);
265 unsigned int width = top >> (16 - volume);
268 buzzerTimeout = timeout;
272 TCCR2B = (TCCR2B & 0xF8) | newCS2;
274 OCR2B = top >> (16 - volume);
275 buzzerTimeout = timeout;
280 ENABLE_TIMER_INTERRUPT();
295 unsigned char volume)
322 unsigned int freq = 0;
323 unsigned char offset_note = note - 16;
334 else if (offset_note > 95)
337 unsigned char exponent = offset_note / 12;
341 switch (offset_note - exponent * 12)
383 freq = freq << exponent;
385 freq = (freq + 5) / 10;
390 freq = (freq * 64 + 2) / 5;
402 return !buzzerFinished || buzzerSequence != 0;
465 DISABLE_TIMER_INTERRUPT();
466 buzzerSequence = notes;
467 use_program_space = 0;
468 staccato_rest_duration = 0;
474 DISABLE_TIMER_INTERRUPT();
475 buzzerSequence = notes_p;
476 use_program_space = 1;
477 staccato_rest_duration = 0;
485 DISABLE_TIMER_INTERRUPT();
487 #ifdef __AVR_ATmega32U4__
488 TCCR4B = (TCCR4B & 0xF0) | TIMER4_CLK_8;
489 unsigned int top = (F_CPU/16) / 1000;
495 TCCR2B = (TCCR2B & 0xF8) | TIMER2_CLK_32;
496 OCR2A = (F_CPU/64) / 1000;
506 static char currentCharacter()
511 if(use_program_space)
512 c = pgm_read_byte(buzzerSequence);
516 if(c >=
'A' && c <=
'Z')
518 }
while(c ==
' ' && (buzzerSequence ++));
526 static unsigned int getNumber()
528 unsigned int arg = 0;
531 char c = currentCharacter();
532 while(c >=
'0' && c <=
'9')
537 c = currentCharacter();
543 static void nextNote()
545 unsigned char note = 0;
546 unsigned char rest = 0;
547 unsigned char tmp_octave = octave;
548 unsigned int tmp_duration;
549 unsigned int dot_add;
554 if(staccato && staccato_rest_duration)
557 staccato_rest_duration = 0;
564 c = currentCharacter();
573 goto parse_character;
577 goto parse_character;
601 note_type = getNumber();
602 duration = whole_note_duration/note_type;
603 goto parse_character;
606 if(currentCharacter() ==
'l')
611 staccato_rest_duration = 0;
614 goto parse_character;
617 octave = tmp_octave = getNumber();
618 goto parse_character;
625 whole_note_duration = 60*400/getNumber()*10;
626 duration = whole_note_duration/note_type;
627 goto parse_character;
630 volume = getNumber();
631 goto parse_character;
635 whole_note_duration = 2000;
642 tmp_duration = duration;
643 goto parse_character;
649 note += tmp_octave*12;
652 c = currentCharacter();
653 while(c ==
'+' || c ==
'#')
657 c = currentCharacter();
663 c = currentCharacter();
667 tmp_duration = duration;
670 if(c >
'0' && c <
'9')
671 tmp_duration = whole_note_duration/getNumber();
675 dot_add = tmp_duration/2;
676 while(currentCharacter() ==
'.')
679 tmp_duration += dot_add;
685 staccato_rest_duration = tmp_duration / 2;
686 tmp_duration -= staccato_rest_duration;
710 play_mode_setting = mode;
727 if(buzzerFinished && buzzerSequence != 0)
729 return buzzerSequence != 0;