본문 바로가기

아두이노/IoT 아두이노 프로젝트!

[Home-Automation] Wizwiki-W7500 + RFID-RC522 + Web Server 구현하기

Wizwiki-W7500 Platform을 이용하여 RFID를 읽어보는 예제를 구현하였다.
RFID가 Tag되면 Buzzer가 울리고 RFID 정보를 Web page에 출력하여 정상적으로 RFID가 출력되는 것을 확인하는 것이 목적이다.

-응용범위

위 예제는 RFID를 Tag하면 Web server로 RFID가 보여지게 구현을 하였다. 차후 이 예제를 변형하여 제작한다면, RFID가 Tag되면 모터를 동작하여 도어의 여닫이를 컨트롤할 수 있겠고, 혹은 Log를 Web Server로 출력하여 언제 Tag가 되었는지 나타낼 수 있을 것이다.

- Need item
1. RFID-RC522
2. Wizwiki-W7500
3. Buzzer
4. Wire Cable (connect to board)
5. USB cable (Firmware download)
6. LAN Cable

- Content creation sequence
1. RFID-RC522를 이용하여 먼저 RFID가 읽히는지 구현.

2. RFID 정보를 Web page로 출력하게 구현.

- IDE (TOOL)
1. KEIL - KEIL Compiler
2. mbed - WEB Compiler

Wizwiki-W7500보드는 공식적으로 2개의 IDE를 제공한다. 여기서 필자는 mbed - WEB Compiler를 사용하였다.

- Description
1. Wizwiki-W7500
Wizwiki-W7500은 Arduino compatible한 Connector를 가지고 있기 때문에 mbed & Arduino 호환이 가능하다.
그리고 Wizwiki-W7500의 Main MCU는 W7500으로 ARM-CoretexM3 + TCP/IP Stack 을 구현한 칩이다.

2. RFID-RC522
RFID-RC522은 passive 방식(카드를 reader에 가져다 대면 작동), 13.56Mhz 주파수를 통해 작동하는 RFID를 지원한다. 일반적으로 회사에서 쓰는 신분증 태그가 이를 활용한다. ISO14443A 프로토콜 호환되는 태그를 지원한다고 하며, 매우 낮은 전력으로 작동하므로(30mA이하) Arduino UNO의 3.3V 전원 공급만으로 작동한다. (그렇다 이 부품은 3.3V 기반이다. 5V에 꼽지 않도록 유의하자.)
구글 위키에서 RFID에 대한 설명을 확인 바란다. https://ko.wikipedia.org/wiki/RFID

RFID-RC522는 SPI / I2C 방식을 지원한다. 여기서 필자는 SPI방식을 채택하여 구현하였다. 그리고 RFID가 읽히면 Buzzer에서 소리가 나오게 제작을 하였다.

그렇다면, 제작에 앞서 어떻게 H/W 연결을 할 것인지 아래 그림을 확인바란다.

RFID_HW

위 그림을 보면 SPI 및 3.3V / GND를 간단하게 연결하여 구성해논 것을 확인할 수 있다.

자, 이제 H/W를 구현하였으니, F/W를 구현할 차례이다. 먼저 구현하기에 앞서 RFID가 어떤 방식으로 동작하는지 알아볼 필요가 있다.
아래의 그림을 확인하면 RFID가 어떠한 동작을 하는지 알 수 있다.

RFID_원리

위 그림의 원리대로 코드를 구현하면 된다.

3. Web Server
Web Server는 Wiznet사의 Echoback Library를 기반으로 제작을 하였다.
Echoback은 Loopback이라고도 불리며, 모든 Ethernet 통신의 기반이 되는 코드이다.

Web server는 Web Client(browser)와 TCP 통신을 하며, HTTP기반 통신을 한다.
Web Server를 이해하기 위해서는 먼저 TCP통신을 이해할 필요성이 있고, HTTP가 무엇인지, HTML이 무엇인지 알아야 한다.

아래에 기본적인 설명을 기재하였다. 확인바란다.

HTML(HyperText* Markup* Language)
웹 문서를 만들기 위하여 사용하는 기본적인 프로그래밍 언어의 한 종류이다. 하이퍼텍스트를 작성하기 위해 개발되었다.

HTTP(HyperText* Transfer Protocol)
- Web Server와 Web Browser간 통신하기 위한 하나의 규약(약속)이다.

Web Server
- Web Browser로부터 HTTP 요청을 받아들이고, HTML 문서 등의 웹 페이지를 Web Browser로 전달하는 컴퓨터 프로그램.

*HyperText – 여러가지의 정보를 효과적으로 연결 or 관리하기 위한 문서
기존의 문서가 순차적이며 서열형 구조라면, 하이퍼텍스트는 링크에 따라 그 차례가 바뀌어 임의적이면서 나열형인
구조를 가진다. Hyper link와 함께 사용
*Markup – 문서에 포함된 문장, 표 소리 등과 같은 문서 내용의 정보가 아니라, 그 문장과 그림, 표가 어떻게 배치되고
글자는 어떤 크기와 모양을 가지며, 들여쓰기와 줄간격, 여백은 어느정도인지에 대한 정보를 의미한다.

- Source (Code)

아래의 mbed wiki에도 Code를 올려놓았으니 그대로 받아서 사용해도 무방하다.
https://developer.mbed.org/users/najgh08/code/RFID-RC522-WebServer-WIZwiki-W7500/

Main 코드는 아래와 같다.
1. MFRC522.h - RFID Library
2. EthernetInterface.h - WIZnet TCP Library

2가지의 Library를 포함하여 제작하였다.

[code language="c"]
#include "mbed.h"
// Ethernet
#include "EthernetInterface.h"
// MFRC522(RFID)
#include "MFRC522.h"

#define WEB_SERVER_PORT   80

Serial pc(USBTX, USBRX);

// MFRC522 reset (pick another D pin if you need D8)
#define MF_RESET    D8
// Buzzer
#define VOLUME 0.02
#define BPM 100.0
// LED
DigitalOut Led(LED1);

// Buzzer
PwmOut pwm_pin(D3);
 
// Plays a sound with the defined frequency, duration, and volume
void playNote(float frequency, float duration, float volume) {
    pwm_pin.period(1.0/(double)frequency);
    pwm_pin = ((double)volume/2.0);
    wait(duration);
    pwm_pin = 0.0;
}
float beat_duration;

// CARD number
uint8_t CARD_1 = 0x44;
uint8_t CARD_2 = 0xCB;
uint8_t CARD_3 = 0x2A;
uint8_t CARD_4 = 0xA4;

uint8_t CARD_5 = 0xA2;
uint8_t CARD_6 = 0xCE;
uint8_t CARD_7 = 0xEC;
uint8_t CARD_8 = 0xD5;

MFRC522    RfChip   (D11, D12, D13, D10, MF_RESET);

//HTTP WEB SERVER
// recv buffer
char recv_buffer[1024] = {0,};
// send
char echoHeader[1024] = {0,};
char * findrfid = 0;
char change_rfid[4] = {1,2,3,4};

int main (void) 
{
    pc.printf("1st starting...\r\n");
    printf("2nd starting...\r\n");
    
    // Init. RC522 Chip
    RfChip.PCD_Init();
    pc.printf("Init end\r\n");
    // WEB SERVER Start
    printf("Wait a second...\r\n");
    #ifdef dhcp
        uint8_t mac_addr[6] = {0x00, 0x08, 0xDC, 0x00, 0x01, 0x02}; 
        EthernetInterface eth;
        eth.init(mac_addr); //Use DHCP
        eth.connect();
    #else
        uint8_t mac_addr[6] = {0x00, 0x08, 0xDC, 0x00, 0x01, 0x02};
        char ip_addr[] = "192.168.1.111";
        char subnet_mask[] = "255.255.255.0";
        char gateway_addr[] = "192.168.1.1";
        EthernetInterface eth;
        eth.init(mac_addr, ip_addr, subnet_mask, gateway_addr); //Not Use DHCP
        
        while(1) { //Wait link up
        if(eth.link() == true)
            break;
        }
        printf("Check Ethernet Link\r\n");
        printf("Link up\r\n");
    #endif
    
    #ifdef TARGET_WIZWIKI_W7500
    #endif
    
    //eth.connect();
    printf("Server IP Address is %s\r\n", eth.getIPAddress());
    
    TCPSocketServer server;
    server.bind(WEB_SERVER_PORT);
    printf("bind complete\r\n");
    server.listen();
    printf("listen complete\r\n");
    while (true) 
    {    
        printf("Wait for new connection...\r\n");
        TCPSocketConnection client;
        server.accept(client);
        client.set_blocking(false, 15000); // Timeout after (1.5)s
        
        printf("Connection from: %s\r\n", client.get_address());

        while (true) {            
            int n = client.receive(recv_buffer, sizeof(recv_buffer));
            if (n <= 0) break; // n = n < 0
            
            // print received message to terminal
            recv_buffer[n] = '\0';
            printf("Received message from Client :'%s'\r\n",recv_buffer);
            if(recv_buffer[0] == 'G' && recv_buffer[1] == 'E' && recv_buffer[2] == 'T')
            {
                printf("GET request incomming.\n\r");
                
                //setup http response header + data
                char send_buffer[] = "\r\n\n\r\n\r\n\r\n\r\n\r\n\rWizwiki-W7500 Web Server\n\r\n\r\n\r\n\r\r\n

Wizwiki-W7500 Home-Automation RFID

\r\n

Read RFID = $$$$$$$$$$$

\r\n\n\r\r\n";
                
                findrfid = strstr(send_buffer, "$$$$$$$$$$$");
                memset(findrfid,0,11);
                sprintf(change_rfid, "%X,%X,%X,%X", RfChip.uid.uidByte[0],RfChip.uid.uidByte[1],RfChip.uid.uidByte[2],RfChip.uid.uidByte[3]);
                memcpy(findrfid,change_rfid,11);                  
                
                sprintf(echoHeader,"HTTP/1.1 200 OK\n\rContent-Length: %d\n\rContent-Type: text/html\n\rConnection: Closen\n\rRefresh: 5\n\r\n\r\n\r",strlen(send_buffer));
                client.send(echoHeader,strlen(echoHeader));
                client.send(send_buffer,strlen(send_buffer));
                
                // RFID Area
                // Look for new cards
                if ( ! RfChip.PICC_IsNewCardPresent())
                {
                  wait_ms(500);
                  continue;
                }
                // Select one of the cards
                if ( ! RfChip.PICC_ReadCardSerial())
                {
                  wait_ms(500);
                  continue;
                }
                // Print Card UID
                pc.printf("Card UID: ");
                for (uint8_t i = 0; i < RfChip.uid.size; i++)
                {
                  pc.printf(" %X02", RfChip.uid.uidByte[i]);
                }
                pc.printf("\n\r");
                // Print Card type
                uint8_t piccType = RfChip.PICC_GetType(RfChip.uid.sak);
                pc.printf("PICC Type: %s \n\r", RfChip.PICC_GetTypeName(piccType));
                wait_ms(1000);
                
                // RFID check
                if((RfChip.uid.uidByte[0] == CARD_1) && (RfChip.uid.uidByte[1] == CARD_2) && (RfChip.uid.uidByte[2] == CARD_3) && (RfChip.uid.uidByte[3] == CARD_4))
                {
                    // Buzzer Sound
                    pc.printf("TAG Read !\r\n");
                    beat_duration = 60.0 / BPM;
                    playNote(999.999, (0.75 * (double)beat_duration), VOLUME);
                }
                else if((RfChip.uid.uidByte[0] == CARD_5) && (RfChip.uid.uidByte[1] == CARD_6) && (RfChip.uid.uidByte[2] == CARD_7) && (RfChip.uid.uidByte[3] == CARD_8))
                {
                    pc.printf("CARD Read !\r\n");
                    beat_duration = 60.0 / BPM;
                    playNote(111.111, (0.75 * (double)beat_duration), VOLUME);
                }
            }
            if (n <= 0) break;
        }
        client.close();
    }
}
[/code]

- Result

결과 page는 다음과 같다.

web_page

-향후 PLAN

Web page가 아니라 App으로 연동하는 좀 더 상품성 있는 제품을 제작해보겠다.