51单片机连接RC522芯片并通过UART串口与上位机编写的Python脚本实现通信

一、项目介绍

本项目是我本科毕业设计的硬件部分,主要功能为使用RC522一次读取多个内嵌在餐盘中的M1卡片中的价格,然后学生刷卡或者刷手机或者穿戴设备进行支付。

涉及到的设备有:51开发板、RC522芯片、5v-3.3v降压芯片(有可能不需要)、M1卡(非接触式IC卡的一种,我用的是S50方形卡和异形卡)
请添加图片描述
请添加图片描述

二、RC522模块套件介绍

简单来说RC522能够读取或写入数据到单片机和IC卡,并且能够对值域进行增值和减值。

M1卡的结构如下图:请添加图片描述
M1卡总共有16个扇区编号0~15,每个扇区有4块,其中第四块(编号为3)为控制块,限制前3块的访问权限,每张卡有唯一的4字节的id编号。具体如何操作参考:
在这里插入图片描述
其中第1号扇区 不知怎地 被我给写坏了 现在已经不能够读写了。

三、项目代码解读

1. 管脚接线

管脚接线图
其中IRQ管脚不接。 根据自己的排线合理选择管脚,以避免冲突。

2.项目目录结构

在这里插入图片描述

3.核心代码讲解

void writePlatePrice()
{
    
    
		unsigned char status;
		while(1){
    
    
			status = PcdRequest(PICC_REQIDL, g_ucTempbuf1);//*PICC_REQALL=0x52:寻找所有符合规定卡  PICC_REQIDL=0x26:只寻找未休眠的卡
			if (status == MI_OK)
			{
    
    
				status = PcdAnticoll(g_ucTempbuf1);  					// 防冲撞,g_ucTempbuf1获得卡号
			}
			
			if (status == MI_OK)
			{
    
    
				status = PcdSelect(g_ucTempbuf1);    //选定卡
			}
			
			if (status == MI_OK) 
			{
    
    
				status = PcdAuthState(PICC_AUTHENT1A, 8, DefaultKey, g_ucTempbuf1);//打卡天线,验证密码,这里验证的块与下面读取的块一定要一致
			}
			if (status == MI_OK)   
			{
    
    
				status = PcdWrite(8, w_ucTempbuf);//在8号块写入数据
			}
			if (status == MI_OK)   
			{
    
    
				status = PcdRead(8, g_ucTempbuf2);//读取8号块的数据
			}
			if(status == MI_OK)
			{
    
    
				CALL_isr_UART();
				Buzzer_Time(500);
				PcdHalt();
				mode = readPlate_mode;   //切换模式
				P2_1 = 1; //
				break;   //
			}
	}
}

RC522的读写机制:在这里插入图片描述
python脚本获取串口数据:

# TODO 串口读取数据
# Auther wjw

import logging
import serial  # 导入串口包
import time  # 导入时间包
import threading

plate_list = ['c3cc260c', '038af109']  # 餐盘id列表
campusCard_list = ['31340380']  # 校园卡列表
subtract_list = []  # 点的菜品数据

'''
    初始化串口
'''


def InitSerial():
    ser = serial.Serial("COM3", 4800, timeout=5)  # 开启com3口,波特率4800,超时5
    ser.flushInput()  # 清空缓冲区
    return ser


'''
    16进制显示数据
'''


def HexShow(argv):
    try:
        result = ''
        hLen = len(argv)
        for i in range(hLen):
            hvol = argv[i]
            hhex = '%02x' % hvol
            result += hhex+' '
        return result
    except Exception as e:
        print("---异常---:", e)


'''
    获得卡片id
'''


def GetUID(recv):
    return '%02x' % recv[0] + '%02x' % recv[1] + '%02x' % recv[2] + '%02x' % recv[3]


'''
    包装浮点数金额
'''


def PackFloat(f):
    f = str(round(f, 2))  # 保留两位小数转成字符串
    if len(f) > 16:
        raise Exception("金额数据过长")
    f = f.zfill(16)  # 右对齐 做填充0
    return f


'''
    接受到的串口数据转浮点并加入到待扣列表
'''


def DePackFloat(f):
    tempStr = ''
    for i in range(4, len(f)):
        if f[i] == 46:
            tempStr += '.'
        else:
            tempStr += str(f[i]-48)
    if tempStr != '':
        subtract_list.append(float(tempStr))
    else:
        subtract_list.append(0)


'''
    结算模式
'''


def SettlementMode(recv):
    totalMoney = 0
    for t in subtract_list:
        totalMoney += t
    subtract_list.clear()  # 清空扣款列表
    print('成功结算,总计价格:', totalMoney)
    print('结算对象:', GetUID(recv))


'''
    读取串口数据
'''


def ReadSerialData(ser):
    while True:
        count = ser.inWaiting()  # 获取串口缓冲区数据
        if count != 0:
            recv = ser.read(count)  # 读出串口数据,数据采用16进制存储
            print("串口接受到数据:", recv)
            print("16进制ascii码存储:", HexShow(recv))  # 打印一下子
            if len(recv) == 1:
                print('模式选择')
            elif GetUID(recv) in plate_list:
                DePackFloat(recv)
                print("已读入该餐盘价格")
            elif GetUID(recv) in campusCard_list and len(recv) == 5 and recv[4] == 255:
                print("进入结算模式")
                SettlementMode(recv)
        time.sleep(0.1)  # 延时0.1秒,免得CPU出问题


def writeMoney(ser):
    while True:
        if input("请输入指令:") == 'w':
            try:
                money = float(input("请输入要设定的金额:"))
                t = PackFloat(money).encode()
                ser.write(PackFloat(money).encode())
            except:
                print("输入的金额有误")
        time.sleep(1)


if __name__ == '__main__':
    ser = InitSerial()  # 获取初始化串口对象
    threading.Thread(target=ReadSerialData, args=(ser,)).start()  # 读串口数据子线程
    threading.Thread(target=writeMoney, args=(ser,)).start()  # 写金额子线程

这里使用了两个线程,一个用于读取数据,向卡中写入数据。

四、项目遇到的坑及难点

  1. 了解到RC522只能用3.3v供电,我这个开发板上没有3.3v的引脚,最后在淘宝买了个稳压芯片解决。
  2. 中断定时器问题,才开始uart通信的代码是在网上找的,好像是晶振不同,导致中断定时器的初值不对,以及一些寄存器配置错误,导致uart通信不了,最后改改就行了。
  3. 如何存值的问题,因为我要存浮点数,但是卡片只能存16进制的,才开始想着用计算机组成原理中的IEEE754方法把浮点数存起来,然后发现太麻烦,而且我只存小数点后两位,完全没必要用IEEE754那么高的精度,最后to通过把浮点数凑成16字节(包含小数点,高低位补0,刚好一块),然后转成ascii码的16进制形式进行的存储,同样读取只需要逆着来就行。
  4. 卡片休眠问题,我想一次读取多张卡,我才开始用的方法是一张一张的读,读完一张然后令这张卡休眠(开始只寻找未休眠的卡)然后读取下一张,不知怎地,后面竟然读取不了了,我找了大概两三天的时间,问题是那个扇区给读坏了,我读取8号块就是第2号扇区就可以了。
  5. 我当时修改了代码中的函数名,后面发现怎么都调用不了了,最后发现原来.h文件中的函数声明没有修改。
  6. uart的中断处理函数中不能在调用其他执行时间长的函数,也不能咋函数中进行延时操作。

猜你喜欢

转载自blog.csdn.net/zhanghongbin159/article/details/122933624
今日推荐