范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

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;    //金额. 第一次激活卡,就将金额清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("用户信息:%sr ",data.phone);              printf("余额:%dr ",data.money);          }          else if(data.stat==88)          {               printf("此卡已挂失.请先解锁.r ");          }          //卡没有激活          else           {               printf("此卡没有激活.r ");          }             //复位--释放选中的卡片          RC522_PcdReset();      }  }      /*  函数功能: 对卡进行充值. 充值就是累加金额  */  void Recharge_CardInformation()  {      CARD data;      if(IC_Card_Read(&data)==MI_OK)      {          //判断卡是否已经激活          if(data.stat==66)          {              printf("用户信息:%sr ",data.phone);              printf("充值前的余额:%dr ",data.money);                                          //累加金额              data.money+=100; //充值100块                            //重新写入到卡里              RC522_PcdWrite(1, (u8*)&data); //写数据到第addr块,data入的数据值。;                            printf("充值后的余额:%dr ",data.money);          }          //卡已经挂失          else if(data.stat==88)          {               printf("此卡已挂失.请先解锁后再充值.r ");          }          //卡没有激活          else           {               printf("此卡没有激活.请先激活后再充值.r ");          }             //复位--释放选中的卡片          RC522_PcdReset();      }  }      /*  函数功能: 消费. 消费就是减少金额.  */  void Consumption_CardInformation()  {      CARD data;      if(IC_Card_Read(&data)==MI_OK)      {          //判断卡是否已经激活          if(data.stat==66)          {              printf("用户信息:%sr ",data.phone);              printf("消费前的余额:%dr ",data.money);                            //消费金额,假如:我要消费10元,先判断卡里有没有10元,没有就不能消费.              printf("即将消费10元...r ");                            //余额足够才能消费              if(data.money>=10)              {                  data.money-=10; //减去10块                                                //重新写入到卡里                  RC522_PcdWrite(1, (u8*)&data); //写数据到第addr块,data入的数据值。;                                    printf("消费后的余额:%dr ",data.money);              }              else              {                  printf("余额不足,消费失败...r ");              }          }          //卡已经挂失          else if(data.stat==88)          {               printf("此卡已挂失.请先解锁后再进行消费流程.r ");          }          //卡没有激活          else           {               printf("此卡没有激活.请先激活后再进行消费流程.r ");          }             //复位--释放选中的卡片          RC522_PcdReset();      }  }        /*  函数功能: 对卡挂失。将卡状态设置为88  */  void locking_CardInformation()  {      CARD data;      if(IC_Card_Read(&data)==MI_OK)      {          //判断卡是否已经激活          if(data.stat==66)          {              printf("用户信息:%sr ",data.phone);                          //设置挂失状态             data.stat=88;                           //重新写入到卡里             RC522_PcdWrite(1, (u8*)&data); //写数据到第addr块,data入的数据值。;                           printf("此卡已成功挂失.r ");                        }          //卡已经挂失          else if(data.stat==88)          {               printf("此卡已挂失.r ");          }          //卡没有激活          else           {               printf("此卡没有激活.请先激活.r ");          }             //复位--释放选中的卡片          RC522_PcdReset();      }  }        /*  函数功能: 对卡解锁--去除挂失状态。将卡状态设置为66  */  void Unlock_CardInformation()  {      CARD data;      if(IC_Card_Read(&data)==MI_OK)      {          //判断卡是否已经激活          if(data.stat==66)          {             printf("此卡已解锁.r ");          }          //卡已经挂失          else if(data.stat==88)          {              //设置解锁状态             data.stat=66;                           //重新写入到卡里            RC522_PcdWrite(1, (u8*)&data); //写数据到第addr块,data入的数据值。;                           printf("此卡已成功解锁.r ");          }          //卡没有激活          else           {               printf("此卡没有激活.请先激活.r ");          }             //复位--释放选中的卡片          RC522_PcdReset();      }  }    /*  函数功能: 对卡激活-将卡状态设置为66    激活卡也叫注册卡。可以写入一些用户信息到卡里.  */  void Activation_CardInformation()  {      CARD data;      if(IC_Card_Read(&data)==MI_OK)      {          //判断卡是否已经激活          if(data.stat==66)          {             printf("此卡已激活,不需要重复激活.r ");          }          //卡已经挂失          else if(data.stat==88)          {             printf("此卡已激活,并挂失,锁定,请先解锁...r ");          }          //卡没有激活          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("此卡已成功激活.用户信息:%sr ",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=%dr ",xpt2046_touch.x,xpt2046_touch.y);              printf("x0=%d,y0=%dr ",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 ");                                  //充值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 ");                  //查询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 ");                  //充值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 ");                  //消费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 ");                  //挂失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 ");                  //解锁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 运行效果
  点击下方,第一时间了解华为云新鲜技术~
  华为云博客_大数据博客_AI博客_云计算博客_开发者中心-华为云

集数据可视化日志监控监控告警为一体的分布式开源监控系统真正的大师,永远都怀着一颗学徒的心!一项目简介集监控点监控数据可视化日志监控监控告警为一体的分布式开源监控系统。二实现功能支持jsphpshelljs支持监控告警查看支持支持日志查发现春之美春游High!春季出游正当时!央广网萍乡3月5日消息(记者胡斐)春意盎然,春季旅游正当时,三月的武功山满山浪漫。江西省萍乡市武功山景区推出多项旅游惠民活动政策,景区游人如潮,带热了当地春季旅游市场。游客们正在有当发现女儿偷偷夹腿两位妈妈的做法,造就了女儿不同的人生今天看到这样一段新闻,在前段时间,全国政协委员高晓笛提案建议在各级各类学校实施性教育进课堂。建议一出,在微博上迅速成了热议的话题。评论区下面,网友更是一边倒的支持。孩子的性教育,确力挽狂澜!美媒晒出哈登过去三次对阵雄鹿的数据,得分均30今天NBA常规赛76人客场对阵雄鹿的比赛已经结束。全场战罢,76人以133130战胜雄鹿。本场比赛,76人球员詹姆斯哈登出战39分钟,26投11中,其中三分球9投5中,罚球11投1Python爬虫获取双色球历史开奖数据看到昨天大乐透的开奖数据心都凉了半截,全奇数,脑洞大开,所以今天不说选号,直接来硬核技术,教大家爬虫技术取历史开奖数据大致分为以下三步确定目标网络即,要找到一个有记录开奖数据的网站湖南发现了冬笋为什么长出地面上来了冬竹笋是立冬到清明这段时间,长在土里未出土的笋。冬笋味甘,性微寒,归胃,肺经,具有滋阴凉血,和中润肠,清热化痰,解渴除烦,清热益气,利隔爽胃,利尿通便,解毒透疹,养肝明目,消食的功复旦大学联合考古发掘西夏瓷窑项目获评2022年六大考古新发现新民晚报讯(记者姜燕)日前,国家文物局通报了中国社会科学院考古学论坛2022年中国考古新发现评选结果,复旦大学联合发掘的宁夏贺兰县苏峪口西夏瓷窑址成功入选,这是该校联合发掘考古项目低估了俄罗斯,高估了自己!西方发现已经拿俄罗斯没办法我们都知道,俄罗斯跟乌克兰这两个邻居之间之所以会发生这场已经持续了一年时间持久的军事冲突,除了是因为两国那些长年累月积累下来的矛盾纠纷没有得到完美解决,最终积小成多升级爆发出来之外券业备战全面注册制丨兴业证券投行总裁徐孟静注册制更侧重对企业价值的发现和挖掘21世纪经济报道见习记者易妍君广州报道全面注册制作为丰富和完善多层次资本市场的重要改革,进一步优化了企业IPO并购重组等业务规则。在此背景下,投研能力销售能力以及内控管理能力成为券西山区第七幼儿园家庭公益课堂进社区掌上春城讯3月2日上午,西山区第七幼儿园家庭教育公益大讲堂在进福海街道办事处新河社区开讲。社区20余名家长孩子参与本次公益课堂。在第七幼儿园,部分孩子在生活自理能力动作发展语言发展睡了要叫醒喂药吗?关于儿童退烧药的十大热点问题儿童退烧药十大热点问题近期,医院儿童发热门诊接诊大量患儿,很多新手爸妈对宝宝发烧充满恐惧,其中,退烧药的使用是焦点问题,以下对咨询最集中的问题进行一一解答,带您深入了解退热药物,并
高甜约会花式遛娃赏灯撸宠成都融创乐园带你度过甜蜜情人节寒假临近尾声,情人节即将到来有什么地方,既可以带家中神兽释放能量,度过假期最后一个周末又可以和亲爱的TA浪漫约会度过甜蜜的情人节呢朝这儿看animatetransformanima当兵的日子系列(52)之那山那水那山,显得雄伟苍茫,绿色叠峦,主峰突起,叫常达山。从四平市区出来,大概是路过平东工业区以后不远,就可看见。其中有一个缺口,形似山门,故曰半拉山门。那水,时称吉林省四平市山门水库。现吃牛油果该知道点什么?1适量食用牛油果虽说常吃牛油果能稳定血糖水平有助对抗糖尿病,又有饱腹感,但毕竟其热量颇高(100克牛油果热量为160卡路里),远超绿色果蔬,所以适量食用很有必要。建议男士一天可吃一春吃芽胜过肉,推荐4种芽菜的做法,鲜嫩爽口,遇见别手软一年之计在于春,春天是一个温暖的季节,春暖花开,鸟语花香,春意盎然,大地一片生机勃发的景象,冰河化冻,冬眠的动物也都苏醒了过来,到处寻找食物,无论小草还是柳树都开始萌发了新芽,春天打工人的开工日,睡眠经济的爆发时新春假期结束,五湖四海的打工人的又要投入忙碌的工作之中。春节最后一晚还沉浸在睡起自由的假期情绪内,开工闹钟响起的那一刻,却又不得不投入到调休而来的七天漫漫打工日中。无法脱离假期状态吃懂了江湖菜,你就读懂了重庆人的美味有重庆人的地方,就有江湖菜。如何看一个重庆人拿不拿你当朋友?很简单,看你到重庆的第一顿,他是带你吃城里的网红火锅,还是开车围着各路山头带你宰鸡宰鱼,到南山脚下吃泉水鸡歌乐山半山腰吃滋阴补血,驱寒除湿的麻油鸡做法简单易做风麻油鸡有滋阴补血,驱寒除湿,汤汁浓稠麻油香醇味美,可以用来捞饭或拌面吃,鸡肉中蛋白质的含量比例很高,而且消化率高,很容易被人体吸收利用,有增强体力强壮身体的作用。最适合生产后妇女蒸馒头和包子时,总会出现塌皮,不蓬松等现象,我来教你正确做法蒸馒头和包子时,总会出现塌皮,不蓬松等现象,我来教你正确做法对于经常下厨房的人来说,蒸馒头和包子真的是需要一些操作技巧和经验的。毕竟制作发酵面食品时,很容易出现各种各样的错误,有时让舌尖惊艳的美味!教你营养好吃的酸辣花甲魔芋结,值得一试天南地北大拜年欢迎大家,我是中原辣哥,喜欢美食的朋友,可以关注一下我们哦。中国的饮食文化源远流长,菜系方面也是有着很多,各种各样的美食总会让人眼花缭乱,不知道该去选择什么。作为一个流放宁古塔到底有多可怕?犯人宁愿勒死妻女,也不愿她们到那去流放宁古塔永世不得入关,在清宫剧中,我们经常能听到皇帝对犯人说这句话。热播剧甄嬛传中,甄嬛的父亲甄远道因被人告发私藏叛党钱明世的诗集,被雍正一怒之下,发往宁古塔。临行前,雍正顾念与英雄传奇人物郑成功郑成功收复台湾后,派何廷斌前往高山族聚居的山村了解情况,并向当地民众说明义军来此是为了赶走荷夷,收复国土,拯救人民的。原来,荷夷利用传教士散布谣言,说国姓爷打来,为的是抢夺财物,见