Hackster is hosting Hackster Holidays, Finale: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Tuesday!Stream Hackster Holidays, Finale on Tuesday!
kzra
Published © MIT

LED Matrix Metronome

Combine Arduino, an 8*8 bicolour LED matrix and a piezo buzzer to make a cool visual metronome.

BeginnerFull instructions provided5,741
LED Matrix Metronome

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
Buzzer, Piezo
Buzzer, Piezo
×1
Rotary potentiometer (generic)
Rotary potentiometer (generic)
×1
Tactile Switch, Top Actuated
Tactile Switch, Top Actuated
×1
Adafruit Bicolor LED Square Pixel Matrix with I2C Backpack
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Schematics

Breadboard Layout for LED Matrix Metronome

For information about the wiring of the LED Matrix, see https://learn.adafruit.com/adafruit-led-backpack/0-8-8x8-matrix-arduino-wiring-and-setup

Image of Breadboard Layout

For information about the wiring of the LED Matrix, see https://learn.adafruit.com/adafruit-led-backpack/0-8-8x8-matrix-arduino-wiring-and-setup

Code

ledMatrixMetronome.ino

C/C++
Note: you will need to install the Adafruit LED Backpack library and the Adafruit GFX library to run this code. They can be installed directly from the Arduino IDE using the Arduino library manager. For detailed instructions see: https://learn.adafruit.com/adafruit-led-backpack/0-8-8x8-matrix-arduino-wiring-and-setup
#include <Wire.h>
#include <Adafruit_GFX.h>
#include "Adafruit_LEDBackpack.h"

// LED matrix object
Adafruit_BicolorMatrix matrix = Adafruit_BicolorMatrix();

// variables associated with to ptm switch
const int switchPin = 2;
int switchState = 0;

// variables associated with potentiometer + smoothing
const int numReadings = 10;
double potReadings[numReadings];
int readIndex = 0;
int potTotal = 0;
int potAverage = 0;

//variables associated with time keeping
int state = 0;
unsigned long previousTime = 0;
int interval;

// variables determining display pattern 
// 4/4
const int x0[] = {0,0,4,4,0,0,4,4,0,0,4,4,0,0,4,4};
const int y0[] = {0,4,4,0,0,4,4,0,0,4,4,0,0,4,4,0};
const int z0[] = {2,2,2,2,3,3,3,3,1,1,1,1,0,0,0,0};
const int w0[] = {4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4};
const int h0[] = {4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4};

// 3/4
const int x1[] = {2,0,4,2,0,4,2,0,4,2,0,4};
const int y1[] = {0,4,4,0,4,4,0,4,4,0,4,4};
const int z1[] = {2,2,2,3,3,3,1,1,1,0,0,0};
const int w1[] = {4,4,4,4,4,4,4,4,4,4,4,4};
const int h1[] = {4,4,4,4,4,4,4,4,4,4,4,4};

// 6/8
const int x2[] = {0,0,4,4,0,0,0,0,4,4,0,0};
const int y2[] = {4,0,4,0,4,0,4,0,4,0,4,0};
const int z2[] = {1,1,1,3,3,3,2,2,2,0,0,0};
const int w2[] = {4,8,4,4,8,4,4,8,4,4,8,4};
const int h2[] = {4,4,4,4,4,4,4,4,4,4,4,4};

// pointers to current display pattern 
const int *xp = x0;
const int *yp = y0;
const int *zp = z0;
const int *wp = w0;
const int *hp = h0;

// number of iterations of display pattern
int stateLimit = 16;

// default and number of display patterns 
int TimeSig = 0;
int TimeSigLimit = 3;

//variables associated with piezo 
const int piezoPin = 8;
int modulo = 4; // accent the first beat of the bar 


void setup() {
  Serial.begin(9600);
  Serial.println("8x8 LED Matrix Test");
  
  matrix.begin(0x70);  // pass in the address
  matrix.setRotation(3); // rotate so pins are at 0th row 
  
  pinMode(switchPin, INPUT);
  
  // initialise all pot readings to 0
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    potReadings[thisReading] = 0;
  } 
}


void loop() {
  
  //potentiometer smoothing 
  potTotal = potTotal - potReadings[readIndex]; //subtract the last reading 
  potReadings[readIndex] = analogRead(A0); 
  potTotal = potTotal + potReadings[readIndex]; //add current reading to total 
  readIndex = readIndex + 1; //advance to next position in array 
  // if we're at the end of the array...
  if (readIndex >= numReadings) {
    // ...wrap around to the beginning:
    readIndex = 0;
  }
  potAverage = sqrt(potTotal/numReadings) * 100; //take the square root to get a non linear tempo response, multiply by 100 to increase the sensitivity of map (which can only handle integers). 
  delay(1); // delay in between reads for stability 

  // map the pot average to an interval (bpm = 1000/interval * 60). 
  interval = map(potAverage,0,3200,1500,200); //bpm can be set between 45bpm (1500 ms interval) and 300bpm (200ms interval). Must be mapped in reverse to encode non linear tempo mapping. 
  Serial.println(interval);

  //check whether the button has been pressed to change time sig 
  switchState = digitalRead(switchPin);
  if(switchState == HIGH){
    // move to next time signature
    TimeSig += 1; 
    // if the time signature limit is reached go back to start 
    if (TimeSig == TimeSigLimit){
      TimeSig = 0;
    }
    // update the display pattern based on the time signature 
    switch(TimeSig){
    // 4/4
    case 0:
    xp = x0;
    yp = y0;
    zp = z0;
    wp = w0;
    hp = h0;
    stateLimit = 16;
    modulo = 4;
    break;
    // 3/4
    case 1:
    xp = x1;
    yp = y1;
    zp = z1;
    wp = w1;
    hp = h1;
    stateLimit = 12;
    modulo = 3;
    break;
    // 6/8
    case 2:
    xp = x2;
    yp = y2;
    zp = z2;
    wp = w2;
    hp = h2;
    stateLimit = 12;
    modulo = 6;
    break;
    }  
    // reset the state counter 
    state = 0;
    // clear the display
    matrix.clear();
    matrix.writeDisplay();
    // delay to allow button time to unpress
    delay(250);
  }

  // update matrix with new pattern 
  matrix.fillRect(xp[state],yp[state],wp[state],hp[state],zp[state]);

  //how much time has passed since the last beat?
  unsigned long currentTime = millis();
  
  // if is time for the next beat
  if (currentTime - previousTime > interval){
    // reset time keeping
    previousTime = currentTime;
    // update matrix display
    matrix.writeDisplay();
    // if is the first beat of the bar play tone an octave higher (A at 880hz)
    if(state % modulo == 0){
      tone(piezoPin,880,20);
    }
    // else play an A at 440 hz
    else{
      tone(piezoPin,440,20);
    }
    // increase state
    state += 1; 
    // reset state to 0 once it has reached state limit
    if(state == stateLimit){
      state = 0;
    }
  }
}

Credits

kzra
0 projects • 8 followers

Comments