#include <LiquidCrystal.h>
#include <math.h>
// lcd(RS, E, D4, D5, D6, D7) pin configuration for the LCD screen
const int rs = 2, en = 3, d4 = 4, d5 = 5, d6 = 6, d7 = 7;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7); // Initialise the LCD
const int sensorPin = A0; // Analogue pin connected to the potentiometer to control tempo.
const int timeSigPin = A1; // Analogue pin connected to another potentiometer to control time signature.
const int led1 = 12; // Pin for the first LED.
const int led2 = 11; // Pin for the second LED.
const int led3 = 10; // Pin for the third LED.
const int led4 = 9; // Pin for the fourth LED.
const int buzzer = 8; // Pin for the buzzer to give sound feedback on each beat.
const int power = 1; // Pin for the slide switch to control the metronome power.
int sensorValue; // Variable to store potentiometer reading for tempo.
int timeSigValue; // Variable to store potentiometer reading for time signature.
int bpm; // Variable to store the calculated BPM (beats per minute).
double interval; // Time interval (in ms) between each LED flash.
int counter = 0; // Counter to track which LED should be turned on.
int timeSignature = 4; // Default time signature (e.g., 4/4), can be changed by potentiometer.
int beepLength = 80; // Duration of the buzzer beep.
void setup() {
pinMode(led1, OUTPUT); // Set the first LED as output.
pinMode(led2, OUTPUT); // Set the second LED as output.
pinMode(led3, OUTPUT); // Set the third LED as output.
pinMode(led4, OUTPUT); // Set the fourth LED as output.
lcd.begin(16, 2); // Initialise the LCD with 16 columns and 2 rows.
Serial.begin(9600); // Start the serial communication at 9600 baud rate.
}
void loop() {
if (digitalRead(power) == HIGH) { // Check if the power switch is on.
lcd.setCursor(0, 0); // Move the cursor to the first position of the first row on the LCD.
lcd.print("Tempo:"); // Print "Tempo:" on the LCD to label the BPM display.
sensorValue = analogRead(sensorPin); // Read the potentiometer value for tempo.
timeSigValue = analogRead(timeSigPin); // Read the potentiometer value for time signature.
bpm = map(sensorValue, 0, 1023, 40, 220); // Map the potentiometer value to a BPM range of 40 to 220.
timeSignature = map(timeSigValue, 0, 1023, 2, 4); // Map the potentiometer value to a time signature range of 2/4 to 4/4.
interval = 60000 / bpm; // Calculate the time interval between beats in milliseconds (60000 ms per minute).
lcd.setCursor(7, 0); // Move the cursor to display the BPM value.
lcd.print(String(bpm)); // Display the current BPM on the LCD screen.
lcd.setCursor(13, 0); // Move the cursor to display the time signature.
lcd.print(String(timeSignature) + "/4"); // Display the current time signature on the LCD screen.
// Display beat indicators on the second row of the LCD based on BPM thresholds.
if (bpm >= 40) { lcd.setCursor(0, 1); lcd.write(255); }
if (bpm >= 60) { lcd.setCursor(1, 1); lcd.write(255); }
if (bpm >= 80) { lcd.setCursor(2, 1); lcd.write(255); }
if (bpm >= 100) { lcd.setCursor(3, 1); lcd.write(255); }
if (bpm >= 120) { lcd.setCursor(4, 1); lcd.write(255); }
if (bpm >= 140) { lcd.setCursor(5, 1); lcd.write(255); }
if (bpm >= 160) { lcd.setCursor(6, 1); lcd.write(255); }
if (bpm >= 180) { lcd.setCursor(7, 1); lcd.write(255); }
if (bpm >= 200) { lcd.setCursor(8, 1); lcd.write(255); }
if (bpm == 220) { lcd.setCursor(9, 1); lcd.write(255); }
counter += 1; // Increment the counter to track the current beat.
// Use the counter value to determine which LED should be turned on/off.
switch(counter) {
case 1:
tone(buzzer, 10000); // Generate a high-pitched beep for the first beat.
digitalWrite(led1, HIGH); // Turn on the first LED for the first beat.
delay(beepLength); // Wait for the beep duration.
noTone(buzzer); // Stop the beep.
delay(interval - beepLength); // Wait for the remainder of the interval.
digitalWrite(led1, LOW); // Turn off the first LED.
break;
case 2:
if (timeSignature >= 2) { // Flash the second LED if the time signature has at least 2 beats.
tone(buzzer, 5000); // Generate a lower-pitched beep for the second beat.
digitalWrite(led2, HIGH); // Turn on the second LED for the second beat.
delay(beepLength);
noTone(buzzer);
delay(interval - beepLength); // Wait for the remainder of the interval.
digitalWrite(led2, LOW); // Turn off the second LED.
}
break;
case 3:
if (timeSignature >= 3) { // Flash the third LED if the time signature has at least 3 beats.
tone(buzzer, 5000);
digitalWrite(led3, HIGH); // Turn on the third LED for the third beat.
delay(beepLength);
noTone(buzzer);
delay(interval - beepLength); // Wait for the remainder of the interval.
digitalWrite(led3, LOW); // Turn off the third LED.
}
break;
case 4:
if (timeSignature == 4) { // Flash the fourth LED if the time signature is 4/4.
tone(buzzer, 5000);
digitalWrite(led4, HIGH); // Turn on the fourth LED for the fourth beat.
delay(beepLength);
noTone(buzzer);
delay(interval - beepLength); // Wait for the remainder of the interval.
digitalWrite(led4, LOW); // Turn off the fourth LED.
}
break;
}
// Reset the counter based on the time signature to start a new measure.
if (counter >= timeSignature) {
counter = 0; // Reset counter when reaching the end of the measure.
}
lcd.clear(); // Clear the LCD screen for the next loop.
} else {
counter = 0; // Reset counter if the metronome is powered off.
}
}