全新论坛MCU智学网上线,欢迎访问新论坛!稀缺资源、技术干货、参考设计、原厂资料尽在MCU智学网
更新自动建库工具PCB Footprint Expert 2023.13 Pro / Library Expert 破解版

单片机实现非接触式IC卡读写

[复制链接]
2535 1

本文包含原理图、PCB、源代码、封装库、中英文PDF等资源

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
/*****************************************/
/* Copyright (c) 2005, 通信工程学院 */
/* All rights reserved. */
/* 作 者:戴 佳 */
/*****************************************/

#include "RFICRdWr.h"

/* 延时t毫秒函数 */
void delay(uint t)
{
uint i;
while(t--)
{
/* 对于11.0592M时钟,约延时1ms */
for (i=0;i<125;i++)
{}
}
}

/* 定时器0中断服务子程序 */
void timer0() interrupt 1 using 1
{
TR0 = 0; // 停止计数

TH0 = -5000/256; // 重设计数初值
TL0 = -5000%256;

count++;

if (count>300) // 第一次检测到卡1.5s后
{
count = 0;
if(!flagok) // 如果检测到1.5s后读写标志还是失败,则蜂鸣器报警
{
BP = 0;
delay(2000); // 报警持续2s
BP = 1;
}
}
else
TR0 = 1; // 启动T0计数
}

/* 串口发送命令函数 */
void sendcmd(uchar *str)
{
while(*str != 0)
{
TI = 0; // 清发送标志位
SBUF = *str; // 发送数据
str++;
while(!TI); // 等待发送完成
}
}

/* 字符数组转换为16进制字符串函数,16进制字符串附接在给定字符串后,
参数byte为数组地址,len为数组长度,str为转换后字符串 */
void Byte2Hex(uchar *byte,uchar len,uchar *str)
{
uchar i, j;
uchar tmp;

j = strlen(str);
for(i=0; i<len; i++)
{
tmp = ((*byte)>>4)&0x0f; // 字节高位
if(tmp < 0x0a)
*(str+j) = tmp+0x30;
else
*(str+j) = tmp-0x0a+'a';
str++;
tmp = (*byte)&0x0f; // 字节低位
if(tmp < 0x0a)
*(str+j) = tmp+0x30;
else
*(str+j) = tmp-0x0a+'a';
str++;
}
*(str+j) = 0; // 字符串结束
}

/* 16进制字符串转换为字节数组函数,参数str为要转换的字符串,byte为
转换后数组地址,若str长度不为偶数,则转换后最后一个字节高位补0*/
void Hex2Byte(uchar *str, uchar *byte)
{
uchar tmp;

while(*str != 0)
{
tmp = ((*str)<<4)&0xf0; // 字节高位
str++;
if(*str == 0) // 若str长度为奇数,则转换后最后一个字节高位补0
{
*byte = (tmp>>4)&0x0f;
return;
}
tmp += (*str)&0x0f; // 字节低位
*byte = tmp;
byte++;
}
}

/* 串口初始化 */
void serial_init()
{
/* 9600,n,8,1,外部晶振11.0592MHz,查询方式 */
TMOD = 0x20; // T1使用工作方式2
TH1 = 250; // 设置T1初值
TL1 = 250;
TR1 = 1; // T1开始计数
PCON = 0x80; // SMOD = 1
SCON = 0x50; // 工作方式1,波特率9600bit/s,允许接收
ES = 0; // 关闭串行中断
}

/* H6152复位函数 */
void H6152Rst()
{
strcpy(hbuf,"x");
sendcmd(hbuf); // 发送命令"x"
delay(300); // 延时300ms确保H6152复位完毕
}

/* 卡片检测函数,检测到有卡在读写器有效区域内返回 */
void cardcheck()
{
strcpy(hbuf,"c");
sendcmd(hbuf); // 发送命令"c",命令进入“连续读”模式
delay(10); // 延时10ms

/* 一旦发现串口接收到数据就立即返回,
表示检测到读写器有效区域内有卡片 */
RI = 0;
while(!RI);
delay(10); // 延时10ms,消抖
RI = 0;
while(!RI);
/* 确认工作区内有卡片,返回 */
}

/* 停止卡片检测函数,即取消“连续读"模式 */
void endcheck()
{
strcpy(hbuf," ");
sendcmd(hbuf); // 发送" "取消”连续读“模式
delay(10); // 延时10ms
}

/* 自动选卡函数,读取所有卡片,随机选中并
返回其序列号,主要用于第一次选卡 */
uchar autoselect(uchar *buf)
{
uchar i;
strcpy(hbuf,"m\r");
sendcmd(hbuf); // 发送"m<CR>"
for(i=0;i<8;i++) // 接收第一张卡的序列号
{
RI = 0;
while(!RI);
*(hbuf+i) = SBUF;

/* 如果接收到错误信息则返回错误代码 */
if((*(hbuf+i)>0x39)&&(*(hbuf+i)<'a'))
return *(hbuf+i);
}
*(hbuf+i) = 0;
Hex2Byte(hbuf,buf); // 第一张卡片序列号由16进制字符串转换为字节数组

strcpy(hbuf,"m");
Byte2Hex(buf,4,hbuf);
delay(10);
sendcmd(hbuf); // 发送"m<SN>",选中第一张卡片
for(i=0;i<8;i++) // 接收选中卡片的序列号
{
RI = 0;
while(!RI);
*(hbuf+i) = SBUF;
/* 如果接收到错误信息则返回错误代码 */
if((*(hbuf+i)>0x39)&&(*(hbuf+i)<'a'))
return *(hbuf+i);
}

return 0; // 成功
}

/* 指定选卡函数,根据制定序列号选卡 */
uchar snselect(uchar *sn)
{
uchar i;

strcpy(hbuf,"m");
Byte2Hex(sn,4,hbuf); // 将序列号sn转换为16进制字符串
delay(10);
sendcmd(hbuf); // 发送"m<SN>",选中第一张卡片
for(i=0;i<8;i++) // 接收选中卡片的序列号
{
RI = 0;
while(!RI);
*(hbuf+i) = SBUF;
/* 如果接收到错误信息则返回错误代码 */
if((*(hbuf+i)>0x39)&&(*(hbuf+i)<'a'))
return *(hbuf+i);
}

return 0; // 成功
}

/* 登录扇区函数,参数sect为扇区号,keytype为密码类型,keyvalue为密码内容。
keyvalue为NULL时,表示使用默认密码;keytype为0x10~0x2f和0x30~0x4f
之间或者0xff时,程序忽略keyvalue的内容。 */
uchar loginsect(uchar sect,uchar keytype,uchar *keyvalue)
{
uchar tmp;

if(sect>16) // 扇区号超过16报错
return ERR_E;

strcpy(hbuf,"l");
Byte2Hex(&sect,1,hbuf); // 将sect转换为16进制字符串

if(((keytype>0x10)&&(keytype<0x2f))||((keytype>0x30)&&(keytype<0x4f)))
Byte2Hex(&keytype,1,hbuf); // "l<sect><reg>
else if((keytype==KEY_A)||(keytype==KEY_B)) // 使用密码A或B登录
{
Byte2Hex(&keytype,1,hbuf);
if (keyvalue==NULL)
strcat(hbuf,"\r"); // "l<sect>aa<CR>或"l<sect>bb<CR>"
else
Byte2Hex(keyvalue,6,hbuf); // "l<sect>aa<value>或"l<sect>bb<value>"
}
else if(keytype==KEY_DEFAULT) // 使用默认密码登录
strcat(hbuf,"\r"); // "l<sect><CR>
else
return ERR_U; // 未知错误

sendcmd(hbuf); // 发送命令

RI = 0;
while(!RI);
tmp = SBUF;
if(tmp=='L') // 登录成功
return 0;
else
return tmp; // 返回错误
}

/* 读块函数,将块中内容读至缓冲区,缓冲区长度应为16字节 */
uchar readblock(uchar block,uchar *buf)
{
uchar i;

if (block>64) // 块号超过64报错
return ERR_E;
strcpy(hbuf,"r");
Byte2Hex(&block,1,hbuf); // block转换为16进制字符串
sendcmd(hbuf); // "r<block>"

for (i=0;i<32;i++) // 接收块数据
{
RI = 0;
while(!RI);
*(hbuf+i) = SBUF;
/* 如果接收到错误信息则返回错误代码 */
if((*(hbuf+i)>0x39)&&(*(hbuf+i)<'a'))
return *(hbuf+i);
}
*(hbuf+32) = 0;
Hex2Byte(hbuf,buf); // 将块内容由16进制字符串转换为字节数组

return 0; // 成功
}

/* 写块函数,将缓冲区中内容写入块,缓冲区长度16字节 */
uchar writeblock(uchar block,uchar *buf)
{
uchar i;

if (block>64) // 块号超过64报错
return ERR_E;
strcpy(hbuf,"w");
Byte2Hex(&block,1,hbuf); // block转换为16进制字符串
Byte2Hex(buf,16,hbuf); // 将要写入块的内容转换为16进制字符串
sendcmd(hbuf); // "w<block><data>"

for (i=0;i<32;i++) // 接收返回数据,为写入的内容
{
RI = 0;
while(!RI);
*(hbuf+i) = SBUF;
/* 如果接收到错误信息则返回错误代码 */
if((*(hbuf+i)>0x39)&&(*(hbuf+i)<'a'))
return *(hbuf+i);
}

return 0; // 成功
}

/* 主程序,选取一张卡,将0~15共16个数写入扇区1的块0中,然后再从该扇区的
块0中读出这16个数,存入缓冲区block0buf,接着再将block0buf中的内容写入
该扇区的块1中,最后再从块1中读出16个数,存入缓冲区block1buf中。本程序
的主要功能是验证H6152模块对非接触式IC卡的读写 */
void main()
{
char sn[4];
uchar sectno,blockno; // 扇区号、块号
uchar blockbuf[16]; // 要写入块的内容缓冲区
uchar i;

sectno = 1; // 扇区1
blockno = 0; // 块0
flagok = 0;
flagfirst = 1;
flagselok = 0;
flaglogok = 0;
count = 0;

for (i=0;i<16;i++) // 写入0~15共16字节
blockbuf=i;

CTRL = 0; // H6152正常工作
BP = 1; // 蜂鸣器不发声

EA = 1;
TMOD = 0x01; // 模式1,T0为16位定时/计数器
TH0 = -5000/256; // 设置计数初值
TL0 = -5000%256;
ET0 = 1; // 打开T0中断

serial_init(); // 串口初始化

H6152Rst(); // H6152复位

while(!flagok)
{
cardcheck(); // 卡片检测
endcheck(); // 停止检测
if (flagfirst) // 如果是第一次选卡
{
flagfirst = 0;
if (autoselect(sn)==0) // 第一张卡片选择成功,并保存序列号sn
{
flagselok = 1;
TR0 = 1; // T0开始计时
}
}
else
{
if(snselect(sn)==0) // 指定序列号sn的卡片选择成功
flagselok = 1;
}
if (flagselok)
{
if(loginsect(sectno,KEY_DEFAULT,NULL)=='L') // 登录成功
flaglogok = 1;
else
{
flagselok = 0; // 登录不成工,重新去选卡
flaglogok = 0;
}
if (flaglogok)
{
flagwr = writeblock(blockno,blockbuf);
if(flagwr!=0)
flagselok = 0; // 写块错误,重新去选卡
else
{
flagrd = readblock(blockno,block0buf);
if (flagrd!=0)
flagselok = 0; // 读块错误,重新去选卡
else
{
flagwr = writeblock(blockno+1,block0buf);
if (flagwr!=0)
flagselok = 0; // 写块错误,重新去选卡
else
{
flagrd = readblock(blockno+1,block1buf);
if (flagrd!=0)
flagselok = 0; // 读块错误,重新去选卡
else
flagok = 1; // 读写成功
}
}
}
}
}
}
}

5_3_c4e0275174890c7.jpg

举报

回复

1 个评论

c51le***  新手上路  发表于 2013-7-3 18:41:05  | 显示全部楼层
这个好,,,正想了解一下呢..多谢楼主!
*滑块验证:
您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

打开支付宝扫一扫,最高立得1212元红包
搜索

图文热点

更多

社区学堂

更多

客服中心

QQ:187196467 服务时间:周一至周日 8:30-20:30

关注我们

关于我们
关于我们
友情链接
联系我们
帮助中心
网友中心
购买须知
支付方式
服务支持
资源下载
售后服务
定制流程
关注我们
官方微博
官方空间
官方微信
快速回复 返回顶部 返回列表