습도가 20초과이면 서보모터가 열림
미만이면 닫힘 상태로 작동하고, 시리얼 모니터에 현재 창문이 열렸는지와 온/습도 출력 프로그램.
9번(SG90),2번(DHT11)핀 사용
#include <Servo.h>
#include <DHT.h>
// [핀 설정]
#define DHTPIN 2 // DHT11 데이터 핀
#define DHTTYPE DHT11 // 센서 타입 설정
#define SERVO_PIN 9 // 서보 모터 핀
// [객체 생성]
DHT dht(DHTPIN, DHTTYPE);
Servo myServo;
// [상태 관리 변수]
unsigned long lastSensorRead = 0;
const unsigned long interval = 2000; // 2초 간격
void setup() {
Serial.begin(9600);
dht.begin();
myServo.attach(SERVO_PIN);
myServo.write(0); // 초기 상태: 닫힘
Serial.println("--- Arduino Intelligent Window System Start ---");
}
void loop() {
// [논블로킹 타이머] millis()를 사용해 2초마다 실행
unsigned long currentMillis = millis();
if (currentMillis - lastSensorRead >= interval) {
lastSensorRead = currentMillis;
// 데이터 읽기
float hum = dht.readHumidity();
float temp = dht.readTemperature();
// 센서 오류 체크
if (isnan(hum) || isnan(temp)) {
Serial.println("Failed to read from DHT sensor!");
return;
}
// 시리얼 모니터 출력
Serial.print("Temp: "); Serial.print(temp);
Serial.print("C, Hum: "); Serial.print(hum);
Serial.print("% | Window: ");
// --- 히스테리시스 제어 로직 ---
if (hum > 20) {
myServo.write(90); // 90도로 이동
Serial.println("OPEN");
}
else if (hum < 20) {
myServo.write(0); // 0도로 이동
Serial.println("CLOSED");
}
// 이전 각도 유지
else {
Serial.println("KEEPING STATE");
}
}
// 루프가 멈추지 않으므로 여기에 다른 실시간 코드 추가 가능!
}
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "UART0.h" // 기존에 사용하던 UART 라이브러리 포함
// [핀 정의]
#define DHT11_PIN PD2 // DHT11 데이터 (디지털 2번)
#define SERVO_PIN PB1 // SG90 신호 (디지털 9번)
// [서보 각도 설정]
#define WINDOW_OPEN 3000 // 90도 (약 1.5ms)
#define WINDOW_CLOSE 1000 // 0도 (약 0.5ms)
volatile uint32_t ms_ticks = 0;
// --- [1] Timer 0: 1ms 시스템 틱 (논블로킹 시간 측정) ---
void Timer0_Init(void) {
TCCR0A = (1 << WGM01); // CTC 모드
TCCR0B = (1 << CS01) | (1 << CS00); // 분주비 64
OCR0A = 249;
TIMSK0 |= (1 << OCIE0A);
}
// --- [2] Timer 1: 서보 하드웨어 PWM ---
void Timer1_Init(void) {
DDRB |= (1 << SERVO_PIN);
TCCR1A = (1 << COM1A1) | (1 << WGM11);
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11);
ICR1 = 39999;
OCR1A = WINDOW_CLOSE;
}
// --- [3] DHT11: 직접 제어 함수 ---
uint8_t DHT11_read_byte(void) {
uint8_t result = 0;
for (int i = 0; i < 8; i++) {
while (!(PIND & (1 << DHT11_PIN)));
_delay_us(30);
if (PIND & (1 << DHT11_PIN)) result |= (1 << (7 - i));
while (PIND & (1 << DHT11_PIN));
}
return result;
}
int8_t DHT11_get_data(uint8_t *h, uint8_t *t) {
uint8_t data[5];
DDRD |= (1 << DHT11_PIN);
PORTD &= ~(1 << DHT11_PIN);
_delay_ms(18);
PORTD |= (1 << DHT11_PIN);
_delay_us(30);
DDRD &= ~(1 << DHT11_PIN);
_delay_us(40);
if (PIND & (1 << DHT11_PIN)) return -1;
_delay_us(80);
if (!(PIND & (1 << DHT11_PIN))) return -1;
_delay_us(80);
for (int i = 0; i < 5; i++) data[i] = DHT11_read_byte();
if (data[4] == (data[0] + data[1] + data[2] + data[3])) {
*h = data[0];
*t = data[2];
return 0;
}
return -2;
}
ISR(TIMER0_COMPA_vect) {
ms_ticks++;
}
// --- [4] 메인 루프 ---
int main(void) {
Timer0_Init();
Timer1_Init();
UART0_init(); // UART 초기화 (9600bps 가정)
sei();
uint8_t hum = 0, temp = 0;
uint32_t last_sensor_read = 0;
UART0_print_string("--- Intelligent Ventilation System Start ---\r\n");
while (1) {
// [논블로킹] 2초마다 센서 감시 및 시리얼 출력
if (ms_ticks - last_sensor_read >= 2000) {
last_sensor_read = ms_ticks;
if (DHT11_get_data(&hum, &temp) == 0) {
// 1. 시리얼 모니터로 현재 상태 전송
UART0_print_string("Temp: ");
UART0_print_1_byte_number(temp);
UART0_print_string("C, Hum: ");
UART0_print_1_byte_number(hum);
UART0_print_string("% | Window: ");
// 2. 히스테리시스 제어 로직 및 창문 상태 출력
if ( hum > 20) {
OCR1A = WINDOW_OPEN;
UART0_print_string("OPEN\r\n");
}
else if (hum < 20) {
OCR1A = WINDOW_CLOSE;
UART0_print_string("CLOSED\r\n");
}
else {
UART0_print_string("KEEPING STATE\r\n");
}
} else {
UART0_print_string("Sensor Read Error!\r\n");
}
}
// 메인 루프는 계속 회전하므로 다른 실시간 작업 추가 가능
}
}
#include "UART0.h"
void UART0_init(void)
{
UBRR0H = 0x00;
UBRR0L = 207; // 9,600 보율 설정
UCSR0A |= _BV(U2X0); // 2배속 모드
UCSR0C = 0x06; // 비동기, 8비트 데이터, 패리티 없음, 1비트 정지 비트
UCSR0B |= _BV(RXEN0); // 수신 가능
UCSR0B |= _BV(TXEN0); // 송신 가능
}
void UART0_transmit(char data)
{
while(!(UCSR0A & (1<<UDRE0))); // 송신 대기
UDR0 = data;
}
unsigned char UART0_receive(void)
{
while(!(UCSR0A & (1<<RXC0))); // 수신 대기
return UDR0;
}
void UART0_print_string(char *str)
{
for(int i = 0; str[i]; i++)
UART0_transmit(str[i]);
}
void UART0_print_1_byte_number(uint8_t n)
{
char numString[4] = "0";
int i, index = 0;
if(n > 0) {
for(i = 0; n != 0; i++) {
numString[i] = n % 10 + '0';
n = n / 10;
}
numString[i] = '\0';
index = i - 1;
}
for(i = index; i >= 0; i--)
UART0_transmit(numString[i]);
}
#ifndef UART0_H_
#define UART0_H_
#include <avr/io.h>
void UART0_init(void);
void UART0_transmit(char data);
unsigned char UART1_receive(void);
void UART0_print_string(char *str);
void UART0_print_1_byte_number(uint8_t n);
#endif /* UART0_H_ */