Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Премиальный набор датчика влажности и температуры в корпусе из ореха — Arduino + NeoPixel + TFT-дисплей

Компоненты и материалы

Компонент Количество
Arduino UNO 1
Кольцо NeoPixel: WS2812 5050 RGB LED (24 LED) 1
Датчик температуры и влажности DHT22 1
TFT-дисплей 1.44" ST7735R с MicroSD (Adafruit) 1
Беспаяльная макетная плата 1
Корпус для 4×AA батареек 1
Перемычки (набор) 1

Инструменты

О проекте

История создания

Мы построили элегантный монитор влажности и температуры в корпусе из ореха с «ласточкиным хвостом» (dovetail), используя Arduino Uno и компоненты Adafruit. Проект объединяет столярное дело и базовую электронику — идеально для начинающих.

Мы живём в Центральном Техасе, где весной происходят резкие скачки влажности и температуры, что вредно для столярных изделий. Это устройство предупреждает об изменении влажности, позволяя вовремя убрать заготовки в дом или отложить фрезеровку. К тому же, оно выглядит отлично и украшено нашим логотипом!

Мы были новичками в Arduino и учились в процессе — теперь планируем новые проекты.

Видео сборки

Смотрите подробное видео по сборке на нашем канале.

Программный код

#include <Adafruit_NeoPixel.h>
#include <Adafruit_ST7735.h>
#include <Adafruit_GFX.h>
#include <FastLED.h>
#include <SPI.h>
#include <SD.h>
#include <cactus_io_DHT22.h>

// Пины
#define TFT_CS 10
#define TFT_RST 9
#define TFT_DC 8
#define DHT_PIN 2
#define PIXEL_PIN 6
#define PIXEL_NUM 24
#define SD_PIN 4
#define BMP_BUF 20

// Глобальные переменные
int currentColor = 9999;
CRGB leds[PIXEL_NUM];
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
DHT22 dht(DHT_PIN);
int loopDelay = 2000;

void setup() {
  Serial.begin(9600);
  Serial.println("Starting up.");

  dht.begin();
  tft.initR(INITR_144GREENTAB);

  Serial.print("Initializing SD card.");
  if (!SD.begin(SD_PIN)) {
    Serial.println("Failed!");
    return;
  }

  tft.fillScreen(ST7735_BLACK);
  FastLED.addLeds<NEOPIXEL, PIXEL_PIN>(leds, PIXEL_NUM);
  delay(500);
}

void loop() {
  dht.readTemperature();
  dht.readHumidity();
  int f = dht.temperature_F;  // °F
  int h = dht.humidity;       // %

  // Иконка градусов
  tft.fillCircle(102, 42, 6, ST7735_WHITE);
  tft.fillCircle(102, 42, 4, ST7735_BLACK);

  drawTemperature(f);
  setHumidityColors(h);

  Serial.print("Temperature: "); Serial.println(f);
  Serial.print("Humidity: "); Serial.print(h); Serial.println("%");

  delay(1000);
}

// Отрисовка температуры битмапами с SD-карты
void drawTemperature(int temp) {
  int digits = numDigits(temp);
  int x1_2 = 62, x2_2 = 32;
  int x1_3 = 1, x2_3 = 1, x3_3 = 1;
  int y = 38;
  char digitStr1[24], digitStr2[24], digitStr3[24];

  itoa(temp % 10, digitStr1, 10); strcat(digitStr1, ".bmp");
  if (digits == 2) { itoa((temp/10)%10, digitStr2, 10); strcat(digitStr2, ".bmp"); }
  if (digits == 3) { itoa((temp/100)%10, digitStr3, 10); strcat(digitStr3, ".bmp"); }

  if (digits > 2) {
    bmpDraw(digitStr1, x1_3, y);
    bmpDraw(digitStr2, x2_3, y);
    bmpDraw(digitStr3, x3_3, y);
  } else {
    bmpDraw(digitStr1, x1_2, y);
    bmpDraw(digitStr2, x2_2, y);
  }
}

int numDigits(int number) {
  return (number > 99) ? 3 : 2;
}

// Загрузка BMP с SD и вывод на TFT
void bmpDraw(char *filename, uint8_t x, uint8_t y) {
  File bmpFile;
  int bmpWidth, bmpHeight;
  uint8_t bmpDepth;
  uint32_t bmpImageoffset, rowSize;
  uint8_t sdbuffer[3*BMP_BUF];
  uint8_t buffidx = sizeof(sdbuffer);
  boolean goodBmp = false, flip = true;
  int w, h, row, col;
  uint8_t r, g, b;
  uint32_t pos = 0, startTime = millis();

  if ((x >= tft.width()) || (y >= tft.height())) return;

  if ((bmpFile = SD.open(filename)) == NULL) {
    Serial.print("Bitmap file not found!"); return;
  }

  if (read16(bmpFile) == 0x4D42) { // BMP signature
    read32(bmpFile); (void)read32(bmpFile);
    bmpImageoffset = read32(bmpFile);
    read32(bmpFile);
    bmpWidth = read32(bmpFile);
    bmpHeight = read32(bmpFile);
    if (read16(bmpFile) == 1) {
      bmpDepth = read16(bmpFile);
      if ((bmpDepth == 24) && (read32(bmpFile) == 0)) {
        goodBmp = true;
        rowSize = (bmpWidth * 3 + 3) & ~3;
        if (bmpHeight < 0) { bmpHeight = -bmpHeight; flip = false; }
        w = bmpWidth; h = bmpHeight;
        if ((x+w-1) >= tft.width()) w = tft.width() - x;
        if ((y+h-1) >= tft.height()) h = tft.height() - y;
        tft.setAddrWindow(x, y, x+w-1, y+h-1);
        for (row=0; row= sizeof(sdbuffer)) {
              bmpFile.read(sdbuffer, sizeof(sdbuffer)); buffidx = 0;
            }
            b = sdbuffer[buffidx++];
            g = sdbuffer[buffidx++];
            r = sdbuffer[buffidx++];
            tft.pushColor(tft.Color565(r,g,b));
          }
        }
      }
    }
  }
  bmpFile.close();
  if (!goodBmp) Serial.println("BMP format not recognized.");
}

uint16_t read16(File f) {
  uint16_t result;
  ((uint8_t*)&result)[0] = f.read();
  ((uint8_t*)&result)[1] = f.read();
  return result;
}

uint32_t read32(File f) {
  uint32_t result;
  ((uint8_t*)&result)[0] = f.read();
  ((uint8_t*)&result)[1] = f.read();
  ((uint8_t*)&result)[2] = f.read();
  ((uint8_t*)&result)[3] = f.read();
  return result;
}

// Управление цветами NeoPixel по влажности
void setColors(int r, int g, int b) {
  for (int i = 0; i < PIXEL_NUM; i++) {
    leds[i].setRGB(r, g, b);
    leds[i].fadeLightBy(125);
    FastLED.show();
    delay(100);
  }
}

void setHumidityColors(int humidity) {
  // Цветовая шкала влажности:
  // 0-17%   — Красный
  // 18-34%  — Оранжевый
  // 35-51%  — Жёлтый
  // 52-68%  — Зелёный
  // 69-85%  — Синий
  // 86-100% — Фиолетовый
  int cRed[3] = {255,0,0};
  int cOrange[3] = {255,90,0};
  int cYellow[3] = {255,255,0};
  int cGreen[3] = {0,255,0};
  int cBlue[3] = {0,175,255};
  int cPurple[3] = {255,0,255};

  int range = map(humidity, 0, 100, 0, 6);
  switch (range) {
    case 0: if (currentColor != 0) { setColors(cRed[0],cRed[1],cRed[2]); currentColor=0; } break;
    case 1: if (currentColor != 1) { setColors(cOrange[0],cOrange[1],cOrange[2]); currentColor=1; } break;
    case 2: if (currentColor != 2) { setColors(cYellow[0],cYellow[1],cYellow[2]); currentColor=2; } break;
    case 3: if (currentColor != 3) { setColors(cGreen[0],cGreen[1],cGreen[2]); currentColor=3; } break;
    case 4: if (currentColor != 4) { setColors(cBlue[0],cBlue[1],cBlue[2]); currentColor=4; } break;
    case 5: if (currentColor != 5) { setColors(cPurple[0],cPurple[1],cPurple[2]); currentColor=5; } break;
  }
}

Корпус (CAD)

3D-модель корпуса из ореха с ласточьиным хвостом доступна в разделе Custom parts.

Схемы подключения

Схема выполнена в Fritzing (компоненты подобраны приближенно).

Производственный процесс

  1. Датчики влажности: принцип работы и ключевые применения
  2. Датчик DHT11: принцип работы и ключевые применения
  3. Sensirion SVM30: Все-в-одном мультигазовый, влажность и температура модуль для очистителей воздуха и HVAC
  4. Создание удалённого датчика температуры на Raspberry Pi и Python — пошаговое руководство
  5. Бесшовный мониторинг температуры и влажности на Raspberry Pi с EzTemp
  6. Создание многодатчиковой системы мониторинга температуры и света с Raspberry Pi и DS18B20
  7. Создайте автоматизированную аэропоническую систему с Raspberry Pi и датчиком влажности
  8. Создайте домашний монитор температуры на Raspberry Pi с MCP9808, InfluxDB и Grafana
  9. Проверка и калибровка датчика влажности для точных измерений
  10. Лабораторный чип NASA Goddard обеспечивает мониторинг потока и температуры в реальном времени