这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » 基础知识 » 我的NFC学习之旅(6)---Ai8051下读写M1卡中数据的实践

共2条 1/1 1 跳转至

我的NFC学习之旅(6)---Ai8051下读写M1卡中数据的实践

专家
2026-07-15 19:18:27     打赏

根据前面的学习,我们开始学习在51 系统下对M1卡的扇区块进行读写的操作处理。

读写扇区、块数据,要严格按照以下顺序操作:

1、寻卡 (Request):让RC522模块寻找附近的M1卡,获取卡片类型代码。

2、防冲突 (Anticollision):当有多张卡时,选出一张进行通信,并获得该卡的UID(唯一标识符,4字节)。

3、选卡 (Select Tag):正式选定刚才通过防冲突检测的卡片。

4、认证扇区 (Authentication):这是最关键的一步。在操作某个扇区前,必须用该扇区的密码(KeyA或KeyB)进行身份验证。比如要读取1号扇区,就需要用1号扇区的密码去认证。

5、/写操作 (Read/Write):认证成功后,才能对同一个扇区内的数据块(块0、1、2)进行读写。

在前面读取M1卡的UID的时候,1~3的操作已经被实现了,我们就在这个基础上,简单修改代码,追加读写操作。

本以为很简单的,有现成的库支持,应该很快就能写好程序、测试,结果出了问题。折腾了两天。导致出问题的点是第三步选卡的动作没有加进去。结果在认证扇区的处理中,一直出现认证失败的情况。为此又是研读Arduino下的RC522支持库源码,又是学习Arduino下读写的额处理,又是尝试按照Arduino下的RC522支持库源码修改本地51系统下的代码。直到今天晚些时候才发现,整体的处理中漏掉了PcdSelect(MLastSelectedSnr);的处理步骤,才彻底解决问题。

现有代码,与RC522的通讯使用的是软件模拟SPI方式通讯。出问题时,一度以为模拟处理中SCK的脉冲时间太短,导致数据、指令没有正确传达给RC522,为此做了好长时间的修改、调试,虽然在处理上有了一些变化,比如认证处理的返回值,从29、39、到0D、0B等发生了变化,却依旧没有从根本上解决问题。而且不同卡的表现还不一样,差点以为是卡的问题。还好,在加入选卡处理之后,所有卡都能正常被扫描到,并完成数据的读写处理。

以下是主体程序的代码(RC522的文件改动不大)。

void main() {
	unsigned char i, dat = 0;
	char status;
	unsigned long t;	
	unsigned char buff[24]={'\0'};
    
    // 初始化单片机
    sys_inti();
    
    // 打开调试信号
    LED = 1;
    
    // 初始化定时2,串口波特率发生器
    Timer2Init();
    
    // 初始化串口1
    Uart1Init();
    
    // 开总中断
    EA = 1;
    
    // 关闭调试信号
    LED = 0;
    
    // 输出测试日志
    printf("Start Test !\r\n");
    
    // 初始化液晶
    lcd_25696_init();
    
    delay_ms(10);
    
    // 测试液晶
    lcd25696_test();
	
	delay_ms(2000);
		
	// 显示开始处理的标志字符串
	clear_screen(); //清屏 
	display_string_16x16(0, 0, "Test:");
	
	PCD_Init();
	M500PcdConfigISOType( 'A' );	
	
	t = 0;			// 计时
	
	// 打印 UID
	display_string_16x16(0, 2, "ID: ");
		
    while(1) {
				// 1、寻卡,防冲突,选择卡    返回卡类型(2 bytes)
				status= PcdRequest(PICC_REQALL, &RevBuffer[2]);
			  //printf("PcdRequest 返回信息: %02X %02X  \n", RevBuffer[3], RevBuffer[2]);
			
				if(status != STATUS_OK) {
					//status= PcdHalt();
				} else {
					printf("ATQA: 0x%02X 0x%02X\n", RevBuffer[3], RevBuffer[4]);  // 0x00 0x04
					printf("卡片类型: MIFARE Classic 1K\n");					
					
					// 2、防冲突 读卡的系列号
					//status = PcdAnticoll(&RevBuffer[2]);
					status = PcdAnticoll(MLastSelectedSnr);
					if(status != STATUS_OK) {
						status= PcdHalt();			
					}
					printf("UID: %02X %02X %02X %02X\n", MLastSelectedSnr[0], MLastSelectedSnr[1], MLastSelectedSnr[2], MLastSelectedSnr[3]);
					
					t++;
					sprintf(buff, "%d", t);
					display_string_16x16(50, 0, buff);
					
					// 显示卡ID
					cardid[0] = ASCII[MLastSelectedSnr[0]/16];
					cardid[1] = ASCII[MLastSelectedSnr[0]%16];
					cardid[2] = ASCII[MLastSelectedSnr[1]/16];
					cardid[3] = ASCII[MLastSelectedSnr[1]%16];
					cardid[4] = ASCII[MLastSelectedSnr[2]/16];
					cardid[5] = ASCII[MLastSelectedSnr[2]%16];
					cardid[6] = ASCII[MLastSelectedSnr[3]/16];
					cardid[7] = ASCII[MLastSelectedSnr[3]%16];
					cardid[8] = '\0';
					display_string_16x16(0, 2, "ID:");
					display_string_16x16(30, 2, cardid);
				
				
					// 3. 选卡 - 确认卡片已选中
					status = PcdSelect(MLastSelectedSnr);
					if (status == MI_OK) {
							printf("选卡成功!\n");
					} else {
							printf("选卡失败!\n");
					}

					// 4、认证1号扇区(使用KeyA,认证尾部块地址7),PcdAuthState
					// 参数:验证模式, 块地址, 密钥, UID
					// 认证1扇区0块,物理地址的第4块
					status = PcdAuthState(PICC_AUTHENT1A, BLOCK_1_0, DefaultKey, MLastSelectedSnr);
					if (status != STATUS_OK) {
						// 认证1扇区0块失败,可能密码错误
						printf("认证 1 扇区 0 块失败,返回值=%02x\n", status);
						display_string_16x16(100, 0, "Authentication!");	
						display_string_16x16(0, 4, "                                ");
						display_string_16x16(0, 6, "                                ");
						display_string_16x16(0, 8, "                                ");
					}	else {
						printf("认证 1 区 0 块成功!\n");
						display_string_16x16(100, 0, "               ");
						// 认证成功后,读取1号扇区的块0、块1、块2
						// 注意:操作同一扇区的数据块前,只需认证一次该扇区的尾部块
						status = PcdRead(BLOCK_1_0, RevBuffer);
						if (status == MI_OK) {
								printf("读取 1 区 0 块成功!\n");
								// 成功读取块0数据,RevBuffer[0]~RevBuffer[15]即为数据
								showBlockData(0, 4, RevBuffer, 10);
							    printf("Data : %02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X \n",
							         RevBuffer[0], RevBuffer[1], RevBuffer[2], RevBuffer[3], RevBuffer[4], RevBuffer[5], RevBuffer[6], RevBuffer[7], RevBuffer[8], RevBuffer[9]
							        );							
								// 前8个数据加16后,回写
								for (i=0; i<8; i++) {
										RevBuffer[i] += 0x10;
								}
								status = PcdWrite(BLOCK_1_0, RevBuffer);
								if (status == MI_OK) {
										printf("回写 1 区 0 块成功!\n");
									  // 再读
									  status = PcdRead(BLOCK_1_0, RevBuffer);
										if (status == MI_OK) {
												printf("再次读取 1 区 0 块成功!\n");
												// 再次成功读取块0数据,RevBuffer[0]~RevBuffer[15]即为数据
												showBlockData(0, 6, RevBuffer, 10);
												printf("Update : %02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X \n",
															 RevBuffer[0], RevBuffer[1], RevBuffer[2], RevBuffer[3], RevBuffer[4], RevBuffer[5], RevBuffer[6], RevBuffer[7], RevBuffer[8], RevBuffer[9]
															);											
										}
								}						
						} else {
								printf("读取 1 区 0 块失败,返回值=%02x\n", status);
						}
	
						delay_ms(3000);	
					}
				} 
        	PcdHalt();
		delay_ms(500);	
    }
}

红色标记的部分,是开始时漏掉的代码。主要处理逻辑是读取扇区数据、修改、回写、再读,显示对比。开发板使用的STC的擎天柱开发板,烧录频率22.1184MHz。端口连接上参照以下设置:

/////////////////////////////////////////////////////////////////////

//端口定义

/////////////////////////////////////////////////////////////////////

//MFRC522

sbit     MF522_RST  =    P0^4;                   // 复位

sbit     MF522_NSS  =    P0^2;                  // 片选

sbit     MF522_SCK  =    P0^1;                  // 时钟

sbit     MF522_SI   =    P0^0;                   // 接RC522模块的MOSI

sbit     MF522_SO   =    P0^3; // 接RC522模块的MISO


 

图片1.png

图片中ID为扫描的M1卡的UID。第三行为读取到M1卡第1扇区第0块,也就是物理上的第4块的16进制数据。第四行是取到的数据的前8个加上16后回写给M1卡,在重新读取后的结果。读写是以块(16字节)的方式整体操作的。可以看到,第9、10个数据并没有被改变。

这是串口的输出日志: 

图片2.png

至此终于把51系统下M1卡的读写处理完成了。后面准备在此基础上,继续学习自动加减1的处理。





关键词: 懒猫的学习笔记     NFC    

院士
2026-07-16 10:43:21     打赏
2楼

谢谢分享,学习了。

帖子里面的照片拍得好,液晶屏里面的字符都好清楚,点赞。


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]