Once you have successfully uploaded blink.ino it is not a huge step to convert it into a metronome using a simple buzzer. It might be sufficient to keep your band in time but I hate the sound of buzzers. That is why I preferred real speakers and synthesize the sound which is not too complicated.
At the end it is nothing but a damped vibration. Some properties in my project can be configured: the speed (bpm), the pitch, the decay.The speed is controlled by a potentiometer. You can write marks on the knob to indicate the bpm values. There is an additional output pin where you get the bpm pulses to calibrate the instrument.
/*
Metronome
*/
const byte speakerPin = 10; /* PWM pin OC1B */
const byte syncPin = 2;
const word sampleRate = 16000;
const int L = 360;
float sinTab[L];
/*
c determines the pitch
(how many values in the sine table
will be skipped)
*/
byte c = 20;
long dt1 = 25; /* for decrease in volume */
long dt2 = 1000; /* for bpm */
/* steps when volume decreases */
long t1 = millis() + dt1; /* for decay */
/* time to start the next sound */
long t2 = millis() + 1000; /* for bpm */
float decay = 2.5;
float amp = 127;
int bpm = 60; /* range: 60 - 160 */
void setup() {
Serial.begin(9600);
Serial.println(__FILE__);
for (int i = 0; i < L; i++)
sinTab[i] = sin(TWO_PI * i / L);
pinMode(speakerPin, OUTPUT);
pinMode(syncPin, OUTPUT);
setupTimer1();
setupTimer2();
}
void loop() {
long v = analogRead(A0);
bpm = 60 + 100 * v / 1024;
dt2 = 60000 / bpm;
if (millis() < t1) return;
t1 = t1 + dt1;
amp = amp * decay / (decay + 1);
if (millis() > t2) {
/* new metronome hit */
t2 = t2 + dt2;
amp = 127;
digitalWrite(syncPin, HIGH);
}
else digitalWrite(syncPin, LOW);
}
void setupTimer1() {
/*
Timer1 produces the sound
COM1B1 = 1
Clear OC1B on Compare Match
*/
TCCR1A = B00100001;
TCCR1B = 1;
}
void setupTimer2() {
/*
The Timer2-ISR determines
the PWM-value of Timer1
*/
TCCR2A = 2; /* CTC mode */
TCCR2B = 2; /* prescaler: 8 (do not use 1!!!) */
byte PS = 8;
OCR2A = F_CPU / PS / sampleRate - 1; /* --> 32 kHz */
TIMSK2 = 2; /* Output Compare A Match Interrupt Enable */
}
volatile int i;
ISR(TIMER2_COMPA_vect) {
byte b = 0x80 + amp * sinTab[i];
OCR1B = b;
i = i + c;;
if (i > L) i = i - L;
}
Comments
Please log in or sign up to comment.