用Arduino Uno制作一个音乐节拍器

练习古典吉他不用节拍器,容易节奏不稳
作为电子手工爱好者,DIY一个节拍器,练琴的积极性更高了。

准备材料:

  1. Arduino UNO主板一块
  2. 无源蜂鸣器 (或者8欧0.5W小喇叭一个)
  3. OLED 显示屏(SSD1306)
  4. 旋转编码器 (HW-040)
  5. B20K 电位器
  6. LED小灯珠4个
  7. 10K电阻4个
  8. 100欧电阻
  9. 面包板
  10. 杜邦线若干

连线方法:


metronome_work1.jpg

演示视频:
https://www.bilibili.com/video/BV1hM4y1a7Fh

代码:
需要从Arduino IDE下载一个BasicEncoder的库。(https://github.com/micromouseonline/BasicEncoder

#include <Wire.h> //This is for i2C
#include <SSD1306Ascii.h> //i2C OLED库
#include <SSD1306AsciiWire.h> //i2C OLED库,GitHub开源可下载
 
#include <Encoder.h>
//https://github.com/micromouseonline/BasicEncoder


// i2C OLED
#define I2C_ADDRESS 0x3C
#define RST_PIN -1
SSD1306AsciiWire oled;
float OLEDTimer = 0; //屏幕刷新时间

int rhythm = 2; // 2/4拍 3/4 4/4


// Change these two numbers to the pins connected to your encoder.
//   Best Performance: both pins have interrupt capability
//   Good Performance: only the first pin has interrupt capability
//   Low Performance:  neither pin has interrupt capability
Encoder myEnc(3, 4);
//   avoid using pins with LEDs attached

const byte switchPin = 2;

 

#define NOTE_B0  31
#define NOTE_C1  33
#define NOTE_CS1 35
#define NOTE_D1  37
#define NOTE_DS1 39
#define NOTE_E1  41
#define NOTE_F1  44
#define NOTE_FS1 46
#define NOTE_G1  49
#define NOTE_GS1 52
#define NOTE_A1  55
#define NOTE_AS1 58
#define NOTE_B1  62
#define NOTE_C2  65
#define NOTE_CS2 69
#define NOTE_D2  73
#define NOTE_DS2 78
#define NOTE_E2  82
#define NOTE_F2  87
#define NOTE_FS2 93
#define NOTE_G2  98
#define NOTE_GS2 104
#define NOTE_A2  110
#define NOTE_AS2 117
#define NOTE_B2  123
#define NOTE_C3  131
#define NOTE_CS3 139
#define NOTE_D3  147
#define NOTE_DS3 156
#define NOTE_E3  165
#define NOTE_F3  175
#define NOTE_FS3 185
#define NOTE_G3  196
#define NOTE_GS3 208
#define NOTE_A3  220
#define NOTE_AS3 233
#define NOTE_B3  247
#define NOTE_C4  262
#define NOTE_CS4 277
#define NOTE_D4  294
#define NOTE_DS4 311
#define NOTE_E4  330
#define NOTE_F4  349
#define NOTE_FS4 370
#define NOTE_G4  392
#define NOTE_GS4 415
#define NOTE_A4  440
#define NOTE_AS4 466
#define NOTE_B4  494
#define NOTE_C5  523
#define NOTE_CS5 554
#define NOTE_D5  587
#define NOTE_DS5 622
#define NOTE_E5  659
#define NOTE_F5  698
#define NOTE_FS5 740
#define NOTE_G5  784
#define NOTE_GS5 831
#define NOTE_A5  880
#define NOTE_AS5 932
#define NOTE_B5  988
#define NOTE_C6  1047
#define NOTE_CS6 1109
#define NOTE_D6  1175
#define NOTE_DS6 1245
#define NOTE_E6  1319
#define NOTE_F6  1397
#define NOTE_FS6 1480
#define NOTE_G6  1568
#define NOTE_GS6 1661
#define NOTE_A6  1760
#define NOTE_AS6 1865
#define NOTE_B6  1976
#define NOTE_C7  2093
#define NOTE_CS7 2217
#define NOTE_D7  2349
#define NOTE_DS7 2489
#define NOTE_E7  2637
#define NOTE_F7  2794
#define NOTE_FS7 2960
#define NOTE_G7  3136
#define NOTE_GS7 3322
#define NOTE_A7  3520
#define NOTE_AS7 3729
#define NOTE_B7  3951
#define NOTE_C8  4186
#define NOTE_CS8 4435
#define NOTE_D8  4699
#define NOTE_DS8 4978

int tonePin=A1;//蜂鸣器的pin 

int PIN_LED0=8;
int PIN_LED1=10;
int PIN_LED2=11;
int PIN_LED3=13;

//旋转编码器引脚
int  Encoder_OuputA=3;
int  Encoder_OuputB=4;
int  Encoder_Switch=2;

int Previous_Output;
int Encoder_Count;

bool bBreaked = false;

bool bSound = true;

void setup() {
  // put your setup code here, to run once:
  pinMode(tonePin,OUTPUT);//设置蜂鸣器的pin为输出模式
 
  pinMode(PIN_LED0,OUTPUT);
  pinMode(PIN_LED1,OUTPUT);
  pinMode(PIN_LED2,OUTPUT);
  pinMode(PIN_LED3,OUTPUT);


  Serial.begin(115200);
  pinMode(switchPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(switchPin), handleSwitch, RISING);
  attachInterrupt(digitalPinToInterrupt(Encoder_OuputA), handleEncoder, CHANGE);

  Serial.println("Encoder initalized");
 


   // configure i2C
  Wire.setClock(400000);
  Wire.begin(); //start i2C  
 
  //------------------------------------------------------------------------------
  //OLED 部分
  #if RST_PIN >= 0
    oled.begin(&Adafruit128x32, I2C_ADDRESS, RST_PIN);
  #else // RST_PIN >= 0
    oled.begin(&Adafruit128x32, I2C_ADDRESS);
  #endif // RST_PIN >= 0



    oled.setFont(Adafruit5x7);
    oled.clear(); //clear display
    oled.set2X(); //double-line font size - better to read it
  oled.println("Metonome"); //print a welcome message  
  oled.println("Welcome"); //print a welcome message
  delay(2000);

  
  showRhythm();

}


long oldPosition  = 0;
int  bpm = 45; //每秒多少拍

void loop() {
  int ledArray[] = {PIN_LED0,PIN_LED1,PIN_LED2,PIN_LED3};

  long newPosition = myEnc.read();
  if (newPosition != oldPosition && newPosition %  2 == 0) {
    oldPosition = newPosition;
    Serial.println(newPosition / 2);
    bpm += newPosition / 2;

   
  }

  if(bBreaked)
    showRhythm();

  bBreaked = false;


  if(bpm > 120)
    bpm = 120;
  if(bpm < 25)
    bpm = 25;

  

  // put your main code here, to run repeatedly:
  float delayTime =  60*1000.0/bpm - (rhythm+2)*100;
 Serial.println(delayTime);
 for(int i=0;i<rhythm+2;i++)
 {
    if(bBreaked)
       break;

    closeAllLed();
    digitalWrite(ledArray[i], HIGH);

    if(bSound)
    {
        if(i==0)
        {
          tone(tonePin,NOTE_D5); 
        }
        else
        {
          tone(tonePin,NOTE_D4); 
        }
        delay(100); 

        noTone(tonePin);
    }
     
     for(int j=0;j<10;j++)
     {
       if(bBreaked)
         break;
       delay(delayTime/10);
     }
     

  }
  
 
}

void closeAllLed()
{

  digitalWrite(PIN_LED0, LOW);
  digitalWrite(PIN_LED1, LOW);
  digitalWrite(PIN_LED2, LOW);
  digitalWrite(PIN_LED3, LOW);

}

void handleEncoder()
{
   Serial.println("encoder changed");
    bBreaked = true;
}
void handleSwitch() {
  Serial.println("Switch pressed");
  rhythm ++;
  if(rhythm == 3 )
  {
    rhythm = 0;

  }

  bBreaked = true;

}

void showRhythm()
{
  oled.clear(); //clear display
    oled.set2X(); //double-line font size - better to read it
  oled.println("Metonome!"); //print a welcome message  
  
  String strInfo;

  switch(rhythm)
  {
    case 0:
      strInfo = "2/4 BPM:";
      
      break;
    case 1:
        strInfo = "3/4 BPM:";
      
      break;
    case 2:
        strInfo = "4/4 BPM:";
      break;
    default:
     oled.println("Err");
      break;

  }

  String str = strInfo + bpm;

  oled.println(str);

 
}


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容