아두이노 스마트홈 교구 전체 윤곽 파악하기
모듈 조립하기
모듈 테스트하기
모듈 통합하기
2021년 1월 연수
2020년 9월 연수
능동부저, 수동부저 구별하기 [바로가기]
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);
}
}
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 "));
}
소스코드 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에 저장합니다.
}
소스코드 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);
}
}
소스코드 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();
}
소스코드 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(); // 서보모터 분리(떨림 현상 방지)
}
Tip] 볼트를 조을 때 너트가 헛돌아서 잘 조여지지 않아요.
해결: 커넥트를 위로 당기면서 볼트를 조으면 잘 됩니다.
Tip] 볼트를 조을 때 너트가 헛돌아서 잘 조여지지 않아요.
해결: 소켓을 위로 당기면서 볼트를 조으면 잘 됩니다.
소스코드 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);
}
소스코드 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 앱을 설치하고,
스마트홈 시스템과 채팅하면서 테스트
앱 설치하기 [바로가기]
소스코드 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;
}
모듈별로 만든 테스트 파일을 하나로 통합한다.
통합에 따라 모든 모듈이 하나의 폴더로 관리된다.
/* 스마트홈 모듈 테스트
2020.9.5. ksyun@dge. GNU
*/
// 라이브러리 포함
#include <DHT.h>
#include <MFRC522.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Servo.h>
#include <SoftwareSerial.h>
// 핀번호 매칭
#define buzzPin 4 // 부저&점멸RGB 핀번호
#define servoPin 5 // 서보모터 핀번호
#define echoPin 6 // echoPin 핀번호
#define trigPin 7 // trigPin 핀번호
#define DHTPIN 8 // DHT11 data 핀번호
#define RST_PIN 9 // Rfid 핀번호
#define SS_PIN 10 // Rfid 핀번호
#define cdsPin A1 // 조도센서(cds) 핀번호
#define fanPin A2 // 12Vdc 팬 제어 릴레이 핀번호
#define lampPin A3 // 220Vac 전등 제어 릴레이 핀번호
#define OLED_RESET -1 // OLED Reset 핀번호(-1: 아두이노 RST와 공유)
// 상수 정의
#define DHTTYPE DHT11 // DHT타입 11 설정
#define SCREEN_WIDTH 128 // OLED 가로 픽셀수
#define SCREEN_HEIGHT 64 // OLED 세로 픽셀수
// 객체 인스턴스 생성
DHT dht(DHTPIN, DHTTYPE); // DHT11
MFRC522 rfid(SS_PIN, RST_PIN); // Rfid 객체
MFRC522::MIFARE_Key key; // Rfid key
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // I2C OLED 객체 인스턴스 생성
Servo myServo; // 서보모터 객체 생성
SoftwareSerial BTSerial(2, 3); // BTSerial(Rx, Tx): Adu-Rx(2)<->BT(Tx), Adu-Tx(3)<->BT(Rx) 연결
// 변수 선언
int cdsValue = 0; // 조도센서(cds) 값
float humidity;
float temperature;
long duration, distance; // 거리 측정 변수를 선언합니다.
byte nuidPICC[4]={0x50, 0xF7, 0x0E, 0x30}; // 등록된 Rfid카드 NUID
//// 시스템 초기화: 한번만 실행 ======================
void setup() {
Serial.begin(9600);
BTSerial.begin(9600);
Serial.println("Serial begin");
pinMode(buzzPin, OUTPUT); // 부저와 점멸LED를 출력으로 설정
pinMode(trigPin, OUTPUT); // trigPin 핀을 출력으로 설정
pinMode(echoPin, INPUT); // echoPin 핀을 입력으로 설정
pinMode(fanPin, OUTPUT);
pinMode(lampPin, OUTPUT);
digitalWrite(fanPin, HIGH); // 팬 끄기(Negative Logic)
digitalWrite(lampPin, HIGH); // 전등 끄기(Negative Logic)
dht.begin();
SPI.begin(); // SPI 버스 초기화
rfid.PCD_Init(); // Rfid(MFRC522) 초기화
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // 무한 루프
}
beep(3);
startOLED(); // SmartHome! 표시
delay(1000);
}
//// 계속 반복 실행 ================================
void loop() {
// 부저와 점멸RGB가 1초 간격으로 동작
//buzzer();
// 2초마다 온습도 측정(시리얼 모니터에서 확인)
//getDHT();
// 0.5초마다 초음파 센서 거리 측정(시리얼 모니터에서 확인)
//distance = getDistance(); // 거리값 읽기
//Serial.print(distance); Serial.println(" cm"); // distance를 시리얼 모니터에 출력합니다.
//delay(500); // 0.5초동안 기다립니다.
// Rfid 테스트(시리얼 모니터에서 확인)
//getRfid();
// 5초 간격으로 OLED 업데이트
//startOLED(); // SmartHome! 표시
//delay(2000);
//updateOLED(); // 글자 표시(폰트크기 2)
//delay(2000);
// 서보모터 테스트(220Vac를 켜고 테스트한다)
//servoMove(0);
//delay(500);
//servoMove(90);
//delay(500);
//servoMove(179);
//delay(500);
// 릴레이(전등,팬) 테스트(220Vac를 켜고 테스트한다)
//testRelay(); //전등,팬을 1초간 켜고 2초간 끄기
// 블루투스 테스트
//serial 모니터에서 "Both NL & CR"로 설정한 후,
// "AT" 명령을 보내고 OK를 확인한다.
//BT_test();
// 조도센서 테스트
cdsValue = getCds();
Serial.print(cdsValue); Serial.println("cds");
delay(1000);
}
01ctrlBuzzer.ino *예제>Blink 예제 활용
// 부저와 점멸RGB 제어
// 부저와 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);
}
}
02getDHT.ino *예제>DHTtester 예제 활용
// 2초 간격으로 온습도를 측정하여 시리얼 모니터로 표시
void getDHT(){
// DHT 측정 간격 2초 필요
delay(2000);
// 온습도 센서는 최대 2초 정도 걸리는 매우 느린 센서
humidity = dht.readHumidity(); // 습도 읽기
temperature = dht.readTemperature(); // 섭씨(디폴트)온도 읽기
// 읽기 오류면 얼른 나가기(재시도 위해서).
if (isnan(humidity) || isnan(temperature)) {
Serial.println(F("Failed to read from DHT sensor!"));
return;
}
Serial.print(F("Humidity: "));
Serial.print(humidity,1); // 소수 한자리까지 습도 표시
Serial.print(F("% Temperature: "));
Serial.print(temperature,1); // 소수 한자리까지 온도 표시
Serial.println(F("°C "));
}
03getDistance.ino *인터넷 자료 활용
// 초음파 거리 센서의 거리값 반환
//http://makeshare.org/bbs/board.php?bo_table=arduinosensor&wr_id=366
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에 저장합니다.
}
04getRfid.ino *예제>ReadNUID 수정 사용
// MiFARE방식 카드 읽기(등록여부 판단)
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);
}
}
05ctrlOLED.ino *예제>ssd1306_128x64_i2c 수정 사용
// OLED 테스트
void updateOLED(void) {
// 버퍼비우기
display.clearDisplay();
display.setTextSize(2); // 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();
}
06ctrlServo.ino *예제>Sweep 수정 사용
// 원하는 각도로 이동하고 멈추기
void servoMove(int servoPos){
myServo.attach(servoPin); // 서보모터 연결
myServo.write(servoPos);
delay(500);
myServo.detach(); // 서보모터 분리(떨림 현상 방지)
}
07ctrlRelay.ino *예제>Blink 예제 활용
// 전등과 팬 제어
// 릴레이 모듈이 부논리(Negative Logic)이므로 LOW에서 릴레이 동작
void testRelay(){
digitalWrite(lampPin, LOW); // 전등 켜기
digitalWrite(fanPin, LOW); // 팬 켜기
delay(1000);
digitalWrite(lampPin, HIGH); // 전등 끄기
digitalWrite(fanPin, HIGH); // 팬 끄기
delay(2000);
}
08Bluetooth.ino *예제>SoftwareSerialExample 수정 사용
/* HC-06 bluetooth
serial 모니터에서 "Both NL & CR"로 설정한 후, (\r\n)(\12\15)
"AT" 명령을 보내고 OK를 확인한다.
[참고]
- 버젼 확인: AT+VERSION
- 이름 확인/바꾸기: AT+NAME?, AT+NAME="HC-06(74D2)"
- mac addr. 확인/바꾸기: AT+ADDR?, AT+ADDR:12:34:56:ab:cd:ef
- BR바꾸기: AT+BAUD4 참고)4:9600bps 5:19200, 6:38400, 7:57600
- 비번 확인/바꾸기: AT+PSWD?, AT+PSWD=1234
*/
void BT_test() {
// 블루투스 -> 아두이노
if (BTSerial.available()) {
Serial.write(BTSerial.read());
}
// 아두이노 -> 블루투스
if (Serial.available()) {
BTSerial.write(Serial.read());
}
}
09getCds.ino
// cds값을 읽어서 리턴
int getCds(){
cdsValue= analogRead(cdsPin); //조도값 읽기(1023~0)
cdsValue = 1023-cdsValue; //밝으면 값이 커지도록 역수 취함
return cdsValue;
}
// ▣ 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 예제 활용
// 부저와 점멸RGB 제어
// 부저와 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);
}
}
02getDHT.ino *예제>DHTtester 예제 활용
// 2초 간격으로 온습도를 측정하여 시리얼 모니터로 표시
// DHT값 읽을 때가 되었나?
boolean isTimeToReadDHT(){
now = millis(); // 현재 시각
if (now - prevMillis >= DHTinterval) return true;
else return false;
}
// DHT값 읽기
void getDHT(){
humidity = dht.readHumidity(); // 습도 읽기
temperature = dht.readTemperature(); // 섭씨(디폴트)온도 읽기
// 읽기 오류면 얼른 나가기(재시도 위해서).
if (isnan(humidity) || isnan(temperature)) {
Serial.println(F("Failed to read from DHT sensor!"));
return;
}
prevMillis = now; // 현재 시각 저장
}
03getDistance.ino *인터넷 자료 활용
// 초음파 거리 센서의 거리값 반환
//http://makeshare.org/bbs/board.php?bo_table=arduinosensor&wr_id=366
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에 저장합니다.
}
04getRfid.ino *예제>ReadNUID 수정 사용
// MiFARE방식 카드 읽기(등록여부 판단)
void getRfid() {
bool isAuthID;
if ( ! rfid.PICC_IsNewCardPresent()) return; //새 카드가 인식되지 않았다면 더이상 진행하지 말고 빠져나감
if ( ! rfid.PICC_ReadCardSerial()) return; //ID가 인식되지 않았다면 더이상 진행하지 말고 빠져나감
// 카드 타입 확인하기
MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);
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; // MIFARE 타입이 아니라면 더이상 진행하지 말고 빠져나감
}
// 등록된 카드(ID)인지 확인
for (int i = 0; i < sizeof(nuidPICC) / sizeof(nuidPICC[0]); i++) {
isAuthID = true; // true로 시작하여
for (int j = 0; j < 4; j++) { // 한자리씩 비교
if (rfid.uid.uidByte[j] != nuidPICC[i][j]) { // 등록된 카드와 맞지 않으면
isAuthID = false; // false로 설정하고
break; // 안쪽 for문을 빠져나감
}
}
if (isAuthID) break; // 네자리 모두 같으면 등록된 카드이므로 바깥쪽 for문을 나감
}
if (isAuthID) { // 등록된 카드인 경우
Serial.println(F("This is a confirmed Card."));
beep(5); //비프 울림
doorMode = 1; // 문열기
}
else {
//등록된 ID가 아니라면 tag 정보 표시
Serial.print(F("Unconfirmed Card: "));
printHex(rfid.uid.uidByte, rfid.uid.size); // 사용자 화면에 부정 tag 정보 출력
Serial.println();
beep(2); //비프 울림
doorMode = 0; // 문닫기
}
// 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);
}
}
05ctrlOLED.ino *예제>ssd1306_128x64_i2c 수정 사용
// OLED 테스트
// TextSize(1): 6px(가로 21.2글자) x 8px(세로 8줄)
// TextSize(2): 12px(가로 10.7글자) x 16px(세로 4줄)
//모듈 테스트용
void selfTestOLED(void) {
display.clearDisplay();
display.setCursor(0, 0);
// Line1
display.println("Board Test");
//display.print("L()"); display.println();
// Line2
display.print(temperature, 1); display.print(" 'C ");
display.print(humidity, 1); display.println(" %");
// Line3
display.print(distance); display.print(" cm ");
display.print(cdsValue); display.println(" cds ");
// Line4
// display.print("Door : "); display.println(DoorState[doorMode]);
display.print("D("); display.print(doorMode); display.print("):"); display.println(DoorState[isDoorOpen]);
display.display();
}
// 시스템 상황 표시
void updateOLED(void) {
display.clearDisplay();
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.setCursor(0, 16); // setCursor(열,행)
display.println(F("SmartHome!"));
display.println(F(" ver1.3"));
display.display();
}
06ctrlServo.ino *예제>Sweep 수정 사용
// 도어(서보모터) 제어
// 도어
void servoCtrl(int doorMode) {
if (doorMode == 0 && isDoorOpen) servoMove(DOOR_CLOSE); // 도어 닫기
if (doorMode == 1 && !isDoorOpen)servoMove(DOOR_OPEN); // 도어 열기
}
// 입력값으로 서보모터 제어
void servoMove(int servoPos) {
myServo.attach(servoPin); // 서보모터 연결
myServo.write(servoPos); // 움직이기
delay(500); // 움직임이 끝날 때까지 기다리기
myServo.detach(); // 서보모터 분리(채터링 방지)
if (servoPos == DOOR_OPEN) isDoorOpen = true; //문 열기
if (servoPos == DOOR_CLOSE) isDoorOpen = false; //문 닫기
}
07ctrlRelay.ino *예제>Blink 예제 활용
// 전등과 팬 제어
// 릴레이 모듈이 부논리(Negative Logic)이므로 LOW에서 릴레이 동작
// rfid로 릴레이 제어 테스트
void relayCtrl(int doorMode) {
if (doorMode == 0){ // 문닫기 모드라면
digitalWrite(lampPin, HIGH); // 전등 끄기
digitalWrite(fanPin, HIGH); // 팬 끄기
digitalWrite(buzzPin, LOW); // 부저 끔
}
if (doorMode == 1){ // 문열기 모드라면
digitalWrite(lampPin, LOW); // 전등 켜기
digitalWrite(fanPin, LOW); // 팬 켜기
digitalWrite(buzzPin, HIGH); // 부저 울림
}
}
void testRelay(){
digitalWrite(lampPin, LOW); // 전등 켜기
digitalWrite(fanPin, LOW); // 팬 켜기
delay(1000);
digitalWrite(lampPin, HIGH); // 전등 끄기
digitalWrite(fanPin, HIGH); // 팬 끄기
delay(2000);
}
08Bluetooth.ino *예제>SoftwareSerialExample 수정 사용
/* HC-06 버전별 모듈 사용법
******Ver2.0 , DX_smartv2.0
★★★ line ending 없음
AT: 연결 확인
AT+VERSION : 버전 확인
AT+LADDR : mac 주소 확인
AT+NAME : 이름 확인
AT+NAMEaabbcc : 'aabbcc'로 이름 변경
AT+PIN1234 : '1234'로 비밀번호 변경(최대 4자리)
AT+BAUD : baud 확인
AT+BAUD7 : 57,600baud ( 최댓값)
=============================================
*****Ver3.0 , 3.0-20170609
★★★ Both NL&CR , \r\n
AT: 연결 확인
AT+VERSION : 버전 확인
AT+ADDR : mac 주소 확인
AT+NAME : 이름 확인
AT+NAME=aabbcc : 'aabbcc'로 이름 변경
AT+PSWD : 비밀번호 확인
AT+PSWD=1234 : '1234'로 비밀번호 변경(최대 4자리)
AT+UART : UART 설정값 확인
AT+UART=57600,0,0 :
=============================================
*/
void BT_test() {
// 블루투스 -> 아두이노
if (BTSerial.available()) {
Serial.write(BTSerial.read());
}
// 아두이노 -> 블루투스
if (Serial.available()) {
BTSerial.write(Serial.read());
}
}
09getCds.ino
// cds값을 읽어서 리턴
void getCds(){
cdsValue= analogRead(cdsPin); //조도값 읽기(1023~0)
//cdsValue = 1023-cdsValue; //밝으면 값이 커지도록 역수 취함
}
각 모듈을 통합하여 테스트한다.
모듈 통합 테스트 영상 *ModuleTestV2_2.zip 버전 적용 영상임