RFID仿真器

EM航海卡模拟器





当然,我们去过普通办公室的每个人都对这些非接触式通行证的功能感兴趣。在本文中,我们将讨论非接触式卡的工作原理,并从字面上讲三个无线电组件组成一个仿真器。



RFID技术





RFID标签



RFID的出现(英文射频识别,射频识别)-具有相当宽的频率范围和相当多的不同标准,这些标准以某种方式适用于该技术。供参考:使用的频率为:125-135 kHz,400 kHz,6.78 MHz,13.56 MHz(地铁卡和银行卡),27.125 MHz,40.68 MHz,433.29 MHz,869 MHz,915 MHz,2.45 GHz,5.8 GHz和24.125 GHz。如您所见,频率范围非常宽。



我们将讨论125 kHz频率范围内使用最广泛和保护最少的卡。我将分析EM Marine 4102标准,因为这是我最熟悉的标准。但是,仿真器代码允许您使用工作在125 kHz的其他标准。



为了使我们可以进一步深入研究该理论,应该对RFID的工作原理说几句话。在本文的进一步内容中,将给出与125 kHz EM Marine标准有关的信息,其他RFID解决方案也以类似的方式安排。





阅读器除了进行信息交换外,还提供电源。该标签是由电磁场供电的ROM,通电后,它仅提供记录的信息。





该图清楚地显示了发送器和接收器的布置方式。这两个振荡电路都调谐到谐振状态,用于数据传输和能量传输,为无源标签(我们的卡)供电。



有关工作原理的更多详细信息,请参见[1]。





拆卸后的卡的内部



如果拆卸卡,则可以看到线圈状的天线和填充有化合物的芯片,其中包含ROM和75 pF电容器。



EM4102协议说明



在继续进行之前,让我们了解我们将要模仿的EM4102标准。符合EM4102的RFID标签包含64位只读存储器。实际上,这是ROM,即可以从中读取信息,但是不能更改或写入信息,换言之,该芯片在出厂时已被刷新一次。标签的存储结构如下图所示。





当标签进入RFID阅读器发出的电磁场时,它会从该场接收能量(功率)并开始传输数据。前9位是逻辑位。这些位用作令牌序列,以指示传输开始。由于所有其他数据都使用奇偶校验,因此该9位序列将不再出现在其他任何地方。然后有10组,每组4个数据位和1个奇偶校验位。最后,校验和有4位,最后一个停止位始终为零。



标签在通电时会重复数据传输周期。因此,我们观察到读取器上标签的不断读取。



我将给出一个由标签发送的数据示例,其编号为:0x06是版本号,0x001259E3是数据。





顺便说一句,可以将卡上打印的数字转换为读取器将接收的十六进制数字。例如,数字写在卡上:116,23152



  • 116十进制是0x74十六进制;
  • 十进制的23152是十六进制的0x5A70;


通过将它们组合在一起,我们得到了卡的序列号,读者会给我们:0x00745A70



信号调制



从标签到读取器的数据传输是通过调制读取器载波信号(在我们的情况下,载波频率为125 kHz)进行的。请注意,此载波频率为电源供电,信号由此调制。首先,让我们考虑阅读器和标签之间的简化交互方案。记住这张照片,我们稍后会参考。





如您所见,标签具有一个LC振荡电路,一个用于整流交流电的二极管,一个用于消除纹波的电容器(这是标签电源的一部分)和一个晶体管,通过控制我们可以调制信号。在阅读器上,这将反映在线圈中流动的电流变化中。简而言之,当标签进入阅读器领域时,标签会消耗电流(大约恒定),在传输信息时,标签会改变晶体管消耗的电流值,因此阅读器可以通过测量功耗来接收信号。



读取器使用调制器和线圈产生磁场,并拾取调制后的信号,然后对其进行解码。





载波信号调制的示例



如果我还没有完全使您感到困惑,那么让我们继续。为了传输数据,我们需要调制信号。即,它将所发送的信息的比特叠加在载波频率上。



根据RFID标准,存在三种流行的调制方案:



  • 曼彻斯特代码
  • 两阶段曼彻斯特法则
  • 相移编码


由于EM4102标准使用曼彻斯特编码方案,因此我们将对其进行考虑。当针对EM4102协议进行调制时,一位的传输时间可以是载波频率(125 kHz)的64、32或16个周期。





通过这种编码,标记恰好在一位传输周期的中间改变了信号传输电平。这些时刻从低电平到高电平的转变意味着逻辑“ 1”的状态,而从高电平到低电平的转变代表逻辑“ 0”的状态





在读取器线圈上捕获的实际调制信号。



制作RFID​​仿真器



好吧,如果您仍然在这里,但这样的计算并没有使您的头肿胀,那么该是从两个部分来制造RFID仿真器的时候了。这个简单之处在于天才。我组装了设备,借鉴了Micah Dowty的想法和代码,照片是我的。





这是一种微型蟑螂,可以很好地模仿



Project站点标签。该代码非常有趣,可以说精妙而简洁(使用了汇编程序)。让我们对其进行详细介绍。我们将对其进行分析。您可以在此处查看代码



首先,让我们弄清楚这个东西通常是如何工作的,尽管按照定义它不起作用,因为它与通常的微控制器接线图相矛盾。设备图取自源代码。









女士们,先生们,大约1μH的电感器和一个ATtiny85微控制器,这是真正的黑客,当您对设备操作特性的理解水平使您能够创建超出制造商指定限制的技术解决方案时!并且它可以工作,需要亲自验证。这是“黑客”一词的真实含义,与黑客和盗窃无关。



展望未来,我要说的是该线圈不足以进行正常操作,但我不得不制作一根普通天线,挂起电源电容器和一个谐振电容器。但是,为了说明工作原理,这是非常合适的。

它是如何工作的:



  • AVR /. /, . , . , . , . , . , .
  • AVR. , , , ( 0,1 ). AVR. , , 125!
  • . ATtiny85 2,5 . 1,8 . AVR , ...
  • , ! , , . Clock ! 125 , RFID. , !
  • ? -, . . EM4102 32 . HID FSK 4 . RFID- . « » , RFID -.
在解析该仿真器的代码之前,让我们使其成为普通天线。我对当前电路的实验显示出其工作极度不稳定。它仅在离读者很近的地方起作用,即使如此,也并非总是如此。因此,首先我在控制器的电源引脚上焊接了一个0.1 F电容,然后决定制作一个真正的大型振荡电路,如真实标签所示。





第一个修改是用于电源的0.1 uF电容器



天线制作



制作线圈天线没有任何技巧,但是您仍然需要熟悉文档并了解过程的物理原理……这并不困难,即使是小学生也可以处理,只需要一点耐心和毅力即可。



就像[1]中的图片一样,组装和配置天线非常容易





要计算天线,您需要记住一些理论。我们需要制作一个可调谐到125 kHz频率的振荡电路。让我们打开“电气工程理论基础”课程,然后阅读振荡电路是什么:

振荡电路,包含电感器和电容器的电路,在其中可以激发电振荡。




并联振荡电路



如果我们不考虑所有数学原理,则振荡电路具有谐振频率等参数,该参数由公式确定。



f=12πLC



其中f是振荡频率,L是线圈的电感,C是电容器的电容。



在这种情况下,我们有一个固定的参数-频率,我们可以使用电容和电感。为了计算线圈,我们将使用文档[2]。每个以某种方式要制造RFID标签天线(任何频率)的人都必须熟悉它!

对于读者和仿真器来说,很多工匠(这一点并不重要)都制造圆形线圈。它们更易于计数和制造,但是它们有一个明显的缺点-它们的线性尺寸比卡片大。我想制造一个矩形的电感器,其线性尺寸小于标准卡的尺寸,从而使设备成为标准RFID卡的尺寸。结果,我选择的未来电感器的尺寸实际上与现在的标记相同,即大约70x40 mm... 如果选择10 nF的电容,则线圈的电感(根据上述公式)对于我们应该为162μH。现在,让我们看一下计算矩形线圈的文档。为了缠绕线圈,我选择了横截面为0.2毫米的电线。结果,我们打开了文档的相应部分,并向我们展示了以下辉煌的公式。





如您所见,线圈厚度和宽度的参数是未知的且可变的(它们取决于0.2 mm的线厚),但是一般的估算值是42圈。可以进行多次迭代,并进行简单,准确的计算,但是在我们的情况下,它可以做到。



之后,需要制作一个70x40 mm的框架来缠绕线圈。我是用PCB制造的,并在其上绕了一个线圈。





PCB框架







绕组和成品线圈



不幸的是,我没有电感计,所以我不得不使用科学的oke法进行进一步研究。由于我可能在计算时以及在缠绕线圈时圈数方面都犯了一个错误,因此我大概是用肉眼做的,所以我决定手动选择谐振电容。为此,我将线圈固定在读卡器上,将其末端插入面包板(“带孔的床垫”)中,然后开始一个接一个地连接容器,同时在示波器上记录信号。





谐振电容器入门



首先,我检查了应该谐振的10nF电容器。但是与空线圈相比,信号幅度立即下降。然后我拿了一个较小的电容器。因此,我经历了电容器,直到引起共振。因此,电容器的谐振电容为3.2nF。





信号不带电容器,空线圈





10 nF信号





1 nF,2 nF





3 nF,4 nF,2.2 nF





3.2 nF



可以看出,我尝试了不同的选择,很明显,最大值在3到4 nF之间,结果是一个3.2 nF的电容器(由两个并联的电容器组成)。就是这样,我们的线轴已经准备好进行进一步的实验。



总的来说,我想指出的是,线圈通常可以在印刷电路板上以迹线的形式制成,而对于少量产品,则应这样做。这是亚历山大·古斯曼 Alexander Guthmann)以125 kHz发射的这种板的示例。不幸的是,该网站实际上已经死亡,作者很长时间没有联系,所以我们只满意我的照片。如果有人可以帮助找到它,我将不胜感激!我不知道他怎么了





因此,立即将仿真器制成印刷电路板的形式没有问题。我认为拥有手册[2]即可自己计算,因为14岁的德国小学生可以做到。



让我们看一下代码



让我们快速看一下代码,您可以在这里看到有一个模拟两种类型卡的示例,我将仅分析EM4102。



首先,如代码所示,在对微控制器进行刷新时,我们需要将熔丝位刷新为lfuse到0xC0:以便控制器由外部发生器提供时钟。我要引起您的注意的是,任何控制器闪烁都会与需要从外部时钟源发出信号的事实有关,因为我们正在设置由外部发生器产生的保险丝位!



所有代码均基于宏。让我提醒您什么是宏-一个准备编译代码的程序。我们的程序仅包含一些汇编程序指令:rjmp,call(2个时钟),nop,ldi,out和ret(全部1个时钟)!一切,其余所有代码均由宏组成,具体取决于序列号宏(定义)。这项工作的特殊性是我们只有很少的时钟周期可以正常工作。考虑到AVR控制器中的跳转指令需要2个时钟周期,请尝试在32个时钟周期内执行操作。因此,所有代码都是由宏根据ID卡生成的。



#define FORMAT_IS_EM4102
#define EM4102_MFR_ID		0x12
#define EM4102_UNIQUE_ID	0x3456789A


定义我们要模拟的卡类型并设置ID卡。这是形成其余代码的主要宏。而且,塔达姆,他的宏伟宏



    .macro	delay cycles
    .if \cycles > 1
    rjmp	.+0
    delay	(\cycles - 2)
    .elseif \cycles > 0
    nop
    delay	(\cycles - 1)
    .endif
    .endm


延迟宏,将延迟时钟周期数作为输入。一个相当明显的递归宏,它使用nop命令(无操作,1个时钟周期)和rjmp。+ 0命令(移至下一行,2个时钟周期)执行延迟。通过将这些命令彼此组合,可以使小节中所需长度的延迟。实际上,代码什么都不做,只是浪费机器时间。



如果您仍在思考,那么我会完全强奸您的大脑,但是代码太巧妙了,您必须忍受。



通过曼彻斯特代码进行递归宏编码。



    .macro	manchester bit, count=1
    .if		\count
    manchester (\bit >> 1), (\count - 1)
    .if		\bit & 1
    baseband_1
    baseband_0
    .else
    baseband_0
    baseband_1
    .endif
    .endif
    .endm

    .macro	stop_bit
    baseband_0
    baseband_1_last
    .endm


实际上,所有逻辑都在这里实现。接受位掩码和位计数器作为输入。如果计数器不为零,则我们再次调用自己,使计数器递减(是递归宏,是的)。在主体本身中,进一步调用了基带_0,基带_1和基带_1_last宏。根据我们具有“ 1”或“ 0”的位,将曼彻斯特代码信号从零调制为一,或从一调制为零。



记得上面我在文章中提供了一张表格,说明卡的内容如何编码,奇偶校验位在何处以及末尾的停止位。因此,我们的任务是使用这种方法对ID标签进行编码,为此,我们有两个宏。



#define ROW_PARITY(n)  ( (((n) & 0xF) << 1) | \
                         (((n) ^ ((n) >> 1) ^ ((n) >> 2) ^ ((n) >> 3)) & 1) )

#define COLUMN_PARITY  ( (EM4102_MFR_ID >> 4) ^        \
                         (EM4102_MFR_ID) ^             \
                         (EM4102_UNIQUE_ID >> 28) ^    \
                         (EM4102_UNIQUE_ID >> 24) ^    \
                         (EM4102_UNIQUE_ID >> 20) ^    \
                         (EM4102_UNIQUE_ID >> 16) ^    \
                         (EM4102_UNIQUE_ID >> 12) ^    \
                         (EM4102_UNIQUE_ID >> 8) ^     \
                         (EM4102_UNIQUE_ID >> 4) ^     \
                         (EM4102_UNIQUE_ID) )


ROW_PARITY-计算四位字符串中的奇偶校验位,COLUMN_PARITY-计算整个消息的校验和。



.main中的宏描述了我们工作的所有逻辑。



        header
        manchester	ROW_PARITY(EM4102_MFR_ID >> 4), 5
        manchester	ROW_PARITY(EM4102_MFR_ID >> 0), 5
        manchester	ROW_PARITY(EM4102_UNIQUE_ID >> 28), 5
        manchester	ROW_PARITY(EM4102_UNIQUE_ID >> 24), 5
        manchester	ROW_PARITY(EM4102_UNIQUE_ID >> 20), 5
        manchester	ROW_PARITY(EM4102_UNIQUE_ID >> 16), 5
        manchester	ROW_PARITY(EM4102_UNIQUE_ID >> 12), 5
        manchester	ROW_PARITY(EM4102_UNIQUE_ID >> 8), 5
        manchester	ROW_PARITY(EM4102_UNIQUE_ID >> 4), 5
        manchester	ROW_PARITY(EM4102_UNIQUE_ID >> 0), 5
        manchester	COLUMN_PARITY, 4
        stop_bit


好吧,就是说,我们只是以相同的方式传输标头的9位,然后进行曼彻斯特编码,每4位计算奇偶校验位,最后是校验和和停止位。



仍然需要弄清楚什么是基带。为此,我们还有一个包装宏(是的,可以有几个宏,是吗?)。



        .macro baseband_0
        rcall	baseband30_0
        rjmp	.+0
        .endm

        .macro baseband_1
        rcall	baseband30_1
        rjmp	.+0
        .endm
        
        .macro baseband_1_last
        rcall	baseband30_1
        rjmp	main
        .endm

        .macro header
        manchester 0x1FF, 9
        .endm


基带*宏-执行汇编代码:调用适当的函数,然后过渡到另一条指令。 baseband_1_last宏与baseband_1宏类似,不同之处在于它无条件地跳转到以下命令,而不跳转到主函数的开头。宏标头-用于显示九个相同类型的等于1的位的标头,并调用曼彻斯特宏以传输数量和发送的位数。



最后要解析的是基带30_0和基带30_1函数。它们由以下代码描述。



baseband30_0:
        ldi	r16, OUT_PINS		// 1
        rjmp	baseband30		// 2

        /*
         * Emit a 1 at the baseband layer.
         * Takes a total of 30 clock cycles, including call overhead.
         */
baseband30_1:
        ldi	r16, 0			// 1
        rjmp	baseband30		// 2
        
        /*
         * Internal routine for baseband32_0 and _1. Must use
         * a total of 24 clock cycles. (32 - 1 ldi - 2 rjmp - 3 rcall)
         */ 
baseband30:
        out	_SFR_IO_ADDR(DDRB), r16		// 1
        delay	19				// 19
        ret					// 4


根据哪个功能称为基带30_0或基带30_1,应将I / O引脚上应有的值写入寄存器r16:1或0。此后,无条件转换到基带30,执行输出,并延迟19个时钟周期,然后返回。



该代码的最大魔力在于,它是在每个时钟周期之前精确计算的,曼彻斯特代码的每个传输时钟所占用的周期恰好是标准允许的周期,即32个处理器时钟周期!这太神奇了,您必须记住每个命令占用多少条。



让我们编译它,看看它是什么样,所有这些宏如何扩展。我们使用make命令编译(在安装avr-gcc之后)并反汇编生成的elf文件



00000000 __vectors:
   0:	0e c0       	rjmp	.+28     	; 0x1e __ctors_end
   2:	15 c0       	rjmp	.+42     	; 0x2e __bad_interrupt
...


首先,我们有中断向量,但是我们只对第一个跳转感兴趣。由于其余向量不在任何地方领先。



0000001e __ctors_end:
  1e:	11 24       	eor	r1, r1
  20:	1f be       	out	0x3f, r1	; 63
  22:	cf e5       	ldi	r28, 0x5F	; 95
  24:	d2 e0       	ldi	r29, 0x02	; 2
  26:	de bf       	out	0x3e, r29	; 62
  28:	cd bf       	out	0x3d, r28	; 61
  2a:	02 d0       	rcall	.+4      	; 0x30 main
  2c:	11 c1       	rjmp	.+546    	; 0x250 _exit


在这里,我们设置I / O端口,并调用main函数。一个主信号包括对基带30 *和跳转函数的疯狂调用(这就是我们如此宏大的宏hell戏的样子)。



00000030 main:
  30:	01 d1       	rcall	.+514    	; 0x234 baseband30_1
  32:	00 c0       	rjmp	.+0      	; 0x34 main+0x4
  34:	fd d0       	rcall	.+506    	; 0x230 baseband30_0
  36:	00 c0       	rjmp	.+0      	; 0x38 main+0x8
  38:	fd d0       	rcall	.+506    	; 0x234 baseband30_1
  3a:	00 c0       	rjmp	.+0      	; 0x3c main+0xc
  3c:	f9 d0       	rcall	.+498    	; 0x230 baseband30_0
  3e:	00 c0       	rjmp	.+0      	; 0x40 main+0x10
  40:	f9 d0       	rcall	.+498    	; 0x234 baseband30_1
  42:	00 c0       	rjmp	.+0      	; 0x44 main+0x14
  44:	f5 d0       	rcall	.+490    	; 0x230 baseband30_0
  46:	00 c0       	rjmp	.+0      	; 0x48 main+0x18
  48:	f5 d0       	rcall	.+490    	; 0x234 baseband30_1
  4a:	00 c0       	rjmp	.+0      	; 0x4c main+0x1c
  4c:	f1 d0       	rcall	.+482    	; 0x230 baseband30_0
...
 22e:	00 cf       	rjmp	.-512    	; 0x30 main


依此类推...直到回到主



界面,让我们看看基带模块的外观。



00000230 baseband30_0:
 230:	08 e1       	ldi	r16, 0x18	; 24
 232:	02 c0       	rjmp	.+4      	; 0x238 baseband30

00000234 baseband30_1:
 234:	00 e0       	ldi	r16, 0x00	; 0
 236:	00 c0       	rjmp	.+0      	; 0x238 baseband30

00000238 baseband30:
 238:	07 bb       	out	0x17, r16	; 23
 23a:	00 c0       	rjmp	.+0      	; 0x23c baseband30+0x4
 23c:	00 c0       	rjmp	.+0      	; 0x23e baseband30+0x6
 23e:	00 c0       	rjmp	.+0      	; 0x240 baseband30+0x8
 240:	00 c0       	rjmp	.+0      	; 0x242 baseband30+0xa
 242:	00 c0       	rjmp	.+0      	; 0x244 baseband30+0xc
 244:	00 c0       	rjmp	.+0      	; 0x246 baseband30+0xe
 246:	00 c0       	rjmp	.+0      	; 0x248 baseband30+0x10
 248:	00 c0       	rjmp	.+0      	; 0x24a baseband30+0x12
 24a:	00 c0       	rjmp	.+0      	; 0x24c baseband30+0x14
 24c:	00 00       	nop
 24e:	08 95       	ret


最后,您可以看到延迟如何扩展为该延迟的跳转和nop列表。这真是美丽的魔力。



好了,我们找出了代码。收集耳朵里干brain的大脑,然后进行测试。



测验



我们将应用所有获得的知识并进行测试。我们编译固件,刷新控制器,记住正确设置保险丝位。





固件围巾我们



连接振荡电路,并在真正的工业读取器上进行测试,没有采取任何措施,要有公平的战斗条件。





测试台



瞧瞧它可以工作,正确读取并在循环中提供正确的ID!没有外部电源,只能从现场操作。剩下的就是将所有这些整理好并制作一个真正的RFID标签。





标签的最终“层压”版本





我可以坦白地说,我并不完全相信它会起作用。由现场供电,控制器为非标准工作模式,严格按照时钟周期工作,自制电感器。加上RFID本身的工作。而现在,阅读文档和汇报工作似乎花费了几个月的时间。但这是有效的,而且这件事确实很棒。伙计们,这种事情是真正的黑客。去吧!



家庭作业



由于您仍然阅读这篇很酷的文章,所以我写了它,尝试了一下,做了,现在是时候尝试做点什么了。模拟器代码包含一个部分,该部分使用相移编码来模拟HID感应卡。您应该了解HID标准和此编码,以便获得更好的娱乐性。在评论中发送解决方案。祝好运。



参考书目



  1. AppNote 411 RFID Made Easy
  2. AN710 Antenna Circuit Design for RFID Applications
  3. priority1design.com





All Articles