3の倍数と3がつく数字の時だけ高音になる電子工作をESP32で実装してみたら結構いい勉強になった


## 何が学べる？？
・ESP32のセットアップ
・ESP32特有のコード(PWM制御)
・７セグメントLEDの使い方
・８ビットシフトレジスタの使い方
・圧電ブザーの使い方
・上記部品を制御するための簡単なプログラム


※ESP３２で今回実装していますが、arduinoやラズパイなどなど他のマイコンでも構いません。私はたまたまラズパイが壊れた＆ESP32に興味があったので今回採用しています。

##ESP３２とは？
Wi-FiとBluetoothを内臓しているマイコンです。低コストな上に、Arduino IDEで開発できるので開発コストも高くありません。
IoT技術が発展しているこのご時世、Arduinoやラズパイと並んでメジャーな存在になっている印象があります。
[参考：ESP32 Wiki](https://ja.wikipedia.org/wiki/ESP32)

##ESP32 セットアップ
下記記事参考にどうぞ。ついでにLチカまでやってみてください
[esp32-wroomDevkitCをarduino IDEでセットアップからサーボ駆動まで(Windows)](https://qiita.com/WK_ZAKK/items/d7fbbb8c0c8eebe5682d)

##7セグメントLEDと8ビットシフトレジスタの使い方
私の過去記事を参考にしてください
7セグLEDは何桁でも構いませんが、4桁が勉強になると思います
8ビットシフトレジスタは使った方がピンの節約になるので使うことをおすすめします。

[Arduinoと8ビットシフトレジスタで７セグを制御する](https://qiita.com/taiyyytai/items/6bc81144f46852783a76)

##実装内容
・7セグLEDに０からカウントアップ開始
・カウント毎に音を鳴らす
・3の倍数と3のつく数字の時に高音になるようにする
・9999以上になったらリセット

こちらあまり参考になりませんが配置図です。4桁7セグが用意できず配線しきれませんでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342722/10c4d254-6226-cf8e-9645-d9bd137a2736.png)

こちらarduinoで実装した場合。ESP32も似たように配線可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342722/fd5457ff-e65a-5ca5-6996-1ef0b735c53c.png)

##LEDCについて
ESP32にはArduinoのようにanalogWrite()やtone()が実装されていません。その代わりledcWriteTone()というものが使えますのでブザーはそちらで制御するようにします。
LEDCについてはESP32を使用する上で必要な知識となりますので、簡単なブザーで今回なんとなく使い方を勉強して起きましょう。
下記サンプルです。

```C++

#define BUZZER_PIN (14)
void setup() {
  ledcSetup(1, 12000, 8);
  ledcAttachPin(BUZZER_PIN, 1);
}

void loop() {
 ledcWriteTone(1, 1000);//高音
}

```


##イメージ動画

[3の倍数と3が付く数字のときだけ高音になる電子工作](https://www.youtube.com/watch?v=NIiz_18ueBQ)

##実際のコード
```C++
#define SRCLK   (25)//シフトレジスタのクロック信号
#define RCLK    (26)//ストレージレジスタのクロック信号
#define SER     (27)//シリアル入力

#define num_1   (12)//1桁目
#define num_2    (13)//2桁目
#define num_3     (32)//3桁目
#define num_4     (33)//4桁目

#define BUZZER_PIN (14)

int _cnt = 0;
int _number = 0; 
int _flg = 1;//桁数を格納するフラグ
int led_num1 = 0;
int led_num2 = 0;
int led_num3 = 0;
int led_num4 = 0;

bool three_flg;

void setup() {
  Serial.begin(9600);

  pinMode(SRCLK, OUTPUT);
  pinMode(RCLK,  OUTPUT);
  pinMode(SER,   OUTPUT);
  pinMode(num_1, OUTPUT);
  pinMode(num_2, OUTPUT);
  pinMode(num_3, OUTPUT);
  pinMode(num_4, OUTPUT);

  ledcSetup(1, 12000, 8);
  ledcAttachPin(BUZZER_PIN, 1);
}

// 点灯パターン
const uint8_t PATTERNS[] = {
  B11010111,//0
  B00010100,//1
  B11001101,//2
  B01011101,//3
  B00011110,//4
  B01011011,//5
  B11011011,//6
  B00010111,//7
  B11011111,//8
  B01011111,//9
};

int pattern_num = sizeof(PATTERNS) / sizeof(PATTERNS[0]);


//どの数字を光らせるか
void NumPrint(int Number) {
  // 8ビット分のデータをシフトレジスタへ送る
  shiftOut(SER, SRCLK, LSBFIRST, PATTERNS[Number]);
  // シフトレジスタの状態をストレージレジスタへ反映させる
  digitalWrite(RCLK,  LOW);
  digitalWrite(RCLK,  HIGH);
}
//各桁の数字を返す
int NumParse(int Number, int s) {
  if (s == 1) {
    return Number % 10;
  }
  else if (s == 2) {
    return (Number / 10) % 10; //10で割った値を整数にする = 2桁目の値
  }

  else if (s == 3) {
    return (Number / 100) % 10; //100で割った値を整数にする = 3桁目の値
  }

  else if (s == 4) {
    return (Number / 1000) / 10; //100で割った値を整数にする = 3桁目の値
  }
  return 0;
}

void loop() {

  if (_number >= 10000) {
    _number = 0;
  }


  if (_flg == 1) {
    digitalWrite(num_1, LOW);
    digitalWrite(num_2, HIGH);
    digitalWrite(num_3, HIGH);
    digitalWrite(num_4, HIGH);
    _flg = 2;
    NumPrint(led_num1);
  }
  else if (_flg == 2) {
    digitalWrite(num_1, HIGH);
    digitalWrite(num_2, LOW);
    digitalWrite(num_3, HIGH);
    digitalWrite(num_4, HIGH);
    _flg = 3;
    NumPrint(led_num2);
  }
  else if (_flg == 3) {
    digitalWrite(num_1, HIGH);
    digitalWrite(num_2, HIGH);
    digitalWrite(num_3, LOW);
    digitalWrite(num_4, HIGH);
    _flg = 4;
    NumPrint(led_num3);
  }

  else if (_flg == 4) {
    digitalWrite(num_1, HIGH);
    digitalWrite(num_2, HIGH);
    digitalWrite(num_3, HIGH);
    digitalWrite(num_4, LOW);
    _flg = 1;
    NumPrint(led_num4);
  }

 //1秒に1回ここに入る
  if (_cnt >= 10000) {
    _number++;
    _cnt = 0;
    led_num1 = NumParse(_number, 1);
    led_num2 = NumParse(_number, 2);
    led_num3 = NumParse(_number, 3);
    led_num4 = NumParse(_number, 4);
    if (led_num1 == 3 or led_num2 == 3 or led_num3 == 3 or led_num4 == 3 or _number % 3 == 0) {
      ledcWriteTone(1, 1000);//高音
    }
    else {
      ledcWriteTone(1, 100);//常時低音
    }
    delay(50);
    three_flg = false;
    Serial.print("NUMBER:");
    Serial.println(_number);
    Serial.println(_cnt);

  }
  _cnt++;
  delayMicroseconds(100);
  ledcWriteTone(1, 0);//音は止める

}
```

##終わりに
IoTが騒がれるようになり、勉強を始める方も多いと思います。どうしてもソフト側、サーバ側の情報量が多く学習コスト・ハードルもかなり低くなってきていると思います。もちろんそちらも大切だと思いますが、ハード側も知識をつけて行くと、実装の幅も増えてきてより楽しくなると思います！