基于单片机的IC卡读写 - 图文

更新时间:2024-05-28 19:30:02 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

基于单片机的IC卡读写系统

实验目的:

1.学会并掌握可keil软件的使用; 2.学会并掌握protues软件的使用; 3.实现基于单片机的IC卡读写;

4.通过实验巩固单片机相关知识和检验自身动手能力

实验要求:

掌握单片机相关知识,利用单片机控制和射频模块组合来读写IC卡,并实现软硬件的仿真模拟。lC卡读卡器以MCS-51系列单片机作为核心构成,主要用于家庭和机构门锁的开关,具有安全稳定的特点,在识别,删除,添加,自动开锁时,用于对IC卡进行读写操作。

实验设备和仪器:

1.89c51单片机最小系统

2.射频模块RC522,智能IC卡以及其他附加电路

实验内容:

本次实验设计是由小组五个成员共同完成基于单片机的IC卡读写系统并完成实物搭建和撰写实验报告。 方案一:实验步骤:

1.利用protues画电路图,电路图如图1所示:

图1:方案一电路图

2.模拟刷卡后显示,如图二:

图2:方案一实现图

3.根据电路图编写C语言代码: 代码如下:

#include \#include \#include \#include

#include \#include \

#define uchar unsigned char #define uint unsigned int

sbit Speak = P2^7;//蜂鸣器 sbit RED = P3^4; //红色指示灯 sbit GREEN = P3^3;//绿色指示灯 sbit Relay = P3^2; //继电器

sbit KEY1 = P1^3;//小时加按键 sbit KEY2 = P1^4; //小时减按键 sbit KEY3 = P1^5; //分钟加按键 sbit KEY4 = P1^6; //分钟减按键 sbit KEY5 = P1^7; //添加删除卡

sbit KEY = P2^6; //开门

unsigned char idata RevBuffer[30]; unsigned char Card_Num; void iccardcode(); //系统初始化

void InitializeSystem()//IC卡初始化 {

PcdReset(); //IC卡初始化

PcdAntennaOff(); //IC卡初始化 PcdAntennaOn(); //IC卡初始化

M500PcdConfigISOType( 'A' );//IC卡初始化 }

unsigned char idata UID[4],Temp[4];//读取卡号数组 unsigned char Table[3];//显示数组 unsigned char Num; unsigned Count,Countf,Count1,Count2,Count3,Count4,Count5,C_flag;//卡序号void Auto_Reader(void) //自动寻卡 {

if(PcdRequest(0x52,Temp)==0) //找到卡 {

if(PcdAnticoll(UID)==0) {

char Speak=0;delay_10ms(20);Speak=1;//蜂鸣器提示

Table[0]=UID[0]/100+0x30; //卡号显示 Table[1]=UID[0]/10+0x30; //卡号显示 Table[2]=UID[0]+0x30; //卡号显示

LCD1602_Disp_ZF(0x80+0x40,\卡号显示

LCD1602_Disp_ZF(0x84+0x40,Table,3); //卡号显示 Count = UID[0]; //判断卡是不是有效

if((Count==Count1)||(Count==Count2)||(Count==Count3)||(Count==Count4)||(Count==Count5)) {

LCD1602_Disp_ZF(0x88+0x40,\卡有效

GREEN = 0;Relay=0;delay_10ms(200);Relay=1;GREEN = 1; //绿灯亮,打开继电器

C_flag=1; } else {

LCD1602_Disp_ZF(0x88+0x40,\卡无效 RED = 0;delay_10ms(500);RED = 1; //红灯亮 C_flag=2; }

delay_10ms(200); LCD1602_Disp_ZF(0x80+0x40,\Swipecard\显示初始界面

} } }

uchar DS1302_Table[7]={0}; //读取时间值

void Display_LCD2(uchar Dis_Hour,uchar Dis_Min,uchar Dis_Sec)//显示时间值 {

uchar Dis_Table[8]=\

Dis_Table[0] = Dis_Hour/10+0x30; Dis_Table[1] = Dis_Hour+0x30;

Dis_Table[3] = Dis_Min/10+0x30; Dis_Table[4] = Dis_Min+0x30;

Dis_Table[6] = Dis_Sec/10+0x30;

Dis_Table[7] = Dis_Sec+0x30;

LCD1602_Disp_ZF(0x85,Dis_Table,8);//显示时间值 }

void Run_DS1302(void) {

uchar sec, min, hour, day, month, week, year;

v_W1302(0x8f, 0);

sec = bcdtodec(uc_R1302(0x81)); //读出DS1302中的秒 v_W1302(0x8f, 0);

min = bcdtodec(uc_R1302(0x83)); //读出DS1302中的分 v_W1302(0x8f, 0);

hour = bcdtodec(uc_R1302(0x85)); //读出DS1302中的小时 v_W1302(0x8f, 0);

day = bcdtodec(uc_R1302(0x87)); //读出DS1302中的日 v_W1302(0x8f, 0);

month = bcdtodec(uc_R1302(0x89)); //读出DS1302中的月 v_W1302(0x8f, 0);

week = bcdtodec(uc_R1302(0x8b)); //读出DS1302中的星期 v_W1302(0x8f, 0);

year = bcdtodec(uc_R1302(0x8d)); //读出DS1302中的年

DS1302_Table[0]=year; DS1302_Table[1]=month; DS1302_Table[2]=day; DS1302_Table[3]=week; DS1302_Table[4]=hour; DS1302_Table[5]=min; DS1302_Table[6]=sec;

Display_LCD2(DS1302_Table[4],DS1302_Table[5],DS1302_Table[6]);//显示时间值 }

void main(void) {

InitializeSystem(); LCD1602_init();

//Money_1=x24c02_read(0X01); //x24c02_write(0X03,Money_3); LCD1602_Disp_ZF(0x80,\

//0123456789abcdef

LCD1602_Disp_ZF(0x80+0x40,\

//LCD1602_Disp_ZF(0x80+0x40,\

//ISP_ERASE(0x2c00); //注意:字节编程时必须要先要擦除整个扇区 //for(i=0;i<255;i++)

// ISP_PROGRAM(0x2c00+i, 0x00);

while (1) {

////////////////////////// if(!KEY) {

Speak=0;delay_10ms(20);Speak=1;//蜂鸣器提示

LCD1602_Disp_ZF(0x88+0x40,\卡有效

GREEN = 0;Relay=0;delay_10ms(200);Relay=1;GREEN = 1; //绿灯亮,打开继电器

delay_10ms(200); LCD1602_Disp_ZF(0x80+0x40,\Swipecard\显示初始界面 }

Run_DS1302(); //时间显示 //delay_10ms(200); if(!KEY1) //调节小时加 {

delay_10ms(50);

if(!KEY1) //调节小时加 {

DS1302_Table[4]++; //调节小时加

Write_DS1302Init(0,0,0,0,DS1302_Table[4],DS1302_Table[5],0); //调节小时加 } }

if(!KEY2) //调节小时减 {

delay_10ms(50);

if(!KEY2) //调节小时减

{ //调节小时减 DS1302_Table[4]--; //调节小时减

Write_DS1302Init(0,0,0,0,DS1302_Table[4],DS1302_Table[5],0);//调节小时减

} }

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

if(!KEY3) //调节分钟加 {

delay_10ms(50); //调节分钟加 if(!KEY3) {

DS1302_Table[5]++; //调节分钟加

Write_DS1302Init(0,0,0,0,DS1302_Table[4],DS1302_Table[5],0); //调节分钟加

} }

if(!KEY4) //调节分钟减 {

delay_10ms(50); //调节分钟减 if(!KEY4) //调节分钟减 {

DS1302_Table[5]--; //调节分钟减

Write_DS1302Init(0,0,0,0,DS1302_Table[4],DS1302_Table[5],0); //调节分钟减 } }

if(!KEY5) //添加删除卡 {

delay_10ms(50);

if(!KEY5) //添加删除卡 {

if(C_flag==2) //添加卡 {

//0123456789abcdef

LCD1602_Disp_ZF(0x80+0x40,\ Countf++;

if(Countf==6)Countf=1;

if(Countf==1) Count1 = Count;//记忆卡号 if(Countf==2) Count2 = Count; //记忆卡号 if(Countf==3) Count3 = Count; //记忆卡号 if(Countf==4) Count4 = Count; //记忆卡号 if(Countf==5) Count5 = Count;//记忆卡号

}

if(C_flag==1)//删除卡 {

//0123456789abcdef

LCD1602_Disp_ZF(0x80+0x40,\ if(Count==Count1)Count1=0;//删除卡号 if(Count==Count2)Count2=0; //删除卡号 if(Count==Count3)Count3=0; //删除卡号 if(Count==Count4)Count4=0; //删除卡号 if(Count==Count5)Count5=0; //删除卡号

}

Speak=0;delay_10ms(200);Speak=1;

LCD1602_Disp_ZF(0x80+0x40,\

C_flag =0; while(!KEY5); } }

////////////////////// } }

void iccardcode() {

unsigned char cmd; unsigned char status;

cmd = RevBuffer[0]; switch(cmd) {

case 1: // Halt the card //终止卡的操作 status= PcdHalt();; RevBuffer[0]=1;

RevBuffer[1]=status; break;

case 2: // Request,Anticoll,Select,return CardType(2 bytes)+CardSerialNo(4 bytes)

// 寻卡,防冲突,选择卡 返回卡类型(2 bytes)+ 卡系列号(4 bytes)

status= PcdRequest(RevBuffer[1],&RevBuffer[2]); if(status!=0) {

status= PcdRequest(RevBuffer[1],&RevBuffer[2]); if(status!=0) {

RevBuffer[0]=1;

RevBuffer[1]=status; break; } }

RevBuffer[0]=3; RevBuffer[1]=status; break;

case 3: // 防冲突 读卡的系列号 MLastSelectedSnr

status = PcdAnticoll(&RevBuffer[2]); if(status!=0) {

RevBuffer[0]=1; RevBuffer[1]=status; break; }

//memcpy(MLastSelectedSnr,&RevBuffer[2],4); RevBuffer[0]=5;

RevBuffer[1]=status; break;

case 4: // 选择卡 Select Card //status=PcdSelect(MLastSelectedSnr); if(status!=MI_OK) {

RevBuffer[0]=1; RevBuffer[1]=status; break; }

RevBuffer[0]=3;

RevBuffer[1]=status; break;

case 5: // Key loading into the MF RC500's EEPROM

//status = PcdAuthState(RevBuffer[1], RevBuffer[3], DefaultKey, MLastSelectedSnr);// 校验卡密码 RevBuffer[0]=1;

RevBuffer[1]=status; break; case 6:

RevBuffer[0]=1;

RevBuffer[1]=status; break; case 7:

RevBuffer[0]=1;

RevBuffer[1]=status; break;

case 8: // Read the mifare card // 读卡

status=PcdRead(RevBuffer[1],&RevBuffer[2]); if(status==0)

{RevBuffer[0]=17;} else

{RevBuffer[0]=1;}

RevBuffer[1]=status; break;

case 9: // Write the mifare card // 写卡 下载密码

status=PcdWrite(RevBuffer[1],&RevBuffer[2]); RevBuffer[0]=1;

RevBuffer[1]=status; break; case 10:

PcdValue(RevBuffer[1],RevBuffer[2],&RevBuffer[3]); RevBuffer[0]=1; RevBuffer[1]=status; break;

case 12: // 参数设置

PcdBakValue(RevBuffer[1], RevBuffer[2]); RevBuffer[0]=1; //contact RevBuffer[1]=0; break; } }

4.实物验证结果如图4所示:

图4:实物验证结果

实物验证可以实现IC卡的读写,由于每个开发板不同,相比仿真程序,对实物验证程序进行了略微的修改,最小系统的LCD1602口不能使用使用外接杜邦线,为了稳定最终选择重新字节焊接板子,最终能达到要求。

方案二:实验步骤: 1.电路图如图5所示:

图5:方案一电路图 2.刷卡前后显示以及操作,如下图6:

图6:方案一实现图

3.根据电路图编写C语言部分主要代码: 代码如下:

#include \#include \#include \#include \#include \#include \#include \#include \#include \#include \void init_all(void) {EA = 0; PT1 = 1;

init_timer(); Serial_init() ; init_rc522(); lcd_init();

EEPROM_READ(0,Card_SN_BUF,4); EEPROM_READ(1,Card_SN_BUF1,4); EEPROM_READ(2,Card_SN_BUF2,4); EEPROM_READ(3,Card_SN_BUF3,4); EEPROM_READ(4,Card_SN_BUF4,4); EEPROM_READ(5,Card_SN_BUF5,4); EEPROM_READ(6,Card_NUM_BUF,1); EEPROM_READ(7,KEY_BUF,8); EA = 1; }

void main(void) {INT8U key;

relay_OFF(); Delay_ms(500); init_all(); LED_BLINK_1(); display(0,0,7); display(1,0,8); display(2,0,9); display(3,0,10); Delay_ms(500); Delay_ms(500); Delay_ms(500); Delay_ms(500); Delay_ms(500);

display_clear_line(0); display_clear_line(1); display_clear_line(2); display_clear_line(3); display(0,0,0); while(1)

{ key=key_scan();

if(key==12) if(states>0) states--; else states=0;

if(key==13) if(++states>3) states=3; ctrl_process(); }} #include #include

#define uchar unsigned char #define uint unsigned int

#define LCD_data P0 //数据口

sbit LCD_RS = P2^2; //寄存器选择输入 sbit LCD_RW = P2^1; //液晶读/写控制 sbit LCD_EN = P2^0; //液晶使能控

uchar code dis0[]=\卡读写系统 %uchar code dis1[]=\卡输入 %uchar code dis2[]=\密码输入:8位 %uchar code dis3[]=\卡登记 %uchar code dis4[]=\密码设置:8位 %uchar code dis5[]=\成功 %uchar code dis6[]=\失败 %uchar code dis7[]=\桂林电子科技大学%uchar code dis8[]=\控制工程 \

uchar code dis9[]=\接口实验 \ uchar code dis10[]=\司亚 \void delay(int ms) //延时xms {while(ms--) { uchar i;

for(i=0;i<250;i++)

{_nop_();_nop_();_nop_();_nop_();}}} void delayNOP() //延时4us

{ _nop_(); _nop_(); _nop_(); _nop_();} bit lcd_busy()

{ bit result; LCD_RS = 0; LCD_RW = 1; LCD_EN = 1; delayNOP();

result = (bit)(LCD_data&0x80); LCD_EN = 0;

return(result); }

void write_cmd(uchar cmd) { unsigned int K=20000;

while(lcd_busy() && K--); //预防没插LCD时候停在这 LCD_RS = 0; LCD_RW = 0; LCD_EN = 0; _nop_(); _nop_();

LCD_data = cmd; delayNOP(); LCD_EN = 1; delayNOP(); LCD_EN = 0; }

void lcd_wdat(uchar dat) { unsigned int K=20000;

while(lcd_busy() && K--); LCD_RS = 1; LCD_RW = 0; LCD_EN = 0; LCD_data= dat; delayNOP(); LCD_EN = 1; delayNOP(); LCD_EN = 0; } void lcd_init()

{ write_cmd(0x36); delay(5);

write_cmd(0x30); delay(5);

write_cmd(0x0C); delay(5);

write_cmd(0x01); delay(5);}

void lcd_pos(uchar X,uchar Y) {uchar pos; if (X==0) {X=0x80;} else if (X==1) {X=0x90;} else if (X==2) {X=0x88;} else if (X==3) {X=0x98;} pos = X+Y ; write_cmd(pos);} void display_all() {uchar i;

lcd_pos(0,0); // i = 0;

while(dis0[i] != '\\0')

{lcd_wdat(dis0[i]); // i++; }

lcd_pos(1,0); // i = 0;

while(dis1[i] != '\\0')

{ lcd_wdat(dis1[i]); // i++;}

lcd_pos(2,0); // i = 0;

第一行显示数字0~9 显示字母 第二行显示字母 显示字母 第三行显示文字 while(dis2[i] != '\\0') {lcd_wdat(dis2[i]); i++;}

lcd_pos(3,0); //第四行显示广工无线电社 i = 0;

while(dis3[i] != '\\0') {

lcd_wdat(dis3[i]); i++; }}

void display(uchar a,uchar b,uchar c) {uchar i;

lcd_pos(a,b); i = 0; switch(c)

{case 0: while(dis0[i] != '\\0') {lcd_wdat(dis0[i]); i++; } break;

case 1:while(dis1[i] != '\\0')

{lcd_wdat(dis1[i]);i++;}break; case 2:

while(dis2[i] != '\\0') {lcd_wdat(dis2[i]); i++; }break;

case 3: while(dis3[i] != '\\0') {lcd_wdat(dis3[i]);i++; } break;

case 4: while(dis4[i] != '\\0')

{lcd_wdat(dis4[i]); i++;}break;

case 5: while(dis5[i] != '\\0')

{lcd_wdat(dis5[i]); i++;} break; case 6: while(dis6[i] != '\\0')

{lcd_wdat(dis6[i]); i++;} break; case 7: while(dis7[i] != '\\0')

{lcd_wdat(dis7[i]); i++;} break; case 8: while(dis8[i] != '\\0')

{lcd_wdat(dis8[i]); i++;} break; case 9: while(dis9[i] != '\\0')

{lcd_wdat(dis9[i]); i++;} break;

case 10: while(dis10[i] != '\\0')

{ lcd_wdat(dis10[i]); i++;} break; default :break; } }

void display2(uchar a,uchar b,uchar *p,uchar num) { uchar i;

lcd_pos(a,b);

for(i=0;i

lcd_wdat(p[i]); } void display_clear_line(uchar a) {

uchar i;

lcd_pos(a,0);

for(i=0;i<16;i++) lcd_wdat(' '); }

4.实物验证结果如图7所示:

图7:实物验证结果

实物验证可以实现IC卡的读写加密,使用LCD12864中文字幕可以更方便读取信息,对实物验证程序进行了略微的修改,第一次买的射频模块是坏的浪费了太多时间。换了新板子,最终能达到要求。

心得体会:

通过本次的实验,小组成员都发现自己的知识面还是非常的狭窄,缺少的东

西也有很多,在网上查找一些相关的资料以及在图书馆借阅了几本关于单片机方面的书籍,慢慢的懂了一些关于编程和仿真方面的问题。通过这次实验,成员们都发现各自还是存在一些问题。这些不经意的东西虽然看起来不起眼,但是在试验中是不可忽视的问题。这次试验,硬件调试让我遇到的困难有很多,例如一开始在编程的时候,IC卡在射频模块上无法读取以及上位机无法显示,失败之后吸取经验最终在同学帮助下实现了读写。这次的实验,学习到的内容也有很多,不求在一个试验中就能让我学到很多的东西,但在以后的学习中,会慢慢的一点点改进,熟练的理解以及掌握相关的知识,希望能在这方面学到的越来越多。

本文来源:https://www.bwwdw.com/article/c537.html

Top