当前位置:   article > 正文

【STM32学习】(11)STM32 Mifare_One(S50) M1S50的使用(读、写、密钥修改,控制位解读)_m1卡 单片机读写

m1卡 单片机读写

最近在研究RFID(射频识别),我用的是 M1卡(Mifare_One(S50)),是一种常用的非接触式IC卡

基础知识不用多讲,网上资料一堆,讲的很详细。

现在我们就直入主题,首先介绍一下卡的执行流程图,如下图。

中文资料里的图,如下:

英文资料里的图,如下:

查资料会发现,所有的参考代码都是按照这个流程图写,很容易懂。不管你在写还是读的时候一定要选卡,放冲突,验卡等流程后才能实现读写操作。

再看一下他的存储结构:

*********引用一个博客文档  开始

我们可以根据控制字来确定卡的读写形式。

M1卡分为16个扇区,每个扇区由4块(块0、块1、块2、块3)组成,前3个块是数据区,第4块是密钥区。每个块都能存储16个字节的数据,密钥区的16个字节数据是有特殊含义的:
6个字节的密码A + 4个字节密钥控制位 + 6个字节的密码B
其中密钥控制位决定这个扇区的读写规则,对于M1卡密钥控制位及控制规则的说明,这篇文章里面讲述得很清楚了:
https://wenku.baidu.com/view/76afde36312b3169a451a4e6.html
这里只是给没有耐心看文章朋友提炼一下,控制字的组合方式虽然多,但实际用得比较多的方案自认为无外乎四种:

1.默认方式 控制位为“FF 07 80 69”
这种方式下密钥A或密钥B都可以读写数据区,密钥A可写密钥区,优点是密钥控制字无需重新计算,读写方便,缺点是安全性能差,密钥A容易泄露。

2.密钥B写方式 控制位为“7F 07 88 69”
这种方式下密钥A或密钥B都可以读写数据区,而对于密钥区只能由密钥B来写。优点是密钥B权限最高,只要知道密钥B,无论密钥A写成什么都可以改写,由最高管理员掌握密钥B,可下发多种密钥A的一般管理员,一般不会废卡的。缺点是密钥B很重要,一旦忘记,卡就不能再改写密钥了。

3.A读B写方式 控制位为“08 77 8F 69”
这种方式下由密钥A读密钥B来写,可以说是上面一种方式的变体,对于密钥B有更强的保护。

4.只读不写方式 控制位为“FF 00 F0 69”
这种方式下密钥A或密钥B都可以读数据区,但都不能写数据区(数值可减少,不能增加),密钥A可以改写密钥区。这种方式对于数据是极大的保护,尤其是定额卡,里面的钱只能减少而不能增加。

 

以上是常用的几种控制方式,更多的组合方式可以利用“M1+卡控制字节生成工具.exe”工具来生成

结束   ******

1.完成RFID卡的读函数代码

  1. /* 读取RFID卡片信息 **/
  2. void Read_RFID_Card_wt(void)
  3. {
  4. char status = MI_ERR;
  5. uint8_t CT[2]; //卡类型
  6. uint8_t SN[4]; //卡号
  7. uint8_t KEY[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; //密钥 // 密钥已被我修改 2019.11.19 王艇
  8. uint8_t s = 0x01;
  9. #define DATA_LEN 16 //定义数据字节长度
  10. LED1 = 0;
  11. LED2 = 0;
  12. LED3 = 0;
  13. LED4 = 0;
  14. status = PcdRequest(PICC_REQALL,CT); //寻卡
  15. //Send_ZigbeeData_To_Fifo(CT,2); // wt 2019.10.18
  16. if(status == MI_OK) //寻卡成功
  17. {
  18. status=MI_ERR;
  19. LED1 = 1;
  20. status = PcdAnticoll(SN); //防冲撞
  21. //Send_ZigbeeData_To_Fifo(SN,4); // wt 2019.10.18
  22. if(status == MI_OK)
  23. {
  24. status=MI_ERR;
  25. LED2 = 1;
  26. status =PcdSelect(SN); //选定此卡
  27. if(status == MI_OK) //选定成功
  28. {
  29. status=MI_ERR;
  30. LED3 = 1;
  31. MP_SPK = 1;
  32. status =PcdAuthState(PICC_AUTHENT1A,0x03,KEY,SN); //验证密钥
  33. if(status == MI_OK)
  34. {
  35. status = MI_ERR;
  36. status=PcdRead(s,RXRFID); //读卡
  37. if(status == MI_OK)
  38. {
  39. status = MI_ERR;
  40. LED4 = 1; //读卡成功
  41. MP_SPK = 0;
  42. //Send_InfoData_To_Fifo(RXRFID,16);
  43. //Send_InfoData_To_Fifo("\n",2);
  44. //Send_ZigbeeData_To_Fifo(RXRFID,16);
  45. }
  46. }
  47. }
  48. }
  49. }
  50. }

这里我是读取0扇区第二块(0X01)的数据,其实读取其他也很简单,需要修改0X03(这个是0-15扇区的控制块,如:0扇区的控制块是0X03,1扇区的控制块是0X07 等等)

随后还要修改,s,这个s就是你要验证的哪个扇区的数据块地址还控制块地址(如:想读1扇区的0块数据,这个s的值就是0X04,我们这里读取的是0扇区第二块(0X01)的数据):

注意:一般新卡的默认密钥都是KEYA或KEYB   0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,但有时候密钥会被修改,那这时就要填写正确的key值,才能验证成功,这样也很容易理解,只有配上正确的密码才能激活卡片。

2.完成RFID卡的写函数代码

  1. void Write_RFID_Card_wt(void)
  2. {
  3. char status = MI_ERR;
  4. uint8_t CT[2]; //卡类型
  5. uint8_t SN[4]; //卡号
  6. uint8_t KEY[6]={0xff,0xff,0xff,0xff,0xff,0xff}; //{0x01,0xB2,0xC3,0xD4,0xE5,0xF6}; //密钥 // 密钥已被我修改 2019.11.19 王艇
  7. uint8_t s = 0x01;
  8. #define DATA_LEN 16 //定义数据字节长度
  9. LED1 = 0;
  10. LED2 = 0;
  11. LED3 = 0;
  12. LED4 = 0;
  13. status = PcdRequest(PICC_REQALL,CT); //寻卡
  14. //Send_ZigbeeData_To_Fifo(CT,2); // wt 2019.10.18
  15. if(status == MI_OK) //寻卡成功
  16. {
  17. status=MI_ERR;
  18. LED1 = 1;
  19. status = PcdAnticoll(SN); //防冲撞
  20. //Send_ZigbeeData_To_Fifo(SN,4); // wt 2019.10.18
  21. if(status == MI_OK)
  22. {
  23. status=MI_ERR;
  24. LED2 = 1;
  25. status =PcdSelect(SN); //选定此卡
  26. if(status == MI_OK) //选定成功
  27. {
  28. status=MI_ERR;
  29. LED3 = 1;
  30. MP_SPK = 1;
  31. status =PcdAuthState(PICC_AUTHENT1A,0x03,KEY,SN); //验证密钥
  32. if(status == MI_OK)
  33. {
  34. status = MI_ERR;
  35. status = PcdWrite(s,TXRFID); //写卡
  36. if(status == MI_OK)
  37. {
  38. status = MI_ERR;
  39. }
  40. }
  41. }
  42. }
  43. }
  44. }

这里是给0扇区1数据块(0X01)写数据,这个写函数也是可以给其他扇区中数据块写数据的,如现在要给我1扇区,2块中写入数据:uint8_t TXRFID[16]  =  {0x7C,0x32,0x2F,0X30,0X33,0X2D,0X32,0X7C,0X7C,0X33,0X2F,0X30,0X35,0X2D,0X31,0X7C}

这里选择的是默认密钥,全F,验证A密钥(PICC_AUTHENT1A

下面的 0X03需要改成0X07(扇区1 控制块地址),因为控制块中包含密钥,需要验证

下面s要修改成0X06(表示1扇区,数据块2的地址)TXRFID 是所要写入的数据

这样就完成了对指定扇区,指定数据块中写入指定数据。
3.修改RFID卡的密钥代码

  1. void Write_RFID_Card_wt(void)
  2. {
  3. char status = MI_ERR;
  4. uint8_t CT[2]; //卡类型
  5. uint8_t SN[4]; //卡号
  6. uint8_t KEY[6]={0xff,0xff,0xff,0xff,0xff,0xff}; //{0x01,0xB2,0xC3,0xD4,0xE5,0xF6}; //密钥 // 密钥已被我修改 2019.11.19 王艇
  7. uint8_t s = 0x03;
  8. #define DATA_LEN 16 //定义数据字节长度
  9. LED1 = 0;
  10. LED2 = 0;
  11. LED3 = 0;
  12. LED4 = 0;
  13. status = PcdRequest(PICC_REQALL,CT); //寻卡
  14. //Send_ZigbeeData_To_Fifo(CT,2); // wt 2019.10.18
  15. if(status == MI_OK) //寻卡成功
  16. {
  17. status=MI_ERR;
  18. LED1 = 1;
  19. status = PcdAnticoll(SN); //防冲撞
  20. //Send_ZigbeeData_To_Fifo(SN,4); // wt 2019.10.18
  21. if(status == MI_OK)
  22. {
  23. status=MI_ERR;
  24. LED2 = 1;
  25. status =PcdSelect(SN); //选定此卡
  26. if(status == MI_OK) //选定成功
  27. {
  28. status=MI_ERR;
  29. LED3 = 1;
  30. MP_SPK = 1;
  31. status =PcdAuthState(PICC_AUTHENT1A,0x03,KEY,SN); //验证密钥
  32. if(status == MI_OK)
  33. {
  34. status = MI_ERR;
  35. status = PcdWrite(s,TXRFID); //写卡
  36. if(status == MI_OK)
  37. {
  38. status = MI_ERR;
  39. }
  40. }
  41. }
  42. }
  43. }
  44. }

上面的代码仔细看可以发现和2.完成RFID卡的写函数代码,中的代码基本一致,也就是简单修改了几个参数。上面函数的功能是:将扇区0,控制块密钥修改0x01,0xB2,0xC3,0xD4,0xE5,0xF6,原来的密钥是0xff,0xff,0xff,0xff,0xff,0xff

当修改完成后,他的密钥就成了0x01,0xB2,0xC3,0xD4,0xE5,0xF6。

uint8_t TXRFID[16] = {0x01,0xB2,0xC3,0xD4,0xE5,0xF6,0xFF,0x07,0x80,0x69,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};    

现在假如需要修改扇区1的A密钥,之前扇区A的密钥为0xff,0xff,0xff,0xff,0xff,0xff,修改为:0x01,0xB2,0xC3,0xD4,0xE5,0xF6

所以需要修改成的地方有:

  修改控制块地址为0X07,这个地址就是扇区1,控制块地址

这边的控制块地址改成0X07

这个数组为:TXRFID[16] = {0x01,0xB2,0xC3,0xD4,0xE5,0xF6,0xFF,0x07,0x80,0x69,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; 

 

执行成功后,扇区1的密钥A的密码就被修改成功了。

 

这样就完成了数据的读取,和密钥的修改

后期对卡的扣款 充值操作就更容易一点。

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/985045
推荐阅读
相关标签
  

闽ICP备14008679号