1. 딸래미(王)의 귀환
아직 초등학생인 딸래미가 있다. 집에서 먼(대중교통으로 40분) 학원을 다니게 되었는데, 셔틀도 없다. 학원에 갈때는 와이프가 데려다 주지만, 올 때는 내가 퇴근하면서 학원으로 가서 딸래미를 데리고 집으로 온다. 하지만 나도 직딩이라 항상 갈 수는 없는 상황이었다.
딸래미의 귀환 이 걱정되기도 하고, 만일의 사태를 위하여 딸래미에게 선불 교통 카드를 사 주었다.
[ 하트빵빵 귀여운 토끼 버전의 교통카드 ]
한두번 사용해보게 했지만, 잔액을 기억 못하는 상황이라, 집에서도 손쉽게 잔액이 확인 가능하도록 리더를 만들어야 했다.
2. 모듈의 귀환
이번에 제작을 위하여 이전에 사용한
모듈들을 귀환 시켰다. 예전의 포스트에 사용한 PN532 모듈을 제일 먼저 귀환 시키고,
[ PN532를 소개한 포스트 바로 가기 ]
[ PN532 ]
그 다음 OLED 및 ESP8266을 귀환 시켯다.
[ OLED + ESP8266을 이용한 오실로스코프 바로가기 ]
[ OLED ]
3. 제작 결과물 소개
일단 결과물을 소개하면 아래의 이미지와 같다.
[ 나름 투명 아크릴 상판 ]
[ 측면에서 찰칵. 이번엔 배터리 없이 설계 ]
[ 전원을 연결하면 카드를 태깅하라고 궁시렁 ]
[ 좀더 신선하게 고속버스 안에서 촬영 ]
[ 카드를 가져다 대면 잔액이 표시됨 ]
수준이 좀 낮은 상태로 촬영 되었지만, 동작은 아래의 모습으로 진행된다.
VIDEO
4. 제작 방법 소개
납땜할 포인트가 별로 없다. 기껏해야 20-30 포인트 정도된다. 회로도 까지라고 말할 필요도 없고 아래와 같이 연결하면 된다.
[ 심플한 연결도~ ]
나는 모듈들은 모두 소켓 방식을 사용하기 때문에, ESP8266은 기판의 뒷면에 꼽을수 있는 형태로 제작되었다. NFC 나 OLED 모듈은 기판의 앞면에서 꼽는다.
[ 급제작으로 인한 케이블 배선의 엉성함은 참아 주시라~ ]
소스코드는 전체 공개이지만, 라이브러리는 이 포스트에 기록하지 않는다.
먼저 필요한 라이브러리는 2개이다.
PN532관련된 라이브러리는 아래의 링크에서 다운로드 가능하다.
https://github.com/adafruit/Adafruit-PN532
OLED에 한글을 출력하는 과정은 나름 껄끄롭지만, 그 전체 과정 및 라이브러리는 아래의 링크에서 다운로드 가능하다.
http://andy-power.blogspot.com/2018/08/oled.html
대략 이번 선불 교통카드 잔액 조회 기능을 만들기 위해서는 100행 정도를 코딩했으며, 코딩된 전체 내용은 아래와 같다.
/*
------------------------------------------------------
T-Money Checker
+-------- GPL License
--------------------------------+
do not remove contact & url
contact :
terminal0070@gmail.com
blog :
https://andy-power.blogspot.com/
--------------------------------------------------------
*/
#include <Arduino.h>
#include "Adafruit_PN532.h"
#include "Display_SSD1306.h"
#include "HanDraw.h"
#define OLED_RESET - 1 // S/W 리셋 .. 사용하지 않음
// PN532 V3 를 SPI 모드로 사용하기 위해서는 모듈의 스위치를 변경하고 VCC,GND 를 포함하여
// 총 6 개의 선 연결이 필요하다 .
// ESP8266 기준으로 핀 정의
#define PN532_SCK (D5) //
#define PN532_MOSI (D7) //
#define PN532_SS (D3) //
#define PN532_MISO (D6) //
// I2C 모드를 이용하기 위해서는 아래 2 개 선 연결이 필요하다 .
#define PN532_IRQ ( 2 ) // Not Use
#define PN532_RESET ( 0 ) // Not connected by default on the NFC
Shield
//--------------------------------------------------------------
// Global
variables
//--------------------------------------------------------------
Display_SSD1306 Oled (OLED_RESET); // 화면 표시용 객체
Adafruit_PN532 nfc (PN532_SS); // NFC 용 객체
//--------------------------------------------------------------
// Setup
function
//--------------------------------------------------------------
void setup () {
Serial. begin ( 115200 );
delay ( 50 );
pinMode (LED_BUILTIN,
OUTPUT);
digitalWrite (LED_BUILTIN,
HIGH); // 내장 LED 끄고
Serial. println ( "Start
NFC" );
nfc. begin ();
uint32_t versiondata = nfc. getFirmwareVersion ();
if (! versiondata) {
Serial. print ( "Didn't
find PN53x board" );
while ( 1 ); // PN532 를 못찾은 경우에는 다시 부팅해 버린다 .!! ( 찾을때 까지 리부팅 )
}
// 제대로 연결되었으면 정보를 출력한다 .
Serial. print ( "Found chip
PN5" ); Serial. println ((versiondata >> 24 ) & 0xFF , HEX);
Serial. print ( "Firmware
ver. " ); Serial. print ((versiondata >> 16 ) & 0xFF , DEC);
Serial. print ( '.' ); Serial. println ((versiondata
>> 8 ) & 0xFF , DEC);
// Oled 를 I2C 방식으로 연결하고 , 그 주소는 0x3c
Oled. begin (SSD1306_SWITCHCAPVCC,
0x3C , false );
// Callback 함수를 설정해 주면 필요시 호출 하여 사용함 .
HanDraw. begin ( 12 ,
[]( void ) { Oled. clearDisplay (); }, // 화면 지우는 콜백함수
[]( int16_t x, int16_t y, uint16_t color) { // 1 개 픽셀을 그리는 콜백 함수
Oled. drawPixel (x, y,
color); },
[]( void ) { Oled. display (); } // 메모리에서 Display 표시 버퍼까지 보내는 함수
);
// configure board to read RFID tags
nfc. SAMConfig ();
Serial. println ( "Waiting
for an ISO14443A Card ..." );
HanDraw. display (); // 사실상 Oled.display() 와 동일 ....
delay ( 2000 );
HanDraw. clear ();
HanDraw. setFontSize ( 16 );
HanDraw. drawString ( 1 , 13 , " 선불 교통 카드를 " );
HanDraw. drawString ( 1 , 33 , " 태그해 주세요 " );
HanDraw. display (); // 사실상 Oled.display() 와 동일 ...
}
//--------------------------------------------------------------
// loop function
//--------------------------------------------------------------
void loop () {
uint8_t success;
uint8_t responseLength = 64 ;
success = nfc. inListPassiveTarget ();
if (success) {
Serial. println ( "Found
something!" );
// T-money 카드번호 , 날짜등을 읽기 위한것
// OLED 에는 표시하지 않음
uint8_t
cardInfo[responseLength];
uint8_t cardNumSize = 0 ;
uint8_t selectApdu[] = { 0x00 , 0xA4 , 0x00 , 0x00 , 0x02 , 0x42 , 0x00 };
success = nfc. inDataExchange (selectApdu, sizeof (selectApdu),
cardInfo, &responseLength);
if (success) {
Serial. print ( "responseLength:
" ); Serial. println (responseLength);
nfc. PrintHexChar (cardInfo,
responseLength);
if (responseLength
>= 24 ) {
Serial. print ( "card
number : " ); nfc. PrintHexChar (cardInfo + 8 , 8 );
Serial. print ( "card date
: " ); nfc. PrintHexChar (cardInfo + 21 , 4 );
}
}
// 잔고 조회용
// 조회가 완료되면 OLED 에 표시
uint8_t
balance[responseLength];
uint8_t balanceApdu[] = { 0x90 , 0x4C , 0x00 , 0x00 , 0x04 } ;
success = nfc. inDataExchange (balanceApdu, sizeof (balanceApdu),
balance, &responseLength);
if (success) {
Serial. print ( "responseLength:
" ); Serial. println (responseLength);
nfc. PrintHexChar (balance,
responseLength);
if (responseLength
>= 4 ) {
char fpsbuf[ 32 ] = "" ; // 숫자를 문자열로 바꾸어 화면에 출력할때 사용됨
uint32_t money =
balance[ 0 ] * 256 * 256 * 256 + balance[ 1 ] * 256 * 256 + balance[ 2 ] * 256 + balance[ 3 ];
HanDraw. clear ();
HanDraw. drawString ( 2 , 7 , " 교통 카드 잔액 " );
HanDraw. drawString ( 2 , 25 , "------------------" );
dtostrf (( float )money, 10 , 0 , fpsbuf);
HanDraw. drawString ( 2 , 43 , fpsbuf);
HanDraw. display ();
delay ( 2000 );
Serial. print ( "money :
" ); Serial. println (money);
}
}
}
else {
HanDraw. clear ();
HanDraw. drawString ( 1 , 13 , " 선불 교통 카드를 " );
HanDraw. drawString ( 1 , 33 , " 태그해 주세요 " );
HanDraw. display (); // 사실상 Oled.display() 와 동일 ...
}
delay ( 100 );
}
-2024-03-11 추가
위의 코드는 일반적인 선불 교통카드에 대한 조회 기능이다. 휴대폰의 NFC 교통카드 번호 확인은 위의 코드로 불가능하다. nsmaster 님이 알려주신 아래의 APDU로 휴대폰의 교통카드 번호가 확인하다고 댓글을 달아 주셨다. (감사합니다.)
{0x00, 0xA4, 0x04, 0x00, 0x07, 0xD4, 0x10, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00}
집안에 안드로이드폰이 없어서 아직 확인은 못했다.
5. 끝으로
사실 일전에 다 연구한 모듈과 내용을 다시금 정리하고 디스플레이를 추가한 결과물이다. 조회기만을 만드는 것은 당일 저녁 딸래미를 학원에서 집까지 데려오고 나서 시작해서 그날 잠자기 전에 다 만들었다. (수 시간 정도 걸림) 예전에 NFC 모듈 연구 당시 선불교통카드에 APDU 방식으로 커멘드를 보내고 받아야 하는데, 보내야하는 커멘드를 어느 자료에서도 찾을 수가 없어서 정말 고생했다. 이 포스트에서는 관련 커멘드는 1행의 소스코드로 공개되었지만, 이 1행의 코드는 수일간 고생해서 알아낸 코드이다. 연구는 끝이 없고 시간은 적으며, 흰머리는 너무나도 빠르게 늘어간다. ㅠㅠ