☰
PSoC与RC522实现RFID-UART读卡器:从SPI时序到M1卡UID上报
2026/10/19 9:13:57 网站建设 项目流程

简介:基于PSoC的RFID-UART读写项目资料包,是一套面向嵌入式开发者、电子工程学生及物联网入门者的完整工程包,解决基于可编程片上系统构建RFID读写器并实现UART串行通信的问题。资料以PSoC为主控,通过配置内部UART模块完成与外部主机的数据交换,覆盖RFID标签读取、编码传输、指令接收等核心流程,适用于库存管理、物流追踪、门禁控制等典型物联网场景的参考与二次开发。资源共271个文件,压缩包2.4MB,主要包含C/H源码、A51汇编启动文件、HEX固件、LIB静态库以及cyprj、cydwr、cysch等工程与原理图文件,从固件代码到硬件设计一应俱全,可直接导入PSoC Creator环境查看和编译。已有203人学习使用,包内项目结构完整、模块划分清晰,能帮助使用者快速掌握PSoC内部资源调配、RFID工作原理、UART波特率及数据帧配置、主机端通信协议设计等关键技能,是一份适合边学边做的实战参考资料。

1. 一个读卡器工程拆开之后:PSoC 与 RFID-UART 的完整落地链路

当你想给工位机加一张刷卡的功能,搜到的资料多半停在“RC522 模块接线”这一步。我拿到这个工程时的第一反应是:终于有人把 PSoC 上的 RFID-UART 读写做成了能编译、能烧录、能直接改的完整工程,而不是又一张原理图。

这个工程解决的实际问题是:M1 卡的 UID 从 RC522 的天线读出来,经过 PSoC 的 SPI 外设进入寄存器,再打包成自定义帧,从 UART 串口发出去。它适合正在做门禁、工具借还、设备盘点这类读卡上报场景的人,也适合想弄明白 PSoC 的 SPI 和 UART 是怎么串起来的新手。

接下来按硬件链路、工程结构、核心代码、踩坑记录的顺序往下拆,最后给三个我能想到的改造方向。看完你就能把板子跑起来,跑起来之后也知道从哪里下手改。

2. 硬件链路与选型:RFID 卡号到串口的每一段

2.1 一条卡号要经过的完整链路

先别急着看代码。把整条链路从物理层到应用层过一遍,后面读代码的时候就不会迷路。

第一段是射频部分:M1 卡靠近天线后,通过 13.56MHz 电磁场耦合获得能量,RC522 内部的模拟前端负责解调、编码和校验。第二段是数字部分:RC522 把卡号相关的数据放进自己的 FIFO 和寄存器,等待主机来取。第三段是传输部分:PSoC 的 SPI_Master 组件以 8 位模式访问 RC522 的寄存器,一个字节一个字节地把 FIFO 里的内容读出来。第四段是应用部分:PSoC 的主循环里跑寻卡、防碰撞、认证、读块这些流程,把 UID 整理成一个 4 字节数组。最后一段才是输出:UART 把自定义帧发出去,上位机按帧解析。

这里有个容易忽略的分层:PSoC 读到的其实是 RC522 的寄存器状态,而不是直接“看到”卡片的数据。所以任何一次读卡失败,都得先确认是射频层没响应,还是 SPI 层读回来的是无效值,还是 UART 层把数据传丢了。排查顺序永远从物理层往上走。

这个工程把链路简化成了很标准的五层结构,我配置完 PSoC 的外设之后,剩下的工作基本就是写中间三层的代码。

2.2 为什么选 PSoC 和 RC522 的组合

先说 RC522。它是一颗 13.56MHz 的非接触读写芯片,支持 ISO14443A 协议的 M1 卡。它和主控之间可以用 SPI、I2C、UART 三种方式通信,这个工程用的是 SPI,原因很简单:速率够、时序直白、网上成熟的参考代码最多。

再说 PSoC。这块芯片和普通 MCU 最大的区别在于外设是“可重构”的:UART、SPI、定时器这些数字外设,不是固定焊死在某个引脚上的,而是在图形化配置工具里拖出来、连好线、再映射到任意 GPIO。这带来一个实际好处——布线的时候看到哪个引脚顺眼就用哪个,不会因为 UART_TX 恰好被某个功能占用而被迫改板子。

更要紧的是,PSoC 的外设之间可以在内部连接。UART 的 TX 可以接到一个数字输出引脚,这个引脚在原理图上看起来就是一个“引脚”组件,真正占用的是一块内部数字逻辑。相比用 GPIO 模拟 SPI 时序的做法,PSoC 的 SPI_Master 组件发完一个字节后,硬件会自动处理移位和时钟,主循环不会被位冲撞的死循环拖住。这也是我推荐这套组合的原因:RC522 负责射频域的脏活累活,PSoC 负责协议处理和串口输出,两边都不需要软件去模拟时序。

2.3 引脚分配与供电细节

打开工程的引脚约束文件,能看到这张接线表,不同版本具体引脚可能不完全一样,但映射关系是一致的:

PSoC 引脚RC522 丝印方向说明
P0[0]MOSI输出SPI 主机数据输出
P0[1]MISO输入从机数据回读
P0[2]SCK输出SPI 时钟
P0[4]CS / NSS输出片选,低电平有效
P0[5]RST输出复位
P0[6]IRQ输入卡事件中断,本工程可不接
VCCVCC电源模块供电 3.3V
GNDGND电源共地

这里有一个容易翻车的点:PSoC 的 IO 是 3.3V 电平,RC522 模块务必选 3.3V 供电的版本,不要把 5V 模块直接怼上去。选 CS 引脚时,要选默认输出高电平的引脚,避免上电瞬间片选误触发。RST 必须由 PSoC 控制而不是直接拉死,否则上电时序不干净,后面的第 5 章会专门讲这个问题。

模块的天线线圈外围已经配好匹配电容,正常连上 3.3V 就能工作。如果发现读卡距离很近,先不要怀疑模块坏了,多半是天线驱动寄存器配置的问题,我在 4.2 会给出具体寄存器值。

2.4 为什么不直接用串口读卡模块

市面上有一种集成读卡头,主控只需要发一串指令就能拿到卡号,比 RC522 方案少写一大截代码。那这个工程为什么还要从 RC522 裸芯片开始做?核心原因是协议可控性。

集成读卡头的协议通常是厂家定死的,帧格式、轮询周期、指令集都改不了。你在门禁场景里可能只需要卡号,但到了“刷卡 + 写卡号到扇区 + 上报剩余次数”这种场景,厂家模块就做不到了。而这个工程用的是芯片级方案,RC522 的每个寄存器都暴露在 SPI 上,寻卡、防碰撞、选卡、认证、读写块,每一步都能自己控制。

另外,从成本角度看,RC522 芯片方案比集成模块便宜不少。对批量出设备的项目来说,省下的钱够改善天线匹配和外壳了。还有一点是调试效率:集成模块出问题就是个黑匣子,只能来回发指令猜;RC522 方案则可以用逻辑分析仪直接抓 SPI 波形,确认每个寄存器命令的返回值,故障定位快很多。做嵌入式开发的人应该都懂,能抓到波形的问题都不是问题。

2.5 上电时序与复位控制的设计思路

PSoC 的 GPIO 外设比 RC522 的电源稳定早得多,这是很多读卡器上电不稳定的根源。这个工程的做法是把 RST 脚挂在 PSoC 的普通 GPIO 上,然后在初始化函数里手动拉低、拉高,给 RC522 一个干净的复位沿。

验证这个时序是否可靠的方法,是用示波器同时测 RC522 的 VCC 和 RST 两个点:RST 的上升沿至少要滞后 VCC 稳定 10ms,太早了芯片可能还在内部复位,太晚了又会拖慢启动速度。我一般会在初始化里先拉低 RST,然后延时 10ms 再释放,实测这个窗口对 RC522 来说很宽容。如果你自己画的板子把 RST 直接接在 VCC 上,那么每次上电能不能正常工作,基本看运气。

3. 工程搭建与资源配置:从新建 PSoC 工程到进入主循环

3.1 工程文件结构与职责划分

拿到工程后先看目录结构,PSoC Creator 的工程和普通单片机工程不太一样,它带一套自动生成的驱动代码:

RfidUart.cydsn/ main.c // 主循环和业务逻辑 MFRC522.c / MFRC522.h // RC522 驱动封装 TopDesign.cysch // 原理图设计,拖组件、连线都在这里 RfidUart.cydwr // 引脚分配与电气配置 Generated_Source/ // PSoC 自动生成的外设驱动,不要手改

main.c 里只做三件事:启动外设、轮询刷卡、发送帧。MFRC522.c 是重点,它把 RC522 的寄存器操作全部封装成了函数,main.c 不需要关心 SPI 的底层细节。TopDesign.cysch 是 PSoC 的特色,UART、SPI、时钟这些外设组件在这个原理图里以图形方式摆放和连线。Generated_Source 目录是编译前由工具生成的,里面的代码不应该手改,因为每次改动 TopDesign 或引脚分配,它都会被重新生成覆盖。

如果你要做二次开发,大部分改动集中在 main.c 和 MFRC522.c,只在需要新增外设时才动 TopDesign。

3.2 TopDesign 里的三个关键组件

打开 TopDesign.cysch,能看到工程里其实只放了三个组件,但每个的配置都影响最终能不能跑通。

第一个是 UART 组件,配置为 9600 波特率、8 数据位、无校验、1 停止位,TX 映射到 P1[0],RX 映射到 P1[1]。9600 在调试阶段是比较稳的选择,PSoC 内部时钟即使有点误差也不容易乱码。如果后面要高速传输,再改成 115200 并配合外部晶振就行。

第二个是 SPI_Master 组件,配置为 1Mbps、8 位数据、MSB first、SPI Mode 0,也就是 CPOL=0、CPHA=0。RC522 的数据手册推荐的就是这个模式,很多网上示例用的是 Mode 1,读回来的数据就不对,这个坑在第 5 章会展开。这里有个小细节:SPI 的片选信号不要用 SPI_Master 组件自带的 SS 引脚,而是用普通 GPIO 手动控制,这样读卡流程里可以随时拉高拉低,不跟组件的状态机绑定。

第三个是 Clock 组件,作为 SPI 和 UART 的时钟源头。PSoC 的时钟树比较灵活,UART 波特率靠时钟分频出来,所以时钟源选什么、分频系数是多少,直接影响串口准不准。我的习惯是把时钟树里的一个 Clock 组件设为 1MHz 给 SPI 用,UART 组件内部自己再做分频,这样两个外设互不干扰。

配置完成后,打开 .cydwr 文件,在 Pins 页签里把每个组件端口映射到具体引脚,保存后重新编译即可。这里唯一的建议是:引脚映射尽量让 SPI 的四根线集中在相邻引脚,方便布线,也方便逻辑分析仪夹探头。

3.3 初始化顺序和主循环骨架

外设配置好之后,main.c 的骨架是这样的:

int main(void) { CyGlobalIntEnable; UART_Start(); SPI_Master_Start(); MFRC522_Init(); // RC522 复位 + 配置寄存器 + 开天线 UART_UartPutString("RFID Reader Ready\r\n"); for (;;) { uint8_t uid[4] = {0}; if (ReadCardUid(uid) == MI_OK) { SendCardFrame(uid); // 按自定义帧格式从 UART 发出 } CyDelay(100); } }

这段代码有固定的启动顺序:先开全局中断,再启动 UART 和 SPI,最后才调用 MFRC522_Init。MFRC522_Init 里面要写 RC522 的寄存器,如果 SPI 还没 Start,写进去的全是无效值。CyDelay(100) 是主循环的轮询间隔,100ms 对刷卡场景足够,卡片在天线上停留的时间通常超过 300ms,不会漏读;间隔再短反而容易在上电瞬间产生电磁干扰。

读卡成功的判断用 ReadCardUid 的返回值,这个函数在 4.3 会详细拆。它在内部做了寻卡和防碰撞,卡离开天线时立刻返回失败,主循环就继续空转。

3.4 编译、烧录和运行观察

PSoC Creator 里直接点编译,第一次编译会花比较长时间,因为要生成整套外设驱动代码。如果引脚配置有冲突,编译会直接报“Pin assignment conflict”,到 .cydwr 里改掉冲突引脚就行。

烧录用 SWD 接口,接 SWDIO、SWDCLK、VCC、GND 四根线,上电后程序自动运行。运行观察很简单:打开串口助手,波特率设 9600,显示方式切到 Hex,刷卡后应该收到 8 个字节,比如 AA 55 01 04 6B 2D 3E 1F,前两个是帧头,第三个是命令字,中间四个是卡号,最后一个是校验和。

如果刷了几次都没输出,先用万用表确认模块供电和共地,再用逻辑分析仪看 SPI 波形——不要怀疑代码先怀疑硬件,这是我调这类板子最深刻的体会。

4. 核心模块拆解:寻卡、防碰撞、读块与 UART 帧实现

4.1 RC522 寄存器读写底层

RC522 和 PSoC 的通信全部走寄存器读写,这层是所有上层功能的地基。读一个寄存器,实际上是在 SPI 上先发地址字节,再发一个空字节把数据移回来:

uint8_t RC522_ReadReg(uint8_t reg) { uint8_t value = 0; RC522_CS_LOW; // 拉低片选 SPI_Master_WriteByte(((reg << 1) & 0x7E) | 0x80); // 地址左移 + 读标志 SPI_Master_WriteByte(0x00); // 产生时钟,同时读回 value = SPI_Master_ReadByte(); // 取回 MISO 数据 RC522_CS_HIGH; // 拉高片选 return value; }

这里有两个关键点。第一,RC522 的 SPI 地址格式是 A6..A0 七个地址位加上一个读写标志位,所以要先把寄存器地址左移一位,再按读写操作加上 0x80 或 0x00。第二,SPI 是同步协议,主机每发一个字节的同时会从 MISO 移入一个字节,所以第二次 WriteByte(0x00) 的目的不是发数据,而是产生时钟脉冲,让 RC522 把数据从 MISO 送出来。这个“写一个空字节来读数据”的套路,是 SPI 外设和 I2C 最大的不同,刚上手的人经常在这里卡住。

写寄存器就简单很多,把地址加上写标志,再紧接着发送数据字节即可。不同 PSoC 系列的 SPI 组件 API 细节略有差异,但核心都是这个思路,移植到别的型号时以组件数据手册为准。

4.2 RC522 初始化:每个寄存器为什么这么写

void MFRC522_Init(void) { RC522_RST_Write(0); CyDelayUs(2); RC522_RST_Write(1); CyDelayUs(10); RC522_WriteReg(CommandReg, 0x0F); // 软复位 CyDelayUs(30); RC522_WriteReg(TModeReg, 0x8D); // 定时器自动开启、自动重载 RC522_WriteReg(TPrescalerReg, 0x3E); // 定时器分频 RC522_WriteReg(TReloadRegH, 0x00); // 重载值高位 RC522_WriteReg(TReloadRegL, 0xB4); // 重载值低位 RC522_WriteReg(TxAskReg, 0x60); // 天线驱动电流 RC522_WriteReg(BitFramingReg, 0x07); // 帧起始位置设为第 7 位 RC522_WriteReg(TxControlReg, 0x83); // 打开天线 }

初始化做的第一件事是给 RST 一个干净的复位沿:先拉低 2us,再拉高 10us。接下来写 CommandReg,0x0F 是软复位命令,芯片会复位内部状态机,所以后面要延时 30us 等它复位完成。

TModeReg、TPrescalerReg、TReloadReg 这三组寄存器配的是 RC522 内部定时器,它负责控制寻卡和防碰撞时发射信号的窗口宽度。0x8D、0x3E、0x00B4 这几个值来自数据手册的推荐配置,直接照抄就行。TxAskReg 里的 0x60 决定天线驱动能力,配得太小读卡距离会缩到一两厘米,配得太大反而容易让卡片过载。BitFramingReg 的 0x07 表示发送帧从第 7 位开始,这是发寻卡命令前的标准准备。最后 TxControlReg 写 0x83 把天线打开,这一步不写,前面的配置全白搭。

这些值不是玄学,都是从 RC522 数据手册里摘出来的推荐配置。如果换成 PSoC 4 的其他型号,只要 RC522 周围元器件不变,这套值可以原样沿用。

4.3 读卡主流程:寻卡、防碰撞、选卡、读块

读一次卡的完整流程分为三步:寻卡、防碰撞、选卡。寻卡是问一句“附近有没有卡”,防碰撞是在多张卡同时在场时挑出其中一张并拿到 UID,选卡是告诉卡片“我就要跟你通信”。

uint8_t ReadCardUid(uint8_t *uid) { uint8_t status; uint8_t tagType[2]; RC522_WriteReg(CommandReg, PCD_IDLE); // 停止当前命令 status = RC522_Request(PICC_REQIDL, tagType); // 寻卡 if (status != MI_OK) return status; status = RC522_Anticoll(uid); // 防碰撞,拿到 4 字节 UID if (status != MI_OK) return status; RC522_ClearBitMask(CollReg, 0x80); // 清掉防碰撞标志 return MI_OK; }

RC522_Request 的实现是把寻卡命令 0x52(PICC_REQIDL)写进 FIFO,然后启动发射接收,等待卡片应答。卡片应答后,RC522_Anticoll 会往 FIFO 写入 0x93 和 0x20,触发防碰撞仲裁,最终把 4 字节 UID 按顺序放进 FIFO,函数逐个读出来再计算 BCC 校验。

防碰撞返回的 UID 是 4 字节,这是 M1 卡的固定格式。如果你要兼容某些 UID 长度为 7 字节的特殊卡,这个函数就得改成循环读取,工程只面向标准 M1 卡,所以直接按 4 字节处理。清 CollReg 标志这步容易被忽略——上次防碰撞的状态位不清掉,下一次读卡可能在错误状态下开始。

如果要读卡上的数据,比如门禁卡的用户编号存在某个块里,就要在防碰撞之后加上认证和读块两步:

uint8_t key[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; status = RC522_Auth(PICC_AUTHENT1A, 1, key, uid); if (status == MI_OK) { status = RC522_Read(1, buffer); // 读出 block 1 的 16 字节 } RC522_StopCrypto();

M1 卡的 block 0 是厂商只读区,存着厂商代码和 UID,不能改。用户数据一般写在 block 1 到 3。默认出厂的 Key A 和 Key B 全是 0xFF,如果卡的密码被改过,RC522_Auth 就会失败,返回的 status 不是 MI_OK。每次认证完一定要调 RC522_StopCrypto() 退出加密状态,否则下一张卡的时序会乱掉,这是刷第二张卡失败的经典原因。

4.4 UART 帧格式与主循环上报

卡号读出来了,怎么发给上位机?这个工程的方案是自定义一个 8 字节帧:

字节位置内容说明
frame[0]0xAA帧头 1
frame[1]0x55帧头 2
frame[2]0x01命令字,0x01 表示刷卡上报
frame[3..6]UID[0..3]卡号,4 字节
frame[7]SUM前 7 字节的异或校验和
void SendCardFrame(const uint8_t *uid) { uint8_t frame[8]; uint8_t sum = 0; frame[0] = 0xAA; frame[1] = 0x55; frame[2] = 0x01; // 命令字:刷卡上报 memcpy(&frame[3], uid, 4); // 卡号放中间 for (uint8_t i = 0; i < 7; i++) { sum ^= frame[i]; // 异或校验 } frame[7] = sum; for (uint8_t i = 0; i < 8; i++) { UART_UartPutChar(frame[i]); } }

帧头用两个字节,0xAA 0x55 在上位机那边容易做同步。命令字是为后续扩展预留的,比如改成 0x02 表示写卡完成上报。校验用异或和是因为帧短、调试期够用,正式产品建议换成 CRC16,我第 6 章会讲。

主循环里还有一个容易忽略的细节——防重复上报。如果卡片一直贴在天线上,寻卡会一直成功,不加限制的话上位机会被同样的卡号刷屏。工程里的做法是缓存上次的卡号,并记录上报时间:

uint32_t lastUid = 0; uint32_t lastTick = 0; if (ReadCardUid(uid) == MI_OK) { uint32_t now = ((uint32_t)uid[0] << 24) | ((uint32_t)uid[1] << 16) | ((uint32_t)uid[2] << 8) | uid[3]; if (now != lastUid || CyGetTickCount() - lastTick > 300) { SendCardFrame(uid); lastUid = now; lastTick = CyGetTickCount(); } }

这段逻辑的意思是:换了新的卡,立刻上报;还是同一张卡,至少间隔 300ms 才会上报一次。如果产品需求变成“卡一直放着每 5 秒上报一次心跳”,把 300 改成 5000 就行,框架不用动。

5. 常见问题排查:调 RC522 时踩过的五个坑

以下五条都是实际调板时遇到过的,按现象、原因、解决三步写好。排查时先用万用表量供电,再用逻辑分析仪抓 SPI,两个工具能解决八成问题。

5.1 读卡无反应,天线端电压异常

现象:上电后刷卡完全没反应,万用表量天线线圈两端电压只有几十毫伏。

原因:模块供电接的是 5V,而 PSoC 的 IO 是 3.3V,两边没共地,或者 RC522 一直处于复位状态,天线驱动根本没打开。

解决:把模块 VCC 统一改为 3.3V,并确认 GND 和 PSoC 共地。再用示波器测 TX1/TX2 引脚,正常读卡时会出现调制波形。如果一直没波形,检查 TxControlReg 是不是被写回了 0x00。

5.2 SPI 读回来全是 0x00 或 0xFF

现象:上位机偶尔能收到卡号,但大部分是 0x00 0x00 0x00 0x00,或者一直收 0xFF。

原因:SPI 相位配置不对。RC522 数据手册推荐的是 Mode 0,也就是 CPOL=0、CPHA=0,但很多第三方示例工程按 CPHA=1 配置,MISO 采样点落在数据位边沿上,读回来的值自然不对。

解决:用逻辑分析仪抓 SCK 和 MISO,看数据在时钟的哪个相位上稳定下来,然后把 SPI_Master 组件的 CPOL/CPHA 切到 Mode 0,保存重新编译。另外确认片选信号要覆盖整个字节传输,不要用软件按位去拉片选。

5.3 串口乱码:PSoC 的时钟误差

现象:串口助手能看到 0xAA 0x55,但后面的字节偶发错误,把波特率降到 4800 就恢复正常。

原因:PSoC 的 UART 时钟来自内部振荡器时,误差可能到正负 3%。9600 波特率下容差足够,但如果上位机那端的 USB 转串口芯片用的是便宜晶振,两边误差叠加就会临界。

解决:在时钟树里给 UART 接上 PLL 或外部晶振,而不是直接用内部振荡器。调试时先固定 9600,不要一上来就 115200,等数据稳定了再往上提。

5.4 上电偶发卡死,必须手动复位才恢复

现象:每次重新上电,第一次刷卡大概率无反应,按一下板子上的复位键之后就正常了。

原因:RC522 的 RST 脚如果悬空,上电后内部状态机处于不确定状态;或者 PSoC 上电后立即调用 MFRC522_Init,而 RC522 的电源还没稳定,寄存器写不进去。

解决:把 RST 脚接到 PSoC 引脚,初始化时先拉低再拉高,延时 10ms 后再写寄存器。main 函数里把 UART_Start、SPI_Master_Start、MFRC522_Init 的顺序固定住,不要提前初始化。

5.5 连续刷两张卡,第二张卡号丢帧

现象:前一张卡拿走马上刷第二张,上位机收到了第一张,第二张的帧整个缺失或者卡号只有一半。

原因:查询式 UART 发送期间,主循环还在轮询读卡。RC522 的防碰撞仲裁正在进行时,UART 发送 8 个字节要占用几个毫秒,这几毫秒内 RC522 已经把第二张卡的通信流程跑了一半,FIFO 被覆盖。

解决:读卡成功后先关闭天线,等 UART 发送完再重新打开天线;或者把 UART 发送放到中断里,让读卡状态机不被阻塞。简单粗暴的做法是刷卡成功后加 100ms 冷却延时。

6. 二次开发:把只读卡器升级成可写卡、可低功耗唤醒的设备

6.1 从只读卡号到读写扇区

工程现在只上报卡号,但 RC522 的能力不止于此。要写卡,先调 RC522_Auth 认证块密码,再把数据组织成 16 字节写入目标块:

uint8_t key[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; if (RC522_Auth(PICC_AUTHENT1A, 1, key, uid) == MI_OK) { RC522_Write(1, blockData); // blockData 是 16 字节数据 RC522_StopCrypto(); }

注意 block 0 是厂商只读区,不要写,从 block 1 开始写。写完后调 RC522_Read 读回来校验,养成“写后读”的习惯,能挡住大部分低级错误。

6.2 协议升级:加长度字段和 CRC16

异或校验在调试期够用,产品化建议改成:帧头 0xA5 0x5A,加 1 字节长度、1 字节命令、N 字节数据、2 字节 CRC16。把长度放在固定偏移,上位机解析时先按长度切帧,再算 CRC,丢帧和错帧都能识别。UART 接收端用中断加状态机收帧,收到完整帧置标志位,主循环再处理。

6.3 低功耗刷卡唤醒

PSoC 的休眠能力比普通 MCU 强,可以把 RC522 的 IRQ 接到 PSoC 的外部中断引脚。平时芯片进入休眠,卡片靠近时 RC522 产生 IRQ 唤醒 PSoC,读卡后再回去睡,待机电流能从毫安级降到微安级。注意休眠前要把 UART 和 SPI 停掉,唤醒后按顺序重新 Start。

从那以后,我每次接新的无线模块,都强制自己先把 SPI 波形抓出来、把时钟误差算一遍,再开始写业务代码。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询