FPGA通信——实现串口通信(Uart)

FPGA通信——实现串口通信(Uart)

一、串口通信介绍

1.1、核心概念

并行通信 (Parallel):像高速公路,8车道同时跑8辆车。速度快,但占用引脚多,且在长距离传输时容易出现“时钟偏差(Skew)”导致数据错位。

串行通信 (Serial):像单行道,车必须一辆接一辆地排队走。引脚少,成本低,且现代高速串行技术(如PCIE, SATA)通过差分信号解决了速度问题。

我们常说的“串口”通常特指 UART (Universal Asynchronous Receiver/Transmitter,通用异步收发传输器)

1.2、逻辑层面

UART 是一种异步通信协议。

  • 异步 (Asynchronous):发送方和接收方之间没有公共的时钟线(不像 SPI 或 I2C 有 CLK 线)。
  • 约定:双方必须提前约定好相同的波特率 (Baud Rate),否则就像两个人语速不同,无法交流。

数据帧格式 (Frame Format)

FPGA 的状态机就是根据这个时序图来写的:

  1. 空闲位 (Idle):默认高电平(1)。
  2. 起始位 (Start Bit):拉低 1 个周期。告诉接收方:“注意,我要开始说话了!”(这是我们在 Verilog 里检测下降沿的原因)。
  3. 数据位 (Data Bits):通常是 8 位(1 Byte),LSB (低位) 先发
  4. 校验位 (Parity):可选(奇/偶/无)。用于简单的检错,但在工业应用中常被 CRC 取代。
  5. 停止位 (Stop Bit):拉高 1 或 2 个周期。表示一帧结束,并为空闲状态做准备。

1.3、物理层

        FPGA 产生的信号只是逻辑上的 0 和 1(TTL电平),要传输出去,需要穿上不同的“外衣”(电气标准),也就是PCB版上的芯片。

标准传输方式电平特征典型距离拓扑典型应用
TTL单端0~5V<30cm点对点芯片间通信
RS232单端±5~±12V<15m点对点老式PC,工控机
RS485差分A-B电压差<1200m多点/总线PLC、电表
RS422差分4线全双工<1200m点对多较少见,类485

注意:

  • RS-232 是负逻辑(-12V是逻辑1),但 MAX3232 芯片会自动帮你翻转,你在 FPGA 里只需按正逻辑写。
  • RS-485 是抗干扰之王,因为它看的是两根线的压差,外界的共模噪声会被抵消。

1.4、FPGA 实现

在设计代码是应特别关注以下影响设计稳定性的细节:

A. 采样策略 (Sampling)

  • 做法:在波特率计数的中间点读取一次 rx_pin
  • 进阶做法 (过采样):为提高抗噪能力,例如使用 16 倍波特率的时钟去采样,在中间连续采 3 次,取众数(多数表决)。

B. 跨时钟域 (CDC)

  • 外部进来的 rx 信号是异步的,与 FPGA 的 sys_clk 无关。
  • 必须使用“打两拍”处理,否则状态机会因为亚稳态而跑飞。

C. 波特率误差

  • 公式:DIV_CNT = CLK_FREQ / BAUD_RATE
  • 如果系统时钟是 50MHz,波特率 115200:
    • 50,000,000 / 115200 ≈ 434.02
    • 取整 434,误差非常小,可以忽略。
  • 但如果时钟频率很奇葩,导致除不尽,累积误差可能会导致这一帧的最后一位采样偏移出界。一般来说,累积误差控制在 5% 以内都能正常通信。

二、Verilog代码

为了保证代码的鲁棒性,我们将设计分为三个部分:

  • UART_RX (接收模块):关键在于跨时钟域处理(打两拍)和中心对齐采样或者过采样,防止亚稳态和噪声干扰。
  • UART_TX (发送模块):相对简单,主要是状态机控制时序。
  • Top_Loopback (顶层回环):用于板级验证,接收什么就发送什么。

2.1、接收模块(uart_rx)

核心设计:加入了输入两级寄存器同步(消除亚稳态)和比特中心采样逻辑。

module uart_rx #( parameter CLK_FREQ = 50_000_000, // 系统时钟频率 parameter BAUD_RATE = 115200 // 目标波特率 )( input wire clk, input wire rst_n, input wire rx_pin, // 异步串口输入 output reg [7:0] rx_data, // 接收到的数据 output reg rx_done // 接收完成脉冲 ); // 计算分频计数最大值 localparam CNT_MAX = CLK_FREQ / BAUD_RATE; localparam CNT_MID = CNT_MAX / 2; // 采样点(波特率中心) // 状态定义 localparam IDLE = 0; localparam START = 1; localparam DATA = 2; localparam STOP = 3; reg [1:0] state; reg [31:0] clk_cnt; reg [2:0] bit_cnt; // 消除亚稳态:对异步信号 rx_pin 打两拍 reg rx_d1, rx_d2; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin rx_d1 <= 1'b1; rx_d2 <= 1'b1; end else begin rx_d1 <= rx_pin; rx_d2 <= rx_d1; end end // 下降沿检测(用于检测起始位) wire rx_negedge = rx_d2 & (~rx_d1); always @(posedge clk or negedge rst_n) begin if (!rst_n) begin state <= IDLE; clk_cnt <= 0; bit_cnt <= 0; rx_data <= 0; rx_done <= 0; end else begin rx_done <= 0; // 默认拉低 case (state) IDLE: begin if (rx_negedge) begin // 检测到起始位下降沿 state <= START; clk_cnt <= 0; end end START: begin if (clk_cnt == CNT_MID) begin // 在起始位中间再次确认电平 if (rx_d2 == 1'b0) begin clk_cnt <= 0; state <= DATA; end else begin state <= IDLE; // 误触发,或者是毛刺 end end else begin clk_cnt <= clk_cnt + 1; end end DATA: begin if (clk_cnt == CNT_MAX - 1) begin clk_cnt <= 0; rx_data[bit_cnt] <= rx_d2; // 移位接收 if (bit_cnt == 7) begin bit_cnt <= 0; state <= STOP; end else begin bit_cnt <= bit_cnt + 1; end end else begin clk_cnt <= clk_cnt + 1; end end STOP: begin if (clk_cnt == CNT_MAX - 1) begin state <= IDLE; clk_cnt <= 0; rx_done <= 1'b1; // 接收完成,产生一个脉冲 end else begin clk_cnt <= clk_cnt + 1; end end default: state <= IDLE; endcase end end endmodule

2.2、发送模块(uart_tx)

核心设计:加入了输入两级寄存器同步(消除亚稳态)和比特中心采样逻辑。

module uart_tx #( parameter CLK_FREQ = 50_000_000, parameter BAUD_RATE = 115200 )( input wire clk, input wire rst_n, input wire tx_start, // 发送使能信号 input wire [7:0] tx_data, // 待发送数据 output reg tx_pin, // 串口发送引脚 output reg tx_busy // 忙信号 ); localparam CNT_MAX = CLK_FREQ / BAUD_RATE; localparam IDLE = 0; localparam START = 1; localparam DATA = 2; localparam STOP = 3; reg [1:0] state; reg [31:0] clk_cnt; reg [2:0] bit_cnt; reg [7:0] data_reg; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin state <= IDLE; tx_pin <= 1'b1; // 空闲时为高 tx_busy <= 1'b0; clk_cnt <= 0; bit_cnt <= 0; data_reg <= 0; end else begin case (state) IDLE: begin tx_pin <= 1'b1; if (tx_start) begin state <= START; data_reg <= tx_data; tx_busy <= 1'b1; clk_cnt <= 0; end else begin tx_busy <= 1'b0; end end START: begin // 发送起始位 0 tx_pin <= 1'b0; if (clk_cnt == CNT_MAX - 1) begin clk_cnt <= 0; state <= DATA; end else begin clk_cnt <= clk_cnt + 1; end end DATA: begin // 发送8位数据(LSB first) tx_pin <= data_reg[bit_cnt]; if (clk_cnt == CNT_MAX - 1) begin clk_cnt <= 0; if (bit_cnt == 7) begin bit_cnt <= 0; state <= STOP; end else begin bit_cnt <= bit_cnt + 1; end end else begin clk_cnt <= clk_cnt + 1; end end STOP: begin // 发送停止位 1 tx_pin <= 1'b1; if (clk_cnt == CNT_MAX - 1) begin clk_cnt <= 0; state <= IDLE; tx_busy <= 1'b0; // 释放忙信号 end else begin clk_cnt <= clk_cnt + 1; end end default: state <= IDLE; endcase end end endmodule

2.3、顶层模块(uart_top)

核心设计:将RX的 rx_done 直接作为 TX的 tx_start,实现“收到什么发回什么”的回环测试功能,这是验证串口最快的方法。

module uart_loopback_top( input wire clk, // 连接到 PL 时钟 ( 50MHz) input wire rst_n, // 复位信号 input wire uart_rx, output wire uart_tx ); // 参数定义 parameter CLK_FREQ = 50_000_000; parameter BAUD_RATE = 115200; wire [7:0] rx_data; wire rx_done; wire tx_busy; // 实例化 RX uart_rx #( .CLK_FREQ(CLK_FREQ), .BAUD_RATE(BAUD_RATE) ) u_rx ( .clk(clk), .rst_n(rst_n), .rx_pin(uart_rx), .rx_data(rx_data), .rx_done(rx_done) ); // 实例化 TX // 当接收完成(rx_done)且发送不忙时,启动发送 uart_tx #( .CLK_FREQ(CLK_FREQ), .BAUD_RATE(BAUD_RATE) ) u_tx ( .clk(clk), .rst_n(rst_n), .tx_start(rx_done), .tx_data(rx_data), .tx_pin(uart_tx), .tx_busy(tx_busy) ); endmodule

2.4、引脚约束(XDC)

create_clock -period 20.000 -name sys_clk [get_ports clk] set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports clk] set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports rst_n] set_property -dict {PACKAGE_PIN T19 IOSTANDARD LVCMOS33} [get_ports uart_rx] set_property -dict {PACKAGE_PIN J15 IOSTANDARD LVCMOS33} [get_ports uart_tx] set_property SLEW SLOW [get_ports uart_tx]

对时钟信号、复位信号、uart输入输出信号进行引脚及电平绑定,同时对时钟信号进行时序约束。Slew Rate是压摆率控制输出引脚电平变化的“陡峭程度”,通常默认就是SLOW,可用可不用。

三、上板验证

板卡:正点原子启明星ZYNQ7020
软件:Vivado2019.2
串口助手:XCOM

步骤与结果验证:

  1. 参数配置:启动串口调试终端,设置波特率为 115200,8 位数据位,1 位停止位,无校验模式,并打开串口。
  2. 数据收发:在发送缓冲区输入指令“ABCD”等回环测试数据并发送。
  3. 结果判定:接收缓冲区显示的数据与发送数据一致(参见上图)。此现象表明串口数据环回功能运行正常,链路通信可靠。

Read more

一文搞懂Webhook:原理、实操与Langflow落地场景

一文搞懂Webhook:原理、实操与Langflow落地场景

Webhook作为现代系统集成的核心轻量通信机制,以“事件驱动”模式实现跨应用实时数据同步,解决了传统API轮询效率低、资源浪费的痛点。本文从定义、工作原理、核心优势、安全实践四个维度拆解Webhook,重点讲解Langflow产品中Webhook组件的实用操作,并结合企业协作、供应链管理、客户服务等实际场景,展示其如何快速实现无代码/低代码的自动化工作流,帮助开发者与业务人员高效落地跨系统联动需求。 一、什么是Webhook?核心认知拆解 简单来说,Webhook是一种基于HTTP回调的被动式通信机制,本质是“事件触发+自动推送”的桥梁——当系统A发生特定事件(如订单支付、代码提交、消息发送)时,会主动向系统B预先配置的URL(回调地址)发送请求,将事件数据实时推送至系统B,无需系统B主动查询(即轮询)。 类比生活场景:传统API轮询像你反复刷新快递物流页面查进度,而Webhook像快递员送货上门时主动打电话通知你,高效且无需额外操作。其核心价值在于“实时性”与“低资源消耗”,这也是它被广泛应用于现代应用集成的关键原因。 1.1 核心工作流程(4步闭环)

cann-recipes-train 仓库深度解读:昇腾平台下 DeepSeek-R1 与 Qwen2.5 强化学习训练优化实践

cann-recipes-train 仓库深度解读:昇腾平台下 DeepSeek-R1 与 Qwen2.5 强化学习训练优化实践

cann-recipes-train 仓库深度解读:昇腾平台下 DeepSeek-R1 与 Qwen2.5 强化学习训练优化实践 前言 自 DeepSeek-R1 发布以来,大模型的强化学习(RL)训练掀起了新一轮的技术热潮。各大厂商与开源社区纷纷投入实践,持续探索更高效的 RL 训练体系。本文将基于 cann-recipes-train 仓库,解读两个实践样例:DeepSeek-R1 的 RL 训练优化实践样例、基于 verl 框架的 Qwen2.5 强化学习实践样例 cann-recipes-train 仓库全景解析:昇腾训练优化的"实战底座" 大模型训练拼效率的阶段,CANN 直接帮我们搞定了底层异构硬件适配、资源调度这些麻烦事,不用再从零研究 GPU 和 NPU 怎么协同,现有模型代码也不用大改就能对接,训

【开题答辩过程】以《基于web的远程文件管理系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看

【开题答辩过程】以《基于web的远程文件管理系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看

个人简介 慕婉学姐精通Java、PHP、微信小程序、Python、Golang和安卓开发等语言,擅长开发大数据、深度学习、网站、小程序、安卓应用和算法项目。平时从事项目定制开发、代码讲解、答辩教学和文档编写,也掌握一些降重技巧。感谢大家的持续关注! 近期,由于许多同学在选题阶段既想创新又担心内容量,学姐将分享更多新颖的选题和开题答辩案例,希望能为学弟学妹们提供更多的灵感和选择,帮助大家设计出更具有创新性的作品 开题陈述 各位老师好,我的毕业设计题目是《基于Web的远程文件管理系统的设计与实现》。该系统旨在通过B/S架构,让用户能够随时随地通过网络浏览器访问和管理自己电脑中的文件,将个人电脑打造成私有"云盘"。主要功能模块包括用户认证模块、文件上传下载模块、文件操作模块(复制、移动、删除、重命名)、目录浏览模块以及文件搜索模块。技术栈方面,后端采用Spring Boot框架搭建,数据库使用MySQL存储用户信息和文件元数据,开发语言为Java,开发工具选用Eclipse。系统相比传统远程桌面程序,具有操作权限更小、安全性更高、使用更便捷的特点。

Kylin(麒麟)V10系统安装WebLogic 12C

Kylin(麒麟)V10系统安装WebLogic 12C

目录 前言 一、JDK环境 二、安装WebLogic 1. 下载安装包 2. 开始安装 前言 先说下服务器的情况:我的环境是国产化环境,所以和之前的X86架构有些区别之处。 CPU是华为鲲鹏(Kunpeng)ARM64(aarch64)指令集架构,所以操作系统是:Kylin Linux Advanced Server V10 (ARM64) 。 由此我们在安装其他软件的时候也要注意这一点了,需要下载安装ARM64(aarch64)指令集架构的软件了,不然会会报指令集不符的相关错误提示。 一、JDK环境 Kylin V10系统默认安装匹配的是OpenJDK。 这里我安装WebLogic 12C时使用的是Oracle JDK。当然OpenJDK应该也是可以的。 JDK要求:WebLogic 12.2.1.4 需要 JDK 8(1.8.