공부/기초설계

온습도 + 미세먼지 (4)

오비루 2021. 11. 20. 16:05
728x90
728x90

드디어 처음 계획하였던 버튼을 누를시 센서 측정값을 무선으로 받아 lcd 스텝모터(온도) led(미세먼지 농도)로 출력하기를 완성하였다.

온도값으로 표현하려는 캐릭터 수는 8가지이지만 현재는 외관이 미완성 상태라 단순하게 90,180,270,360 회전으로 표현하였다.

//마스터(수신부) 버튼누르고 온도값을 lcd에 출력하고 값에 따라 스텝모터 동작하는곳.

#include <Wire.h>
#include <hd44780.h>
#include <HD44780ioClass/hd44780_I2Cexp.h>//lcd 라이브러리
#include <SoftwareSerial.h>
#include <Stepper.h> //스텝모터 라이브러리 불러옴
#define SW 5 //스위치 핀
#define LED 4
#include <Emotion.h> //특수 문자 라이브러리
#define GREEN 8
#define YELLOW 7
#define RED 6       //미세먼지 측정 led 핀

hd44780_I2Cexp lcd; //LCD 객체
SoftwareSerial BTSerial(2,3); //블루투스의 Tx, Rx핀을 2번 3번핀으로 설정

int steps = 2048; // 한바퀴에 해당하는 값 선언
Stepper stepper(steps, 12, 10, 11, 9);
int step_count = 0; //스텝모터 동작 여부 판단을 위한 카운트

//문자열 받아들이는 변수
String sData = "";
String sTemp = "";
String sHumi = "";
String sCopy = "";
String sDust = "";
char cData, cTemp, cHumi, cDust; //데이터 저장변수, 온도 저장변수, 습도 저장변수, 먼지 저장변수
int index_h = 0, index_t = 0, index_u, sCount = 0;

int hum;//정수 습도값
float tem;//실수 온도값
float dus;//실수 미세먼지값

void setup() {
  Serial.begin(9600);
  Serial.println("Received OK!");
  BTSerial.begin(9600);  
  pinMode(SW, INPUT);
  pinMode(LED, OUTPUT);
  pinMode(GREEN, OUTPUT);
  pinMode(YELLOW, OUTPUT);
  pinMode(RED, OUTPUT);
  Wire.begin();
  lcd.begin(16,2);
  stepper.setSpeed(10);
  // rpm : 1분당 도는 횟수, 너무 큰값을 하면 안돌아감. -높을수록 빨라짐-

  lcd.createChar((byte)0, temp);//온도
  lcd.createChar(1, humi);//습도
  lcd.createChar(2, ug1);//먼지(마이크로)
  lcd.createChar(3, C);//온도
  lcd.createChar(4, ug2);//^3 (3승)
  
}

void loop() {
      if(BTSerial.available()){//블루투스에서 넘어온 데이터가 있다면
    
    //온습도 값 받아들여서 시리얼 모니터에 출력하는 함수들
      sData = BTSerial.readString();
      //Serial.println("sData = "+String(sData)); //문자열을 읽어들여 데이터 값에 저장후 문자열로 출력
      sCopy = sData;//데이터 값을 copy변수로 저장

      //습도 파트
      index_h = sCopy.indexOf('h');//h문자를 찾아내기
      //Serial.println("index_h = "+(String)index_h); //몇번째에 위치한지 찾아내기

      if(index_h != -1){//습도주소에 오류가 없다면
        sHumi = sCopy.substring(0, index_h);//substring(from,to) 0~문자가 있는 부분까지 sHumi 변수에 저장
        //Serial.println(sHumi);
        sCopy = sCopy.substring(index_h + 1);//sCopy에 h주소값에 1을 더해주어 다음 주소값이 나오도록 변수저장(shift)
      }

      //온도 파트      
      index_t = sCopy.indexOf('t');//t문자 찾아내기
      //Serial.println("index_t= "+(String)index_t);//위치 출력
      
      if(index_t != -1){//t주소에 오류 없다면
        sTemp = sCopy.substring(0, index_t);
        //Serial.println(sTemp);
        sCopy = sCopy.substring(index_t + 1);//sCopy에 t주소값에 1을 더해 새로이 주소저장(shift)
      }

      //미세먼지 파트
      index_u = sCopy.indexOf('u');//u문자 찾아내기
      //Serial.println("index_u= "+(String)index_u);//위치 출력
      
      if(index_u != -1){//t주소에 오류 없다면
        sDust = sCopy.substring(0, index_u);
        //Serial.println(sDust);
        sCopy = sCopy.substring(index_u + 1);//sCopy에 u주소값에 1을 더해 새로이 주소저장(shift)
      }

      //오류 검토
      if((index_h == -1) && (index_t == -1) && (index_u == -1)){//오류가 있다면 finished출력
      Serial.println("sCopy = "+(String)sCopy);
      Serial.println("Finished..");
      }        
  }
  
    u8 key = digitalRead(SW); //버튼 값 읽어 key 변수에 저장
    
  if(key == HIGH){//스위치가 눌렸을때
    
      BTSerial.write('1');//버튼을 누르면 블루투스를 통해 1 이라는 데이터값을 전송
      digitalWrite(LED, HIGH);//버튼을 눌렀다는 것을 확인하기 위한 led on

      
      //습도와 온도, 미세먼지 문자열을 실수값으로 변환
      hum = sHumi.toFloat();
      tem = sTemp.toFloat();
      dus = sDust.toFloat();  
    
      lcd.backlight(); //LCD 백라이트 켜짐
      lcd.clear(); //LCD 출력내용 지우기
      lcd.setCursor(0,0);
      //온도값 lcd
      lcd.write((byte)0);
      lcd.print(" ");
      lcd.print(tem,1);
      lcd.write(3);
      //습도값 lcd
      lcd.print(" ");
      lcd.write(1);
      lcd.print(" ");
      lcd.print(hum);
      lcd.print("%");
      //미세먼지값 lcd
      lcd.setCursor(0,1);
      lcd.print("Dust:");
      lcd.print(dus,1);
      lcd.write(2); //특수문자 마이크로 출력
      lcd.print("g/m");
      lcd.write(4); //특수문자 3승 출력
        
      Serial.println("현재 온습도와 미세먼지는");

      Serial.println("Huminity = "+(String)sHumi+"%");
      Serial.println("Temperature = "+(String)sTemp+"'C");//온도와 습도 출력
      Serial.println("dust = "+(String)sDust+"ug");//미세먼지 출력

      if(26<= tem && tem <= 27 && step_count == 0){ // 26~27 도 + 스텝 카운트가 0 일때에는 1번 구역
        stepper.step(steps/360 * 90); //1번구역
        step_count = 1;//스텝 카운트 1번으로 구역화 만들어둠
        Serial.println("1번구역");
      }
      else if(tem <= 25 && step_count == 0){ // 25도 이하 + 스텝 카운트 0 일때 2번 구역
        stepper.step(steps/360 * 180);//2번 구역
        step_count = 2;//이하 동문
        Serial.println("2번구역");
      }
      else if(27 < tem && tem <= 30 && step_count == 0){ // 27~30 + 스텝 카운트 0일때 3번 구역
        stepper.step(steps/360 * 270);//3번 구역
        step_count = 3;
        Serial.println("3번구역");
      }
      else if(tem > 30 && step_count == 0){ // 30도 초과 + 스텝 카운트 0일때 4번 구역
        stepper.step(steps);
        step_count = 4;
        Serial.println("4번구역");
      }

      else{
        stepper.step(0);// 이외의 경우 스텝 모터는 구동하지 않는다.
      }

      
      //센서가 측정하지 못할 경우 측정 종료
      if(isnan(hum)||isnan(tem)){
        Serial.print("Failed to read from DHT sensor!");
        return;
      }

      //미세먼지 값 비교
      
      if(dus <= 80){
        digitalWrite(GREEN, HIGH);
        digitalWrite(YELLOW, LOW);
        digitalWrite(RED, LOW);
        Serial.println("미세먼지가 보통입니다");
      }
      else if(80< dus && dus <= 150){
        digitalWrite(GREEN, LOW);
        digitalWrite(YELLOW, HIGH);
        digitalWrite(RED, LOW);
        Serial.println("미세먼지가 나쁨입니다");
      }
      else if(150< dus){
        digitalWrite(GREEN, LOW);
        digitalWrite(YELLOW, LOW);
        digitalWrite(RED, HIGH);
        Serial.println("미세먼지가 매우나쁨입니다");
      }
      delay(300); 
      }

  else{//스위치가 low 일때
    
     Serial.println("none signal");
     
     lcd.noBacklight();//LCD 백라이트 꺼짐
     
     if(step_count == 1){
      stepper.step(-steps/360 * 90); //1번구역 + 이동한 만큼 역회전 , 이하동문
      step_count = 0;//스텝 카운트 변수를 버튼을 뗀 상태일때 초기화 해준다. 이하 동문
      Serial.println("스텝모터 초기화");
      }
      
     else if(step_count == 2){
      stepper.step(-steps/360 * 180); //2번구역
      step_count = 0;
      Serial.println("스텝모터 초기화");
      }
      
     else if(step_count == 3){
      stepper.step(-steps/360 * 270); //3번구역
      step_count = 0;
      Serial.println("스텝모터 초기화");
      }
      
     else if(step_count == 4){ //4번 구역
        stepper.step(-steps);
        step_count = 0;
        Serial.println("스텝모터 초기화");
      }
      
     else stepper.step(0);//이외의 경우는 스텝모터 작동하지 않는다.
      
     digitalWrite(LED, LOW);//불끄기
     //미세먼지 불끄기    
     digitalWrite(GREEN, LOW);
     digitalWrite(YELLOW, LOW);
     digitalWrite(RED, LOW);

     BTSerial.write('0');//0이란 데이터를 전송하여 측정을 멈추기
     delay(300);
  }
}

 

이전 코드값에서 미세먼지 부분을 추가하고, lcd에 이모티콘으로 온,습도 표현이 가능하도록 하였다.

 

자세한 내용들은 주석을 통해 설명을 해두었으나 간략히 다시 설명하자면

버튼을 동작하면 슬레이브에서 해당 신호를 감지하기 위한 데이터 신호를 보낸다. 그리고 마스터 측은 동작 유무가 가능한 led가 켜지며 센서로부터 받아들인 신호를 실수화하는 과정을 거친다.

실수화 한 값들을 각 온습도, 미세먼지 변수에 저장하고 상황에 맞는 출력을 lcd와 서보모터, led로 보내 동작 후 버튼을 떼어준다. 그럼 초기 상태로 복귀해 동작 유무 확인을 위한 led가 꺼진다.

 

 

320x100

 

 

//슬레이브(송신부) 온습도값 측정하는 곳

#include <SoftwareSerial.h>
#include <DHT.h>
#include <DHT_U.h>
#define DHTPIN 4
#define DHTTYPE DHT11
#define LED 11

unsigned long pulse = 0;
float ugm3 = 0;
int GP2Y1023 = 8;

DHT dht(DHTPIN, DHTTYPE);

SoftwareSerial BTSerial(2,3); // RX, TX

int BTstates=0; //블루투스 신호 상태 저장용 변수

void setup() {
  Serial.begin(9600);
  BTSerial.begin(9600);
  Serial.println("Read sensor");
  Serial.println("Transmit OK!");
  pinMode(LED, OUTPUT);
  dht.begin();//온습도 센서 작동
  pinMode(GP2Y1023,INPUT);//미세먼지 
  
}

//미세먼지 측정 함수
float pulse2ugm3(unsigned long pulse){
  float value = (pulse - 1350)/14.0;
  if(value > 300){
    value = 0;
  }
  return value;
}

void loop() {

  if(BTSerial.available()){//블루투스에서 넘어온 데이터가 있다면
    char str = BTSerial.read();
    if(str == '1'){//1 이라는 데이터 값이 들어오면
      digitalWrite(LED, HIGH); //불이 켜짐
      
      float humi = dht.readHumidity(); //습도 측정
  
      Serial.print(humi);
      Serial.print("h");
      BTSerial.print(humi);
      BTSerial.print("h");

      float temp = dht.readTemperature(); //온도 측정  
     
      Serial.print(temp);
      Serial.print("t");
      BTSerial.print(temp);
      BTSerial.print("t");

      //미세먼지 측정
      pulse = pulseIn(GP2Y1023,LOW,20000);
      ugm3 = pulse2ugm3(pulse);
      if(ugm3>0.1){
        Serial.print(ugm3,2);
        Serial.println("u");
        BTSerial.print(ugm3,2);
        BTSerial.println("u");
      }
    
    delay(300);
    }

    else {//1 외의 데이터가 들어오면
      digitalWrite(LED, LOW); //불이 꺼짐
    }
  }
}

 

 

다음은 슬레이브 코드이다.

이것도 마찬가지로 이전의 코드에서 미세먼지 부분만 추가하였다.

앞서 마스터에서 설명한 데이터 신호중 '1'이라는 데이터 신호가 들어오면 동작 확인을 위한 led가 켜지고, 그 외의 신호가 들어오면 동작이 끝났음을 알리기 위해 led가 꺼지게 된다.

 

 

 

작동 영상

 

 

 

초기에는 단순하게 미세먼지, 온습도 측정만 하는 프로젝트를 진행할 계획이었으나, 측정파트 & 동작파트 나누어서 하는것이 효율적이라는 의견들이 나와 무선센서 HC-06을 추가하게 되었다.

지금와서 생각해보면 어렵지않은 코드이지만 워낙 원하는 정보들이 한정적으로 있어 어디부터 시작해야하는지 감을 잡지 못했던 것 같다. 그래도 당황하지않고 차근차근 해야할 과제의 순서를 정해 벽돌 쌓아 올리듯 코드를 쌓아보았다. 그러다 어느사이 원하던 코드에 근접해 가고 있음을 느낄 즈음엔 처음 과제를 시작했던 순간에 비해 많이 성장한 것을 알게 되었다.

학교수업과 아르바이트 등을 병행하면서 과연 진행할수 있을까? 싶었지만, 시간을 틈틈히내 나름 여유있게 코딩을 마무리 짓게되어 뿌듯(?)한 마음이 든다. 

무엇보다 이번 프로젝트를 진행하며 가장 깊게 느낀 부분은 최종 목표에 도달하기 위해서는 요령따위는 없다는거다.

해당 목표로 가기위해서는 그 전에 수행해야할 과제들이 있고 이전 과제들을 충실히 수행하였다면 앞으로 있을 다음 과제에 많은 도움이 될 수 있다. 그리고 이런 과제들을 꾸준히 해나가는 성실함(?)이 매우 중요함을 마음속에 새겨넣었다.

 

이만 글을 줄이며, 다음 프로젝트 글은 최종 완성본으로 돌아오겠다.

728x90
반응형

'공부 > 기초설계' 카테고리의 다른 글

온습도 + 미세먼지 (최종)  (0) 2021.12.22
온습도 + 미세먼지 (3)  (0) 2021.11.18
온습도+미세먼지 (2)  (0) 2021.11.16
온습도 + 미세먼지 측정을 캐릭터 표현(1)  (0) 2021.11.09