您的位置:首页 > 其它

高频RFID(13.56M)读写模块的设计与应用实例 (下)

2011-08-22 14:28 525 查看
这一篇就讲讲高频RFID(13.56M)读写模块的应用吧,按照上一篇中制作库文件的方法,可以制作属于自己的类库(有点类似VISUAL C++)吧,然后就是应用,因我开发的模块涉及公司的秘密,咱们就以行业内著名的模块供应商周立功ZLG500读写模块来讲解吧。呵呵,以下部分内容来源网络,目的是来完整表达我的思想,也教会新手一些知识,有例子讲解更容易嘛。然我也实际使用过他们的模块,不要说俺盗版,本章绝大部分的内容是俺原创的。

现在智能卡的应用越来越广泛,如校园一卡通系统、城市公交系统、大型会议签到系统、考勤系统、门禁系统等都使用了智能卡。本文以ZLG500读写模块作为卡与门禁机交换数据的接口模块,介绍了ZLG500在智能卡门禁系统中的应用。
1 读写模块ZLG500简介

1.1 ZLG500与MCU的接口原理


ZLG500模块采用Philips公司最新的高集成ISO14443读卡芯片MF RC500,它能读写RC500内EEPROM,提供三线制SPI接口,并具有控制线输出端口,能与任何MCU连接。ZLG500与MCS51单片机的接口原理图如图1所示。此外该模块的EMC性能优良,并且自带无源蜂鸣器信号输出,能用软件控制其输出频率及输出持续时间。



图中SCLK、SDATA、SS为ZLG500与MCU相连接的控制线,分别为时钟线、数据线和片选。主控制器的MCU和读卡模块内的MCU通过此三线相连。接口空闲时,主机的SS=1,SCLK=O,SDATA=0,而从机的SS=1,SCLK=1,SDATA=O。其中SS和DATA都是双向的,而时钟线SCLK是单向的,即时钟只能由主控制器产生,该信号必须严格遵守时序规范,否则将出现通信错误,此时读卡模块必须释放该线。
SS还作为数据发送使能端。若一方有数据要发送给另一方,则该方控制SS线为低电平,并在发送结束后将该线置高电平。接收数据方不得控制该线,双方必须遵守通信协议,不得同时控制该线。SDATA为数据线,由数据发送端控制数据,接收端必须释放该线。该线在一次传输开始时还同时作为数据接收端的响应信号。

1.2 ZLG500与MCU接口的时序及通信协议

ZLG500与MCU无论数据传输的方向如何,SPI线上信号的波形总是如图2所示。由图中可以看出,在SS为低时,时钟和数据线上的信号才有效;在SCLK为低时SDATA变化,在SCLK为高时SDATA应保持稳定。



以上传输中,从数据发送器请求开始至数据接收器响应的时间是不确定的,取决于接收器内的MCU是否忙,因此有必要设置看门狗定时器对数据接收器的响应进行监视。一旦接收器响应,则MCU必须根据数据传输方向,严格控制以下几个时间,以确保数据传输无误。

t1:数据接收器响应至MCU产生第一个SCLK上升沿的时间。

t2:2个字节传输之间SCLK低电平的持续时间。

t3:传输最后1个字节的最后1位的SCLK信号的上升沿至SS上升沿的时间。

tH:SCLK信号的高电平持续时间。

tL:SCLK信号的低电平持续时间。

在数据传输方向不同时,对时间t1、t2、t3、tH和tL都有不同的要求。

MCU与ZLG500的通信必须先由MCU发送命令和数据给ZLG500,ZLG500执行命令完毕后,将命令执行的状态和响应数据发回MCU。

开始通信前,收发双方必须处于空闲状态。首先由MCU发出SS下降沿信号,然后等待ZLG500在SDATA线上的响应,若在50 ms内未检测到此信号,则退出本次传输。若正确响应,则MCU可将命令和数据发送出去。

然后MCU等待ZLG500发回的状态和响应数据,即等待SS线上的下降沿信号。若在50 ms内未检测到此信号,则退出本次传输;若正确检测到SS信号,则可以接收状态和数据。
2 智能卡门禁系统设计

2.1 总体结构

系统采用Philips公司的非接触智能IC卡Mifare 1(M1)卡。以M1卡作为用户卡,以其全球唯一的序列号SN为依据控制门的开启。由于它是一个高频卡,工作频率为13.5 MHz,因而具有较强的抗干扰能力且读写距离远(2.5~10 cm)。

整个智能卡门禁系统分为三大部分:其一是读写器部分,包括MCU、复位电路、时钟电路、显示电路、键盘、数据存储等主控模块及非接触IC卡读写模块和电锁驱动部分;其二是中央控制电脑的软件管理系统模块;其三是中央控制电脑与读写器之间的数据传输模块。总体系统框图如图3所示。



2.上位机部分程序范例

1)zlg500.h

#define STX 0X7E
//正文的开头

#define EXT
0XBB //正文的结束

#define PWD_LEN 0x06 //密码长度

/*错误值*/

#define ERR_NOCARD 0XA0
//没有卡

#define ERR_CMDFAILED 0XA1
//指令执行失败

#define ERR_OVERFLOW 0XA2
//值溢出

#define ERR_COMMERR 0XFF
//通讯错误

/*命令值*/

//低级命令

#define CMD_RESET 0X10
//执行一个软复位

#define CMD_CLOSE 0X11
//关闭RC500

#define CMD_AUTHENOPWD 0X20
//密码验证

#define CMD_LOADPWD 0X21
//装载密匙

#define CMD_REQUEST 0X27
//请求

#define CMD_ANTICOLL 0X28
//防碰撞

#define CMD_SELECT 0X29
//选择

#define CMD_READBLOCK 0X40
//对一块进行读操作

#define CMD_WRITEBLOCK 0X50
//对一块进行写操作

#define CMD_VALUE 0X59
//值操作

#define CMD_ADDVAL 0X60
//对一个块的值进行加操作

#define CMD_REDUCEVAL 0X61
//对一个块的值进行减操作

#define CMD_COPYBLOCK 0X62
//把一块的值复制到另一个块

#define CMD_HALT 0X63
//暂停

#define CMD_CLOSEANTENNA 0X64
//关闭天线输出数ms

//高级命令

#define CMD_SELONECARD 0X30
//选择一张卡

#define CMD_SELCARDS 0X31
//多张卡选择/卡列表

#define CMD_READBLOCKVAL 0X41
//读一个块的值

#define CMD_WRITEBLOCKVAL 0X51
//写一个块的值

//通信控制及其它

#define CMD_READADDR 0X70
//取读卡器的地址号

#define CMD_SETPARAMETER 0X80
//读卡器参数设置

#define CMD_READPARAMETER 0X81
//读取读卡器参数值

#define CMD_CONTROL 0X90
//读卡器指示控制

void __stdcall zlg500_Reset(unsigned char addr);

void __stdcall zlg500_Close(unsigned char addr);

int __stdcall zlg500_AuthenPwd(unsigned char addr,unsigned char keytype,

unsigned char blocknr);

int __stdcall zlg500_LoadPwd(unsigned char addr,unsigned char keytype,

unsigned char keynr,unsigned char *key);

int __stdcall zlg500_Request(unsigned char addr,unsigned char questtype,

unsigned short &type);

int __stdcall zlg500_Anticoll(unsigned char addr,unsigned char bitcount,

unsigned long &snr);

int __stdcall zlg500_Select(unsigned char addr,unsigned long cardnr,

unsigned char &size);

int __stdcall zlg500_ReadBlock(unsigned char addr,unsigned char blocknr,

unsigned char *blockdata);

int __stdcall zlg500_WriteBlock(unsigned char addr,unsigned char blocknr,

unsigned char *blockdata);

int __stdcall zlg500_Value(unsigned char addr,unsigned char mode,

unsigned char blocknr,unsigned long val,

unsigned char desblocknr);

int __stdcall zlg500_AddVal(unsigned char addr,unsigned char blocknr,

unsigned long addval);

int __stdcall zlg500_ReduceVal(unsigned char addr,unsigned char blocknr,

unsigned long reduceval);

int __stdcall zlg500_CopyBlock(unsigned char addr,unsigned char sourceblocknr,

unsigned char desblocknr);

int __stdcall zlg500_Halt(unsigned char addr);

int __stdcall zlg500_CloseAntenna(unsigned char addr,unsigned char time);

/////////////////////////////////////////////////////////////////////////

int __stdcall zlg500_SelCards(unsigned char addr,unsigned long selcardnr,

unsigned long *cardnrs,unsigned char &carnumbers);

int __stdcall zlg500_ReadBlockVal(unsigned char addr,unsigned char blocknr,

long &blockval);

int __stdcall zlg500_WriteBlockVal(unsigned char addr,unsigned char blocknr,

long blockval);

int __stdcall zlg500_ChangePwd(unsigned char addr,unsigned char sectornr,

unsigned char keytype,unsigned char *pwd);

/////////////////////////////////////////////////////////////////////////

int __stdcall zlg500_ReadAddr(unsigned char &devicenrs,unsigned char *deviceaddr);

int __stdcall zlg500_SetParameter(unsigned char addr,unsigned char parameter);

int __stdcall zlg500_ReadParameter(unsigned char addr,unsigned char ¶meter);

int __stdcall zlg500_SetControl(unsigned char addr,

unsigned char controltype,unsigned char acttime,

unsigned char halttime,unsigned char actlen);

//////////////////////////////////////////////////////////////////////////

unsigned char __stdcall zlg500_GetLastErr();

short int __stdcall zlg500_init(int nport=1, int nbaud=9600);

void __stdcall zlg500_exit(void);

2)mainfrm.cpp

// MainFrm.cpp : implementation of the CMainFrame class

//

#include "stdafx.h"

#include "Mifare.h"

#include "MainFrm.h"

#include "zlg500.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

/////////////////////////////////////////////////////////////////////////////

// CMainFrame

IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)

//{{AFX_MSG_MAP(CMainFrame)

ON_WM_CREATE()

ON_WM_CLOSE()

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

static UINT indicators[] =

{

ID_SEPARATOR,

ID_SEPARATOR,

ID_INDICATOR_CAPS,

ID_INDICATOR_NUM,

ID_INDICATOR_SCRL,

};

/////////////////////////////////////////////////////////////////////////////

// CMainFrame construction/destruction

CMainFrame::CMainFrame()

{

// TODO: add member initialization code here

}

CMainFrame::~CMainFrame()

{

}

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

if (CFrameWnd::OnCreate(lpCreateStruct) == -1)

return -1;

/*if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP

| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||

!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))

{

TRACE0("Failed to create toolbar\n");

return -1; // fail to create

}*/

if (!myToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP

| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||

!myToolBar.LoadToolBar(IDR_TOOLBAR1))

{

TRACE0("Failed to create toolbar\n");

return -1; // fail to create

}

if (!m_wndStatusBar.Create(this) ||

!m_wndStatusBar.SetIndicators(indicators,

sizeof(indicators)/sizeof(UINT)))

{

TRACE0("Failed to create status bar\n");

return -1; // fail to create

}

// TODO: Delete these three lines if you don't want the toolbar to

// be dockable

// m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);

// EnableDocking(CBRS_ALIGN_ANY);

// DockControlBar(&m_wndToolBar);

myToolBar.EnableDocking(CBRS_ALIGN_ANY);

EnableDocking(CBRS_ALIGN_ANY);

DockControlBar(&myToolBar);

m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

return 0;

}

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

{

if( !CFrameWnd::PreCreateWindow(cs) )

return FALSE;

// TODO: Modify the Window class or styles here by modifying

// the CREATESTRUCT cs

return TRUE;

}

/////////////////////////////////////////////////////////////////////////////

// CMainFrame diagnostics

#ifdef _DEBUG

void CMainFrame::AssertValid() const

{

CFrameWnd::AssertValid();

}

void CMainFrame::Dump(CDumpContext& dc) const

{

CFrameWnd::Dump(dc);

}

#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////

// CMainFrame message handlers

void CMainFrame::OnClose()

{

// TODO: Add your message handler code here and/or call default

zlg500_exit();

CFrameWnd::OnClose();

}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: