本文分享自华为云社区《RC522射频卡模块与IC卡完成充值消费查询的技术实现思路》,作者: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卡上。包括:激活状态、卡所属人信息,金额等。

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

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

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

//读取卡号u8 IC_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}; //写入的金额;​*/u8 IC_Card_Read(CARD *rdata){u8 KEY[6] = {0xff,0xff,0xff,0xff,0xff,0xff};    //白卡的出厂密码u8 status;​/*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块读出数据值。}return status;}​​/*功能:写数据到指定块参数: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}; //写入的金额;​*/u8 IC_Card_Write(CARD *wdata){u8 KEY[6] = {0xff,0xff,0xff,0xff,0xff,0xff};    //白卡的出厂密码u8 status;​/*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入的数据值。}return status;}

2.2 编写案例接口

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

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

源代码如下:

 #include "app.h"/*函数功能: 查询卡的详细信息,通过串口打印*/void Query_CardInformation(){CARD data;if(IC_Card_Read(&data)==MI_OK){//判断卡是否已经激活if(data.stat==66){printf("用户信息:%s\r\n",data.phone);printf("余额:%d\r\n",data.money);}else if(data.stat==88){printf("此卡已挂失.请先解锁.\r\n");}//卡没有激活else {printf("此卡没有激活.\r\n");}//复位--释放选中的卡片RC522_PcdReset();}}​​/*函数功能: 对卡进行充值. 充值就是累加金额*/void Recharge_CardInformation(){CARD data;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);}//卡已经挂失else if(data.stat==88){printf("此卡已挂失.请先解锁后再充值.\r\n");}//卡没有激活else {printf("此卡没有激活.请先激活后再充值.\r\n");}//复位--释放选中的卡片RC522_PcdReset();}}​​/*函数功能: 消费. 消费就是减少金额.*/void Consumption_CardInformation(){CARD data;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");}}//卡已经挂失else if(data.stat==88){printf("此卡已挂失.请先解锁后再进行消费流程.\r\n");}//卡没有激活else {printf("此卡没有激活.请先激活后再进行消费流程.\r\n");}//复位--释放选中的卡片RC522_PcdReset();}}​​​/*函数功能: 对卡挂失。将卡状态设置为88*/void locking_CardInformation(){CARD data;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");}//卡已经挂失else if(data.stat==88){printf("此卡已挂失.\r\n");}//卡没有激活else {printf("此卡没有激活.请先激活.\r\n");}//复位--释放选中的卡片RC522_PcdReset();}}​​​/*函数功能: 对卡解锁--去除挂失状态。将卡状态设置为66*/void Unlock_CardInformation(){CARD data;if(IC_Card_Read(&data)==MI_OK){//判断卡是否已经激活if(data.stat==66){printf("此卡已解锁.\r\n");}//卡已经挂失else if(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(){CARD data;if(IC_Card_Read(&data)==MI_OK){//判断卡是否已经激活if(data.stat==66){printf("此卡已激活,不需要重复激活.\r\n");}//卡已经挂失else if(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*/​​int main(){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);}//查询Demoelse if(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);}//充值Demoelse if(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);}//消费Demoelse if(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);//等待触摸屏松开}//挂失Demoelse if(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);}  //解锁Demoelse if(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 运行效果

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

动手实操丨RC522射频卡模块与IC卡完成充值消费查询的技术实现思路相关推荐

  1. 动手实操丨基于随机森林算法进行硬盘故障预测

    摘要:业界期望使用机器学习技术来构建硬盘故障预测的模型,更准确地提前感知硬盘故障,降低运维成本,提升业务体验.本案例将使用随机森林算法来训练一个硬盘故障预测模型. 本文分享自华为云社区<基于随机 ...

  2. 荐读:Xilinx ZYNQ 动手实操演练

    今天给大侠带来Xilinx ZYNQ 动手实操演练,话不多说,上货.当我们一提到 Xilinx ZYNQ,大家脑海大多数就会浮现一个描述的词汇,高端,其实这个词很贴切的形容了Zynq系列产品,Xili ...

  3. MySQL经典笔试题(初级)动手实操

    动手实操 1) 创建一张学生表,包含以下信息,学号,姓名,年龄,性别,家庭住址,联系电话 ,其中id为主键,且设置自增长,姓名不能为空. DROP TABLE IF EXISTS student; C ...

  4. 如何区分电梯卡为id卡ic卡_电梯IC卡和ID卡有何不同?

    原标题:电梯IC卡和ID卡有何不同? 在现代社会中,随着科技和经济的高速发展,各种各样的卡也出现在人们生活中,如:医疗卡.会员卡.贵宾卡.保险卡.房卡等,随着这些卡类的快速发展,又有了IC卡和ID卡等 ...

  5. 如何区分电梯卡为id卡ic卡_门禁卡是选择IC卡好还是ID卡好

    门禁卡目前可以封装不同的芯片,因此也可以做成ID的,也可以做成IC的,于是很多人也会这样问:"门禁卡是选择IC卡好还是ID卡好?"对于这个问题,银深源解析其中的个中原委. 其实IC ...

  6. 央行:社保卡与金融IC卡不冲突

    国新办8月30日上午举行发布会,中国人民银行行长助理李东荣和人社部部长胡晓义介绍社保卡加载金融功能相关情况.李东荣表示,社保卡加载金融功能和央行力推的金融IC卡不冲突,两者是互利关系. 根据此前人保部 ...

  7. tengine简单安装_实操丨如何在EAIDK上部署Tengine开发AI应用之物体检测应用入门(C++)...

    前言:近期推出的嵌入式AI系列直播公开课受到广大开发者的喜爱,并收到非常多的反馈信息,其中对如何在EAIDK上面部署Tengine开发AI应用感兴趣的开发者不在少数,我们将分2期以案例实操的形式详细介 ...

  8. 【已鸽】手机添加nfc模块模拟ic卡开门禁

    step1:先查到门禁一卡通的生产公司,找到相应的型号 学校方:校园一卡通应用平台密钥系统通过银联提供的主控密钥生成校园一卡通的应用密钥:校园一卡通应用平台对金融IC卡进行二次发卡,在校园一卡通应用下 ...

  9. java如何读取ic卡_java读取IC卡设备

    有几个项目都用到IC卡设备,IC卡供应商提供的例程里没有java的例子,调试过程发现各种问题,总算是测试通过了,mark一下. 基本思路:通过JNative.jar包调用dll方式,读取IC卡的序列号 ...

最新文章

  1. 从“创业输家”到“创智赢家”
  2. GDI+ 获取本地电脑的图片编码器
  3. VUE内置组件 vue使用插槽分发内容 组件缓存 实现动画的过渡效果
  4. LeetCode 965. 单值二叉树
  5. Java Http编程
  6. Robot Framework中经常用的第三方库的安装方法
  7. 经典机器学习系列(四)【神经网络详解】
  8. b站弹幕姬python_自用 Bilibili 弹幕姬 for macOS
  9. IDEA更改主题颜色
  10. love2d 1. 入门
  11. 中科大自主招生2018年笔试数学之四
  12. DQM Serial Sync Index Program ERROR
  13. 如何做一个基于JAVA房产中介预约看房系统毕业设计毕设作品(springboot框架)
  14. 速腾 RS-Bpearl 显示点云
  15. 使用puppeteer启动并最大化显示Chrome浏览器
  16. 网络安全-IIS短文件名枚举漏洞
  17. javaweb——spring cloud分布式系统(1)搭建配置管理中心
  18. scikit-learn学习笔记-bili莫烦
  19. 满帮集团满身泥泞:市值蒸发近千亿元,戴文建等人减持“套现”
  20. 谷歌SEO老域名攻略

热门文章

  1. 如何做好线上问题分析
  2. 树莓派研究笔记(5)-- FM网络收音机
  3. html+css实战152-定位-hot图标
  4. 15 个开源的顶级人工智能工具
  5. 计算机相关书单汇总:基础、理论、网络、编码、C/C++、其他编程语言
  6. matlab里的function编程,MATLAB 元编程介绍
  7. 人生就是一个完整的项目
  8. C#开发串口小助手(可更改波特率、串口号,可实现数据以及字符的收发)
  9. 人有多成功,那要看你能驾驭自己到什么程度
  10. 文件应该存储在手机的什么地方?