//(app.ino) #include #include #include #include #include "app.h" // WiFi SSID パスワード設定(自分の環境に合わせて設定 const char ssid[] = "your-WifiRouter -SSID"; // SSID //使用するWifiルータ のSSID const char password[] = "your-WifiRouter-password"; // password //使用するWifiルータ のパスワード // サーバー設定ポート80で接続 WebServer server(80); int PlayMode = 1; //1:演奏 2:一時停止 int SkipMode = 0; //0:スキップなし 1:スキップ実行 int GpPwm = 28; //PWM出力 GPIO番号 //ピン番号:34 int GpLedRed = 0; //LED赤 GPIO番号 //ピン番号:1 int GpLedGreen = 1; //LED緑 GPIO番号 //ピン番号:2 int GpPlayPauseSw = 2; //Play/Pause SW  //ピン番号:4 int GpPlaySkipSw = 3; //Skip SW  //ピン番号:5 int VOLUME_PIN = 27; //可変抵抗器AD入力 //ピン番号: 32 int ix; //音符の発音時間、無音時間のモード uint64_t interval_T; //[μsec] //LED ON時間、LEDのOFF時間 //interval_T=5msec/実測=6msec, 2msec/3.2msec, 1mse/2msec, 500μsec/1.7msec, 200μsec/1.5msec, 100μ/1.25msec uint64_t current_T; //現在時刻 //pico起動後の経過時間[μsec] uint64_t target_T; //LED状態遷移時刻 int SwCount_PauseSw; //PauseSWのスイッチ接触検出数 int SwCount_SkipSw; //SkipSWのスイッチ接触検出数 int MelodyMode = 0; int TouchSkipSW = 0; int AdValue12; typedef enum //音符解読ステート { SET_SOUND_FREQUENCY_TIME, CHECK_SOUNDING_TIME, STOP_SOUNDING, CHECH_SHORT_SILENT_TIME, STOP_SHORT_SILENT_TIME, CHECK_SILENT_TIME } STATES; STATES states; //Android ブラウザ画面 表示 StreamString html = R"( PWM Melody Producer by Pico W, with Android-type WiFi remote controller
         

時刻表示部

picoWによる
 スマホ式WiFi_STAモード型リモコン付
  PWMメロディー発生器

               YS電子工作デザイン

0

         

<参考>
・ 最新:NHKニュース

   
)"; void OnkaiOut(int doremi, float duty) //PWM出力 { analogWriteFreq(doremi); //周波数設定 analogWriteRange(1024); //分解能 10bit:1024 analogWrite(GpPwm,1024*duty); //PWM出力ピンに出力 } void ClosePWM(void) //PWM出力停止 { analogWriteFreq(100); //100Hz analogWriteRange(1024); //分解能 10bit:1024 analogWrite(GpPwm,0); //Duty = 0; } void SwCheck(){ //SW操作検出チェック //開始/一時停止SW if(digitalRead(GpPlayPauseSw) == 0)SwCount_PauseSw++; else SwCount_PauseSw = 0; if(SwCount_PauseSw == 20){ //チャタリング対策 if(PlayMode == 0)PlayMode = 1; else PlayMode = 0; } if(SwCount_PauseSw >= 21)SwCount_PauseSw = 21; //メロディ曲のスキップSW if(digitalRead(GpPlaySkipSw) == 0)SwCount_SkipSw++; else SwCount_SkipSw = 0; if(SwCount_SkipSw == 20){ //チャタリング対策 if(SkipMode == 0)SkipMode = 1; else SkipMode = 0; } if(SwCount_SkipSw >= 21)SwCount_SkipSw = 21; } void SkipMelody() //メロディー曲(スキップメカスイッチの場合) { if(SkipMode == 1) { SkipMode = 0; MelodyMode++; states = SET_SOUND_FREQUENCY_TIME; ix = 0; if(MelodyMode >= 3)MelodyMode = 0; } } void LedCont(){ //LED制御 if(PlayMode == 1){ //再生中 digitalWrite(GpLedRed, 1); //LED赤: 点灯 digitalWrite(GpLedGreen, 0); //LED緑: 消灯 } else{ //一時停止中 digitalWrite(GpLedRed, 0); //LED赤: 消灯 digitalWrite(GpLedGreen, 1); //LED緑: 点灯 ClosePWM(); //PWM出力停止 } } // サーバーリクエスト時処理関数 void handleRoot() { server.send(200, "text/html", html); //レスポンス200を返し、htmlデータ送信 } void TouchAndroid(){ //Android 画面 演奏/一時停止タッチ操作処理 if(PlayMode == 0)PlayMode = 1; else PlayMode = 0; handleRoot(); } void TouchSkipMelody(){ //メロディー曲スキップ(Android画面ボタンによるスキップの場合) PlayMode = 0; //演奏一時停止 MelodyMode++; //メロディー曲番号インクリメント states = SET_SOUND_FREQUENCY_TIME; //スキップ後の初期ステート設定 ix = 0; //スキップ後の初期要素番号設定 //{音階(音の周波数),音価(音が発生している時間),無音の時間)}  if(MelodyMode >= 3)MelodyMode = 0; //メロディー曲番号が最後の場合 → 最初のメロディ曲に戻る PlayMode = 1; //演奏再開 handleRoot(); } // ブラウザ表示更新:PlayMode //演奏/一時停止 void getMode(){ int SendData; char buf[32]; AdValue12 = analogRead(VOLUME_PIN); //可変抵抗器AD値を読み出し SendData = PlayMode * 1000000 //100万倍 ////PlayMode、ix、AdValue12データを加算した送信データを作成 + ix * 10000 //1万倍 + AdValue12; sprintf(buf, "%d", SendData); // dataの値を文字列として格納 server.send(200, "text/html", buf); // レスポンス200を返し、dataを文字列で送信 } // ブラウザ表示更新:歌詞更新 void getSongWords(){ char buf[32]; // data文字列格納バッファ char str_Usagi[] = "Usagi"; //兎追いし彼の山 char str_Kobuna[] = "Kobuna"; //小鮒釣りし彼の川 char str_Yumeha[] = "Yumeha"; //夢は今も巡りて char str_Wasure[] = "Wasure"; //忘れ難き故郷 char str_Kiteki[] = "Kiteki"; //汽笛一聲新橋を char str_Hayawaga[] = "Hayawaga"; //はや我汽車は離れたり char str_Atago[] = "Atago"; //愛宕の山に入りのこる char str_Tukiwo[] = "Tukio"; //月を旅路の友として char str_Yuuyake[] = "Yuuyake"; //夕焼け小焼けの 赤とんぼ char str_Owarete[] = "Owarete"; //負われて見たのは いつの日か char str_Space[] = " "; switch(MelodyMode){ case 0: //ふるさと if((ix >= 0) && (ix < 10))sprintf(buf, "%s", str_Usagi); else if(ix < 20)sprintf(buf, "%s", str_Kobuna); else if(ix < 35)sprintf(buf, "%s", str_Yumeha); else if(ix < 45)sprintf(buf, "%s", str_Wasure); else sprintf(buf, "%s", str_Space); break; case 1: //鉄道唱歌 if((ix >= 0) && (ix < 13))sprintf(buf, "%s", str_Kiteki); else if(ix < 26)sprintf(buf, "%s", str_Hayawaga); else if(ix < 39)sprintf(buf, "%s", str_Atago); else if(ix < 52)sprintf(buf, "%s", str_Tukiwo); else sprintf(buf, "%s", str_Space); break; case 2: //赤とんぼ if((ix >= 0) && (ix < 14))sprintf(buf, "%s", str_Yuuyake); else if(ix < 32)sprintf(buf, "%s", str_Owarete); else sprintf(buf, "%s", str_Space); break; default: break; } server.send(200, "text/html", buf); } void setup(void) { //UART開始 Serial.begin(115200); delay(50); // WiFi接続開始(STSモード) WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { //接続完了してなければ delay(500); Serial.print("."); } Serial.print("\nSSID: "); // SSID表示 Serial.println(WiFi.SSID()); Serial.print("IP: "); // IPアドレス表示 Serial.println(WiFi.localIP()); //192.168.43.98 server.on("/", handleRoot);//サーバー設定 server.on("/myTouch", TouchAndroid); //Android画面 Play/Pauseボタン操作 受信処理 //第1引き数の先頭に、"/"必須 //server.on("/#", Led); // //上記の場合 "#"、"/#" いずれでもLed()内の内臓LEDは点灯しない→関数LED()へ制御は達していない server.on("/mySkip", TouchSkipMelody); server.on("/get/mode", getMode); // データ表示更新受信処理 server.on("/get/SongWords",getSongWords); // server.on("/get/AdCovert", getAdConvert); server.begin();//サーバーの起動 server.begin(); Serial.println("HTTP server started"); pinMode(GpPwm, OUTPUT); //PWM 出力モードに設定 pinMode(GpLedRed, OUTPUT); //LED  pinMode(GpLedGreen, OUTPUT); //LED pinMode(GpPlayPauseSw, INPUT_PULLUP); //プルアップ付き入力 pinMode(GpPlaySkipSw, INPUT_PULLUP); //プルアップ付き入力 analogReadResolution(12); //AD変換分解能12ビット pinMode(VOLUME_PIN, INPUT); //AD変換アナログ入力 states = SET_SOUND_FREQUENCY_TIME; //最初の音符解読ステート設定 MelodyMode = 0; } void loop(void) { server.handleClient(); //登録した情報に従ってクライアントからのリクエストを処理する関数 if(PlayMode == 1){ switch(MelodyMode){ case 0: switch(states){ case SET_SOUND_FREQUENCY_TIME: //音階周波数、及びPWM音発生時間設定 OnkaiOut(Furusato[ix][0],0.5); //PWM出力開始 Fursato[][3] interval_T = Furusato[ix][1] * 1000; current_T = time_us_64(); //pico起動後経過の時間取得[μsec] target_T = current_T + interval_T; //PWM終了時刻計算 states = CHECK_SOUNDING_TIME; break; case CHECK_SOUNDING_TIME: //PWM音終了時刻チェック if(target_T <= time_us_64()) states = STOP_SOUNDING; break; case STOP_SOUNDING: //PWM音終了・無音処理 //ショート無音時間設定 analogWrite(GpPwm,0); //PWM 停止 //必須 interval_T = 50 * 1000; current_T = time_us_64(); //pico起動後経過の時間取得[μsec] target_T = current_T + interval_T; //ショート無音時間終了時刻計算 states = CHECH_SHORT_SILENT_TIME; break; case CHECH_SHORT_SILENT_TIME: //ショート無音時間終了チェック if(target_T <= time_us_64()) states = STOP_SHORT_SILENT_TIME; break; case STOP_SHORT_SILENT_TIME: //音符上の休止無音時間、メロディー終了後の無音時間設定 interval_T = Furusato[ix][2] * 1000; current_T = time_us_64(); //pico起動後経過の時間取得[μsec] target_T = current_T + interval_T; //無音終了時刻計算 states = CHECK_SILENT_TIME; break; case CHECK_SILENT_TIME: //音符上の休止無音時間チェック if(target_T <= time_us_64()) { ix++; if(Furusato[ix][0] == -1) { MelodyMode++; states = SET_SOUND_FREQUENCY_TIME; if(MelodyMode >= 3)MelodyMode = 0; ix = 0; //曲の終末を検出 → 曲の先頭から繰り返す } states = SET_SOUND_FREQUENCY_TIME; //初めに戻る } break; default: break; } break; case 1: switch(states){ case SET_SOUND_FREQUENCY_TIME: //音階周波数、及びPWM音発生時間設定 OnkaiOut(TetsudoShoka[ix][0],0.5); //PWM出力開始 Fursato[][3] interval_T = TetsudoShoka[ix][1] * 1000; current_T = time_us_64(); //pico起動後経過の時間取得[μsec] target_T = current_T + interval_T; //PWM終了時刻計算 states = CHECK_SOUNDING_TIME; break; case CHECK_SOUNDING_TIME: //PWM音終了時刻チェック if(target_T <= time_us_64()) states = STOP_SOUNDING; break; case STOP_SOUNDING: //PWM音終了・無音処理 //ショート無音時間設定 analogWrite(GpPwm,0); //PWM 停止 //必須 interval_T = 50 * 1000; current_T = time_us_64(); //pico起動後経過の時間取得[μsec] target_T = current_T + interval_T; //ショート無音時間終了時刻計算 states = CHECH_SHORT_SILENT_TIME; break; case CHECH_SHORT_SILENT_TIME: //ショート無音時間終了チェック if(target_T <= time_us_64()) states = STOP_SHORT_SILENT_TIME; break; case STOP_SHORT_SILENT_TIME: //音符上の休止無音時間、メロディー終了後の無音時間設定 interval_T = TetsudoShoka[ix][2] * 1000; current_T = time_us_64(); //pico起動後経過の時間取得[μsec] target_T = current_T + interval_T; //無音終了時刻計算 states = CHECK_SILENT_TIME; break; case CHECK_SILENT_TIME: //音符上の休止無音時間チェック if(target_T <= time_us_64()) { ix++; if(TetsudoShoka[ix][0] == -1) { MelodyMode++; states = SET_SOUND_FREQUENCY_TIME; if(MelodyMode >= 3)MelodyMode = 0; ix = 0; //曲の終末を検出 → 曲の先頭から繰り返す } states = SET_SOUND_FREQUENCY_TIME; //初めに戻る } break; default: break; } break; case 2: switch(states){ case SET_SOUND_FREQUENCY_TIME: //音階周波数、及びPWM音発生時間設定 OnkaiOut(Akatonbo[ix][0],0.5); //PWM出力開始 Fursato[][3] interval_T = Akatonbo[ix][1] * 1000; current_T = time_us_64(); //pico起動後経過の時間取得[μsec] target_T = current_T + interval_T; //PWM終了時刻計算 states = CHECK_SOUNDING_TIME; break; case CHECK_SOUNDING_TIME: //PWM音終了時刻チェック if(target_T <= time_us_64()) states = STOP_SOUNDING; break; case STOP_SOUNDING: //PWM音終了・無音処理 //ショート無音時間設定 analogWrite(GpPwm,0); //PWM 停止 //必須 interval_T = 50 * 1000; current_T = time_us_64(); //pico起動後経過の時間取得[μsec] target_T = current_T + interval_T; //ショート無音時間終了時刻計算 states = CHECH_SHORT_SILENT_TIME; break; case CHECH_SHORT_SILENT_TIME: //ショート無音時間終了チェック if(target_T <= time_us_64()) states = STOP_SHORT_SILENT_TIME; break; case STOP_SHORT_SILENT_TIME: //音符上の休止無音時間、メロディー終了後の無音時間設定 interval_T = Akatonbo[ix][2] * 1000; current_T = time_us_64(); //pico起動後経過の時間取得[μsec] target_T = current_T + interval_T; //無音終了時刻計算 states = CHECK_SILENT_TIME; break; case CHECK_SILENT_TIME: //音符上の休止無音時間チェック if(target_T <= time_us_64()) { ix++; if(Akatonbo[ix][0] == -1) { MelodyMode++; states = SET_SOUND_FREQUENCY_TIME; if(MelodyMode >= 3)MelodyMode = 0; ix = 0; //曲の終末を検出 → 曲の先頭から繰り返す } states = SET_SOUND_FREQUENCY_TIME; //初めに戻る } break; default: break; } break; default: break; } } //if(PlayMode == 1) SwCheck(); //ボタンスイッチチック SkipMelody(); //メロディをスキップ LedCont(); //LEDの点灯/消灯制御実施 }