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

动手实操丨RC522射频卡模块与IC卡完成充值消费查询的技术实现思路一文手把手教你利用RC522射频卡模块与IC卡完成充值消费查询的技术实现思路。

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

本文分享自华为云社区《RC522射频卡模块与IC卡完成充值消费查询的技术实现思路》,作者:DS小龙哥。

一、IC卡介绍

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

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

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

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

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

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

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

重点总结:

(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;    //金额. 第一次激活卡,就将金额清0
     u8  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); //对卡激活-将卡状态设置为66
 void Unlock_CardInformation(void);    //对卡解锁--去除挂失状态。将卡状态设置为66
 void locking_CardInformation(void);  //对卡挂失。将卡状态设置为88
 void 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屏上绘制了几个矩形,触摸屏点击分别执行对应的功能。

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

 #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");
 
                 //充值Demo
                 Activation_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);
             }
 
             //查询Demo
             else if(xpt2046_touch.x>120&&xpt2046_touch.x<240&&
                xpt2046_touch.y>0&&xpt2046_touch.y<105)
             {
                 printf("----运行查询Demo----\r\n");
                 //查询Demo
                 Query_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);
             }
 
             //充值Demo
             else if(xpt2046_touch.x>0&&xpt2046_touch.x<120&&
                xpt2046_touch.y>105&&xpt2046_touch.y<210)
             {
                 printf("----运行充值Demo----\r\n");
                 //充值Demo
                 Recharge_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);
             }
 
             //消费Demo
             else if(xpt2046_touch.x>120&&xpt2046_touch.x<240&&
                xpt2046_touch.y>105&&xpt2046_touch.y<210)
             {
                 printf("----运行消费Demo----\r\n");
                 //消费Demo
                 Consumption_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);
                 //等待触摸屏松开
             }
 
             //挂失Demo
             else if(xpt2046_touch.x>0&&xpt2046_touch.x<120&&
                xpt2046_touch.y>210&&xpt2046_touch.y<320)
             {
                 printf("----运行挂失Demo----\r\n");
                 //挂失Demo
                 locking_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);
             }  
 
              //解锁Demo
             else if(xpt2046_touch.x>120&&xpt2046_touch.x<240&&
                xpt2046_touch.y>210&&xpt2046_touch.y<320)
             {
                 printf("----运行解锁Demo----\r\n");
                 //解锁Demo
                 Unlock_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卡完成充值消费查询的技术实现思路

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

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

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/159349.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • oracle创建用户、密码、分配权限、基本权限的作用「建议收藏」

    oracle创建用户、密码、分配权限、基本权限的作用「建议收藏」创建用户和密码:createuserusernameidentifiedbypassword;//建用户名和密码例子:oracle,oracle分配权限:grantconnect,resource,dbatousername;//授权例子:grantconnect,resource,dba,sysdbatousername;创建同义词:创建同义词…

  • ServletContextListener使用详解

    ServletContextListener使用详解在 ServletAPI 中有一个 ServletContextListener 接口,它能够监听 ServletContext 对象的生命周期,实际上就是监听 Web 应用的生命周期。当Servlet 容器启动或终止Web 应用时,会触发ServletContextEvent 事件,该事件由ServletContextListener 来处理。在 ServletContextListene

  • GPU利用率低的解决办法

    GPU利用率低的解决办法watch-n0.1-dnvidia-smi#检查GPU利用率参数解决办法:1.dataloader设置参数2.增大batchsize3.减少IO操作,比如tensorboard的写入和打印。4.换显卡

  • StretchDIBits函数

    StretchDIBits函数引用:http://blog.csdn.net/giantchen547792075/article/details/6996011The StretchDIBits functioncopiesthecolordataforarectangleofpixelsinaDIB,JPEG,orPNGimagetothespecifieddestination

  • python endif_在Django模板中的 if else endif

    python endif_在Django模板中的 if else endifif/else{%if%}标签检查(evaluate)一个变量,如果这个变量为真(即,变量存在,非空,不是布尔值假),系统会显示在{%if%}和{%endif%}之间的任何内容,例如:{%iftoday_is_weekend%}Welcometotheweekend!{%endif%}{%else%}标签是可选的:{%iftoday_is_weeke…

    2022年10月26日
  • android开发股票数据接口,股票数据接口-股票数据接口api「建议收藏」

    原标题:股票数据接口-股票数据接口api量亿数据专注金融领域API数据接口,其中包括期货、股票、期权、外汇等,只需要注册即可申请使用。免费申请网址:http://www.liangyee.com/如何获取股票数据,股票数据接口-股票数据接口api,以美股API数据接口为例。5分钟K线接口地址:http://stock.liangyee.com/bus-api/USStock/marketData/…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号