[アナログ入力](折れ線グラフ)サウンドオシロスコープ(XIAO ESP32C6+SSD1306)


参考
----

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


https://qiita.com/caa45040/items/008fb0d65a9be79761c2

いろいろ、注意
----

- 過去ログを見よ!!!
- 3.2.0
- アナログマイク
- SPV1840LR5H-B使用シリコンマイクモジュールキット
- 入力 GPIO (0)







結果
----


![image_original(44).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/3ccd5dbc-d689-448f-9eea-d3fc35d2eb6c.jpeg)


例

```c++

if( RE(dot8[2], dot8[3], x) ) {a = a | 0b00001000;}

```

![https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_840352_dd681cad-333a-468e-95dc-a17af687195b.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/b65095b0-35cd-4220-a886-65f66a29ccae.jpeg)


プログラム
----



```c++



//秋月のOLEDとアイテンドウのOLEDのアドレスは3C
//ssd1306_Sound_Oscilloscope_ch1_line_XIAO_ESP32C6_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 RE(A, B, C) ((A < B) ? ((C >= A) && (C <= B)) : ((C >= B) && (C <= A)))


//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


//座標
int SO_X = 0;
int SO_Y = 0;

//8ドット分のデータ
char dot8[8];

//ブロックカウント
char b_count = 0;

int p_bk = 0;

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

  if (SO_Y >= 64) {

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

    SO_Y = 0;

    //while(1){} //debug
  }  //end if

  dot8[b_count] = L1;

  b_count++;
  //b_count = 7; //debug
  if (b_count > 7) {


    //データの配列の定義
    uint8_t databytes[2] = { DATA_MODE, 0x00 };
    for (int x = 0; x < 128; x++) {

      //dot8[0]=0;dot8[1]=8;dot8[2]=16;dot8[3]=32;
      //dot8[4]=0;dot8[5]=9;dot8[6]=16;dot8[7]=32;
      int a = 0;  //一時
      if( RE(p_bk   , dot8[0], x) ) {a = a | 0b00000001;}
      if( RE(dot8[0], dot8[1], x) ) {a = a | 0b00000010;}
      if( RE(dot8[1], dot8[2], x) ) {a = a | 0b00000100;}
      if( RE(dot8[2], dot8[3], x) ) {a = a | 0b00001000;}
      if( RE(dot8[3], dot8[4], x) ) {a = a | 0b00010000;}
      if( RE(dot8[4], dot8[5], x) ) {a = a | 0b00100000;}
      if( RE(dot8[5], dot8[6], x) ) {a = a | 0b01000000;}
      if( RE(dot8[6], dot8[7], x) ) {a = a | 0b10000000;}
      
      databytes[1] = a;
      write_s(databytes, 2);

      b_count = 0;
    }  //for x

    p_bk = dot8[7];

  }  //end if b_count

  SO_Y++;

}  //Sound_Oscilloscope


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

  //I2Cの初期化
  Wire.begin(D9, D10);  //XIAO ESP32C6+SSD1306
  //Wire.begin(D10,D9); //XIAO ESP32C6+GROVE
  delay(200);

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

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

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

}  //display_begin


//初期化
void setup() {

  //SSD1306の初期化
  display_begin();

/*
  //シリアルの初期化
  Serial.begin(9600);
  Serial.println();
  //シリアルの待ちが0.5*9
  for (int i = 0; i < 9; i++) {
    delay(500);  //接続待ち
    Serial.print('.');
  }  //for
  Serial.println();
*/

}  //setup


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

  //static int L1 = 0;
  //L1 = L1 + (random(16) - 8);
  //if (L1 < 0) {
  //  L1 = 0;
  //} else if (L1 > 127) {
  //  L1 = 127;
  //}
  //L1 = 32;

  static int L1 = 0;
  int vo = 0;  //電圧
  int cl = 0;  //L ch

  //L1
  for (int i = 0; i < 8; i++) {  //平均化する

    //センサーの値から電圧に変換(x39.0625/8)
    vo = analogRead(0);  //センサーの値
    //vo = 2048;
    //vo = ((vo * 39U) + (vo >> 4)) >> 3; //電圧こと 0～5000 //M5NanoC6
    //vo = (vo * 3300) >> 12; //adc -> vo ((3.3V)4096 3300)
    //Serial.println(vo);delay(10);

    if (vo < 1650) { vo = 1650; }  //マイナス側のカット(マイクだから+-あり)
    vo = vo - 1650;                //中心にする
    cl = cl + vo;
  }  //for
  cl = cl / 8;
  //Serial.println(cl); //debug
  cl = cl * 1 + cl >> 0;  //倍率を掛ける(好みで変える)

  //L1 = cl >> 5; //32
  //L1 = cl >> 4; //16
  //L1 = cl >> 3; //8
  //L1 = cl >> 2; //4
  //L1 = cl >> 1; //2
  L1 = cl;        //1
  if (L1 < 0) {L1 = 0;} else if (L1 > 127) {L1 = 127;}

  static int L2 = 0;
  //L2 = L2 + ( random(16) - 8 );
  //if( L2 < 0 ) { L2 = 0; } else if ( L2 > 127 ){ L2 = 127;}
  // //L1 = 32;


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

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

}  //loop



```