Wyświetlacz pogody typ PixelArt

Typ_projektu
Arduino
Zdjecie główne
Krótki opis projektu

To projekt wykorzystujący matrycę LED 16x16 do wyświetlania zadanych stanów pogody w formie animowanego PixelArtu. System obsługuje 5 różnych typów pogody, z których każdy posiada unikalną animację. Dodatkowo wyświetlana jest temperatura w zakresie od -9 do 99 stopni Celsjusza. Informacje o pogodzie i temperaturze są przesyłane do urządzenia za pomocą komend wpisywanych w Serial Monitor w Arduino IDE.

Niezbędne elementy

Ramka SIC PixelArt

Sprzęt

Komputer PC z Arduino IDE

Opis projektu

Projekt został zrealizowany przy pomocy mikrokontrolera ESP32 DevKit oraz matrycy LED PixelArt 16x16. Za pomocą prostych komend wpisywanych w monitorze portu szeregowego możliwe jest wyświetlanie sześciu różnych typów pogody, każdej z własną animacją, oraz aktualnej temperatury w zakresie od -9°C do 99°C.

Obsługiwane typy pogody:

  • s – Słońce z promieniami poruszającymi się cyklicznie

  • r – Deszcz z dynamicznie spadającymi kroplami

  • t Burza z efektem błyskawicy i migającego światła

  • n – Śnieg z opadającymi płatkami

  • f – Mgła z animowaną warstwą o zmiennym natężeni

Temperatura:

Temperatura wyświetlana jest w prawym dolnym rogu matrycy. Jest to pismo bitmapowe. Pozwala ona na ustawianie temperatury w zakresie -9 do 99 stopni Celcjusza. Można ją zmienić poprzez wpisywanie jej w Serial Monitor

Interakcja:

Wszystkie funkcje projektu obsługiwane są z poziomu Serial Monitor:

  • Litera (s, r, t, n,) zmienia aktualnie wyświetlaną pogodę.

  • Wpisanie liczby (np. 23, -4) ustawia wyświetlaną temperaturę.

Zastosowane funkcje:

  • getPixelIndex(x, y) – konwertuje współrzędne (x, y) do indeksu LED-a w układzie ZIG-ZAG

  • clearMatrix() – czyści ekran

  • drawCloud(...) – uniwersalne rysowanie chmur

  • drawBitmapDigit(...) – wyświetlanie cyfr (do temperatury)

  • drawMinus(...) – rysowanie znaku minus

  • drawTemperature(temp) – główna funkcja wyświetlania temperatury

  • animateSun() – animacja słoneczna

  • animateRain() – animacja deszczu

  • animateStorm() – animacja burzy z błyskawicą

  • animateSnow() – animacja śniegu

  • animateFog() – animacja mgły

Zdjęcia
słońce
deszcz
burza
śnieg
mgła
kod programu
#include <Adafruit_NeoPixel.h>

#define LED_PIN    15
#define LED_WIDTH  16
#define LED_HEIGHT 16
#define NUM_LEDS   (LED_WIDTH * LED_HEIGHT)

Adafruit_NeoPixel matrix(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);

int currentTemp = 23;  // wartość temperatury do wyświetlenia

// === Konwersja (x, y) → indeks LED-a (ZIG-ZAG) ===
int getPixelIndex(int x, int y) {
  if (x < 0 || x >= LED_WIDTH || y < 0 || y >= LED_HEIGHT) return -1;

  // Odbicie lustrzane X względem osi pionowej
  // Ponieważ (0,0) jest w prawym górnym rogu
  x = LED_WIDTH - 1 - x;

  if (y % 2 == 0)
    return y * LED_WIDTH + x;
  else
    return y * LED_WIDTH + (LED_WIDTH - 1 - x);
}

void clearMatrix() {
  matrix.clear();
}
/////////////////////////////////////////////////////////////////////

// === Uniwersalne rysowanie chmury ===
void drawCloud(int baseX, int baseY, uint32_t color, int width = 8, int height = 4) {
  for (int x = baseX; x < baseX + width; x++) {
    for (int y = 0; y < height; y++) {
      if ((x == baseX || x == baseX + width - 1) && y == 0) continue;
      int idx = getPixelIndex(x, baseY + y);
      if (idx >= 0) matrix.setPixelColor(idx, color);
    }
  }
}
/////////////////////////////////////////////////////////////////
const byte digitBitmap[10][5] = {
  { B111, B101, B101, B101, B111 }, // 0
  { B010, B110, B010, B010, B111 }, // 1
  { B111, B001, B111, B100, B111 }, // 2
  { B111, B001, B111, B001, B111 }, // 3
  { B101, B101, B111, B001, B001 }, // 4
  { B111, B100, B111, B001, B111 }, // 5
  { B111, B100, B111, B101, B111 }, // 6
  { B111, B001, B010, B010, B010 }, // 7
  { B111, B101, B111, B101, B111 }, // 8
  { B111, B101, B111, B001, B111 }  // 9
};

void drawBitmapDigit(int digit, int baseX, int baseY, uint32_t color) {
  if (digit < 0 || digit > 9) return;

  for (int row = 0; row < 5; row++) {
    byte bits = digitBitmap[digit][row];
    for (int col = 0; col < 3; col++) {
      if (bits & (1 << (2 - col))) {  // sprawdzamy bit od lewej
        int x = baseX-1 + col;
        int y = baseY + row;
        int idx = getPixelIndex(x, y);
        if (idx >= 0) matrix.setPixelColor(idx, color);
      }
    }
  }
}

////////////////////////////////////////////////////////////////////////
void drawMinus(int baseX, int baseY, uint32_t color) {
  for (int col = 0; col < 3; col++) {
    int x = baseX - 1 + col;
    int y = baseY + 2;  // środek symbolu "-"
    int idx = getPixelIndex(x, y);
    if (idx >= 0) matrix.setPixelColor(idx, color);
  }
}

void drawTemperature(int temp) {
  uint32_t color = matrix.Color(255, 255, 255);
  if (temp < 0) {
    drawMinus(10, 11, color);
    drawBitmapDigit(abs(temp), 14, 11, color);
  } else {
    int dzies = temp / 10;
    int jedn = temp % 10;

    if (temp < 10) {
      drawBitmapDigit(jedn, 14, 11, color);
    } else {
      drawBitmapDigit(dzies, 10, 11, color);
      drawBitmapDigit(jedn, 14, 11, color);
    }
  }
}
// === Animacje ===/////////////////////////////////////////////////////
void animateSun() {
  static int frame = 0;
  clearMatrix();
  int cx = 7, cy = 7;
  uint32_t sunColor = matrix.Color(255, 200, 50);

  for (int dx = 0; dx <= 2; dx++) {
    for (int dy = 0; dy <= 2; dy++) {
      int idx = getPixelIndex(cx - 1 + dx, cy - 1 + dy);
      if (idx >= 0) matrix.setPixelColor(idx, sunColor);
    }
  }

  const int rays[8][2][2] = {
    { { 0, -3 }, { 0, -4 } }, { { 2, -2 }, { 3, -3 } }, { { 3, 0 }, { 4, 0 } }, { { 2, 2 }, { 3, 3 } },
    { { 0, 3 }, { 0, 4 } }, { { -2, 2 }, { -3, 3 } }, { { -3, 0 }, { -4, 0 } }, { { -2, -2 }, { -3, -3 } }
  };

  int group = frame % 2;
  for (int i = 0; i < 8; i++) {
    bool isDiagonal = (i % 2 == 1);
    if (isDiagonal == (group == 1)) {
      for (int j = 0; j < 2; j++) {
        int x = cx + rays[i][j][0];
        int y = cy + rays[i][j][1];
        int idx = getPixelIndex(x, y);
        if (idx >= 0) matrix.setPixelColor(idx, sunColor);
      }
    }
  }

  drawTemperature(currentTemp);
  matrix.show();
  frame = (frame + 1) % 2;
  delay(250);
}
//////////////////////////////////////////////////////////////////
void animateStorm() {
  static int frame = 0;
  clearMatrix();
  uint32_t gray = matrix.Color(60, 60, 60);
  uint32_t yellow = matrix.Color(255, 255, 100);
  uint32_t flashColor = matrix.Color(100, 100, 100);

  if (frame % 12 == 0) {
    for (int i = 0; i < NUM_LEDS; i++) matrix.setPixelColor(i, flashColor);
  }

  drawCloud(3, 3, gray);

  if (frame % 6 < 3) {
    int bolt[7][2] = {
  {7, 5}, {8, 6}, {7, 7}, {8, 8}, {7, 9}, {8, 10}, {8, 11}
};
    for (int i = 0; i < 7; i++) {
      int idx = getPixelIndex(bolt[i][0], bolt[i][1]);
      if (idx >= 0) matrix.setPixelColor(idx, yellow);
    }
  }

  drawTemperature(currentTemp);
  matrix.show();
  frame++;
  delay(160);
}
///////////////////////////////////////////////////////////
void animateRain() {
  static int frame = 0;
  clearMatrix();

  uint32_t gray = matrix.Color(60, 60, 60);
  uint32_t blue = matrix.Color(0, 120, 255);
  uint32_t splash = matrix.Color(0, 80, 200);

  drawCloud(3, 3, gray); // przesunięcie w lewo!

 int columns[] = {4, 5, 6, 7};  // też przesuwamy kolumny deszczu!
  for (int i = 0; i < 4; i++) {
    int col = columns[i];
    int dropY = 7 + ((frame + i * 4) % 8);
    for (int j = 0; j < 4; j++) {
      int y = dropY + j;
      if (y < LED_HEIGHT - 1) {
        int idx = getPixelIndex(col, y);
        if (idx >= 0) matrix.setPixelColor(idx, blue);
      } else if (y == LED_HEIGHT - 1) {
        int splashIdx = getPixelIndex(col, y);
        if (splashIdx >= 0) matrix.setPixelColor(splashIdx, splash);
      }
    }
  }

  drawTemperature(currentTemp);
  matrix.show();
  frame++;
  delay(130);
}
////////////////////////////////////////////////////////////////////////////////
void animateSnow() {
  static int frame = 0;
  clearMatrix();

  uint32_t gray = matrix.Color(80, 80, 80);
  uint32_t white = matrix.Color(255, 255, 255);

  drawCloud(3, 3, gray);

  int flakes[] = {4, 5, 6, 7};
  for (int i = 0; i < 4; i++) {
    int col = flakes[i];
    int flakeY = 7 + ((frame + i * 3) % 9);
    int idx = getPixelIndex(col, flakeY);
    if (idx >= 0) matrix.setPixelColor(idx, white);
  }

  drawTemperature(currentTemp);
  matrix.show();
  frame++;
  delay(160);
}
///////////////////////////////////////////////////////////////////////////
void animateFog() {
  static int frame = 0;
  clearMatrix();

  // Kolory mgły o różnym natężeniu (lekka, średnia, gęsta)
  uint32_t lightFog = matrix.Color(60, 60, 60);
  uint32_t midFog   = matrix.Color(90, 90, 90);
  uint32_t heavyFog = matrix.Color(130, 130, 130);

  for (int y = 4; y <= 12; y++) {
    for (int x = 0; x < LED_WIDTH; x++) {
      int wave = (x + frame / 2) % 16;
      uint32_t color;

      if (wave < 5) color = lightFog;
      else if (wave < 10) color = midFog;
      else color = heavyFog;

      // lekkie falowanie warstw mgły
      int offsetY = (int)(1.5 * sin((x + frame) * 0.3));
      int idx = getPixelIndex(x, y + offsetY);
      if (idx >= 0) matrix.setPixelColor(idx, color);
    }
  }

  drawTemperature(currentTemp);
  matrix.show();
  frame++;
  delay(120);
}
///////////////////////////////////////////////////////////////////////////


void setup() {
  matrix.begin();
  matrix.setBrightness(50);
  clearMatrix();
  matrix.show();
  Serial.begin(9600);
 Serial.println("Wpisz: s (słońce), r (deszcz), t (burza), n (śnieg), f (mgła), m (ksiezyc) lub liczbę temperatury (np. 23):");
}

void loop() {
  static char mode = 's';
  static String inputBuffer = "";

 while (Serial.available()) {
  char c = Serial.read();
  if (isdigit(c) || c == '-') {  // <-- pozwalamy na '-'
    inputBuffer += c;
  } else if (c == '\n' || c == '\r') {
    if (inputBuffer.length() > 0) {
      int newTemp = inputBuffer.toInt();  // obsługuje również wartości ujemne
      if (newTemp >= -9 && newTemp <= 99) {  // zakres rozszerzony o minus
        currentTemp = newTemp;
        Serial.print("Ustawiono temperaturę: ");
        Serial.println(currentTemp);
      }
      inputBuffer = "";
    }
  } else if (c == 's' || c == 'r' || c == 't'|| c == 'n' || c == 'f'|| c == 'm') {
    mode = c;
  }
}


  if (mode == 's') animateSun();
  else if (mode == 'r') animateRain();
  else if (mode == 't') animateStorm();
  else if (mode == 'n') animateSnow();   // 'n' jak "śnieg"
  else if (mode == 'f') animateFog();    // 'm' jak "mgła"
}
Pliki_projektu
Schemat
Youtube
Tagi
Arduino Pogoda Wyświetlacz LED PixelArt