Arduino I2C, SPI 통신, RFID

<I2C (Inter-Integrated Circuit)>

 - 아두이노에서 TWI(Two Wire Interface) 통신이라고도 한다.

 - 근거리에서 장치들끼리의 통신을 위해 만들어진 방식

 - 두 개의 선을 이용해서 작업

   SDA (Serial Data) : 데이터 선 - A4핀

   SCL (Serial Clcok) : 클럭 신호 선 - A5핀

 - master/slave 구조

 - 데이터를 전송하거나 수신하거나 종료하거나 모든 결정은 마스터가 한다.

 - 마스터가 slave로 데이터를 전송

 - 1개의 데이터선이기 때문에 동시에 데이터를 주고 받을 수 없다.

 - 모든 통신은 마스터가 주도

   * 마스터가 slave한테 데이터를 요구하면 slave는 response

   * slave가 먼저 마스터에게 데이터를 보내지 않는다.

 - I2C 통신에서는 slave는 address로 구분한다

                                 ---------

                                  주로 제품을 만든 업체에서 부여한 주소

                                  각 slave는 개별주소를 갖고 있다.

 - SDA와 SCL은 기본적으로 HIGH 상태 유지

 - HIGH에서 LOW로 바뀔때 데이터 전송이 시작

 - 고속 통신이 필요 없을때 하는 통신

https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library

 

GitHub - fdebrabander/Arduino-LiquidCrystal-I2C-library: Library for the LiquidCrystal LCD display connected to an Arduino board

Library for the LiquidCrystal LCD display connected to an Arduino board. - GitHub - fdebrabander/Arduino-LiquidCrystal-I2C-library: Library for the LiquidCrystal LCD display connected to an Arduino...

github.com

 

여기서 zip파일을 다운 받고

방금 받은 zip파일을 선택하면 된다.

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2); //adress,열,행
void setup() {
  lcd.begin();
  lcd.print("hello");
}

void loop() {
  
}

이렇게 하고 글씨가 나오는지 보자.

글씨가 안나오면 

이걸 돌려주면 글씨가 나오게 된다.

https://maxpromer.github.io/LCD-Character-Creator/

 

LCD Custom Character Generator

Clear      Invert Link

maxpromer.github.io

한글로 글씨 쓰기

 

 

 

<SPI (Serial Peripheral Interface)>

 - 근거리에 있는 부품들끼리 통신을 하기 위해서 만들어진 기술

 - 3개의 선을 이용한다.

   MOSI (Master Output Slave Input) : 데이터선

   MISO (Master Input Slave Output) : 데이터선

   SCK : 클럭 신호를 전송하기 위한 선

 - 모든 통신의 시작과 통신의 방향은 마스터가 결정

 - I2C통신보다 속도가 빠르다.

 - chip selection핀을 가지고 구분한다.

   * 기본상태로 HIGH값을 유지하고 있다.

   * 이 HIGH값이 LOW로 바뀌는 순간 데이터가 전송되는 slave를 구분한다고 생각하면 된다.

   * 데이터 전송이 완료되면 LOW신호를 HIGH신호로 바꿔준다.

 

 

RFID 칩을 보자.

UART, I2C, SPI 통신이 모두 가능하다

가능한 핀 번호들도 다 나와 있다.

 

우노보드 데이터시트

 

오른쪽 핀부터 꼽아보자.

3.3V - 3.3V연결

RST - 9번핀

GND - GND핀

IRQ - 인터럽트 핀 - 아직 안씀

MISO - 12번핀

MOSI - 11번핀

SCK - 13번핀

SDA - 10번핀

 

라이브러리 매니저에 들어가서 MFRC검색 한다음

by GithubCommunity 있는것을 설치해준다.

 

#include <MFRC522.h>
#include <SPI.h>
//Slave와 통신할 수 있도록 SS핀과 reset핀을 셋팅하고 MFRC522클래스를 생성
#define SS_PIN 10
#define RESET_PIN 9

MFRC522 rfid(SS_PIN, RESET_PIN); //rfid를 사용하기 위한 메인객체
void setup() {
  Serial.begin(9600);
  SPI.begin();
  rfid.PCD_Init(); //MFRC522 초기화
}

void loop() {
  //태그가 접촉되지 않거나 ID가 읽히지 않는 경우 체크
  //PICC_IsNewCardPresent() -> 태크가 접촉되면 1을 리턴
  //PICC_ReadCardSerial() -> id를 읽으면 1을 리턴
  if(!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) {
    delay(500);
    return;
  }
  //태그의 ID를 출력
  //태그의 고유ID (UID)
  //UID는 식별자 - 장비를 식별하기 위해서 사용하는 값
  //              4가지 숫자가 조합
  //MFRC522라이브러리를 통해 접근할 수 있는 uid 객체의 uidByte배열에 저장되어 있다.
  Serial.print("카드의 Tag ID:");
  for(byte i=0; i<4; i++) {
    Serial.print(rfid.uid.uidByte[i]);
    Serial.print(" ");
  }
  Serial.println();
  delay(1000);
}

그럼 시리얼모니터에 태그 uid가 뜰거다.

 

 

문제)

조건을 만족할 수 있도록 출입 관리 시스템 구현

RFID, PIR센서, I2C LCD, 부저, LED, 서보모터를 이용, push버튼

조건

1. PIR센서를 이용해서 접근하는 사용자가 있는 경우 LCD에 접근자가 있음을 출력

2. RFID태그를 인식해서 미리 등록된 사용자인 경우

   - 서보모터를 이용하여 도어를 개방한다.

   - 문이 열린 후 10초 후에 문이 닫히도록 구현

   - LCD에 환영합니다. 메시지 출력

3. RFID태그를 인식해서 미리 등록된 사용자가 아닌 경우

   - 삐 소리가 출력되도록

   - 잘못된 사용자입니다. 메시지 출력

   - led불들어 오도록

4. 매니저가 push 버튼을 누르면 문이 열리도록 처리

   (매니저를 인식할 수 없으므로 push버튼을 누르면 동작)

   - 문이 열린 후 다시 push버튼을 누르면 문이 닫히도록 구현

5. 함수를 적절하게 사용하기

 

더보기

lcd 영문 버전

#include <LiquidCrystal_I2C.h> //LCD
#include <MFRC522.h> // RFID
#include <SPI.h> // RFID통신
#include <Servo.h> //서보모터

#define PIR_S 2 //pir핀 번호
#define SS_PIN 10 //rfid
#define RESET_PIN 9 //rfid
#define SERVO 4 //servo모터 핀
#define PIEZO 5 //피에조 부저 핀
#define LEDPIN 7 //LED핀
#define PUSH 8 //버튼 핀

#define DOOROPEN myservo.write(90)
#define DOORCLOSE myservo.write(0)

LiquidCrystal_I2C lcd(0x27,16,2);
MFRC522 rfid(SS_PIN, RESET_PIN);
Servo myservo;
int pirValue; //pir센서 값
int state = 0; //버튼 상태 확인

byte card_uid[] = {162,69,136,26}; //RFID 고유 번호 등록

void setup() {
  Serial.begin(9600);
  lcd.begin();
  SPI.begin();
  rfid.PCD_Init();
  myservo.attach(SERVO);
  DOORCLOSE; //문 닫힌 상태로 설정
  pinMode(PIR_S, INPUT);
}

void loop() {
  pirValue = digitalRead(PIR_S);
  userApproach(pirValue);
  rfidCheck();
  if(digitalRead(PUSH) == HIGH)
    manage();
}

void userApproach(int value) {
  if(value == 1) {
    lcd.setCursor(0,0);
    lcd.print("USER approach");
  }else
    lcd.clear();
}

void rfidCheck() {
  rfid.PCD_Init(); //2번 이상 태그가 되면 2번째부터 태그가 안되어 넣음
  if(!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) {
    delay(500);
    return;
  }
  byte check = 0; // 등록된 회원 아닐경우 확인 용도
  for(byte i=0; i<4; i++) {
    if(card_uid[i] == rfid.uid.uidByte[i]) {
      Serial.print(rfid.uid.uidByte[i]);
      Serial.print(" ");
    }else
      check = 1;
  }
  Serial.println();
  door(check);
}

void door(byte value) {
  if(value == 0) { //등록된 회원이라면
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Welcome");
    DOOROPEN;
    delay(10000);
    lcd.clear();
    DOORCLOSE;
  }else if(value == 1) { //등록되지 않은 회원이라면
    lcd.setCursor(0,0);
    lcd.print("Not User");
    tone(PIEZO, 330,300);
    digitalWrite(7, HIGH);
    delay(5000);
    digitalWrite(7, LOW);
    lcd.clear();
  }
}
void manage() {
  if(state == 0) {
    DOOROPEN;
    state = 1;
  }else if(state == 1) {
    DOORCLOSE;
    state = 0;
  }
}

lcd 한글 버전

#include <LiquidCrystal_I2C.h> //LCD
#include <MFRC522.h> // RFID
#include <SPI.h> // RFID통신
#include <Servo.h> //서보모터

#define PIR_S 2 //pir핀 번호
#define SS_PIN 10 //rfid
#define RESET_PIN 9 //rfid
#define SERVO 4 //servo모터 핀
#define PIEZO 5 //피에조 부저 핀
#define LEDPIN 7 //LED핀
#define PUSH 8 //버튼 핀

#define DOOROPEN myservo.write(90)
#define DOORCLOSE myservo.write(0)

LiquidCrystal_I2C lcd(0x27,16,2);
MFRC522 rfid(SS_PIN, RESET_PIN);
Servo myservo;
int pirValue; //pir센서 값
int state = 0; //버튼 상태 확인
byte check; //회원 체크

byte card_uid[] = {162,69,136,26}; //RFID 고유 번호 등록

byte per_char1[8] = {0x0A,0x0A,0x16,0x17,0x02,0x00,0x00,0x00};//사
byte per_char2[8] = {0x1E,0x06,0x1E,0x13,0x1E,0x02,0x00,0x00};//라
byte per_char3[8] = {0x1F,0x10,0x1F,0x00,0x1F,0x04,0x0A,0x04};//등
byte per_char4[8] = {0x1E,0x0A,0x16,0x17,0x02,0x04,0x0A,0x04};//장
byte per_char5[8] = {0x1F,0x11,0x1F,0x00,0x00,0x00,0x00,0x00};//ㅁ

byte user_char1[8] = {0x0A,0x1E,0x0A,0x17,0x0A,0x00,0x08,0x1E};//화
byte user_char2[8] = {0x09,0x15,0x17,0x09,0x03,0x09,0x14,0x08};//영
byte user_char3[8] = {0x10,0x10,0x1F,0x00,0x00,0x00,0x00,0x00};//ㄴ

byte not_char1[8] = {0x1F,0x10,0x1F,0x00,0x1F,0x04,0x0A,0x04};//등
byte not_char2[8] = {0x1F,0x01,0x1F,0x10,0x1F,0x04,0x04,0x1F};//로
byte not_char3[8] = {0x0A,0x16,0x16,0x0B,0x02,0x08,0x08,0x0F};//안
byte not_char4[8] = {0x0A,0x1E,0x0A,0x17,0x16,0x0A,0x02,0x00};//하
byte not_char5[8] = {0x1E,0x02,0x02,0x02,0x00,0x00,0x00,0x00};//ㄱ
byte not_char6[8] = {0x1F,0x11,0x1F,0x00,0x00,0x00,0x00,0x00};//ㅁ


void setup() {
  Serial.begin(9600);
  lcd.begin();
  SPI.begin();
  rfid.PCD_Init();
  myservo.attach(SERVO);
  DOORCLOSE; //문 닫힌 상태로 설정
  pinMode(PIR_S, INPUT);
}

void loop() {
  pirValue = digitalRead(PIR_S);
  userApproach(pirValue);
  rfidCheck();
  if(digitalRead(PUSH) == HIGH)
    manage();
}

void userApproach(int value) {
  if(value == 1) {
    approach_print();
  }else
    lcd.clear();
}

void rfidCheck() {
  rfid.PCD_Init(); //2번 이상 태그가 되면 2번째부터 태그가 안되어 넣음
  if(!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) {
    delay(500);
    Serial.println("error");
    return;
  }
  check = 0;
  for(byte i=0; i<4; i++) {
    if(card_uid[i] == rfid.uid.uidByte[i]) {
      Serial.print(rfid.uid.uidByte[i]);
      Serial.print(" ");
    }else{
      Serial.println("dd");
      check = 1;
    }
  }
  Serial.println();
  door(check);
}

void door(byte value) {
  Serial.println("eee");
  if(value == 0) { //등록된 회원이라면
    lcd.clear();
    welcome_print();
    DOOROPEN;
    delay(10000);
    lcd.clear();
    DOORCLOSE;
  }else if(value == 1) { //등록되지 않은 회원이라면
    notUser_print();
    tone(PIEZO, 330,300);
    digitalWrite(7, HIGH);
    delay(5000);
    digitalWrite(7, LOW);
    lcd.clear();
  }
}
void manage() {
  if(state == 0) {
    DOOROPEN;
    state = 1;
  }else if(state == 1) {
    DOORCLOSE;
    state = 0;
  }
}

void approach_print() {
  lcd.createChar(0,per_char1);
  lcd.createChar(1,per_char2);
  lcd.createChar(2,per_char3);
  lcd.createChar(3,per_char4);
  lcd.createChar(4,per_char5);
  lcd.setCursor(0,0);
  lcd.write(0);
  lcd.write(1);
  lcd.write(2);
  lcd.write(3);
  lcd.setCursor(1,1);
  lcd.write(4);
}
void welcome_print() {
  lcd.createChar(0,user_char1);
  lcd.createChar(1,user_char2);
  lcd.createChar(2,user_char3);
  lcd.setCursor(0,0);
  lcd.write(0);
  lcd.write(1);
  lcd.setCursor(0,1);
  lcd.write(2);
}
void notUser_print() {
  lcd.createChar(0,not_char1);
  lcd.createChar(1,not_char2);
  lcd.createChar(2,not_char3);
  lcd.createChar(3,not_char4);
  lcd.createChar(4,not_char5);
  lcd.createChar(5,not_char6);
  lcd.setCursor(0,0);
  lcd.write(0);
  lcd.write(1);
  lcd.write(2);
  lcd.write(3);
  lcd.setCursor(1,1);
  lcd.write(4);
  lcd.setCursor(3,1);
  lcd.write(5);
}

 

댓글

Designed by JB FACTORY