Moduł Wemos D1 jest mały i to jest (moim zdaniem jego zaleta), do różnego rodzaju testów nie potrzeba budować ogromnej machiny z kabli na wielkie płytce stykowej.
Tym razem na małej płytce stykowej umieściłem moduł Wemos D1 mini (Wemos D1 mini v3.1.0 ESP8266 WiFi Python NodeMCU tak brzmi jego pełna nazwa), moduł mikrofonu KY-038 oraz moduł wyświetlacza graficznego OLED SSD1306 dispaly (128×64). Dlaczego właśnie te elementy? Bo je kupiłem z myślą o przetestowaniu i sprawdzeniu jak je używać w aplikacji miernika poziomu natężenia dźwięku.
Połączenie wszystkiego jest banalnie proste. Napięcie 3,3V z wyjścia Wemos idzie na wejście „+” modułu mikrofonu i Vcc wyświetlacza OLED. Masa zasilania z wyjścia GND Wemos na GND wyświetlacza OLED i wejście „G” mikrofonu. Wyjście analogowe mikrofonu „A0” do wejścia pomiarowego A0 modułu Wemos. Wyjścia SDA i SCL należy podłączyć do odpowiednich wejść SDA i SCL modułu Wemos (D2 – SDA, D1-SCL).
No to bazę sprzętową przedstawiłem a teraz oprogramowanie. Inaczej, niż poprzednio postanowiłem do programowania Wemos D1 mini wykorzystać Arduino. Wemos to po prawdzie ESP8266 z „opakowaniem” więc w Arduino da się zaprogramować.
W „menadżerze płytek” jeśli nie macie „esp8266 by ESP community” to musicie ją zainstalować. Wybieracie następnie odpowiednią płytkę – u mnie to „LOLIN(Wemos) D1 R2& mini”.
W edytorze Arduino należy wpisać program:
/*******************************************
* Decybelometr - test wersion
*
* Test project for KY-038 microphone and Wemos D1
* with OLED SSD1306 dispaly (128x64)
*******************************************
* last change: 2020-09-23
*******************************************/
#include <ESP8266WiFi.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SENSOR_PIN A0 // pin for measurement
#define UART_SPEED 115200 // set UART speed
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
const int sampleWindow = 100; // Sample window width in mS (100 mS = 10Hz)
unsigned int sample;
int rawVal = 0;
const String SSID = "***"; // wifi network name
const String PASS = "***"; // password for access to wifi network
int step = 0;
void setup() {
pinMode (SENSOR_PIN, INPUT); // Set the signal pin as input
Serial.begin(UART_SPEED); // set UART speed to 115200
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // OLED display start
display.display(); // show buffer
display.clearDisplay(); // clear buffer
display.setTextSize(1); // Set text size to 1 (1-6)
display.setTextColor(WHITE); // Set text color to BLUE in my display
display.setCursor(0,0); // cursor to upper left corner
display.println("2020 - Decybelometr"); // write title
display.setCursor(20,50);
display.println("rafalrebacz.pl");
display.display(); // show title
delay(1000); // wait 1 seconds
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0,0);
display.println("Connecting to WiFi");
display.display();
WiFi.begin(SSID,PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(100);
display.print(".");
display.display();
Serial.print(".");
}
Serial.print("\nWiFi CONNECTED!");
Serial.print("IP: ");
Serial.println(WiFi.localIP());
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0,0);
display.println("WiFi CONNECTED!\n");
display.print("IP: ");
display.println(WiFi.localIP());
display.display();
delay(3000);
}
void loop() {
unsigned long startMillis= millis(); // Start of sample window
float peakToPeak = 0; // peak-to-peak level
unsigned int signalMax = 0; // minimum value
unsigned int signalMin = 1024; // maximum value
float rms = 0;
float sumSquare = 0;
int licznik = 0;
while (millis() - startMillis < sampleWindow) // collect data for 100 mS
{
sample = analogRead(SENSOR_PIN); // get reading from microphone
sumSquare += sample * sample;
licznik +=1;
if (sample < 1024) { // toss out spurious readings
if (sample > signalMax) {
signalMax = sample; // save just the max levels
}
else if (sample < signalMin) {
signalMin = sample; // save just the min levels
}
}
}
rms = sqrt(sumSquare/licznik);
peakToPeak = signalMax - signalMin; // max - min = peak-peak amplitude
float db = map(peakToPeak,20,900,49.5,90); // calibrate for deciBels
//(it's not correct, but it works as a sample!)
double volts = (peakToPeak * 3.3) / 1024;
display.setCursor(0,0); // cursor to upper left corner
display.setTextSize(3); // set text size to 2
display.print(db,1); // write calibrated deciBels
display.print(" dB");
display.drawRect(0,32,128,10, WHITE); // draw outline of bar graph
int r = map(db,0,120,1,128); // set bar graph for width of screen
display.fillRect(1,32,r,8,WHITE); // draw rectangle bar graph with a width of r
display.setTextSize(2); // Set text size to 1 (1-6)
display.setTextColor(WHITE); // Set text color to WHITE (no choice)
if (db < 55) {
display.setCursor(45,50);
display.print("GOOD");
} else if (db < 65) {
display.setCursor(10,50);
display.print("NOT GOOD");
} else {
display.setCursor(40,50);
display.print("ALARM");
}
// heartbit drawing - small rotating lines in left bottom corner
switch (step) {
case 0:
display.drawLine(0,59,5,64,WHITE);
break;
case 1:
display.drawLine(3,59,3,64,WHITE);
break;
case 2:
display.drawLine(5,59,0,64,WHITE);
break;
case 3:
display.drawLine(0,61,5,61,WHITE);
break;
}
if (step < 3) {
step += 1;
} else {
step = 0;
}
display.display(); // show all that we just wrote & drew
display.clearDisplay(); // clear the display
// print values via UART
Serial.print(millis());
// Serial.print("RMS: ");
Serial.print("\t");
Serial.print(rms,1);
// Serial.print("\twynik dB: ");
Serial.print("\t");
Serial.print(db);
// Serial.print("\tnapiecie: ");
Serial.print("\t");
Serial.println(volts);
}
Zasada działania jest prosta. Moduł mikrofonu wzmacnia sygnał jaki do niego dociera i wystawia na wejście A0 modułu Wemos D1. Na tym wejściu dokonywane jest n pomiarów w założonym czasie i uśredniane.
Wartość ta jest skalowana na dB (niepoprawnie 🙂 od razu zaznaczam) i służy do wyświetlania na ekranie wyświetlacza OLED oraz wystawiana jest na port UART. W oparciu o progi (dowolnie ustawione/wybrane) wyświetlana jest na ekranie informacja „GOOD”, „NOT GOOD”, „ALARM” – to w innej wersji „miernika” posłuży do wyświetlania „koloru” na kolorowym wyświetlaczu z diodami WS2812B.
W programie jest też dodany mały wskaźnik „heartbit” w lewym dolnym narożniku wyświetlacza w postaci kręcącej się linii – ot taki „ficzer” ;).