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 디스플레이에 생소하신 분들께서는 아래 두개의 포스팅을 먼저 보시면 내용 이해에 많은 도움이 되실 것 같습니다. (제가 글빨이 딸리기때문에 설명이 매끄럽지 못해요...)
준비물
- 아두이노 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앱은 정말 간단한 작업만 가능한 수준입니다. 불편해서 못써요.) 무료프로그램인데다가 정말 목적에 딱 맞게 만들어져 있어서 작업하는 과정을 영상으로 남겨두었습니다.
아무거나 편한 툴을 이용해서 이런 배경을 만들어 줍니다.
그리고 아래 Picture 부분에서 "+"버튼을 눌러서 만들어둔 그림을 불러옵니다. 그림을 불러오실때 주의할 점이 있습니다. 본인이 사용하고자 하는 Nextion 디스플레이의 화명 해상도에 맞게 그림을 조절해 주셔야 합니다. 그렇지 않으면 그림이 잘리거나 여백이 생깁니다. 배경도 역시 0번으로 등록이 됩니다.
HMI 개체 배치
이제 다음과 같이 Toolbox 의 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
마무리
업로드가 완료되고 문제가 없다면 미세먼지 농도, 온도, 습도가 지속적으로 화면에 표시가 됩니다. 참 간단하죠?
이제 최대한 작게 패키징을 해서 온전한 디바이스로 만들어서 들고다닐 수 있도록 만들 계획인데 언제 완성이 될지는 모르겠습니다. ^^
역시 제 글에 관심을 가져 주셔서 감사합니다.
끝!
'Hardware > MCU(Arduino,ESP8266)' 카테고리의 다른 글
아두이노 나노(Arduino nano) 기본사양 (2) | 2019.04.04 |
---|---|
FT232RL USB to UART 드라이버 설치 (4) | 2019.03.30 |
Nextion LCD 사용기, Arduino SoftwareSerial로 연결해서 온습도(DHT22)측정 및 LED컨트롤 (60) | 2019.03.20 |
새로운 Fritzing 부품 만들기 - Nextion Display for Fritzing (9) | 2019.03.15 |
댓글