DIY FSK RFID Reader

This page describes the construction of an RFID reader using only an Arduino (Nano 3.0 was tested, but others may work), a hand-wound wire coil, and some assorted low cost common components.

Credits

The hardware and software designs for this project are based in part on the ideas, code and schematics posted by Micah Dowty here and Asher Glick here.

Background

RFID readers are devices sold by companies such as Parallax to read RFID tags with embedded identification circuits (we focus here on passive tags, activated by the reader's transmitted RF energy). The design presented here shows how to wind a simple wire loop by hand (or create an equivalent printed circuit spiral version), connect it to an Arduino (or its chip), add a few low cost common components and create your own RFID reader. To make it more interesting (i.e. challenging), we will focus on the FSK class of RFID tags, which are fairly common among the 125kHz devices, but for some reason are not supported by the Parallax kits.

Micah Dowty has shown a design for an FSK/ASK RFID reader built around a Parallax Propeller device. His code, which is in assembly language, implements an ingenious (but complex) algorithm to create a dynamically variable analog bias voltage, which is used to pull the weak RFID signal into range, so it can be discriminated into binary signals by the Propeller's digital input circuitry. He also dynamically tweaks the transmit/receive RF frequency to keep the antenna's tank circuit in peak resonance for optimal signal to noise. There are three problems with his approach: first, the passive detection circuit lacks amplification, which makes it very sensitive to noise and therefore raises reliability issues. Second, the design is based on the Propeller chip, and if you are a fan of the Arduino and/or associated Atmel AVR chips, it leaves you out. And third, the dynamic slewing of frequencies and bias voltage is overly complicated, making it hard to debug. His general concept is attractive, however: use a microcontroller chip and wind your own wire loop to create, with some simple components and appropriate code, a complete DIY RFID reader.

Asher Glick has presented a solution for reading and decoding FSK RFID tags using the Arduino/AVR family (which he calls AVRFID), which is good except it apparently requires obtaining and modifying an existing Parallax RFID reader device (which natively only supports ASK).

Our goal here is to present a simple solution for reading FSK tags which addresses the above shortcomings: make it robust and reliable for real-world noise environments, base it on the Arduino, and build the RFID reader ourselves using a few simple low-cost parts, rather than buying and/or modifying one.

Circuit

Arduino DIY FSK-RFID circuit diagram:

The circuit diagram above was derived from the "World's Simplest RFID Reader" design posted by Micah Dowty. Based on the Parallax Propeller, Micah's approach was to use passive components only, without amplification, in order to achieve the ultimate in simplicity. The lack of amplification, however, results in a weak signal, potentially less than 2V PTP. This signal is then biased by an analog level produced by the Propeller, to try to maintain the signal's DC level near the discrimination point of the Propeller's binary-digital input circuitry. His code attempts to dynamically calculate that optimal midpoint level, and feed it into the circuit using a filtered PWM DAC output. Since the signal is weak, it can be distorted by interference and noise, which results in reduced reliability. The circuit presented here includes (as Micah suggests in his documentation) one active component: a common low-cost LM234 quad-opamp IC (or equivalent). This addition provides several significant advantages, at a negligible cost. First, the signal is amplified (using one of the four opamps on the IC package) to a more noise-immune level (of 2-3 volts PTP). Second, the DC level of the signal is maintained at exactly Vcc/2 using another opamp on the IC, which eliminates the need for the DC propping code in the Arduino. Third, having the signal amplifier in place allows another low-pass RC filter stage (another capacitor and resistor), which makes the final discriminated digital signal cleaner and more reliable. The end result is a more robust detected signal with improved noise immunity.

As a quick review of the circuit, the loop is made of a toroidally-wound #22-30 magnet wire (we used an empty roll of Scotch 3.25" I.D. packing tape as former), and can be remoted from the circuit if needed, via coaxial cable. The inductor L1 and capacitance C1 should be matched to resonate at around 125 kHz. When driven at its resonant frequency by the Arduino's 0-5 volt square wave signal, the center point of the resonator (which connects to D1's cathode) will have a fairly pure voltage sine wave, of about 30V PTP. When coupled to an RFID tag, the pure sine wave RF will fluctuate visibly as the tag opens and closes its own loop antenna to repeatedly transmit its code. This modulation is then detected from the RF envelope by D1, C2 and R1, which produce a negative bias voltage with the small detected coded signal, e.g. about 11 RF cycles per coded cycle. The coded cycles are of two different wave lengths (or frequencies), which represent streams of logic ones and zeros, and they need to arrive at the Arduino chip as binary levels which can be timed reasonably accurately so as to reliably tell the difference between the two distinct frequencies.

The relatively large capacitor C3 decouples the negative bias voltage from the signal, and is followed by a low-pass RC filter stage (R2 and C4) which attenuates some of the residual RF spikes from the lower frequency coded RFID signal. Capacitor C5 decouples the resulting signal and presents it to the amplification stage, implemented by the LM324 opamp, IC1. The latter amplifies the weak signal from about .15V to about 3V PTP (depending of the ratio of R4 to R3), and places it on top of a Vcc/2 bias voltage, about 2.5V in the arduino's case. This signal is then fed into one of the digital input ports on the Arduino (which also includes some helpful hysteresis), and is discriminated by the internal comparator into a square wave of ones and zeroes.

Software

The Arduino sketch, derived from the code posted by Asher Glick, uses a single timer channel in the Arduino (using the Timer1 library) for both RF signal generation as well as timing clock to count the width of each input signal wave. There are two distinct cycle lengths in the detected input signal, "long" and "short", corresponding to logical ones and zeroes, respectively. A binary stream of stretches of repeated ones and zeroes is assembled, and then decimated into the original coded bits on the RFID tag, after decoding the Manchester encoding.

Here is the actual code:

/*  Arduino program for DIY FSK RFID Reader
 *  See description and circuit diagram at http://playground.arduino.cc/Main/DIYRFIDReader
 *  Tested on Arduino Nano and several FSK RFID tags
 *  Hardware/Software design is based on and derived from:
 *  Arduino/Timer1 library example
 *  June 2008 | jesse dot tane at gmail dot com
 *  AsherGlick: / AVRFID https://github.com/AsherGlick/AVRFID
 *  Micah Dowty:
 *  http://forums.parallax.com/showthread.php?105889-World-s-simplest-RFID-reader
 *
 *  Copyright (C) 2011 by edude/Arduino Forum

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.

 */

#include "TimerOne.h"

int ledPin = 13; // LED connected to digital pin 13
int inPin = 7;   // sensing digital pin 7
int val;
int bitlenctr = 0;
int curState = 0;

#define maxBuf 1000 //reduce to 100 or so for debugging
#define debug  0

char raw[maxBuf];

int index = 0;
int bufnum = 0;
#define   redLED 12
#define   grnLED 11

void setup()
{
  Serial.begin(9600);
  Timer1.initialize(7);  // initialize timer1, and set the frequency; this drives both the LC tank as well as the pulse timing clock
  // note: modify this as needed to achieve resonance and good match with the desired tags
  // the argument value is in microseconds per RF cycle, so 8us will yield RF of 125kHz, 7us --> 143kHz, etc.

  Timer1.pwm(9, 512);           // setup pwm on pin 9, 50% duty cycle
  Timer1.attachInterrupt(callback);  // attaches callback() as a timer overflow interrupt, once per RF cycle

  pinMode(ledPin, OUTPUT);      // sets the digital pin 13 as output for scope monitoring
  pinMode(inPin, INPUT);      // sets the digital pin 7 as input to sense receiver input signal
  pinMode(grnLED, OUTPUT);
  pinMode(redLED, OUTPUT);
  digitalWrite(grnLED, 0);
  digitalWrite(redLED, 1);
}

void callback()
{
  val = digitalRead(inPin);
  digitalWrite(ledPin, val); // for monitoring
  bitlenctr++;
  if(val != curState) {
    // got a transition
    curState = val;
    if(val == 1) {
      // got a start of cycle (low to high transition)
      if(index < maxBuf) {
        raw[index++] = bitlenctr;
      }
      bitlenctr = 1;
    }
  }
}

void loop()
{
  if(index >= maxBuf) {

    Serial.print("got buf num: ");
    Serial.println(bufnum);

    if(debug) {
      for(int i = 0; i < maxBuf;
      i++) {
          Serial.print((int)raw[i]);
        Serial.print("/");
      }
      Serial.println("///raw data");
      delay(2000);
    }

    // analyze this buffer
    // first convert pulse durations into raw bits
    int tot1 = 0;
    int tot0 = 0;
    int tote = 0;
    int totp = 0;
    raw[0] = 0;
    for(int i = 1; i < maxBuf; i++) {
      int v = raw[i];
      if(v == 4) {
        raw[i] = 0;
        tot0++;
      }
      else if(v == 5) {
        raw[i] = raw[i - 1];
        totp++;
      }
      else if(v == 6 || v == 7) {
        raw[i] = 1;
        tot1++;
      }
      else {
        raw[i] = 101; // error code
        tote++;
      }
    }  

    // next, search for a "start tag" of 15 high bits in a row
    int samecnt = 0;
    int start = -1;
    int lastv = 0;
    for(int i = 0; i < maxBuf; i++) {
      if(raw[i] == lastv) {
        // inside one same bit pattern, keep scanning
        samecnt++;
      }
      else {
        // got new bit pattern
        if(samecnt >= 15 && lastv == 1) {
          // got a start tag prefix, record index and exit
          start = i;
          break;
        }
        // either group of 0s, or fewer than 15 1s, so not a valid tag, keep scanning
        samecnt = 1;
        lastv = raw[i];
      }
    }

    // if a valid prefix tag was found, process the buffer
    if(start > 0 && start < (maxBuf - 5*90)) { //adjust to allow room for full dataset past start point
      process_buf(start);
    }
    else {
      Serial.println("no valid data found in buffer");
    }
    if(debug) {
      for(int i = 0; i < maxBuf;
        i++) {
          Serial.print((int)raw[i]);
        Serial.print("/");
      }
      Serial.print("///\nbuffer stats: zeroes:");
      Serial.print(tot0);
      Serial.print("/ones:");
      Serial.print(tot1);
      Serial.print("/prevs:");
      Serial.print(totp);
      Serial.print("/errs:");
      Serial.println(tote);
      delay(1000);
    }

    // start new buffer, reset all parameters
    bufnum++;
    curState = 0;
    index = 0;
  }
  else {
    delay(5);
  }
}

// process an input buffer with a valid start tag
// start argument is index to first 0 bit past prefix tag of 15+ ones
void process_buf(int start) {
  // first convert multi bit codes (11111100000...) into manchester bit codes
  int lastv = 0;
  int samecnt = 0;
  char manch[91];
  char final[45];
  int manchindex = 0;

  Serial.println("got a valid prefix, processing data buffer...");
  for(int i = start + 1; i < maxBuf && manchindex < 90; i++) {
    if(raw[i] == lastv) {
      samecnt++;
    }
    else {
      // got a new bit value, process the last group
      if(samecnt >= 3 && samecnt <= 8) {
        manch[manchindex++] = lastv;
      }
      else if(samecnt >= 9 && samecnt <= 14) {
        // assume a double bit, so record as two separate bits
        manch[manchindex++] = lastv;
        manch[manchindex++] = lastv;
      }
      else if(samecnt >= 15 && lastv == 0) {
        Serial.println("got end tag");
        // got an end tag, exit
        break;
      }
      else {
        // last bit group was either too long or too short
        Serial.print("****got bad bit pattern in buffer, count: ");
        Serial.print(samecnt);
        Serial.print(", value: ");
        Serial.println(lastv);
        err_flash(3);
        return;
      }
      samecnt = 1;
      lastv = raw[i];
    } //new bit pattern
  }

  Serial.println("converting manchester code to binary...");
  // got manchester version, convert to final bits
  for(int i = 0, findex = 0; i < 90; i += 2, findex++) {
    if(manch[i] == 1 && manch[i+1] == 0) {
      final[findex] = 1;
    }
    else if(manch[i] == 0 && manch[i+1] == 1) {
      final[findex] = 0;
    }
    else {
      // invalid manchester code, exit
      Serial.println("****got invalid manchester code");
      err_flash(3);
      return;
    }
  }

  // convert bits 28 thru 28+16 into a 16 bit integer
  int code = 0;
  int par = 0;
  for(int i = 28, k = 15; i < 28+16; i++, k--) {
    code |= (int)final[i] << k;
  }
  int paritybit = final[28+16];
  for(int i = 0; i < 45; i++) {
    par ^= final[i];
  }

  if(par) {
    Serial.print("got valid code: ");
    Serial.println((unsigned int)code);
    // do something here with the detected code...
    //
    //
    digitalWrite(redLED, 0);
    digitalWrite(grnLED, 1);
    delay(2000);
    digitalWrite(grnLED, 0);
    digitalWrite(redLED, 1);
  }
  else {
    Serial.println("****parity error for retrieved code");
    err_flash(3);
  }
}

// flash red for duration seconds
void err_flash(int duration) {
  return;
  for(int i = 0; i < duration*10; i++) {
    digitalWrite(redLED, 0);
    delay(50);
    digitalWrite(redLED, 1);
    delay(50);
  }
}

Status

The device and transceiver antenna have been built and tested on multiple FSK RFID tags of various kinds, in breadboard and soldered perfboard versions, connected to remote and local probes. When the probe is properly tuned, the device can reliably detect FSK RFID tags within a range of 0 to at least 2 inches from the coil, although it may be possible that this can be extended with larger coil sizes and/or other optimizations. The circuit has also been simulated on Spice, as described below.

Spice simulation

LTspiceIV simulated waveforms of FSK RFID reader plus transponder tag:

As seen in the LTspiceIV screenshot above, the circuit (with a passive virtual ground reference - see note below) was simulated on a computer, and the results confirmed the essential design, closely replicating the waveforms actually seen on the oscilloscope. The RFID transponder tag was simulated as a coupled transformer winding with a resonantly tuned capacitor, shunted to ground by a square-wave signal. The RFID tag's ground is connected to the main circuit's ground for simulation purposes. The inductive coupling between the two "transformer windings" is a variable which can be changed in LTspice, and was varied for testing between 1 and 0.01 (0.015 is shown in the waveforms above), equivalent to having the RFID tag positioned at different distances from the reader coil.

Notes

The Vcc/2 virtual ground voltage for IC1's non-inverting input can also be taken directly from the midpoint of the 100K voltage divider resistors, bypassing the second opamp. In such a case, the divider's midpoint should be connected to pin3 of IC1 via a 1M resistor.

References

原帖连接:http://playground.arduino.cc/Main/DIYRFIDReader

时间: 2024-10-28 10:03:54

DIY FSK RFID Reader的相关文章

极客DIY:RFID飞贼打造一款远距离渗透利器

本文使用最新的渗透工具RFID飞贼(Tastic RFID Thief)和RFID感应破解技术来获取一些拥有安防的建筑物的访问权限. Tastic RFID Thief是一个无声远距离RFID读卡器,可不为人知地远距离盗取RFID信息,当不知情人员佩戴门禁卡或射频设备时,便会被它攻破.Tastic RFID Thief针对的是低频125KHz的射频系统,例如那些使用HID Prox或者Indala Prox的产品,不仅如此,你还可以利用它的电路板改造成一个13.56MHz的高频RFID读卡器,这

意法收购AMS RFID资产,助力新业务扩展

最新消息, 意法半导体(以下简称ST)在其官网宣布收购奥地利微电子公司(AMS)NFC和RFID reader的所有资产,获得相关的所有专利.技术.产品以及业务,以强化ST在安全微控制器解决方案的实力,为ST在移动设备.穿戴式.金融.身份认证.工业化.自动化以及物联网等领域的发展提供助力. 据了解,本次收购直接到账的资金是7780万美元,根据收购之后的发展情况还将支付起码1300万美元,最多不超过3700万美元.也就是说本次ST收购AMS总共花费9080万-1.148亿美元. 此外,值得一提的是

进监狱全攻略之 Mifare1 Card 破解

补充新闻:程序员黑餐馆系统 给自己饭卡里充钱 ,技术是双刃剑,小心,小心! 前言 从M1卡的验证漏洞被发现到现今,破解设备层出不穷,所以快速傻瓜式一键破解不是本文的重点,年轻司机将从本文中获得如下技能. 如果你想简单快速的上手,你可以选择ACR122-like,Proxmark3等容易购买到的操作简单的设备,或者有个带有NFC功能并安装有安卓Mifare Classic Tool (MCT)软件的手机也是个不错的选择. 本文基于树莓派加RC522,PN532模块试验,如果你是刚入门的Geek爱好

TRAIS:使RFID更健壮

2015年年底,中国自主研发的一项物联网安全关键技术TRAIS被纳入国际标准,成为中国在物联网核心技术RFID领域的首个国际标准.这条新闻在第二届世界互联网大会召开期间,经新华社记者挖掘并报道,被各大媒体广泛转载,但这项技术究竟指的是什么?记者就此详细采访了这项技术的研发者西电捷通公司RFID安全技术项目组. "这个也太麻烦了吧."黄振海掂着记者给他展示的"超级安全钱包"--某国外品牌生产的射频识别防护RFID钱包笑着说. 在淘宝网的页面上,是这样介绍这款钱包的:随

汽车制造业RFID应用浅析

目前汽车行业信息化程度良莠不齐,有些信息化程度很高,有些则刚刚处于起步状态,有些甚至仍然沿用完全手工操作记录的方式.但所有企业都希望能够建立识别系统来帮助整个企业的管理提升到一定的水平,整个物流环节的效率能够提高,差错率能够降低.虽然各个企业大都建立了自己的ERP系统,但每个企业都存在信息系统各自为政,信息孤岛情况严重,而且信息化程度严重的不一致,我们国内企业的信息化状况尤其落后.可是每个企业对信息化建设的投入却都是长期的,对识别系统建立的迫切性渴望性非常强烈. 汽车零部件工业是汽车工业的重要组

福建档案馆应用RFID技术 实现库房管理现代化

应用RFID技术 实现库房管理现代化 2013年12月,由福州震旦计算机技术有限公司承建的福建省档案馆"档案实体安全认证智能管理系统"项目(一期)通过竣工验收并投入试运行.根据权限,可实现库存档案动态查询.档案目录数据检索.在线申请调阅档案.自动记录档案出入库信息.自动清点档案数量和归库档案定位,以及非法调取档案实时报警灯多项功能.项目(一期)共完成档案数字化近10万卷,有效提升了档案保管工作科学化水平. 福建省档案馆新馆在档案安全管理方面,配备了较为先进的保安防盗报警.摄像监控.红外

科普了!RFID技术的这些事儿

什么是RFID RFID技术(Radio Frequency Identification)即射频识别,俗称"电子标签",是一种非接触式的自动识别技术,可通过无线电讯号识别特定目标并读写相关数据,而无需识别系统与特定目标之间建立机械或光学接触,常称为感应式电子芯片或近接卡.感应卡.非接触卡.电子卷标.电子条形码等.应用非常广泛,如动物芯片.门禁管制.停车场管制.生产线自动化.物料管理等. 三大组成部分:应答器.阅读器.天线 电子标签(Tag)又称应答器.数据载体,由耦合组件及芯片组成,

RFID技术应用带来服装企业的新“革命”

1 服装企业现状 花色.款式.品种变化得很快,这是服装类产品的特点,因此对服装生产企业的管理生产.库存.分发周转速度有较高的要求.过季的品种要很快地清出柜台,换上新的品种.存货不能积压,积压的产品会给企业造成很大的负担.控制存货的数量,保证销售部门有合适的品种放在柜台上,满足顾客的需要;同时也要保证生产出的产品大部分都可以售出,不会产生大量滞销存货是鞋帽服装业企业要考虑的关键问题.同时,服装企业经常遇到一下几个问题:人为因素造成的错装.漏装.多装等装箱数据统计不准确而且慢;盘点需要大量人工作业好

RFID全新风貌展现物联网主导实力

在大卖场结帐时无需大排长龙的等待,只要将整台购物车推过一道装有感应器的门,马上就能瞬间完成结帐,即使带小朋友出门购物也不用担心手忙脚乱,方便又有效率.你还以为这是遥不可及的梦想吗? !其实它早就以不同面貌,融入我们的生活,举凡宠物晶片.智能商店.文物行动导览,甚至是快速追踪疾病的感染源等都拜它所赐.此外,它还可能取代条码,引爆一场物流革命的〝新科技〞究竟是什么? ! RFID全新风貌展现物联网主导实力 RFID(Radio Frequency Identification)无线射频识别系统,又称