eDOT: 내장 IR 리모컨·자동 밝기 조절 갖춘 정밀 아두이노 시계·기상 관측소
부품 및 소모품
Microchip ATMEGA 328P-PU
×
1
MAXIM MAX7219
×
6
BOSCH BME280 - GY-BMEP 브레이크아웃 보드
×
1
Adafruit Luckylight 8x8 도트 매트릭스 LED 디스플레이 - M1603095
×
6
DS3231 (RTC 클록)
×
1
Arduino Nano R3
×
1
Arduino UNO
×
1
eDOTcore (전용 PCB)
×
1
필수 도구 및 장비
Flashforge Dreamer (3D 프린터)
앱 및 온라인 서비스
Arduino IDE
프로젝트 소개
eDOT
eDOT 은 아두이노 기반 정밀 시계이자 기상 관측소로, 내장 IR 리모컨 수신기와 자동 밝기 조절 기능을 갖췄습니다. 추가 하드웨어(와이파이 모듈 등)로 쉽게 확장 가능하도록 설계되었습니다.
여섯 개의 8×8 도트 매트릭스 LED 디스플레이 덕분에 내부 센서 데이터, 사용자 정의 스크롤 메시지, 인터넷(RSS 등)에서 가져온 정보 등 다양한 정보를 표시할 수 있습니다. 소비 전력이 매우 낮고, 유리 전면과 3D 프린팅 바디가 어우러진 심플하고 우아한 디자인입니다. 프로젝트는 현재 개발 중이며 지속적으로 업데이트됩니다.
3D 프린팅 부품은 Thingiverse 에서 다운로드 가능합니다. 더 많은 프로젝트는 유튜브 채널 참고.
B.O.M. (자재 명세서)
3D 프린팅 좌측 바디 1개
3D 프린팅 우측 바디 1개
3D 프린팅 좌측 커버 1개
3D 프린팅 우측 커버 1개
3D 프린팅 발 2개
3D 프린팅 디스플레이 서포트 12개
버니시드 유리 240×75×5 mm 1개
주황색 필터 1개
Adafruit 8×8 도트 매트릭스 Luckylight M1603095(백색) 6개
MAX7219 컨트롤러 보드 6개
USB 브레이크아웃 보드 1개
BME280 브레이크아웃 보드 1개
DS3231 칩 1개
IR 수신기 IRM-56384 1개
포토레지스터 LDR-07 1개
ATMEGA328PU (아두이노 커스텀 보드용) 1개
OMRON 12mm 택트 스위치 6개
eDOTcore PCB
드디어 eDOT 제어 보드 첫 프로토타입이 나왔습니다.
eDOTcore 프로젝트 페이지 이동
코드
eDOT: 다용도 정밀 기상 관측소 및 시계 Arduino
// eDOT: Versatile precision weather station and clock
// HISTORY
// 11/12/2105 측정 보정 계수 추가
// 09/06/2016 자동 디스플레이 밝기 추가
// 09/06/2016 작업 스케줄러 추가
// 07/08/2016 eDOT 스플래시 스크린 추가
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>
#include <Average.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include "RTClib.h"
#include <EasyScheduler.h>
Adafruit_BME280 bme; // I2C
RTC_DS3231 rtc;
int pinCS = 10; // CS 핀, DIN→MOSI, CLK→SCK (cf https://arduino.cc/en/Reference/SPI)
int numberOfHorizontalDisplays = 7;
int numberOfVerticalDisplays = 1;
Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays);
#define TEMPERATURE 0
#define HUMIDITY 1
#define PRESSURE 2
#define TIME 3
#define DAY 4
#define DATE 5
float temp, tempavg; char tempf[8];
float hum, humavg; char humf[8];
float press, pressavg; char pressf[8];
int screen = 0;
long previousLEDMillis = 0;
long LEDInterval = 5000;
int screenMax = 5;
bool screenChanged = true;
float lightsens, screenBrt = 0, lightsensavg;
Average<float> avetemp(60);
Average<float> avehum(60);
Average<float> avepress(60);
Average<float> avelightsens(40);
// 보정 계수
float temp_o = -1.70, temp_s = 1.0, temp_lin;
float hum_o = 2.45, hum_s = 1.0, hum_lin;
float press_o = 0.0, press_s = 1.0, press_lin;
float brt_o = -4, brt_s = 1.35;
Schedular Task1;
Schedular Task2;
void setup() {
Task1.start(); Task2.start();
Wire.begin();
bme.begin(0x76);
matrix.setIntensity(screenBrt); // 0~15
// matrix.setPosition(0, 0, 0);
// matrix.setPosition(1, 1, 0);
matrix.setRotation(0, 1);
matrix.setRotation(1, 1);
matrix.setRotation(2, 1);
matrix.setRotation(3, 1);
matrix.setRotation(4, 1);
matrix.setRotation(5, 1);
matrix.setRotation(6, 1);
matrix.setRotation(7, 1);
// matrix.setRotation(8, 1);
// matrix.setRotation(9, 1);
rtc.begin();
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// rtc.adjust(DateTime(2016, 02, 28, 16, 44, 0));
// Serial.begin(9600);
// eDOT 스플래시 스크린
matrix.fillScreen(0); matrix.write();
matrix.setCursor(12,0); matrix.print("eDOT");
for(screenBrt=0; screenBrt<=15; screenBrt++){
delay(25); matrix.setIntensity(screenBrt); matrix.write();
}
delay(250);
for(screenBrt=15; screenBrt>=0; screenBrt--){
delay(50); matrix.setIntensity(screenBrt); matrix.write();
}
delay(500);
matrix.fillScreen(0); matrix.write();
delay(1000);
}
void loop() {
Task1.check(acq1, 500);
Task2.check(acq2, 20);
}
void acq1() {
// 데이터 수집 및 평균화
temp = bme.readTemperature(); avetemp.push(temp); tempavg = avetemp.mean();
hum = bme.readHumidity(); avehum.push(hum); humavg = avehum.mean();
press = bme.readPressure(); avepress.push(press); pressavg = avepress.mean();
DateTime now = rtc.now();
outSec = now.second(); outMin = now.minute(); outHour = now.hour();
outday = now.day(); outmonth = now.month(); outyear = now.year() - 2000;
dow = now.dayOfTheWeek();
}
void acq2() {
lightsens = analogRead(A3);
avelightsens.push(lightsens);
lightsensavg = avelightsens.mean();
screenBrt = constrain(((lightsensavg/1023*15)*brt_s + brt_o), 0, 15);
matrix.setIntensity(screenBrt);
// 데이터 선형화
temp_lin = tempavg * temp_s + temp_o;
hum_lin = humavg * hum_s + hum_o;
press_lin = pressavg * press_s + press_o;
unsigned long currentLEDMillis = millis();
if(currentLEDMillis - previousLEDMillis > LEDInterval) {
previousLEDMillis = currentLEDMillis;
screen++;
if(screen > screenMax) screen = 0;
screenChanged = true;
}
// if(screenChanged) { screenChanged = false; }
switch(screen){
case TEMPERATURE:
dtostrf(temp_lin,4,2,tempf);
matrix.setCursor(6,0); matrix.setTextSize(1); matrix.setTextColor(255);
matrix.print(tempf); matrix.drawRect(37,0,2,2,255); matrix.setCursor(40,0); matrix.print("C");
matrix.write(); matrix.fillScreen(0); break;
case HUMIDITY:
dtostrf(hum_lin,4,2,humf);
matrix.setCursor(6,0); matrix.setTextSize(1); matrix.setTextColor(255);
matrix.print(humf); matrix.setCursor(37,0); matrix.print("%");
matrix.write(); matrix.fillScreen(0); break;
case PRESSURE:
dtostrf(press_lin,6,0,pressf);
matrix.setCursor(0,0); matrix.setTextSize(1); matrix.setTextColor(255);
matrix.print(pressf); matrix.setCursor(37,0); matrix.print("Pa");
matrix.write(); matrix.fillScreen(0); break;
case TIME:
matrix.setCursor(0,0); matrix.setTextSize(1); matrix.setTextColor(255);
if(outHour<10) matrix.print("0");
matrix.print(outHour); matrix.print(":");
if(outMin<10) matrix.print("0");
matrix.print(outMin); matrix.print(":");
if(outSec<10) matrix.print("0");
matrix.print(outSec);
matrix.write(); matrix.fillScreen(0); break;
case DATE:
matrix.setCursor(0,0); matrix.setTextSize(1); matrix.setTextColor(255);
if(outday<10) matrix.print("0");
matrix.print(outday); matrix.print("/");
if(outmonth<10) matrix.print("0");
matrix.print(outmonth); matrix.print("/");
matrix.print(outyear);
matrix.write(); matrix.fillScreen(0); break;
case DAY:
matrix.setCursor(15,0); matrix.setTextSize(1); matrix.setTextColor(255);
matrix.print(daysOfTheWeek[dow]);
matrix.write(); matrix.fillScreen(0); break;
}
}