Графическая шкала и иконка капли
Научиться измерять влажность почвы с помощью датчика и выводить результат на дисплей OLED SSD1306 (0.96") в виде шкалы и иконки капли.
Датчик почвы
OLED SSD1306
Опционально: питание датчика можно подать через пин D7, чтобы включать его только на момент измерений и снизить коррозию.
Перед компиляцией нужно установить:
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_ADDR 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
#define SOIL_PIN A0
#define SOIL_PWR 7
const bool USE_SENSOR_POWER = true;
const int AIR_VALUE = 1000; // сухо (воздух)
const int WET_VALUE = 420; // мокро (вода)
const uint8_t SAMPLES = 10;
const uint16_t MEASURE_DELAY_MS = 15;
const uint16_t POWER_STABILIZE_MS = 60;
const uint16_t UPDATE_PERIOD_MS = 1000;
uint32_t lastUpdate = 0;
int readSoilRaw();
int readSoilPercent();
void drawDrop(int x, int y, bool filled);
void drawUI(int percent, int raw);
void setup() {
Serial.begin(9600);
if (USE_SENSOR_POWER) {
pinMode(SOIL_PWR, OUTPUT);
digitalWrite(SOIL_PWR, LOW);
}
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
Serial.println(F("SSD1306 не найден."));
for (;;);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println(F("Soil Moisture Monitor"));
display.print(F("AIR=")); display.print(AIR_VALUE);
display.print(F(" WET=")); display.println(WET_VALUE);
display.display();
delay(1200);
}
void loop() {
uint32_t now = millis();
if (now - lastUpdate < UPDATE_PERIOD_MS) return;
lastUpdate = now;
int percent = readSoilPercent();
int raw = analogRead(SOIL_PIN);
Serial.print(F("RAW="));
Serial.print(raw);
Serial.print(F(" PERCENT="));
Serial.print(percent);
Serial.println('%');
drawUI(percent, raw);
}
int readSoilRaw() {
if (USE_SENSOR_POWER) {
digitalWrite(SOIL_PWR, HIGH);
delay(POWER_STABILIZE_MS);
}
long acc = 0;
for (uint8_t i = 0; i < SAMPLES; i++) {
acc += analogRead(SOIL_PIN);
delay(MEASURE_DELAY_MS);
}
if (USE_SENSOR_POWER) {
digitalWrite(SOIL_PWR, LOW);
}
return (int)(acc / SAMPLES);
}
int readSoilPercent() {
const int raw = readSoilRaw();
long p = map(raw, AIR_VALUE, WET_VALUE, 0, 100);
if (p < 0) p = 0;
if (p > 100) p = 100;
return (int)p;
}
void drawUI(int percent, int raw) {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
display.println(F("Soil Moisture"));
display.setTextSize(2);
display.setCursor(0, 14);
display.print(percent);
display.println(F("%"));
display.setTextSize(1);
display.setCursor(0, 34);
display.print(F("RAW: "));
display.println(raw);
const int barX = 0;
const int barY = 48;
const int barW = 120;
const int barH = 12;
display.drawRect(barX, barY, barW, barH, SSD1306_WHITE);
int fillW = map(percent, 0, 100, 0, barW - 2);
display.fillRect(barX + 1, barY + 1, fillW, barH - 2, SSD1306_WHITE);
bool filled = (percent >= 50);
drawDrop(120, 4, filled);
display.display();
}
void drawDrop(int x, int y, bool filled) {
display.drawLine(x, y + 8, x, y, SSD1306_WHITE);
display.drawLine(x, y, x - 6, y + 8, SSD1306_WHITE);
display.drawLine(x, y, x + 6, y + 8, SSD1306_WHITE);
display.drawCircle(x, y + 12, 6, SSD1306_WHITE);
if (filled) {
for (int i = 1; i <= 6; i++) {
display.drawLine(x - i, y + 12 + i/2, x + i, y + 12 + i/2, SSD1306_WHITE);
}
display.fillCircle(x, y + 12, 4, SSD1306_WHITE);
}
}
Подключаем:
Wire.h
— работа с I²C;Adafruit_GFX
— текст и графика;Adafruit_SSD1306
— управление OLED.Указываем размеры (128×64) и адрес 0x3C
, создаём объект display
.
SOIL_PIN = A0
— аналоговый выход AO;SOIL_PWR = 7
— питание через D7;USE_SENSOR_POWER = true
— включать датчик только при измерении.AIR_VALUE = 1000
— сухо (воздух);WET_VALUE = 420
— мокро (в воде);setup()
loop()
readSoilRaw()
readSoilPercent()
drawUI()
drawDrop()