스마트홈/교사연수/1일차

0 오늘 목표

  • 아두이노 스마트홈 교구 전체 윤곽 파악하기

  • 모듈 조립하기

  • 모듈 테스트하기

  • 모듈 통합하기

0-1 스마트홈 개발 세부 절차

아두이노스마트홈개발절차

0-2 아두이노 포트 구성 및 브레드보드 배선

2021년 1월 연수

2020년 9월 연수

01 능동부저와 자동점멸RGB

능동부저? 자동점멸RGB?

능동부저, 수동부저 구별하기 [바로가기]

부저 & 자동점멸RGB 회로 결선

부저 & 자동점멸RGB 소스코드

01ctrlBuzzer.ino

#define buzzPin 4 // 부저 핀번호


void setup() {

pinMode(buzzPin, OUTPUT);

}


void loop() {

//buzzer();

beep(3);

delay(2000);

}


// 부저와 LED 1초 간격으로 동작

void buzzer(){

digitalWrite(buzzPin, HIGH);

delay(1000);

digitalWrite(buzzPin, LOW);

delay(1000);

}


// 비프음 n회 발생

void beep(int n) {

for (int i = 0; i < n; i++) {

digitalWrite(buzzPin, HIGH); // 비프 울림

delay(20);

digitalWrite(buzzPin, LOW); // 비프 꺼짐

if(n>1) delay(30);

}

}

02 온습도 센서(DHT11)

DHT11?

DHT 회로 결선

DHT 라이브러리 설치

DHT 예제 실행 <DHTtester>

DHT 소스 코드

02getDHT.ino

#include <DHT.h>


#define DHTPIN 8 // Digital pin connected to the DHT sensor

#define DHTTYPE DHT11 // DHT 11


DHT dht(DHTPIN, DHTTYPE);


void setup() {

Serial.begin(9600);

Serial.println(F("DHT11 test!"));

dht.begin();

}


void loop() {

getDHT();

}


void getDHT(){

// DHT 측정 간격 2초 필요

delay(2000);


// 온습도 센서는 최대 2초 정도 걸리는 매우 느린 센서

float h = dht.readHumidity(); // 습도 읽기

float t = dht.readTemperature(); // 섭씨(디폴트)온도 읽기


// 읽기 오류면 얼른 나가기(재시도 위해서).

if (isnan(h) || isnan(t)) {

Serial.println(F("Failed to read from DHT sensor!"));

return;

}


Serial.print(F("Humidity: "));

Serial.print(h);

Serial.print(F("% Temperature: "));

Serial.print(t);

Serial.println(F("°C "));


}


03 초음파 거리 센서 (HC-SR04)

초음파 센서 ?

초음파 센서 회로 결선

초음파 센서 소스 코드

소스코드 03getDistance.ino

//http://makeshare.org/bbs/board.php?bo_table=arduinosensor&wr_id=366


#define trigPin 7 // trigPin을 7로 설정합니다.

#define echoPin 6 // echoPin을 6으로 설정합니다.

long duration, distance; // 각 변수를 선언합니다.


void setup() {

Serial.begin (9600); // 시리얼 모니터를 사용하기 위해 보드레이트를 9600으로 설정합니다.

pinMode(trigPin, OUTPUT); // trigPin 핀을 출력핀으로 설정합니다.

pinMode(echoPin, INPUT); // echoPin 핀을 입력핀으로 설정합니다.

}


void loop() {


distance = getDistance(); // 거리값 읽기

Serial.print(distance); Serial.println(" cm"); // distance를 시리얼 모니터에 출력합니다.

delay(500); // 0.5초동안 기다립니다.

}


long getDistance() {

digitalWrite(trigPin, LOW); // trigPin에 LOW를 출력하고

delayMicroseconds(2); // 2 마이크로초가 지나면

digitalWrite(trigPin, HIGH); // trigPin에 HIGH를 출력합니다.

delayMicroseconds(10); // trigPin을 10마이크로초 동안 기다렸다가

digitalWrite(trigPin, LOW); // trigPin에 LOW를 출력합니다.

duration = pulseIn(echoPin, HIGH); // echoPin핀에서 펄스값을 받아옵니다.


/*

trigPin핀에서 초음파를 발사하였고 그 초음파가 다시 돌아 올 때까지 기다립니다.

만약 벽이나 장애물에 닿아서 다시 echoPin으로 돌아왔다면 그동안의 시간을 duration에 저장합니다.

*/

return duration * 17 / 1000; // duration을 연산하여 센싱한 거리값을 distance에 저장합니다.

}



04 RFID (SPI통신, RFID-RC522)

아두이노의 통신: UART, I2C, SPI

UART vs I2C vs SPI 그림출처: icbanq

SPI통신? RFID?

RFID 회로 결선

RFID 라이브러리 설치

RFID 예제 실행 <ReadNUID>

RFID 소스 코드

소스코드 04getRfid.ino


#include <SPI.h>

#include <MFRC522.h>


#define SS_PIN 10

#define RST_PIN 9

MFRC522 rfid(SS_PIN, RST_PIN); // Instance of the class

MFRC522::MIFARE_Key key;


// 등록된 카드 NUID

byte nuidPICC[4]={0x50, 0xF7, 0x0E, 0x30};


void setup() {

Serial.begin(9600);

SPI.begin(); // Init SPI bus

rfid.PCD_Init(); // Init MFRC522

Serial.println(F("This code scan the MIFARE Classsic NUID."));

}

void loop() {

getRfid();

}


void getRfid(){

// 카드를 반복해서 계속 읽지 안도록 빠져나감

if ( ! rfid.PICC_IsNewCardPresent()) return;


// ID가 인식되지 않았다면 더이상 진행하지 말고 빠져나감

if ( ! rfid.PICC_ReadCardSerial()) return;


// 카드 타입 읽기

MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);


// MIFARE 타입이 아니라면 더이상 진행하지 말고 빠져나감

if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI &&

piccType != MFRC522::PICC_TYPE_MIFARE_1K &&

piccType != MFRC522::PICC_TYPE_MIFARE_4K) {

Serial.println(F("Your tag is not of type MIFARE Classic."));

return;

}


// 읽은 ID와 등록된 ID값을 비교

if (rfid.uid.uidByte[0] == nuidPICC[0] ||

rfid.uid.uidByte[1] == nuidPICC[1] ||

rfid.uid.uidByte[2] == nuidPICC[2] ||

rfid.uid.uidByte[3] == nuidPICC[3] ) {

Serial.println(F("This is a confirmed Card."));

}

else {

//등록된 ID가 아니라면 tag 정보 표시

Serial.print(F("Unconfirmed Card: "));

printHex(rfid.uid.uidByte, rfid.uid.size); // 사용자 화면에 부정 tag 정보 출력

Serial.print("\n");

}


// rfid 종료

rfid.PICC_HaltA(); // PICC 종료

rfid.PCD_StopCrypto1(); // 암호화 종료

}



// 카드 tag 출력

void printHex(byte *buffer, byte bufferSize) {

for (byte i = 0; i < bufferSize; i++) {

Serial.print(buffer[i] < 0x10 ? " 0" : " ");

Serial.print(buffer[i], HEX);

}

}


05 OLED 디스플레이(I2C 통신)

I2C통신? OLED?

OLED 회로 결선

OLED 라이브러리 설치

I2C 스캔 예제 실행 - 설치한 OLED의 주소 찾기

OLED 예제 실행 < SSD1306_128x64_12c >

OLED 소스 코드

소스코드 05ctrlOLED.ino

#include <SPI.h>

#include <Wire.h>

#include <Adafruit_GFX.h>

#include <Adafruit_SSD1306.h>


#define SCREEN_WIDTH 128 // OLED 가로 픽셀수

#define SCREEN_HEIGHT 64 // OLED 세로 픽셀수


// I2C OLED 객체 인스턴스 생성

#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)

Adafruit_SSD1306 display(OLED_RESET);

//Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


void setup() {

Serial.begin(9600);

// SSD1306_SWITCHCAPVCC: generate display voltage from 3.3V internally

if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64

Serial.println(F("SSD1306 allocation failed"));

for(;;); // Don't proceed, loop forever

}



}


void loop() {

testdrawstyles(); // 글자 표시(사용자 폰트)

delay(2000);

startOLED(); // SmartHome! 표시

delay(2000);

}



void testdrawstyles(void) {

// 버퍼비우기

display.clearDisplay();

display.setTextSize(1); // Draw 2X-scale text

display.setTextColor(SSD1306_WHITE);

display.setCursor(0, 0);

display.println(F("Line 1"));

display.println(F(" Line 2"));

display.println(F(" Line 3"));

display.println(F("12345678901"));

display.display();

}


void startOLED(void) {

// 버퍼비우기

display.clearDisplay();

display.setTextSize(2); // Draw 2X-scale text

display.setTextColor(SSD1306_WHITE);

display.setCursor(0, 16); // setCursor(열,행)

display.println(F("SmartHome!"));

display.println(F(" ver1.3"));

display.display();

}

06 서보모터 (SG-90)

서보모터? PWM?

서보모터 지터링 현상

서보모터 회로 결선

서보모터 예제 실행 <Sweep>

서보모터 소스 코드

소스코드 06ctrlServo.ino

// 원하는 각도로 이동하여 멈추기


#include <Servo.h>


#define servoPin 5 //서보모터 핀번호


Servo myServo; // 서보모터 객체 생성


void setup() {

servoMove(0);

delay(500);

servoMove(90);

delay(500);

servoMove(175);

delay(500);

}


void loop() {

}


void servoMove(int servoPos){

myServo.attach(servoPin); // 서보모터 연결

myServo.write(servoPos);

delay(500);

myServo.detach(); // 서보모터 분리(떨림 현상 방지)

}

07 릴레이 (2채널)

이 프로젝트는 심각한 부상이나 사망을 초래할 수있는 높은 전압을 사용합니다.

모든 필요한 예방 조치를 취하고 작업하기 전에 회로의 모든 전원을 끄십시오.

릴레이?

릴레이 회로 결선

가. 작업 순서

전원 연결 커넥터 설치 -> 220V 전구 소켓 설치 -> 12V 팬 설치 -> 커넥터-소켓- 팬-2채널 릴레이 배선 연결

나. 220V 전원 연결 커넥터 부착

Tip] 볼트를 조을 때 너트가 헛돌아서 잘 조여지지 않아요.

해결: 커넥트를 위로 당기면서 볼트를 조으면 잘 됩니다.

다. 220V 전구 소켓 부착

Tip] 볼트를 조을 때 너트가 헛돌아서 잘 조여지지 않아요.

해결: 소켓을 위로 당기면서 볼트를 조으면 잘 됩니다.

라. 220V 전구 소켓 전선 연결

마. 220V 전구 소켓과 2채널 릴레이 전선 연결

바. 2채널 릴레이 전원쪽 전선 연결

사. 220V 중간 스위치 전선 연결

아. 12V 어댑터 연결

자. 12V 팬 설치

릴레이 소스 코드

소스코드 07ctrlRelay.ino

#define fanPin A2 // 12Vdc 팬 제어 릴레이 핀번호

#define lampPin A3 // 220Vac 전등 제어 릴레이 핀번호


void setup() {

pinMode(fanPin, OUTPUT);

pinMode(lampPin, OUTPUT);

digitalWrite(fanPin, HIGH); // 팬 끄기(Negative Logic)

digitalWrite(lampPin, HIGH); // 전등 끄기(Negative Logic)

}


void loop() {


}


void testRelay(){

digitalWrite(lampPin, LOW); // 전등 켜기

digitalWrite(fanPin, LOW); // 팬 켜기

delay(2000);

digitalWrite(lampPin, HIGH); // 전등 끄기

digitalWrite(fanPin, HIGH); // 팬 끄기

delay(2000);

}

08 블루투스 (HC-06)

블루투스?

HC-05 vs HC-06 그리고 제품마다 다른 펌웨어...

블루투스 회로 결선

블루투스 예제 실행 <SoftwareSerial>

AT 명령어

겉모습이 같은 HC-06 블루투스 모듈이라도 펌웨어에 따라 AT 명령어 사용법이 서로 다르니 주의.

블루투스 소스 코드

소스코드 08Bluetooth.ino

#include <SoftwareSerial.h>


SoftwareSerial BTSerial(2, 3); // BTSerial(Rx, Tx): Adu-Rx(2)<->BT(Tx), Adu-Tx(3)<->BT(Rx) 연결


void setup() {

Serial.begin(9600);

BTSerial.begin(9600);

Serial.println("Bluetooth Test");

Serial.println("Set to [Both NL&CR] and input 'AT'");

}


void loop() { // run over and over

// 블루투스 -> 아두이노

if (BTSerial.available()) {

Serial.write(BTSerial.read());

}

// 아두이노 -> 블루투스

if (Serial.available()) {

BTSerial.write(Serial.read());

}

}

스마트기기에 Serial Bluetooth Terminal 앱을 설치하고,

스마트홈 시스템과 채팅하면서 테스트

앱 설치하기 [바로가기]

09 조도 센서 (CDS)

CDS?

조도센서 회로 결선

조도센서 소스 코드

소스코드 09getCds.ino

#define cdsPin A1 // 조도센서(cds) 핀번호


int cdsValue = 0; // 조도센서(cds) 값


void setup() {

Serial.begin(9600);

}


void loop(){

cdsValue = getCds();

Serial.print(cdsValue);

Serial.println("cds");

delay(1000);

}


// cds값을 읽어서 리턴

int getCds(){

int readValue= analogRead(cdsPin); //조도값 읽기(1023~0)

readValue = 1023-readValue; //밝으면 값이 커지도록 역수 취함

return readValue;

}

10 모듈 통합

전체 회로도

조립 완성 실물

가. 모듈 통합 <ModuleTestV2_1>

  • 모듈별로 만든 테스트 파일을 하나로 통합한다.

  • 통합에 따라 모든 모듈이 하나의 폴더로 관리된다.

메인 ModuleTestV2_1.ino * 전체 다운로드 <ModuleTestV2_1.zip>

  1. /* 스마트홈 모듈 테스트

  2. 2020.9.5. ksyun@dge. GNU

  3. */


  4. // 라이브러리 포함

  5. #include <DHT.h>

  6. #include <MFRC522.h>

  7. #include <SPI.h>

  8. #include <Wire.h>

  9. #include <Adafruit_GFX.h>

  10. #include <Adafruit_SSD1306.h>

  11. #include <Servo.h>

  12. #include <SoftwareSerial.h>


  13. // 핀번호 매칭

  14. #define buzzPin 4 // 부저&점멸RGB 핀번호

  15. #define servoPin 5 // 서보모터 핀번호

  16. #define echoPin 6 // echoPin 핀번호

  17. #define trigPin 7 // trigPin 핀번호

  18. #define DHTPIN 8 // DHT11 data 핀번호

  19. #define RST_PIN 9 // Rfid 핀번호

  20. #define SS_PIN 10 // Rfid 핀번호

  21. #define cdsPin A1 // 조도센서(cds) 핀번호

  22. #define fanPin A2 // 12Vdc 팬 제어 릴레이 핀번호

  23. #define lampPin A3 // 220Vac 전등 제어 릴레이 핀번호

  24. #define OLED_RESET -1 // OLED Reset 핀번호(-1: 아두이노 RST와 공유)


  25. // 상수 정의

  26. #define DHTTYPE DHT11 // DHT타입 11 설정

  27. #define SCREEN_WIDTH 128 // OLED 가로 픽셀수

  28. #define SCREEN_HEIGHT 64 // OLED 세로 픽셀수


  29. // 객체 인스턴스 생성

  30. DHT dht(DHTPIN, DHTTYPE); // DHT11

  31. MFRC522 rfid(SS_PIN, RST_PIN); // Rfid 객체

  32. MFRC522::MIFARE_Key key; // Rfid key

  33. Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // I2C OLED 객체 인스턴스 생성

  34. Servo myServo; // 서보모터 객체 생성

  35. SoftwareSerial BTSerial(2, 3); // BTSerial(Rx, Tx): Adu-Rx(2)<->BT(Tx), Adu-Tx(3)<->BT(Rx) 연결


  36. // 변수 선언

  37. int cdsValue = 0; // 조도센서(cds) 값

  38. float humidity;

  39. float temperature;

  40. long duration, distance; // 거리 측정 변수를 선언합니다.

  41. byte nuidPICC[4]={0x50, 0xF7, 0x0E, 0x30}; // 등록된 Rfid카드 NUID


  42. //// 시스템 초기화: 한번만 실행 ======================

  43. void setup() {

  44. Serial.begin(9600);

  45. BTSerial.begin(9600);

  46. Serial.println("Serial begin");

  47. pinMode(buzzPin, OUTPUT); // 부저와 점멸LED를 출력으로 설정

  48. pinMode(trigPin, OUTPUT); // trigPin 핀을 출력으로 설정

  49. pinMode(echoPin, INPUT); // echoPin 핀을 입력으로 설정

  50. pinMode(fanPin, OUTPUT);

  51. pinMode(lampPin, OUTPUT);


  52. digitalWrite(fanPin, HIGH); // 팬 끄기(Negative Logic)

  53. digitalWrite(lampPin, HIGH); // 전등 끄기(Negative Logic)

  54. dht.begin();

  55. SPI.begin(); // SPI 버스 초기화

  56. rfid.PCD_Init(); // Rfid(MFRC522) 초기화

  57. if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {

  58. Serial.println(F("SSD1306 allocation failed"));

  59. for(;;); // 무한 루프

  60. }

  61. beep(3);

  62. startOLED(); // SmartHome! 표시

  63. delay(1000);

  64. }


  65. //// 계속 반복 실행 ================================

  66. void loop() {


  67. // 부저와 점멸RGB가 1초 간격으로 동작

  68. //buzzer();

  69. // 2초마다 온습도 측정(시리얼 모니터에서 확인)

  70. //getDHT();


  71. // 0.5초마다 초음파 센서 거리 측정(시리얼 모니터에서 확인)

  72. //distance = getDistance(); // 거리값 읽기

  73. //Serial.print(distance); Serial.println(" cm"); // distance를 시리얼 모니터에 출력합니다.

  74. //delay(500); // 0.5초동안 기다립니다.


  75. // Rfid 테스트(시리얼 모니터에서 확인)

  76. //getRfid();


  77. // 5초 간격으로 OLED 업데이트

  78. //startOLED(); // SmartHome! 표시

  79. //delay(2000);

  80. //updateOLED(); // 글자 표시(폰트크기 2)

  81. //delay(2000);


  82. // 서보모터 테스트(220Vac를 켜고 테스트한다)

  83. //servoMove(0);

  84. //delay(500);

  85. //servoMove(90);

  86. //delay(500);

  87. //servoMove(179);

  88. //delay(500);

  89. // 릴레이(전등,팬) 테스트(220Vac를 켜고 테스트한다)

  90. //testRelay(); //전등,팬을 1초간 켜고 2초간 끄기


  91. // 블루투스 테스트

  92. //serial 모니터에서 "Both NL & CR"로 설정한 후,

  93. // "AT" 명령을 보내고 OK를 확인한다.

  94. //BT_test();


  95. // 조도센서 테스트

  96. cdsValue = getCds();

  97. Serial.print(cdsValue); Serial.println("cds");

  98. delay(1000);

  99. }

01ctrlBuzzer.ino *예제>Blink 예제 활용

  1. // 부저와 점멸RGB 제어


  2. // 부저와 LED 1초 간격으로 동작

  3. void buzzer(){

  4. digitalWrite(buzzPin, HIGH);

  5. delay(1000);

  6. digitalWrite(buzzPin, LOW);

  7. delay(1000);

  8. }


  9. // 비프음 n회 발생

  10. void beep(int n) {

  11. for (int i = 0; i < n; i++) {

  12. digitalWrite(buzzPin, HIGH); // 비프 울림

  13. delay(20);

  14. digitalWrite(buzzPin, LOW); // 비프 꺼짐

  15. if(n>1) delay(30);

  16. }

  17. }


02getDHT.ino *예제>DHTtester 예제 활용

  1. // 2초 간격으로 온습도를 측정하여 시리얼 모니터로 표시


  2. void getDHT(){

  3. // DHT 측정 간격 2초 필요

  4. delay(2000);


  5. // 온습도 센서는 최대 2초 정도 걸리는 매우 느린 센서

  6. humidity = dht.readHumidity(); // 습도 읽기

  7. temperature = dht.readTemperature(); // 섭씨(디폴트)온도 읽기


  8. // 읽기 오류면 얼른 나가기(재시도 위해서).

  9. if (isnan(humidity) || isnan(temperature)) {

  10. Serial.println(F("Failed to read from DHT sensor!"));

  11. return;

  12. }


  13. Serial.print(F("Humidity: "));

  14. Serial.print(humidity,1); // 소수 한자리까지 습도 표시

  15. Serial.print(F("% Temperature: "));

  16. Serial.print(temperature,1); // 소수 한자리까지 온도 표시

  17. Serial.println(F("°C "));


  18. }

03getDistance.ino *인터넷 자료 활용

  1. // 초음파 거리 센서의 거리값 반환

  2. //http://makeshare.org/bbs/board.php?bo_table=arduinosensor&wr_id=366


  3. long getDistance() {

  4. digitalWrite(trigPin, LOW); // trigPin에 LOW를 출력하고

  5. delayMicroseconds(2); // 2 마이크로초가 지나면

  6. digitalWrite(trigPin, HIGH); // trigPin에 HIGH를 출력합니다.

  7. delayMicroseconds(10); // trigPin을 10마이크로초 동안 기다렸다가

  8. digitalWrite(trigPin, LOW); // trigPin에 LOW를 출력합니다.

  9. duration = pulseIn(echoPin, HIGH); // echoPin핀에서 펄스값을 받아옵니다.


  10. /*

  11. trigPin핀에서 초음파를 발사하였고 그 초음파가 다시 돌아 올 때까지 기다립니다.

  12. 만약 벽이나 장애물에 닿아서 다시 echoPin으로 돌아왔다면 그동안의 시간을 duration에 저장합니다.

  13. */

  14. return duration * 17 / 1000; // duration을 연산하여 센싱한 거리값을 distance에 저장합니다.

  15. }

04getRfid.ino *예제>ReadNUID 수정 사용

  1. // MiFARE방식 카드 읽기(등록여부 판단)

  2. void getRfid(){

  3. // 카드를 반복해서 계속 읽지 안도록 빠져나감

  4. if ( ! rfid.PICC_IsNewCardPresent()) return;


  5. // ID가 인식되지 않았다면 더이상 진행하지 말고 빠져나감

  6. if ( ! rfid.PICC_ReadCardSerial()) return;


  7. // 카드 타입 읽기

  8. MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);


  9. // MIFARE 타입이 아니라면 더이상 진행하지 말고 빠져나감

  10. if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI &&

  11. piccType != MFRC522::PICC_TYPE_MIFARE_1K &&

  12. piccType != MFRC522::PICC_TYPE_MIFARE_4K) {

  13. Serial.println(F("Your tag is not of type MIFARE Classic."));

  14. return;

  15. }


  16. // 읽은 ID와 등록된 ID값을 비교

  17. if (rfid.uid.uidByte[0] == nuidPICC[0] ||

  18. rfid.uid.uidByte[1] == nuidPICC[1] ||

  19. rfid.uid.uidByte[2] == nuidPICC[2] ||

  20. rfid.uid.uidByte[3] == nuidPICC[3] ) {

  21. Serial.println(F("This is a confirmed Card."));

  22. }

  23. else {

  24. //등록된 ID가 아니라면 tag 정보 표시

  25. Serial.print(F("Unconfirmed Card: "));

  26. printHex(rfid.uid.uidByte, rfid.uid.size); // 사용자 화면에 부정 tag 정보 출력

  27. Serial.print("\n");

  28. }


  29. // rfid 종료

  30. rfid.PICC_HaltA(); // PICC 종료

  31. rfid.PCD_StopCrypto1(); // 암호화 종료

  32. }



  33. // 카드 tag 출력

  34. void printHex(byte *buffer, byte bufferSize) {

  35. for (byte i = 0; i < bufferSize; i++) {

  36. Serial.print(buffer[i] < 0x10 ? " 0" : " ");

  37. Serial.print(buffer[i], HEX);

  38. }

  39. }

05ctrlOLED.ino *예제>ssd1306_128x64_i2c 수정 사용

  1. // OLED 테스트


  2. void updateOLED(void) {

  3. // 버퍼비우기

  4. display.clearDisplay();

  5. display.setTextSize(2); // Draw 2X-scale text

  6. display.setTextColor(SSD1306_WHITE);

  7. display.setCursor(0, 0);

  8. display.println(F("Line 1"));

  9. display.println(F(" Line 2"));

  10. display.println(F(" Line 3"));

  11. display.println(F("12345678901"));

  12. display.display();

  13. }


  14. void startOLED(void) {

  15. // 버퍼비우기

  16. display.clearDisplay();

  17. display.setTextSize(2); // Draw 2X-scale text

  18. display.setTextColor(SSD1306_WHITE);

  19. display.setCursor(0, 16); // setCursor(열,행)

  20. display.println(F("SmartHome!"));

  21. display.println(F(" ver1.3"));

  22. display.display();

  23. }

06ctrlServo.ino *예제>Sweep 수정 사용

  1. // 원하는 각도로 이동하고 멈추기


  2. void servoMove(int servoPos){

  3. myServo.attach(servoPin); // 서보모터 연결

  4. myServo.write(servoPos);

  5. delay(500);

  6. myServo.detach(); // 서보모터 분리(떨림 현상 방지)

  7. }

07ctrlRelay.ino *예제>Blink 예제 활용

  1. // 전등과 팬 제어

  2. // 릴레이 모듈이 부논리(Negative Logic)이므로 LOW에서 릴레이 동작


  3. void testRelay(){

  4. digitalWrite(lampPin, LOW); // 전등 켜기

  5. digitalWrite(fanPin, LOW); // 팬 켜기

  6. delay(1000);

  7. digitalWrite(lampPin, HIGH); // 전등 끄기

  8. digitalWrite(fanPin, HIGH); // 팬 끄기

  9. delay(2000);

  10. }

08Bluetooth.ino *예제>SoftwareSerialExample 수정 사용

  1. /* HC-06 bluetooth

  2. serial 모니터에서 "Both NL & CR"로 설정한 후, (\r\n)(\12\15)

  3. "AT" 명령을 보내고 OK를 확인한다.

  4. [참고]

  5. - 버젼 확인: AT+VERSION

  6. - 이름 확인/바꾸기: AT+NAME?, AT+NAME="HC-06(74D2)"

  7. - mac addr. 확인/바꾸기: AT+ADDR?, AT+ADDR:12:34:56:ab:cd:ef

  8. - BR바꾸기: AT+BAUD4 참고)4:9600bps 5:19200, 6:38400, 7:57600

  9. - 비번 확인/바꾸기: AT+PSWD?, AT+PSWD=1234

  10. */


  11. void BT_test() {

  12. // 블루투스 -> 아두이노

  13. if (BTSerial.available()) {

  14. Serial.write(BTSerial.read());

  15. }

  16. // 아두이노 -> 블루투스

  17. if (Serial.available()) {

  18. BTSerial.write(Serial.read());

  19. }

  20. }

09getCds.ino

  1. // cds값을 읽어서 리턴

  2. int getCds(){

  3. cdsValue= analogRead(cdsPin); //조도값 읽기(1023~0)

  4. cdsValue = 1023-cdsValue; //밝으면 값이 커지도록 역수 취함

  5. return cdsValue;

  6. }

나. 모듈 통합 테스트 <ModuleTestV20220117.zip> <ModuleTestV2_2.zip>

메인 ModuleTest20220117.ino * 전체 다운로드 [ModuleTest20220117.zip]

// ▣ last update 2022.01.17 , ksyun@woonam.hs.kr, GNU

// Bluetooth HC-06 DX_smartv2.0 칩셋용 코드


// 라이브러리 포함

#include <DHT.h> // 온습도 센서

#include <Servo.h> // 서보모터

#include <Wire.h> // OLED용 I2C

#include <SPI.h> // RFID를 위한 SPI

#include <MFRC522.h> // RFID

#include <Adafruit_GFX.h> // OLED를 위한 Adafruit 공통

#include <Adafruit_SSD1306.h> // OLED

#include <SoftwareSerial.h> // Serial 통신 라이브러리


// 핀번호 매칭

#define buzzPin 4 // 부저 핀번호

#define servoPin 5 // 서보모터 핀번호

#define echoPin 6 // 초음파센서(echoPin) 핀번호

#define trigPin 7 // 초음파센서(trigPin) 핀번호

#define DHTPIN 8 // 온습도센서(DHT11) 핀번호

#define RST_PIN 9 // RFID Reset PIN

#define SS_PIN 10 // RFID SS(SDA:ChipSelect) PIN

#define OLED_RESET -1 // OLED Reset 핀번호(-1: 아두이노 RST와 공유)

#define cdsPin A1 // 조도센서 핀번호

#define fanPin A2 // 12Vdc 팬 제어 릴레이 핀번호

#define lampPin A3 // 220Vac 전등 제어 릴레이 핀번호


// 상수 정의

#define DHTTYPE DHT11 // DHT타입 11 설정

#define DOOR_OPEN 90 // 서보모터 열기 각도

#define DOOR_CLOSE 0 // 서보모터 닫기 각도


// RFID 카드 등록

byte nuidPICC[3][4] = {{0xF7, 0x3E, 0x80, 0x4A},

{0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0x00, 0x00}};


// 객체 인스턴스 생성

Adafruit_SSD1306 display(OLED_RESET); // OLED 인스턴스 생성

DHT dht(DHTPIN, DHTTYPE); // 온습도센서 인스턴스 생성

Servo myServo; // 서보모터 인스턴스 생성

MFRC522 rfid(SS_PIN, RST_PIN); // RFID 인스턴스 생성

SoftwareSerial BTSerial(2, 3); // BTSerial(Rx, Tx): Adu-Rx(2)<->BT(Tx), Adu-Tx(3)<->BT(Rx) 연결


// 변수 선언

int cdsValue = 0; // 조도(cds) 값

long distance = 0; // 초음파센서 값

float temperature = 0.; // 온도(dht) 값

float humidity = 0.; // 습도(dht) 값

unsigned long now = 0; // 현재 시각

unsigned long prevMillis = 0; // 온습도 이전 측정 시각

const long DHTinterval = 2000; // 온습도 측정 간격


// 도어상태: 닫힘(0), 열림(1), 경비(2), 차고(3)

const char *DoorState[] = {"Closed", "Opened", "Armed", "Garage"};

int doorMode = 0; // 출입 모드(0:닫힘, 1:열림, 2:경비, 3:차고)

bool isDoorOpen = false; // 문이 열렸는가?


//// 시스템 초기화: 한번만 실행 ======================

void setup() {

Serial.begin(9600);

BTSerial.begin(9600);

Serial.println("Serial begin");

pinMode(fanPin, OUTPUT);

pinMode(lampPin, OUTPUT);

pinMode(buzzPin, OUTPUT); // 부저와 점멸LED를 출력으로 설정

pinMode(trigPin, OUTPUT); // trigPin 핀을 출력으로 설정

pinMode(echoPin, INPUT); // echoPin 핀을 입력으로 설정


digitalWrite(fanPin, HIGH); // 팬 끄기(Negative Logic)

digitalWrite(lampPin, HIGH); // 전등 끄기(Negative Logic)

myServo.attach(servoPin); // 서보 연결

servoMove(DOOR_CLOSE); // 시작 시 문 닫기


dht.begin();

SPI.begin(); // SPI 버스 초기화

rfid.PCD_Init(); // Rfid(MFRC522) 초기화

if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {

Serial.println(F("SSD1306 allocation failed"));

for(;;) beep(2); // 무한 루프

}

display.clearDisplay(); // OLED 화면 지우기

// display.setTextSize(1);

display.setTextColor(SSD1306_WHITE);

beep(3);

//startOLED(); // SmartHome! 표시

delay(1000);

}


//// 계속 반복 실행 ================================

void loop() {


//(1) 입력========================================================================================

// 센서값 읽기(조도, 거리, 온도, 습도)

if (isTimeToReadDHT())

getDHT(); // 온도,습도 읽기 (2초 간격으로)

cdsValue = analogRead(cdsPin); // 조도 읽기

distance = getDistance(); // 거리 읽기

getRfid(); // RFid 카드 읽기


//(2) 처리&제어=====================================================================================

servoCtrl(doorMode); // 도어 제어

relayCtrl(doorMode); // 전등 제어


//(3) 화면표시=====================================================================================

selfTestOLED(); // OLED 화면에 표시

//(4) 블루투스 테스트 serial 모니터에서 "line ending 없음"으로 설정한 후,

// "AT" 명령을 보내고 OK를 확인한다.

BT_test();

}

01ctrlBuzzer.ino *예제>Blink 예제 활용

  1. // 부저와 점멸RGB 제어


  2. // 부저와 LED 1초 간격으로 동작

  3. void buzzer(){

  4. digitalWrite(buzzPin, HIGH);

  5. delay(1000);

  6. digitalWrite(buzzPin, LOW);

  7. delay(1000);

  8. }


  9. // 비프음 n회 발생

  10. void beep(int n) {

  11. for (int i = 0; i < n; i++) {

  12. digitalWrite(buzzPin, HIGH); // 비프 울림

  13. delay(20);

  14. digitalWrite(buzzPin, LOW); // 비프 꺼짐

  15. if(n>1) delay(30);

  16. }

  17. }


02getDHT.ino *예제>DHTtester 예제 활용

  1. // 2초 간격으로 온습도를 측정하여 시리얼 모니터로 표시


  2. // DHT값 읽을 때가 되었나?

  3. boolean isTimeToReadDHT(){

  4. now = millis(); // 현재 시각

  5. if (now - prevMillis >= DHTinterval) return true;

  6. else return false;

  7. }


  8. // DHT값 읽기

  9. void getDHT(){

  10. humidity = dht.readHumidity(); // 습도 읽기

  11. temperature = dht.readTemperature(); // 섭씨(디폴트)온도 읽기


  12. // 읽기 오류면 얼른 나가기(재시도 위해서).

  13. if (isnan(humidity) || isnan(temperature)) {

  14. Serial.println(F("Failed to read from DHT sensor!"));

  15. return;

  16. }

  17. prevMillis = now; // 현재 시각 저장

  18. }

03getDistance.ino *인터넷 자료 활용

  1. // 초음파 거리 센서의 거리값 반환

  2. //http://makeshare.org/bbs/board.php?bo_table=arduinosensor&wr_id=366


  3. long getDistance() {

  4. digitalWrite(trigPin, LOW); // trigPin에 LOW를 출력하고

  5. delayMicroseconds(2); // 2 마이크로초가 지나면

  6. digitalWrite(trigPin, HIGH); // trigPin에 HIGH를 출력합니다.

  7. delayMicroseconds(10); // trigPin을 10마이크로초 동안 기다렸다가

  8. digitalWrite(trigPin, LOW); // trigPin에 LOW를 출력합니다.

  9. duration = pulseIn(echoPin, HIGH); // echoPin핀에서 펄스값을 받아옵니다.


  10. /*

  11. trigPin핀에서 초음파를 발사하였고 그 초음파가 다시 돌아 올 때까지 기다립니다.

  12. 만약 벽이나 장애물에 닿아서 다시 echoPin으로 돌아왔다면 그동안의 시간을 duration에 저장합니다.

  13. */

  14. return duration * 17 / 1000; // duration을 연산하여 센싱한 거리값을 distance에 저장합니다.

  15. }

04getRfid.ino *예제>ReadNUID 수정 사용

  1. // MiFARE방식 카드 읽기(등록여부 판단)


  2. void getRfid() {

  3. bool isAuthID;


  4. if ( ! rfid.PICC_IsNewCardPresent()) return; //새 카드가 인식되지 않았다면 더이상 진행하지 말고 빠져나감

  5. if ( ! rfid.PICC_ReadCardSerial()) return; //ID가 인식되지 않았다면 더이상 진행하지 말고 빠져나감


  6. // 카드 타입 확인하기

  7. MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);

  8. if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI &&

  9. piccType != MFRC522::PICC_TYPE_MIFARE_1K &&

  10. piccType != MFRC522::PICC_TYPE_MIFARE_4K) {

  11. Serial.println(F("Your tag is not of type MIFARE Classic."));

  12. return; // MIFARE 타입이 아니라면 더이상 진행하지 말고 빠져나감

  13. }


  14. // 등록된 카드(ID)인지 확인

  15. for (int i = 0; i < sizeof(nuidPICC) / sizeof(nuidPICC[0]); i++) {

  16. isAuthID = true; // true로 시작하여

  17. for (int j = 0; j < 4; j++) { // 한자리씩 비교

  18. if (rfid.uid.uidByte[j] != nuidPICC[i][j]) { // 등록된 카드와 맞지 않으면

  19. isAuthID = false; // false로 설정하고

  20. break; // 안쪽 for문을 빠져나감

  21. }

  22. }

  23. if (isAuthID) break; // 네자리 모두 같으면 등록된 카드이므로 바깥쪽 for문을 나감

  24. }


  25. if (isAuthID) { // 등록된 카드인 경우

  26. Serial.println(F("This is a confirmed Card."));

  27. beep(5); //비프 울림

  28. doorMode = 1; // 문열기

  29. }

  30. else {

  31. //등록된 ID가 아니라면 tag 정보 표시

  32. Serial.print(F("Unconfirmed Card: "));

  33. printHex(rfid.uid.uidByte, rfid.uid.size); // 사용자 화면에 부정 tag 정보 출력

  34. Serial.println();

  35. beep(2); //비프 울림

  36. doorMode = 0; // 문닫기

  37. }


  38. // rfid 종료

  39. rfid.PICC_HaltA(); // PICC 종료

  40. rfid.PCD_StopCrypto1(); // 암호화 종료

  41. }



  42. // 카드 tag 출력

  43. void printHex(byte *buffer, byte bufferSize) {

  44. for (byte i = 0; i < bufferSize; i++) {

  45. Serial.print(buffer[i] < 0x10 ? " 0" : " ");

  46. Serial.print(buffer[i], HEX);

  47. }

  48. }

05ctrlOLED.ino *예제>ssd1306_128x64_i2c 수정 사용

  1. // OLED 테스트

  2. // TextSize(1): 6px(가로 21.2글자) x 8px(세로 8줄)

  3. // TextSize(2): 12px(가로 10.7글자) x 16px(세로 4줄)


  4. //모듈 테스트용

  5. void selfTestOLED(void) {

  6. display.clearDisplay();

  7. display.setCursor(0, 0);


  8. // Line1

  9. display.println("Board Test");

  10. //display.print("L()"); display.println();

  11. // Line2

  12. display.print(temperature, 1); display.print(" 'C ");

  13. display.print(humidity, 1); display.println(" %");

  14. // Line3

  15. display.print(distance); display.print(" cm ");

  16. display.print(cdsValue); display.println(" cds ");

  17. // Line4

  18. // display.print("Door : "); display.println(DoorState[doorMode]);

  19. display.print("D("); display.print(doorMode); display.print("):"); display.println(DoorState[isDoorOpen]);


  20. display.display();


  21. }


  22. // 시스템 상황 표시

  23. void updateOLED(void) {

  24. display.clearDisplay();

  25. display.setCursor(0, 0);

  26. display.println(F("Line 1"));

  27. display.println(F(" Line 2"));

  28. display.println(F(" Line 3"));

  29. display.println(F("12345678901"));

  30. display.display();

  31. }


  32. // 시작화면

  33. void startOLED(void) {

  34. display.clearDisplay();

  35. display.setCursor(0, 16); // setCursor(열,행)

  36. display.println(F("SmartHome!"));

  37. display.println(F(" ver1.3"));

  38. display.display();

  39. }

06ctrlServo.ino *예제>Sweep 수정 사용

  1. // 도어(서보모터) 제어


  2. // 도어

  3. void servoCtrl(int doorMode) {

  4. if (doorMode == 0 && isDoorOpen) servoMove(DOOR_CLOSE); // 도어 닫기

  5. if (doorMode == 1 && !isDoorOpen)servoMove(DOOR_OPEN); // 도어 열기

  6. }


  7. // 입력값으로 서보모터 제어

  8. void servoMove(int servoPos) {

  9. myServo.attach(servoPin); // 서보모터 연결

  10. myServo.write(servoPos); // 움직이기

  11. delay(500); // 움직임이 끝날 때까지 기다리기

  12. myServo.detach(); // 서보모터 분리(채터링 방지)

  13. if (servoPos == DOOR_OPEN) isDoorOpen = true; //문 열기

  14. if (servoPos == DOOR_CLOSE) isDoorOpen = false; //문 닫기

  15. }

07ctrlRelay.ino *예제>Blink 예제 활용

  1. // 전등과 팬 제어

  2. // 릴레이 모듈이 부논리(Negative Logic)이므로 LOW에서 릴레이 동작


  3. // rfid로 릴레이 제어 테스트

  4. void relayCtrl(int doorMode) {

  5. if (doorMode == 0){ // 문닫기 모드라면

  6. digitalWrite(lampPin, HIGH); // 전등 끄기

  7. digitalWrite(fanPin, HIGH); // 팬 끄기

  8. digitalWrite(buzzPin, LOW); // 부저 끔

  9. }

  10. if (doorMode == 1){ // 문열기 모드라면

  11. digitalWrite(lampPin, LOW); // 전등 켜기

  12. digitalWrite(fanPin, LOW); // 팬 켜기

  13. digitalWrite(buzzPin, HIGH); // 부저 울림

  14. }

  15. }


  16. void testRelay(){

  17. digitalWrite(lampPin, LOW); // 전등 켜기

  18. digitalWrite(fanPin, LOW); // 팬 켜기

  19. delay(1000);

  20. digitalWrite(lampPin, HIGH); // 전등 끄기

  21. digitalWrite(fanPin, HIGH); // 팬 끄기

  22. delay(2000);

  23. }

08Bluetooth.ino *예제>SoftwareSerialExample 수정 사용

  1. /* HC-06 버전별 모듈 사용법

  2. ******Ver2.0 , DX_smartv2.0

  3. ★★★ line ending 없음

  4. AT: 연결 확인

  5. AT+VERSION : 버전 확인

  6. AT+LADDR : mac 주소 확인

  7. AT+NAME : 이름 확인

  8. AT+NAMEaabbcc : 'aabbcc'로 이름 변경

  9. AT+PIN1234 : '1234'로 비밀번호 변경(최대 4자리)

  10. AT+BAUD : baud 확인

  11. AT+BAUD7 : 57,600baud ( 최댓값)

  12. =============================================

  13. *****Ver3.0 , 3.0-20170609

  14. ★★★ Both NL&CR , \r\n

  15. AT: 연결 확인

  16. AT+VERSION : 버전 확인

  17. AT+ADDR : mac 주소 확인

  18. AT+NAME : 이름 확인

  19. AT+NAME=aabbcc : 'aabbcc'로 이름 변경

  20. AT+PSWD : 비밀번호 확인

  21. AT+PSWD=1234 : '1234'로 비밀번호 변경(최대 4자리)

  22. AT+UART : UART 설정값 확인

  23. AT+UART=57600,0,0 :

  24. =============================================

  25. */


  26. void BT_test() {

  27. // 블루투스 -> 아두이노

  28. if (BTSerial.available()) {

  29. Serial.write(BTSerial.read());

  30. }

  31. // 아두이노 -> 블루투스

  32. if (Serial.available()) {

  33. BTSerial.write(Serial.read());

  34. }

  35. }

09getCds.ino

  1. // cds값을 읽어서 리턴

  2. void getCds(){

  3. cdsValue= analogRead(cdsPin); //조도값 읽기(1023~0)

  4. //cdsValue = 1023-cdsValue; //밝으면 값이 커지도록 역수 취함

  5. }

  • 각 모듈을 통합하여 테스트한다.