---
title: 不调IP核，纯手写三大通信协议：这个Zynq-7020项目，把“黑盒”拆给你看
url: "https://www.fpgalearn.com/79230.html"
kind: article
id: 79230
excerpt: 你调过UART的波特率，配置过SPI的时钟极性，也给I2C设过从机地址。但如果面试官问“起始位是怎么被采样的”“ACK/NACK在硬件里怎么实现”，你能讲清楚吗…
published_at: 2026-10-05
author: 二牛学FPGA
word_count: 3796
source: "https://www.fpgalearn.com"
---

# 不调IP核，纯手写三大通信协议：这个Zynq-7020项目，把“黑盒”拆给你看

> 你调过UART的波特率，配置过SPI的时钟极性，也给I2C设过从机地址。但如果面试官问“起始位是怎么被采样的”“ACK/NACK在硬件里怎么实现”，你能讲清楚吗…

> 你调过UART的波特率，配置过SPI的时钟极性，也给I2C设过从机地址。但如果面试官问“起始位是怎么被采样的”“ACK/NACK在硬件里怎么实现”，你能讲清楚吗…

> 你调过UART的波特率，配置过SPI的时钟极性，也给I2C设过从机地址。但如果面试官问“起始位是怎么被采样的”“ACK/NACK在硬件里怎么实现”，你能讲清楚吗？
大多数FPGA工程师的通信协议经验，停留在“配置IP核”的阶段。
打开Vivado的Block Design，拖一个UART IP进去，设一下波特率，连上AXI总线，生成比特流。能用，但你不知道里面发生了什么。
GitHub上有一个项目，**用VHDL从零手写了UART、SPI、I2C三大通信协议**，在Zynq-7020上跑通，并且用一块**几十块钱的Arduino Uno**做了对端验证。
![图片](https://admin.shaonianxue.cn/wp-content/uploads/2026/10/UARTSPII2C2.jpg)
## 01 它到底做了什么？
项目的目标很明确：**不调用任何通信IP核，用纯VHDL状态机实现三大协议，并通过与Arduino Uno的实际通信验证功能正确性**。
仓库结构非常清晰，分三个目录：`Arduino/`（Arduino端的测试代码）、`VHDL/`（Zynq-7020上的VHDL源码）、`Vitis/`（ARM处理器的C代码）。这意味着你拿到的不是一堆散落的RTL文件，而是一个**完整的、可复现的工程**——FPGA端和MCU端的代码都在里面。
三大协议各自独立实现，每一个都是从状态机开始，一行一行写出来的。
## 02 UART：从波特率生成到采样时序
UART是最基础的异步串行协议，也是最容易“调通就行、深究就懵”的协议。
项目的UART实现基于**125MHz主时钟**，通过分频器生成9600Hz的采样时钟，用于接收端的**过采样和中心采样**。接收端从`rx`引脚接收串行数据，转换成8位并行输出到LED显示；发送端在按键触发后，发送ASCII码‘A’（01000001）。
**核心模块拆解：**
**时钟分频器（Clk_div.vhd）** ——把125MHz主时钟分频到9600Hz。分频比的计算公式是：`分频数 = 主时钟频率 / (16 × 波特率)`。在100MHz时钟下跑9600波特率，分频数是651。为什么乘16？因为接收端需要**16倍过采样**——在每个数据位的中心位置采样，而不是在位边缘。这样可以有效抵抗时钟抖动和噪声。
**UART接收器（UART_rx.vhd）** ——一个有限状态机，从IDLE状态开始，检测到起始位（低电平）后进入数据接收状态，在每个数据位的中心采样，接收完8位数据后检查停止位。
**UART发送器（UART_tx.vhd）** ——同样是一个状态机，从IDLE开始，依次发送起始位、8位数据（LSB先发）、停止位。
**边沿检测模块（Edge_detection.vhd）** ——用于按键消抖，检测按键的上升沿，避免一次按键触发多次发送。
![图片](https://admin.shaonianxue.cn/wp-content/uploads/2026/10/UARTSPII2C3.jpg)
## 03 SPI：时钟极性与相位的配置逻辑
SPI是同步串行协议，比UART多了一个时钟线。但也正因为有时钟线，SPI的**时钟极性（CPOL）和时钟相位（CPHA）** 有了四种组合模式，这是最容易让初学者困惑的地方。
项目的SPI实现在VHDL中从零构建了主机控制器，包含**时钟生成、片选控制和数据移位**三个核心部分。SPI的时钟由FPGA内部生成，通过分频得到合适的SCL频率。数据在MOSI上逐位输出，在MISO上逐位采样。
**关键设计点：**
SPI主机需要精确控制**数据建立时间和保持时间**。项目通过状态机在SCL的上升沿或下降沿（取决于CPHA配置）采样MISO，同时更新MOSI。这种“边沿采样、边沿更新”的机制，确保了数据在传输过程中不会发生竞争冒险。
## 04 I2C：开漏输出与ACK/NACK的硬件实现
I2C是三大协议中最复杂的，因为它只有两根线（SDA和SCL），而且SDA是**双向开漏**信号。
开漏意味着：**你不能主动把SDA拉高，只能把它拉低或释放（高阻态）** 。高电平依靠外部上拉电阻维持。这在VHDL中需要用到`std_logic`的‘Z’状态（高阻态）。
项目的I2C实现包含一个**集中式有限状态机**，状态包括：IDLE、START、READ、WRITE、ACK、STOP。
**ACK/NACK的硬件逻辑：** 主机发送完8位数据后，释放SDA线（设为‘Z’），在第9个SCL时钟周期采样SDA。如果从机拉低了SDA，表示ACK；如果SDA保持高电平，表示NACK。这个逻辑在状态机中由“ACK采样状态”实现。
**时钟同步与仲裁：** I2C支持多主设备，当两个主机同时发起传输时，需要通过**时钟同步和仲裁**决定谁先占用总线。虽然入门项目通常只实现单主模式，但理解这个机制对读懂I2C协议至关重要。
![图片](https://admin.shaonianxue.cn/wp-content/uploads/2026/10/UARTSPII2C4.jpg)
## 05 为什么用Arduino做对端测试？
这是这个项目最聪明的地方。
通信协议的验证通常需要**示波器或协议分析仪**——一台入门级示波器也要几千块，协议分析仪更贵。这个项目用一块**几十块钱的Arduino Uno**作为对端设备，通过串口打印或LED指示来验证通信是否成功。
**Arduino端的代码在`Arduino/`目录中**，实现了与Zynq-7020的UART、SPI和I2C通信。你不需要任何专业仪器，只需要一根杜邦线把FPGA和Arduino连起来，就能验证你的协议实现是否正确。
这种方法还有一个额外的好处：**你同时在学两种平台的通信实现**。Arduino的Wire库（I2C）和SPI库是软件实现，而你的FPGA是硬件实现。对比两者的差异，能让你更深入地理解协议本身。
## 06 学习路径：从UART开始，逐步进阶
**第一步：UART。** 从时钟分频器和接收器开始。先让接收器能正确解析Arduino发来的数据，并显示在LED上。然后实现发送器，用按键触发发送‘A’到Arduino。**这一步你会学到：波特率计算、16倍过采样、状态机设计、边沿检测。**
**第二步：SPI。** 实现SPI主机模式，配置CPOL和CPHA。让Zynq作为主机，Arduino作为从机。**这一步你会学到：同步时钟生成、数据移位、片选控制、时序约束。**
**第三步：I2C。** 实现I2C主机控制器，处理START/STOP条件、7位地址、ACK/NACK。**这一步你会学到：开漏输出、三态逻辑、状态机分层设计。**
**第四步：上板验证。** 把三个协议分别综合到Zynq-7020的PL端，用Arduino做对端测试。**这一步你会学到：引脚约束、时序收敛、板级调试。**
## 07 简历怎么写？面试能讲什么？
**简历写法示例：**
> “基于Zynq-7020 FPGA，用VHDL从零实现了UART、SPI、I2C三大通信协议的硬件控制器。通过与Arduino Uno的实际通信验证了协议时序和数据帧格式的正确性。深入理解了16倍过采样、CPOL/CPHA配置、开漏输出与ACK/NACK机制等协议底层细节。”
**面试能讲什么（选一个方向，能讲20分钟）：**
**方向A：UART的采样时序。** 为什么要用16倍过采样而不是1倍？采样点为什么选在数据位的中心？波特率误差容限怎么计算？
**方向B：SPI的四种模式。** CPOL=0和CPOL=1有什么区别？CPHA=0和CPHA=1分别在哪个边沿采样？如果主从设备的模式不匹配，会出现什么现象？
**方向C：I2C的仲裁与时钟同步。** 开漏输出为什么需要上拉电阻？两个主机同时拉低SDA时，怎么判断谁赢了仲裁？时钟同步是怎么实现的？
![图片](https://admin.shaonianxue.cn/wp-content/uploads/2026/10/UARTSPII2C1.jpg)
这个项目不是一个“跑通就行”的Demo。它的价值在于：**它把通信协议从“黑盒”变成了“白盒”**。
你不再只是调一个IP核、设几个参数。你从状态机的第一个状态开始，一行一行地写，一个周期一个周期地调。当Arduino收到你发送的字符，当你看到LED正确显示接收到的数据——**你对协议的理解，就不再是“我知道怎么配置”，而是“我知道它为什么能工作”**。
项目地址：`github.com/CosminGorun/UART-SPI-I2C-Communication-Protocols-VHDL-Zynq_7020`
**关于成电国芯**
成电国芯FPGA课程已升级通信协议硬件实现方向，覆盖UART/SPI/I2C状态机设计、时序分析与约束、板级调试等企业级实战内容。从协议原理到上板验证，每一步都有导师带练。想系统掌握FPGA通信协议开发能力，欢迎联系我们了解课程详情。
