// Learn about the ESP32 WiFi simulation in
// https://docs.wokwi.com/guides/esp32-wifi
#include <WiFi.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C LCD = LiquidCrystal_I2C(0x27, 16, 2);
#define NTP_SERVER "pool.ntp.org"
#define UTC_OFFSET 8*3600
#define UTC_OFFSET_DST 0
void spinner() {
static int8_t counter = 0;
const char* glyphs = "\xa1\xa5\xdb";
LCD.setCursor(15, 1);
LCD.print(glyphs[counter++]);
if (counter == strlen(glyphs)) {
counter = 0;
}
}
int speakerPin = 2;
char notes[] = "cceggCbCag ccdefgagfed eefggabCCDEDCbCbag ee gg CbCagg ee gg CCDDCbC ";
unsigned long beats[] = {2,4,2,4,4,3,1,2,2,4,4,2,4,2,2,2,4,2,2,2,2,4,4,2,4,2,4,4,6,2,4,4,6,2,4,4,2,2,2,2,4,4,2,2,4,2,2,4,3,1,2,2,2,2,4,2,2,4,2,2,2,1,1,4,4,4,4,16,4};
int length = sizeof(notes);
int tempo = 120;
void printLocalTime() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
LCD.setCursor(0, 1);
LCD.println("Connection Err");
return;
}
LCD.setCursor(8, 0);
LCD.println(&timeinfo, "%H:%M:%S");
LCD.setCursor(0, 1);
LCD.println(&timeinfo, "%Y/%m/%d %Z+8");
}
void setup() {
Serial.begin(115200);
pinMode(speakerPin, OUTPUT);
pinMode(14, OUTPUT);
LCD.init();
LCD.backlight();
LCD.setCursor(0, 0);
LCD.print("Connecting to ");
LCD.setCursor(0, 1);
LCD.print("WiFi ");
WiFi.begin("Wokwi-GUEST", "", 6);
while (WiFi.status() != WL_CONNECTED) {
delay(250);
spinner();
}
Serial.println("");
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
LCD.clear();
LCD.setCursor(0, 0);
LCD.println("5A9G018");
LCD.setCursor(0, 1);
LCD.println("Updating time...");
configTime(UTC_OFFSET, UTC_OFFSET_DST, NTP_SERVER);
}
void loop() {
printLocalTime();
digitalWrite(14, HIGH);
delay(125);
digitalWrite(14, LOW);
delay(125);
for (int i = 0; i < length; i++) {
// 如果是空白的話,不撥放音樂
if (notes[i] == ' ') {
delay(beats[i] * tempo); // rest
} else {
// 呼叫 palyNote() 這個 function,將音符轉換成訊號讓蜂鳴器發聲
playNote(speakerPin,notes[i], beats[i] * tempo);
}
digitalWrite(14, HIGH);
// 每個音符之間的間隔,這邊設定的長短會有連音 or 段音的效果
delay(tempo/10);
digitalWrite(14, LOW);
}
}
void playNote(int OutputPin, char note, unsigned long duration) {
// 音符字元與對應的頻率由兩個矩陣表示
char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C', 'D', 'E'};
int tones[] = { 261, 294, 330, 349, 392, 440, 494, 523, 587, 659};
// 播放音符對應的頻率
for (int i = 0; i < (sizeof(tones)/sizeof(tones[0])); i++) {
if (names[i] == note) {
tone(OutputPin,tones[i], duration);
//下方的 delay() 及 noTone (),測試過後一定要有這兩行,整體的撥放出來的東西才不會亂掉,可能是因為 Arduino 送出tone () 頻率後會馬上接著執行下個指令,不會等聲音播完,導致撥出的聲音混合而亂掉
delay(duration);
noTone(OutputPin);
}
}
printLocalTime();
}