본문 바로가기
Hardware/MCU(Arduino,ESP8266)

아두이노 공기질 감시기 만들기 (PMS7003 미세먼지 센서, Nextion LCD를 동시에 Softwareserial 2개로 연결)

by lovey25 2019. 3. 29.

2020-06-20 update log: Nextion LCD를 softwareSerial로 연결하기위해 필요한 설정에 대해서 설명이 생략된 부분이 있어서 보완했습니다.


아두이노 프로젝트 - 미세먼지 측정기 및 온습도계 만들기 (feat. by multiple Softwareserial of Arduino)

아두이노를 활용한 공기질 감시기(미세먼지 측정기 + 온습도계)를 만들어 봤습니다. 저는 미세먼지에 민감한 편인 한사람으로써 미세먼지 관련 프로젝트를 진행하고 있습니다. 가지고 다니면서 온습도 및 미세먼지를 측정할 수 있는 그런 장치를 만들려고 합니다.

이번 포스팅은 그 첫번째 단계로 기능구현을 해보는 그런 작업입니다.

최종 결과물을 먼저 보여드리면 이렇습니다. 미세먼지를 PM1, PM2.5, PM10 3가지에 대한 농도와 온도, 습도를 측정해서 실시간으로 보여주고 일정시간동안의 변화량을 그래프로 보여주는 그런 감지기 되겠습니다. 컨트롤러는 아두이노 우노이고 미세먼지를 측정하기위해서 PMS7003센서, 온습도는 DHT22센서를 사용했습니다. 그리고 결과값을 비~주얼하게 보기위해서 2.4인치 LCD인 Nextion 디스플레이를 사용하였습니다. 자세한 내용은 아래 글 봐주세요. ^^

미세먼지 농도, 온도, 습도 측정중

이번 프로젝트에서는 이전에 작성했던 두개의 포스팅 내용을 짬뽕을 해서 사용하는 그런 프로젝트 되겠습니다. 그래서 관심이 있으신 분들이나 PMS센서나 Nextion 디스플레이에 생소하신 분들께서는 아래 두개의 포스팅을 먼저 보시면 내용 이해에 많은 도움이 되실 것 같습니다. (제가 글빨이 딸리기때문에 설명이 매끄럽지 못해요...)

 

아두이노 미세먼지 측정기 만들기 (PMS7003센서 사용기)

개요 미세먼지 농도를 측정하는 아두이노 프로젝트입니다. 제법 정밀한 센서로 알려져 있는 PMS7003센서를 사용하고 아두이노를 이용해서 센서를 동작하고 데이터를 확인하도록 하겠습니다. 준비물 PMS7003 센서..

kwonkyo.tistory.com

 

Nextion LCD 사용기, Arduino SoftwareSerial로 연결해서 온습도(DHT22)측정 및 LED컨트롤

1.개요 그동안 컴퓨터 시리얼을 연결하지 않고 아두이노에서 독립적으로 동작하는 프로젝트는 IIC방식의 1602 LCD를 사용해서 작동상태를 확인하였습니다. 센서값을 확인하거나 간단히 동작상태를 모니터링 하는..

kwonkyo.tistory.com

준비물

  • 아두이노 Uno R3
  • PMS7003센서
  • DHT22센서
  • Nextion 디스플레이
  • 전원용 USB컨넥터
  • 빵판
  • 점프케이블 종류별 

회로구성(연결도)

Nextion 디스플레이 GUI 디자인

이제부터는 본격적으로 소프트웨어 작업이 들어가는 단계입니다. 먼저 Nextion 디스플레이의 GUI화면 디자인입니다.

Nextion이라는 제품을 처음 접하시는 분들은 제가 글 앞부분에서 언급했던 이전 포스팅 2개중 "Nextion LCD 사용기"를 보시면 쉽게 이해 하실 수 있으실텐데요. 복잡한 코딩작업 없이 아주 간단하게 GUI의 HMI를 꾸밀 수 있는 그런 제품입니다. 자체적으로 제공하는 Nextion Editor라는 프로그램을 이용해서 GUI를 만들어 보고 GUI를 디스플레이에 업로드 해서 사용할 준비를 해보도록 하겠습니다.

먼저 Nextion Editor를 실행을 해주고 먼저 글꼴과 배경을 지정합니다.

글꼴

"Tools >> Font Generator"에서 다음과 같이 글꼴을 만들어 줍니다. 그러면 0번 폰트로 등록됩니다.

GUI 배경이미지

배경으로 사용할 이미지를 만들어야 하는데요. 이미지를 만드는 방법은 여러가지가 있겠습니다만 저는 Adobe Comp라는 아이패드 앱을 사용하였습니다. 이번에 처음 접한 앱인데 정말 대단한 프로그램이었습니다. 이런 이미지를 작업하기위해서는 평소에는 PPT를 사용하는데요 이날은 PC를 사용하지 못하는 상황이어서 어플중에 뭐 쓸만한거 있나 찾아보다가 발견한 앱입니다. (iPad에서 PPT를 사용하면 되지 않냐라고 말씀하시는 분이 계실지도 모르겠는데 iPad앱은 정말 간단한 작업만 가능한 수준입니다. 불편해서 못써요.) 무료프로그램인데다가 정말 목적에 딱 맞게 만들어져 있어서 작업하는 과정을 영상으로 남겨두었습니다.

아무거나 편한 툴을 이용해서 이런 배경을 만들어 줍니다.

PMS_and_DHT_BG.png
0.01MB

그리고 아래 Picture 부분에서 "+"버튼을 눌러서 만들어둔 그림을 불러옵니다. 그림을 불러오실때 주의할 점이 있습니다. 본인이 사용하고자 하는 Nextion 디스플레이의 화명 해상도에 맞게 그림을 조절해 주셔야 합니다. 그렇지 않으면 그림이 잘리거나 여백이 생깁니다. 배경도 역시 0번으로 등록이 됩니다.

HMI 개체 배치

이제 다음과 같이 Toolbox 의 HMI 아이템들을 배치해 줍니다.

HMI 배치

사용한 툴은 "Text"와 "Waveform"두가지 입니다. 각각을 위의 그림과 같이 배치를 합니다.

배치가 끝났으면 아래표와 같이 속성을 지정해 줍니다. 각 부분을 클릭해서 오른쪽에 "Attribute"창에 해당하는 설정값을 입력해 주면 됩니다. 빈칸인 부분은 해당사항이 없는 것들 이고 아래 배경은 말그대로 배경에 대한 속성입니다. 배경을 클릭해 주고 입력하면 되겠습니다.

Waveform

구분 배경 1번 2번
ID 0 1 2
objname   sPMS sDHT
dir   left to right left to right
sta image crop image crop image
ch   3 2
pic 0    
pco0   64041 64041
pco1   64936 21597
pco2   21597  

Text

구분 3번 4번 5번 6번 7번
ID 3 4 5 6 7
objname tPM1_0 tPM2_5 tPM10_0 tHumi tTemp
sta crop image crop image crop image crop image crop image
ppic 0 0 0 0 0
poc 64041 64936 21597 21597 64041
font 0 0 0 0 0
xcen Right Right Right Right Right
ycen Down Down Down Down Down
txt 0 0 0 0 0
txt_maxl 10 10 10 10 10

모든 작업이 완료되었으면 컴파일을 하고 컴파일된 파일을 SD카드에 복사해서 Nextion 디스플레이에 업로드 시켜줍니다. 이에대한 상세는 이전 포스팅을 참고해 주세요.

아두이노 코딩(펌웨어)

드디어 마지막 단계까지 왔습니다. 이 모든 과정을 글로 남겨두려니 정리하는게 시간도 더 걸리고 힘드도네요. 아무튼 마지막입니다.

아두이노는 시리얼포트가 1개 뿐입니다. 그런데 이번 프로젝트에서 사용한 PMS7003센서나 Nextion 디스플레이가 모두 UART통신으로 작동을 하는 아이들이기 때무에 시리얼 포트를 사용해야 합니다. 그러니 소프트웨어시리얼을 사용할 수 밖에 없는데요. 그리고 디버깅도 해야하고 펌웨어도 계속 올리고내리고 반복적으로 작업이 필요하기 때문에 시리얼 포트를 센서연결로 그냥 넘겨주기 아깝습니다. 그래서 전 처음으로 소프트웨어시리얼 2개을 같이 사용하는 방식을 시도해 봤습니다. 

아래 코드를 아두이노에 업로드 해 줍니다. 코드에 대한 상세 설명은 역시 최대한 자세히 주석을 달려고 노력했으니 주석으로 대신하겠습니다.

/*
 Name:		PMS_Monitor_wt_Nextion.ino
 Created:	2019-03-11 오후 9:34:06
 Author:	kwonkyo@tistory.com
  PMS7003 센서를 사용한 미세먼지 측정기 펌웨어입니다.
  측정된 농도값은 Nextion LCD에 표시되도록 하고, 
  PMS센서와 Nextion은 모두 소프트웨어시리얼로 연결합니다.
*/

#include <SoftwareSerial.h>		// 소프트웨어시리얼 사용을 위한 헤더
#include <Nextion.h>			// Nextion LCD용 라이브러리
#include <PMS.h>				// PMS센서용 라이브러리
#include <DHT.h>				// DHT22 센서용 라이브러리

// DHT22 센서 초기화
#define DHTPIN 2			// DHT센서값을 받을 디지털핀
#define DHTTYPE DHT22		// 사용할 센서타입을 DHT22 로 지정
DHT dht(DHTPIN, DHTTYPE);	// 센서 객체 생성

// PMS7003센서 통신용 소프트웨어시리얼
#define PMS_TX 3								// Tx: D3
#define PMS_RX 4								// Rx: D4
SoftwareSerial SerialForPMS(PMS_RX, PMS_TX);	// 소프트웨어시리얼포트 지정
PMS pms(SerialForPMS);							// PMS센서통신포트로 지정

PMS::DATA data;

// Nextion 통신용 소프트웨어시리얼
#define NEX_TX 7								// Tx: D7
#define NEX_RX 6								// Rx: D6
SoftwareSerial SerialForNex(NEX_RX, NEX_TX);	// 스프트웨어시리얼포트 지정

// Nextion 화면개체 선언 - (page id = 0, component id = 1, component name = "b0") 
/// 미세먼지 농도를 표시할 텍스트와 그래프
NexText tPM1_0 = NexText(0, 3, "tPM1_0");
NexText tPM2_5 = NexText(0, 4, "tPM2_5");
NexText tPM10_0 = NexText(0, 5, "tPM10_0");
NexWaveform sPMS = NexWaveform(0, 1, "sPMS");
/// 온습도를 표시할 텍스트와 그래프
NexText tHumi = NexText(0, 6, "tHumi");
NexText tTemp = NexText(0, 7, "tTemp");
NexWaveform sDHT = NexWaveform(0, 2, "sDHT");

// 미세먼지 농도를 측정하고 Nextion에 표시하기위한 함수
void UpdatePMS() {
	// 변수 선언
	uint16_t number[3] = { 0 };
	char temp[10] = { 0 };
	
	SerialForPMS.listen();							// PMS센서가 연결된 시리얼포트 활성화
	while (Serial.available()) { Serial.read(); }	// 버퍼에 남아있을 어떤 데이터를 미리 삭제
	pms.requestRead();			// PMS센서에 측정요청신호 보내기
	
	// 미세먼지 측정이 되었을 경우 측정값을 Nextion에 표시
	if (pms.readUntil(data))				// 측정값이 저장된 버퍼 읽어오기
	{
		number[0] = data.PM_AE_UG_1_0;		// PM 1.0 (ug/m3)값 읽어서 변수에 저장
		utoa(number[0], temp, 10);			// 정수를 텍스트로 변환
		tPM1_0.setText(temp);				// Nextion에 표시
		number[1] = data.PM_AE_UG_2_5;		// PM 2.5 (ug/m3)값 읽어서 변수에 저장
		utoa(number[1], temp, 10);
		tPM2_5.setText(temp);
		number[2] = data.PM_AE_UG_10_0;		// PM 10.0 (ug/m3)값 읽어서 변수에 저장
		utoa(number[2], temp, 10);
		tPM10_0.setText(temp);

		for (int i = 0; i < 3; i++) {				// waveform 0~2ch 차례대로 data전달
			sPMS.addValue(i, (int)(number[i]/3));	// 그래프 범위: 0~300ug/m3으로 스케일링하고 그래프는 300까지만 표시
		}
	}
}

// 온습도를 측정하고 Nextion에 표시하기위한 함수
void UpdateDHT() {
	float h = dht.readHumidity();		// 습도값 요청
	float t = dht.readTemperature();	// 온도값 요청
	
	SerialForNex.listen();				// Nextion이 연결된 시리얼 포트 활성화

	// 온도나 습도의 측정에 문제가 있으면 즉시 함수종료
	if (isnan(h) || isnan(t)) {
		return;
	}

	static char humidityTemp[6];		// 변수선언
	dtostrf(h, 5, 1, humidityTemp);		// 습도값 텍스트로 변환
	tHumi.setText(humidityTemp);		// Nextion에 습도 표시

	static char temperatureTemp[6];		// 변수선언
	dtostrf(t, 5, 1, temperatureTemp);	// 온도값 텍스트로 변환
	tTemp.setText(temperatureTemp);		// Nextion에 온도 표시

	// waveform 그래프 그리기
	sDHT.addValue(0, (int)h);				// 습도 그래프 범위: 0~100% 스케일링없음
	sDHT.addValue(1, (int)(t*3.3-32));		// 온도 그래프 범위: 10~40degC 스케일링
}

void setup() {
	// 장비 초기화
	/// Nextion 초기화
	nexInit();			// 경우에따라 NexConfig.h의 설정값 수정필요 (Nextion용 BaudRate는 9600)
	/// DHT센서 초기화
	dht.begin();
	/// PMS센서 초기화
	pms.passiveMode();	// 센서측정주기와 아두이노 수신주기가 동기되지 않을 수 있기 때문에 수동모드 사용
	pms.wakeUp();
	
	// 시리얼 포트 열기
	Serial.begin(9600);		// 디버깅용
	SerialForPMS.begin(PMS::BAUD_RATE);	// PMS센서 소프트웨어시리얼 열기	
}

void loop() {
	static uint32_t started = 0;	// 타이머용 변수 선언 및 초기화

	if (millis() - started >= 2000)	// 2초간격으로 측정
	{
		started = millis();			// 타이머기준 리셋
		UpdateDHT();				// 온습도관련 함수 호출
		UpdatePMS();				// 미세먼지관련 함수 호출
	}
}

추가로 Nextion 라이브러리의 설정값이 있는 "NexConfig.h" 파일에서도 Nextion이 SoftwareSerial로 연결되도록 수정합니다. Nextion 라이브러리는 아두이노 메가처럼 하드웨어 시리얼 포트가 여러개가 있는 보드를 기준으로 만들어져 있어서 아두이노 우노에서 사용할 경우 수정이 필요합니다. 

"NexConfig.h" 파일에서 "#define nexSerial Serial2" 라는 부분을 찾아서 다음과 같이 수정합니다.

#include <SoftwareSerial.h>
extern SoftwareSerial SerialForNex;
#define nexSerial SerialForNex

마무리

업로드가 완료되고 문제가 없다면 미세먼지 농도, 온도, 습도가 지속적으로 화면에 표시가 됩니다. 참 간단하죠?

정리가 되지않아 어지럽지만, 완성된 모습임

이제 최대한 작게 패키징을 해서 온전한 디바이스로 만들어서 들고다닐 수 있도록 만들 계획인데 언제 완성이 될지는 모르겠습니다. ^^

역시 제 글에 관심을 가져 주셔서 감사합니다.

끝!

728x90

댓글23

  • 2019.09.17 20:36

    비밀댓글입니다
    답글

    • Favicon of https://kwonkyo.tistory.com BlogIcon lovey25 2019.09.18 15:33 신고

      관심가져주셔서 감사합니다.
      저도 프로그래밍에 대해서는 초보를 면하고 있지 못해서 정확히 조언을 드릴 수 있을지는 잘 모르겠습니다만, 올려주신 에러메시지를 보면 Nextion 디스플레이와 통신을 담당하는 Nextion.h 라이브러리를 IDE에서 제대로 인식하지 못하고 있는것 같습니다. 만약 제가 했던것 처럼 Visual Micro를 IDE로 사용하고 계신다면 글 본문에 언급된 관련된 다른 포스팅도 읽어보시기 바랍니다.
      특히, Nextion디스플레이 사용이 처음이시라면 https://kwonkyo.tistory.com/132 글을 먼저 읽어보시면 도움이 되실겁니다.

  • 007NEVER 2020.03.12 18:32

    센서와 디스플레이 유닛도 같이 사용하셨는데, 허용 전류를 초과해서 아두이노가 리셋되는 현상은 없었나요?
    답글

    • Favicon of https://kwonkyo.tistory.com BlogIcon lovey25 2020.03.12 20:00 신고

      네 회로를 보시면 USB파워에서 아두이노와 디스플레이 각각으로 전원이 들어가고 있어서 아두이노의 허용전류를 초과하지는 않습니다.

  • 2020.05.20 22:33

    비밀댓글입니다
    답글

  • Favicon of https://kwonkyo.tistory.com BlogIcon lovey25 2020.05.21 04:59 신고

    PMS7003입니다
    답글

  • 2020.06.19 00:59

    비밀댓글입니다
    답글

  • 2020.06.19 11:38

    비밀댓글입니다
    답글

    • Favicon of https://kwonkyo.tistory.com BlogIcon lovey25 2020.06.19 11:39 신고

      앞서 답변드린것 처럼 이번에는 pms라이브러리를 인식 못한것 같네요. Nextion 라이브러리 문제는 해결되셨나요? 그렇다면 똑같이 pms라이브러리도 확인해 보세요.

  • 2020.06.20 02:18

    비밀댓글입니다
    답글

    • Favicon of https://kwonkyo.tistory.com BlogIcon lovey25 2020.06.20 04:48 신고

      작성하신 코드가 다른 포스팅에 있던 것들과 좀 짬뽕이 된것 같아요. PMSSerial이라는 키워드는 제가 https://kwonkyo.tistory.com/132 에서만 사용한적 있었더라고요. (여기에서도 PSMSerial이라는 키워드는 이름을 잘못 지었네요. 오해의 소지가 있어서 나중에 내용 수정하도록 하겠습니다.)
      이번 포스팅에서 Nextion을 SoftwareSerial로 연결해서 사용하는데에 중요한 부분이 빠져있어서 내용 추가했습니다. 피드백주셔서 감사합니다.

  • 2020.06.20 14:40

    비밀댓글입니다
    답글

    • Favicon of https://kwonkyo.tistory.com BlogIcon lovey25 2020.06.20 20:11 신고

      저도 경험이 없어서 잘은 모르겠는데 대충 구글링해보니 코딩의 문제보다 하드웨어의 문제일 가능성이 높다고 하네요. 도움을 못드려 죄송해요.

  • 전자공학도 2020.11.14 17:32

    아두이노 시리얼 모니터에는 표시 되는데 파워 없이 넥션에 나타낼 수 있나요?
    답글

    • Favicon of https://kwonkyo.tistory.com BlogIcon lovey25 2020.11.14 19:42 신고

      파워가 넥션 전원말씀이신가요?? 아두이노 전원 같이쓰시면됩니다 5V단자에 연결하셔도 되고요

  • 2020.11.14 20:54

    비밀댓글입니다
    답글