(SSD1306)M5StampS3、マイクを使用して、2chレベルメーターで遊ぶ。



参考


https://qiita.com/caa45040/items/3109bdcb9b62fe6bae4c


https://qiita.com/caa45040/items/88ff3c9604bd3a2e692c


https://qiita.com/caa45040/items/ca5747a84d87caeba706




x 過去ログを見よ!!!
x 3.1.1


目的
マイクを使ったサウンドレベルメータを作る
モノラルである。
入力は、GPIOの1である。
平均してマイナス側は、カットである。
ある。ある。である。

軽量
高速
見やすさ重視


マイク　SPV1840LR5H-B

![o_coq801.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/c772d233-7f92-0a78-7e81-0bdc27c4cb42.jpeg)


結果
----

![image_original (40).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/a752fd4b-7cca-540c-1e2a-f65655abd353.jpeg)



プログラム
----



```c++


//秋月のOLEDとアイテンドウのOLEDのアドレスは3C
//ssd1306_level_meter_mic_y1_2ch_S3_1


//ヘッダー
#include <Arduino.h>
#include <Wire.h>


//定義
#define MAX_PAGE                   (7)
#define MAX_COL                    (127)

#define COMMAND_MODE               0x80 // continuation bit is set!
#define DATA_MODE                  0x40

#define SET_COLUMN_ADDRESS         0x21 // takes two bytes, start address and end address of display data RAM
#define SET_PAGE_ADDRESS           0x22 // takes two bytes, start address and end address of display data RAM

#define SET_MEMORY_ADDRESSING_MODE 0x20 // takes one byte as given above
#define HORIZONTAL_ADDRESSING_MODE 0x00

#define SET_SEGMENT_REMAP_0        0xA0 // column address 0 is mapped to SEG0 (Reset)
#define SET_SEGMENT_REMAP_127      0xA1 // column address 127 is mapped to SEG0

#define SET_COMMON_REMAP_0         0xC0 // row address  0 is mapped to COM0 (Reset)
#define SET_COMMON_REMAP_63        0xC8 // row address 63 is mapped to COM0


//I2Cに配列を転送する
void write_s(uint8_t *str1, uint8_t len1) {

  Wire.beginTransmission(  0x3c  );

  for (int ii = 0; ii < len1; ii++) {

    //一文字出力
    Wire.write(*str1 ++);

  }//for

  Wire.endTransmission();

}//write_s


//セットページアドレス(アドレスの移動)
void setPageAddress(uint8_t start, uint8_t end)
{
  uint8_t databytes[6] = {COMMAND_MODE, SET_PAGE_ADDRESS, COMMAND_MODE, start, COMMAND_MODE, end};
  write_s(databytes, 6);
}//setPageAddress


//セットカラムアクセス(アドレスの移動)
void setColumnAddress(uint8_t start, uint8_t end)
{
  uint8_t databytes[6] = {COMMAND_MODE, SET_COLUMN_ADDRESS, COMMAND_MODE, start, COMMAND_MODE, end};
  write_s(databytes, 6);
}//setColumnAddress


//セットメモリーアドレシングモード(画面の端に来たら左上に戻る)
void setMemoryAddressingMode()
{
  uint8_t databytes[4] = {COMMAND_MODE, SET_MEMORY_ADDRESSING_MODE, COMMAND_MODE, HORIZONTAL_ADDRESSING_MODE};
  write_s(databytes, 4);
}//setMemoryAddressingMode


//セットディスプレー Flip(画面に書き込む方向を決める)
void setDisplayFlip(int left, int down)
{
  if ( left == 0) {
    // column address   0 is mapped to SEG0 (Reset)
    //_sendCommand(SET_SEGMENT_REMAP_0);
    uint8_t databytes[2] = {COMMAND_MODE, SET_SEGMENT_REMAP_0};
    write_s(databytes, 2);
  } else {
    // column address 127 is mapped to SEG0
    //_sendCommand(SET_SEGMENT_REMAP_127);
    uint8_t databytes[2] = {COMMAND_MODE, SET_SEGMENT_REMAP_127};
    write_s(databytes, 2);
  }//end if

  if ( down == 0) {
    // Reset mode
    //_sendCommand(SET_COMMON_REMAP_0);
    uint8_t databytes[2] = {COMMAND_MODE, SET_COMMON_REMAP_0};
    write_s(databytes, 2);
  } else {
    // Flip Up/Down (Need to rewrite display before H effect shows)
    //_sendCommand(SET_COMMON_REMAP_63);
    uint8_t databytes[2] = {COMMAND_MODE, SET_COMMON_REMAP_63};
    write_s(databytes, 2);
  }//end if
}//setDisplayFlip


//パターンRAMの内容を液晶に転送
void level_meter(int L1, int L2) {

  //ビットカウント
  static int b_count = 0;

  //8ドット分のデータ
  static char dot_1ch[8];
  static char dot_2ch[8];

  //範囲の設定 (OLED内部のx,yカウンターを初期化してホームポジション0,0に)
  setPageAddress(0, MAX_PAGE);  // all pages
  setColumnAddress(0, MAX_COL); // all columns

  //yのループ
  for (int y = 0; y < 64; y++) {

    if (L1 >= y){dot_1ch[b_count] = 1;}else{dot_1ch[b_count] = 0;}
    if (L2 >= y){dot_2ch[b_count] = 1;}else{dot_2ch[b_count] = 0;}

    b_count++; //0から7までのカウンターに1を足しこむ

    if (b_count > 7 ) { //8個たまると実行

      //L1 L1 L1 vL1 L1 L1 L1 L1 L1
      int a; //一時
      //データの配列の定義
      static uint8_t databytes[9] = {DATA_MODE, 0,0,0,0, 0,0,0,0};
      static uint8_t databytes_null[9] = {DATA_MODE, 0,0,0,0, 0,0,0,0};

      //空白1 8x2
      write_s(databytes_null, 1+8);
      write_s(databytes_null, 1+8);
      
      //L1 L1 L1 L1 L1 L1 L1 L1 L1 L1
      a =     dot_1ch[7] << 7;
      a = a | dot_1ch[6] << 6;
      a = a | dot_1ch[5] << 5;
      a = a | dot_1ch[4] << 4;
      a = a | dot_1ch[3] << 3;
      a = a | dot_1ch[2] << 2;
      a = a | dot_1ch[1] << 1;
      a = a | dot_1ch[0]     ;
      //8x4
      databytes[1] = databytes[2] = databytes[3] = databytes[4] = a;
      databytes[5] = databytes[6] = databytes[7] = databytes[8] = a;
      write_s(databytes, 1+8);
      write_s(databytes, 1+8);
      write_s(databytes, 1+8);
      write_s(databytes, 1+8);

      //空白2 8x4
      write_s(databytes_null, 1+8);
      write_s(databytes_null, 1+8);
      write_s(databytes_null, 1+8);
      write_s(databytes_null, 1+8);

      //L2 L2 L2 L2 L2 L2 L2 L2 L2
      a =     dot_2ch[7] << 7;
      a = a | dot_2ch[6] << 6;
      a = a | dot_2ch[5] << 5;
      a = a | dot_2ch[4] << 4;
      a = a | dot_2ch[3] << 3;
      a = a | dot_2ch[2] << 2;
      a = a | dot_2ch[1] << 1;
      a = a | dot_2ch[0]     ;      
      //8x4
      databytes[1] = databytes[2] = databytes[3] = databytes[4] = a;
      databytes[5] = databytes[6] = databytes[7] = databytes[8] = a;
      write_s(databytes, 1+8);
      write_s(databytes, 1+8);
      write_s(databytes, 1+8);
      write_s(databytes, 1+8);

      //空白3 8x2
      write_s(databytes_null, 1+8);
      write_s(databytes_null, 1+8);

      b_count = 0; //0から7までのカウンターをクリア

    }//end if b_count

  }//for y

  //while(1){} //debug

}//Sound_Oscilloscope


//SSD1306の初期化
void display_begin(void) {

  //I2Cの初期化
  Wire.begin(); //NanoC6
  delay(200);
  //Wire.setClock(2000000); //速度の変更 (I2C高速化 2Mhz)
  //Wire.setClock(1000000); //速度の変更 (I2C高速化 2Mhz)
  //Wire.setClock(800000);  //速度の変更 (I2C高速化 800khz)
  Wire.setClock(400000);  //速度の変更 (I2C高速化 400kMhz)
  //Wire.setClock(200000);  //速度の変更 (I2C高速化 200khz)
  //Wire.setClock(100000);  //速度の変更 (I2C高速化 100hz)

  delay(200);

  //SSD1306の初期化スペル(魔法)
  //0x80,0x8D,0x80,0x14,0x80,0xAF
  write_s( (uint8_t*) "\200\215\200\024\200\257", 6);
  delay(100);

  //セットメモリーアドレシングモード (画面の終端に来たら画面の先頭に)
  setMemoryAddressingMode();

  //セットディスプレー Flip (画面の向きを変える)
  setDisplayFlip(0, 1);

}//display_begin


//初期化
void setup() {

  //SSD1306の初期化
  display_begin();

}//setup


//メインループ
void loop() {

  static int L1 = 0; //値
  static int L2 = 0; //値

  //L1 = random(64); // ランダム
  //L2 = random(64); // 0から63

  float s; //input
  float cl; //L ch
  float cr; //R ch

  //L1
  cl = 0.0f;
  for(int i=0;i<8;i++){ //平均化する
  //センサー入力する
    s = ((float)analogRead(1)); //センサーの値
    s = s * (3.3f / 4096.0f);   //電圧こと
    cl = cl + s;
  }
  cl = cl / 8;
  cl = cl - 1.650f;      //中心にする
  if(cl < 0) {cl = 0;}   //マイナス側のカット(マイクだから+-あり)
  cl = cl * 128;         //倍率を掛ける(好みで変える)
  if(cl > 63) {cl = 63;} //MAXを超えた物をカット
  L1 = (int)cl;          //キャストして転記

  //L2
  cr = 0.0f;
  for(int i=0;i<8;i++){ //平均化する
    //センサー入力する
    s = (float)(analogRead(2)); //センサーの値
    s = s * (3.3f / 4096.0f);   //電圧こと
    cr = cr + s;
  }
  cr = cr / 8;
  cr = cr - 1.650f;      //中心にする
  if(cr < 0) {cr = 0;}   //マイナス側のカット(マイクだから+-あり)
  cr = cr * 128;         //倍率を掛ける(好みで変える)
  if(cr > 63) {cr = 63;} //MAXを超えた物をカット
  L2 = (int)cr;          //キャストして転記
  L2 = L1; //モノラルの時

  level_meter(L1, L2); //画面の再表示

  //delay(1000); //1秒待つ debug

}//loop



```