DSM501A 먼지 센서로 아두이노 기반 공기질 모니터 만들기
부품 및 소모품
| 부품 | 수량 | 비고 |
| Arduino Nano R3 | 1 | 메인 컨트롤러 |
| DSM501A 먼지 센서 모듈 | 1 | PM2.5, PM10 동시 측정 가능 |
| 영숫자 LCD 16x2 (HD44780 호환) | 1 | 측정값 표시용 |
| 40mm 팬 키트 | 1 | 센서 내부로 공기 흡입용 (피크값 개선) |
| LED (일반) | 5 | 공기질 상태 표시용 (색상별) |
| 저항 220Ω | 1 | LCD 백라이트용 |
| 가변저항 10kΩ (단일 턴) | 1 | LCD 대비 조절용 |
필요한 도구
소프트웨어
프로젝트 소개
공기질 모니터링은 1980년대부터 시작된 과학 분야지만, 당시에는 기술이 제한적이고 장비가 복잡하며 매우 비쌌습니다. 오늘날 최신 기술을 활용하면 더 정밀하고 빠르며, 소형이고 저렴한 장치를 만들 수 있습니다.
이 프로젝트는 Samyoung DSM501A 먼지 센서를 사용합니다. 알리익스프레스 등에서 몇 달러에 구매 가능한 가장 저렴한 센서 중 하나로, PM2.5와 PM10 입자를 모두 감지할 수 있습니다.
센서 핀아웃 및 연결
- Vout1 (PM2.5) → Arduino D2
- Vout2 (PM10) → Arduino D3
- Vcc → Arduino 5V
- GND → Arduino GND
LED 5개는 아날로그 핀 A1~A5에 연결하며, 코드에서 출력으로 설정합니다.
LCD 표시 내용
16x2 LCD에는 PM10 농도(개/0.01cf)와 공기질 5단계가 표시됩니다:
- Clean (깨끗함) - PM10 < 1,000
- Good (좋음) - 1,000 ≤ PM10 < 10,000
- Acceptable (보통) - 10,000 ≤ PM10 < 20,000
- Heavy (나쁨) - 20,000 ≤ PM10 < 50,000
- Hazard (매우 나쁨) - PM10 ≥ 50,000
시리얼 모니터에서는 PM10, PM2.5 농도 모두 확인 가능합니다. 오염도에 따라 해당 색상의 LED가 점등되어 직관적으로 상태를 파악할 수 있습니다.
중요 팁: 팬 설치
센서 출구 쪽에 공기를 빨아들이는 팬을 설치하면 원치 않는 피크값을 크게 줄여 측정 정확도가 향상됩니다. 전체 장치는 전기 설치용 플라스틱 박스에 조립했습니다.
향후 계획
추후 몇 가지 저가 먼지 센서를 추가로 테스트하여 비교 결과를 다음 프로젝트에서 공유할 예정입니다.
소스 코드
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
int pin2 = 3; // PM10
int pin1 = 2; // PM2.5
unsigned long duration1, duration2;
unsigned long starttime;
unsigned long sampletime_ms = 30000; // 30초 샘플링
unsigned long lowpulseoccupancy1 = 0;
unsigned long lowpulseoccupancy2 = 0;
float ratio1 = 0, ratio2 = 0;
float concentration1 = 0, concentration2 = 0;
int wLed = A1; // Clean - 흰색
int gLed = A2; // Good - 녹색
int yLed = A3; // Acceptable - 노란색
int rLed = A4; // Heavy - 빨간색
int bLed = A5; // Hazard - 파란색
void setup() {
Serial.begin(9600);
pinMode(2, INPUT);
pinMode(3, INPUT);
pinMode(wLed, OUTPUT);
pinMode(gLed, OUTPUT);
pinMode(yLed, OUTPUT);
pinMode(rLed, OUTPUT);
pinMode(bLed, OUTPUT);
starttime = millis();
lcd.begin(16, 2);
}
void loop() {
duration1 = pulseIn(pin1, LOW);
duration2 = pulseIn(pin2, LOW);
lowpulseoccupancy1 += duration1;
lowpulseoccupancy2 += duration2;
if ((millis() - starttime) > sampletime_ms) {
ratio1 = lowpulseoccupancy1 / (sampletime_ms * 10.0);
concentration1 = 1.1 * pow(ratio1, 3) - 3.8 * pow(ratio1, 2) + 520 * ratio1 + 0.62;
ratio2 = lowpulseoccupancy2 / (sampletime_ms * 10.0);
concentration2 = 1.1 * pow(ratio2, 3) - 3.8 * pow(ratio2, 2) + 520 * ratio2 + 0.62;
lcd.setCursor(0, 0);
lcd.print("PM10 ");
lcd.setCursor(6, 0);
lcd.print(concentration1, 3);
Serial.print("concentration1 = ");
Serial.print(concentration1);
Serial.print(" pcs/0.01cf - ");
Serial.print("concentration2 = ");
Serial.print(concentration2);
Serial.println(" pcs/0.01cf - ");
// LCD 2번째 줄 초기화
lcd.setCursor(0, 1);
for (int i = 0; i < 16; ++i) lcd.write(' ');
// 공기질 등급 판별 및 LED 제어
if (concentration1 < 1000) {
lcd.setCursor(4, 1); lcd.print("CLEAN");
setLED(wLed);
} else if (concentration1 < 10000) {
lcd.setCursor(4, 1); lcd.print("GOOD");
setLED(gLed);
} else if (concentration1 < 20000) {
lcd.setCursor(4, 1); lcd.print("ACCEPTABLE");
setLED(yLed);
} else if (concentration1 < 50000) {
lcd.setCursor(4, 1); lcd.print("HEAVY");
setLED(rLed);
} else {
lcd.setCursor(4, 1); lcd.print("HAZARD");
setLED(bLed);
}
lowpulseoccupancy1 = 0;
lowpulseoccupancy2 = 0;
starttime = millis();
}
}
void setLED(int activePin) {
digitalWrite(wLed, activePin == wLed);
digitalWrite(gLed, activePin == gLed);
digitalWrite(yLed, activePin == yLed);
digitalWrite(rLed, activePin == rLed);
digitalWrite(bLed, activePin == bLed);
}
회로도
프로젝트 페이지의 'Schematics' 섹션에서 전체 회로도 이미지를 확인할 수 있습니다.