射频卡模块(射频卡模块程序)

Mark wiens

发布时间:2022-12-31

射频卡模块(射频卡模块程序)

 

本文分享自华为云社区《鍗庝负浜戣鍧沖浜戣绠楄鍧沖寮€鍙戣€呰鍧沖鎶€鏈鍧�-鍗庝负浜�》,作者:DS小龙哥。

一、IC卡介绍

常用的IC卡一般是M1卡,也称为S50卡,购买RC522刷卡模块送的白卡,蓝色钥匙扣、公交卡、地铁卡都是S50卡。S50卡内部有16个分区,每分区有AB两组密码,总容量为8Kbit。

第0个扇区第0块用于存放厂商代码,意见固话,不可更改。

每个扇区的块0、块1、块2为数据块,可以用于存储数据。数据块可以进行读写操作。

每个扇区的块3为控制块,包括了密码A、存储控制、密码B。具体结构如下:

每个扇区的密码和控制位都是独立的,可以根据实际需求设定各自的密码及存取控制。存取控制为4个字节,共32位,扇区中的每个块(包括数据和控制块)存取条件是由密码和存取控制共同决定的,在存取控制中每个块都有一个相应的三个控制位。

重点总结:

(1)M1卡分为16个扇区,每个扇区由4块(0、1、2、3)组成。在实际操作时,将16个扇区分为64个块,按绝对地址编号为0-63进行访问,也就是程序里需要填块的位置时,范围是0~63。

(2)每个块的大小是16字节,每个扇区里有3个数据块,数据块可以存放自己的自定义数据。

二、一卡通消费机实现原理

2.1 封装核心函数

(1)主要的硬件:单片机选择STM32,刷卡模块采用RC522。

互联网小常识:宽带城域网在组建方案中一定要按照电信级运行的要求,考虑设备冗余、线路冗余、路由冗余,以及系统故障的快速诊断与自动恢复。

(2)实现核心思路:为了方便存储数据,对数据进行管理,保证程序的通用性,将IC卡的所有信息都存放在IC卡上。包括:激活状态、卡所属人信息,金额等。

所以在程序里定义了一个结构体:

pragmapack(1)//这个结构体大小为16个字节,刚好存放到 IC卡的一个块里面typedefstructCARD_INFO{ u8 stat;//卡状态. 66表示此卡已经激活 其他值表示此卡未激活// 88表示此卡挂失,无法再进行消费u32 money;//金额. 第一次激活卡,就将金额清0u8 phone[11];//可以存放电话号码,ID,标识符之类的数据}CARD;externu8 IC_Card_uid[4];

并封装了两个底层函数:接下来的所有对卡的操作只需要调用下面函数即可。

//读取卡号u8IC_Card_uid[4];/* card_uid :卡的id号外部5字节数组 data : 读出来的一个块,16字节数据 addr : 块号,从4开始 数据存放的地址。每个扇区的0、1、2块是存放数据。3是存放密码。 一般填:0、1、2 、4、5、6、8、9、10 数据一般格式:u8 SJ[16]={255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255}; //写入的金额; */u8IC_Card_Read(CARD *rdata) {u8KEY[6] = {0xff,0xff,0xff,0xff,0xff,0xff};//白卡的出厂密码u8status;/*1. 寻卡*/status = search_card(IC_Card_uid);/*2. 验证卡密码*/if(MI_OK==status) { print_CardNnmber(IC_Card_uid); status = RC522_PcdAuthState(PICC_AUTHENT1A,3, KEY, IC_Card_uid);//验证卡片密码 形参参数:验证方式,块地址,密码,卡序列号}/*3. 读出数据*/if(MI_OK==status) { status = RC522_PcdRead(1,(u8*)rdata);//从第addr块读出数据值。}returnstatus; }/* 功能:写数据到指定块 参数: u8 addr :数据存放的地址。每个扇区的0、1、2块是存放数据。3是存放密码。 一般填:0、1、2 、4、5、6、8、9、10 数据一般格式:u8 SJ[16]={255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255}; //写入的金额; */u8IC_Card_Write(CARD *wdata) {u8KEY[6] = {0xff,0xff,0xff,0xff,0xff,0xff};//白卡的出厂密码u8status;/*1. 寻卡*/status = search_card(IC_Card_uid);/*2. 验证卡密码*/if(MI_OK==status) { status = RC522_PcdAuthState(PICC_AUTHENT1A,3, KEY, IC_Card_uid);//验证卡片密码 形参参数:验证方式,块地址,密码,卡序列号}/*3. 写数据到卡*/if(MI_OK==status) { status = RC522_PcdWrite(1, (u8*)wdata);//写数据到第addr块,data入的数据值。}returnstatus; }

2.2 编写案例接口

为了方便理解整体的设计思路,下面针对几个常见的操作编写了函数接口测试Demo。

voidActivation_CardInformation(void);//对卡激活-将卡状态设置为66voidUnlock_CardInformation(void);//对卡解锁--去除挂失状态。将卡状态设置为66voidlocking_CardInformation(void);//对卡挂失。将卡状态设置为88voidConsumption_CardInformation(void);//消费. 消费就是减少金额.voidRecharge_CardInformation(void);//对卡进行充值. 充值就是累加金额voidQuery_CardInformation(void);//查询卡的详细信息,通过串口打印

源代码如下:

include"app.h"/* 函数功能: 查询卡的详细信息,通过串口打印 */void Query_CardInformation() { CARDdata;if(IC_Card_Read(&data)==MI_OK) {//判断卡是否已经激活if(data.stat==66) { printf("用户信息:%s\r\n",data.phone); printf("余额:%d\r\n",data.money); }elseif(data.stat==88) { printf("此卡已挂失.请先解锁.\r\n"); }//卡没有激活else{ printf("此卡没有激活.\r\n"); }//复位--释放选中的卡片RC522_PcdReset(); } }/* 函数功能: 对卡进行充值. 充值就是累加金额 */void Recharge_CardInformation() { CARDdata;if(IC_Card_Read(&data)==MI_OK) {//判断卡是否已经激活if(data.stat==66) { printf("用户信息:%s\r\n",data.phone); printf("充值前的余额:%d\r\n",data.money);//累加金额data.money+=100;//充值100块//重新写入到卡里RC522_PcdWrite(1, (u8*)&data);//写数据到第addr块,data入的数据值。;printf("充值后的余额:%d\r\n",data.money); }//卡已经挂失elseif(data.stat==88) { printf("此卡已挂失.请先解锁后再充值.\r\n"); }//卡没有激活else{ printf("此卡没有激活.请先激活后再充值.\r\n"); }//复位--释放选中的卡片RC522_PcdReset(); } }/* 函数功能: 消费. 消费就是减少金额. */void Consumption_CardInformation() { CARDdata;if(IC_Card_Read(&data)==MI_OK) {//判断卡是否已经激活if(data.stat==66) { printf("用户信息:%s\r\n",data.phone); printf("消费前的余额:%d\r\n",data.money);//消费金额,假如:我要消费10元,先判断卡里有没有10元,没有就不能消费.printf("即将消费10元...\r\n");//余额足够才能消费if(data.money>=10) {data.money-=10;//减去10块//重新写入到卡里RC522_PcdWrite(1, (u8*)&data);//写数据到第addr块,data入的数据值。;printf("消费后的余额:%d\r\n",data.money); }else{ printf("余额不足,消费失败...\r\n"); } }//卡已经挂失elseif(data.stat==88) { printf("此卡已挂失.请先解锁后再进行消费流程.\r\n"); }//卡没有激活else{ printf("此卡没有激活.请先激活后再进行消费流程.\r\n"); }//复位--释放选中的卡片RC522_PcdReset(); } }/* 函数功能: 对卡挂失。将卡状态设置为88 */void locking_CardInformation() { CARDdata;if(IC_Card_Read(&data)==MI_OK) {//判断卡是否已经激活if(data.stat==66) { printf("用户信息:%s\r\n",data.phone);//设置挂失状态data.stat=88;//重新写入到卡里RC522_PcdWrite(1, (u8*)&data);//写数据到第addr块,data入的数据值。;printf("此卡已成功挂失.\r\n"); }//卡已经挂失elseif(data.stat==88) { printf("此卡已挂失.\r\n"); }//卡没有激活else{ printf("此卡没有激活.请先激活.\r\n"); }//复位--释放选中的卡片RC522_PcdReset(); } }/* 函数功能: 对卡解锁--去除挂失状态。将卡状态设置为66 */void Unlock_CardInformation() { CARDdata;if(IC_Card_Read(&data)==MI_OK) {//判断卡是否已经激活if(data.stat==66) { printf("此卡已解锁.\r\n"); }//卡已经挂失elseif(data.stat==88) {//设置解锁状态data.stat=66;//重新写入到卡里RC522_PcdWrite(1, (u8*)&data);//写数据到第addr块,data入的数据值。;printf("此卡已成功解锁.\r\n"); }//卡没有激活else{ printf("此卡没有激活.请先激活.\r\n"); }//复位--释放选中的卡片RC522_PcdReset(); } }/* 函数功能: 对卡激活-将卡状态设置为66 激活卡也叫注册卡。可以写入一些用户信息到卡里. */void Activation_CardInformation() { CARDdata;if(IC_Card_Read(&data)==MI_OK) {//判断卡是否已经激活if(data.stat==66) { printf("此卡已激活,不需要重复激活.\r\n"); }//卡已经挂失elseif(data.stat==88) { printf("此卡已激活,并挂失,锁定,请先解锁...\r\n"); }//卡没有激活else{//设置解锁状态data.stat=66; strncpy((char*)data.phone,"473608901",sizeof(data.phone)-1);//重新写入到卡里// IC_Card_Write(&data);/*3. 写数据到卡*/RC522_PcdWrite(1, (u8*)&data);//写数据到第addr块,data入的数据值。printf("此卡已成功激活.用户信息:%s\r\n",data.phone); }//复位--释放选中的卡片RC522_PcdReset(); } }

2.3 编写操作界面

为了方便测试功能,在LCD屏上绘制了几个矩形,触摸屏点击分别执行对应的功能。

include"app.h"/* RC522射频模块外部的接口: *1--SDA <----->PB5--片选脚 *2--SCK <----->PB4--时钟线 *3--MOSI<----->PA12--输出 *4--MISO<----->PA11--输入 *5--悬空 *6--GND <----->GND *7--RST <----->PA8--复位脚 *8--VCC <----->VCC */intmain(){ USARTx_Init(USART1,72,115200); LCD_Init(); LCD_Clear(BLACK); XPT2046_TouchInit(); RC522_Init();// DisplayString(0,0,16,"12345jkdbdfvdfvdfv7364837340hdxsmsks3743934ndvdfv",BLACK,WHITE);//// POINT_COLOR=0x00FF; //设置画笔颜色// LCD_DrawLine(0,0,200,50); //画线////颜色填充LCD_Fill(0,0,120,105,RED);//颜色填充LCD_Fill(120,0,239,105,RED);//颜色填充LCD_Fill(0,105,120,210,RED);//颜色填充LCD_Fill(120,105,239,210,RED);//颜色填充LCD_Fill(0,210,120,320,RED);//颜色填充LCD_Fill(120,210,239,320,RED); DisplayString(0,0,16,"Activation",BLACK,WHITE); DisplayString(120,0,16,"Query",BLACK,WHITE); DisplayString(0,105,16,"Recharge",BLACK,WHITE); DisplayString(120,105,16,"Consumption",BLACK,WHITE); DisplayString(0,210,16,"locking",BLACK,WHITE); DisplayString(120,210,16,"Unlock",BLACK,WHITE);while(1) {//扫描触摸屏坐标if(XPT2046_ReadXY()) {printf("x=%d,y=%d\r\n",xpt2046_touch.x,xpt2046_touch.y);printf("x0=%d,y0=%d\r\n",xpt2046_touch.x0,xpt2046_touch.y0);// 对卡激活-if(xpt2046_touch.x>0&&xpt2046_touch.x<120&& xpt2046_touch.y>0&&xpt2046_touch.y<105) {printf("---- 对卡激活-Demo----\r\n");//充值DemoActivation_CardInformation();//颜色填充LCD_Fill(0,0,120,105,WHITE); DisplayString(0,0,16,"Activation",BLACK,WHITE);//等待触摸屏松开while(XPT2046_PEN==0){}//颜色填充LCD_Fill(0,0,120,105,RED); DisplayString(0,0,16,"Activation",BLACK,WHITE); }//查询Demoelseif(xpt2046_touch.x>120&&xpt2046_touch.x<240&& xpt2046_touch.y>0&&xpt2046_touch.y<105) {printf("----运行查询Demo----\r\n");//查询DemoQuery_CardInformation();//颜色填充LCD_Fill(120,0,239,105,WHITE); DisplayString(120,0,16,"Query",BLACK,WHITE);//等待触摸屏松开while(XPT2046_PEN==0){}//颜色填充LCD_Fill(120,0,239,105,RED); DisplayString(120,0,16,"Query",BLACK,WHITE); }//充值Demoelseif(xpt2046_touch.x>0&&xpt2046_touch.x<120&& xpt2046_touch.y>105&&xpt2046_touch.y<210) {printf("----运行充值Demo----\r\n");//充值DemoRecharge_CardInformation();//颜色填充LCD_Fill(0,105,120,210,WHITE); DisplayString(0,105,16,"Recharge",BLACK,WHITE);//等待触摸屏松开while(XPT2046_PEN==0){}//颜色填充LCD_Fill(0,105,120,210,RED); DisplayString(0,105,16,"Recharge",BLACK,WHITE); }//消费Demoelseif(xpt2046_touch.x>120&&xpt2046_touch.x<240&& xpt2046_touch.y>105&&xpt2046_touch.y<210) {printf("----运行消费Demo----\r\n");//消费DemoConsumption_CardInformation();//颜色填充LCD_Fill(120,105,239,210,WHITE); DisplayString(120,105,16,"Consumption",BLACK,WHITE);//等待触摸屏松开while(XPT2046_PEN==0){}//颜色填充LCD_Fill(120,105,239,210,RED); DisplayString(120,105,16,"Consumption",BLACK,WHITE);//等待触摸屏松开}//挂失Demoelseif(xpt2046_touch.x>0&&xpt2046_touch.x<120&& xpt2046_touch.y>210&&xpt2046_touch.y<320) {printf("----运行挂失Demo----\r\n");//挂失Demolocking_CardInformation();//颜色填充LCD_Fill(0,210,120,320,WHITE); DisplayString(0,210,16,"locking",BLACK,WHITE);//等待触摸屏松开while(XPT2046_PEN==0){}//颜色填充LCD_Fill(0,210,120,320,RED); DisplayString(0,210,16,"locking",BLACK,WHITE); }//解锁Demoelseif(xpt2046_touch.x>120&&xpt2046_touch.x<240&& xpt2046_touch.y>210&&xpt2046_touch.y<320) {printf("----运行解锁Demo----\r\n");//解锁DemoUnlock_CardInformation();//颜色填充LCD_Fill(120,210,239,320,WHITE); DisplayString(120,210,16,"Unlock",BLACK,WHITE);//等待触摸屏松开while(XPT2046_PEN==0){}//颜色填充LCD_Fill(120,210,239,320,RED); DisplayString(120,210,16,"Unlock",BLACK,WHITE); } } delay_ms(10); } }

2.4 运行效果

点击下方,第一时间了解华为云新鲜技术~

华为云博客_大数据博客_AI博客_云计算博客_开发者中心-华为云

互联网小常识:ipconfig 显示当前TCP/IP网络设置 ;hostname显示当前主机名称;arp 显示和修改arp表;NBTSTAT显示本机与远程计算机的基于TCP/IP的NetBIOS的统计及连接信息;Net 管理网络环境、服务、用户、登录等本地信息;NETSTAT 显示活动的TCP连接、侦听端口、以太网统计信息、IP路由表与IP统计信息。Ping通过发送ICMP报文并监听回应来检查与远程或本地计算机的连接。

互联网小常识:集线器是对“共享介质”的一种改革,并且没有破坏CSMA/CD方法。它仍工作在物理层,所有的结点都在一个冲突域中。从结点和集线器的无屏蔽双绞线的最大长度为100m。

免责声明:本站所有信息均搜集自互联网,并不代表本站观点,本站不对其真实合法性负责。如有信息侵犯了您的权益,请告知,本站将立刻处理。联系QQ:1640731186