基于FPGA的电压表与串口通信系统设计

一、系统概述

本设计基于FPGA(现场可编程门阵列) 实现高精度电压测量串口数据通信功能,核心功能包括:

  • 电压采集:通过ADC0809模数转换器将模拟电压信号转换为数字信号;
  • 数据处理:对ADC数据进行中值校准、二进制转BCD码,提高测量精度;
  • 显示驱动:通过数码管实时显示电压值;
  • 串口通信:将测量数据通过UART协议发送至PC端,支持远程监控。

系统采用模块化设计 ,分为ADC控制模块数据处理模块显示模块串口通信模块 ,具备高精度(±0.02V)低功耗易扩展 特点,适用于实验室电压监测工业设备电压采集等场景。

二、系统架构与硬件设计

1. 系统架构

IN0-IN7
8位数据总线
控制信号
BCD码
UART数据
TXD
时钟
供电
模拟电压输入
ADC0809
FPGA主控 Verilog
数码管显示模块
串口通信模块
PC端 串口调试助手
50MHz晶振
电源模块 5V
B,C,D,E

2. 核心硬件选型

模块 型号/参数 功能
FPGA主控 Altera Cyclone IV EP4CE115F29C7 逻辑控制、数据处理、串口通信
ADC转换器 ADC0809(8位,8通道,100μs转换时间) 模拟电压→数字信号(0-5V输入)
数码管 4位共阳数码管(动态扫描) 显示电压值(格式:XX.XX V)
串口芯片 MAX232(RS232电平转换) FPGA TTL→PC RS232电平
电源 5V/2A适配器+AMS1117-3.3V 系统供电(FPGA/ADC/数码管3.3V)

3. 关键电路设计

(1)ADC0809接口电路
  • 通道选择:通过FPGA的3位地址线(ADDR0-ADDR2)选择ADC0809的8个模拟输入通道(IN0-IN7),本设计使用IN0通道;
  • 控制信号ALE(地址锁存使能,高有效)、START(转换启动,高有效)、EOC(转换结束,低有效)、OE(输出使能,高有效);
  • 数据总线:ADC0809的8位数据总线(D0-D7)直接连接FPGA的GPIO引脚,传输转换后的数字信号。
(2)串口通信电路
  • 电平转换:FPGA的UART_TX(TTL电平)经MAX232转换为RS232电平,连接PC的串口(DB9接口);
  • 波特率:采用115200bps(常用串口波特率),通过FPGA的50MHz晶振分频产生。

三、软件设计(Verilog HDL实现)

1. 开发环境

  • 工具:Quartus Prime 18.1(综合、布局布线)、ModelSim(仿真)、SignalTap II(在线调试);
  • 语言:Verilog HDL(模块化设计,支持参数化);
  • 外设驱动:ADC0809控制、数码管动态扫描、UART串口通信。

2. 核心模块划分

模块 功能 关键信号
adc0809_ctrl ADC0809控制(通道选择、启动转换、读取数据) clk(50MHz)、rst_n(复位)、adc_data(8位数据)、eoc(转换结束)
data_process 数据处理(中值校准、二进制转BCD码) adc_data(输入)、bcd_data(输出,16位BCD)
seg_display 数码管动态扫描显示 bcd_data(输入)、seg(段选)、sel(位选)
uart_tx UART串口发送(115200bps,8-N-1格式) clk(50MHz)、rst_n(复位)、tx_data(8位数据)、tx_start(发送使能)
top 顶层模块,连接各子模块,协调整体逻辑 时钟clk、复位rst_n、外设接口信号

3. 关键代码实现

(1)ADC0809控制模块(adc0809_ctrl.v

功能 :通过状态机控制ADC0809的转换过程,包括地址锁存启动转换等待结束读取数据

v 复制代码
module adc0809_ctrl(
    input clk,          // 50MHz时钟
    input rst_n,        // 复位(低有效)
    input eoc,          // ADC转换结束信号(低有效)
    output reg [2:0] addr,  // 通道选择地址(0-7)
    output reg ale,     // 地址锁存使能(高有效)
    output reg start,    // 转换启动信号(高有效)
    output reg oe,      // 输出使能信号(高有效)
    input [7:0] adc_data,  // ADC数据总线
    output reg [7:0] data_out,  // 处理后的ADC数据
    output reg data_valid  // 数据有效标志(高有效)
);

// 状态定义
typedef enum {IDLE, LATCH_ADDR, START_CONV, WAIT_EOC, READ_DATA} state_t;
state_t state;

// 状态机逻辑
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        state <= IDLE;
        addr <= 3'd0;
        ale <= 1'b0;
        start <= 1'b0;
        oe <= 1'b0;
        data_out <= 8'd0;
        data_valid <= 1'b0;
    end else begin
        case (state)
            IDLE: begin
                ale <= 1'b1;  // 锁存地址
                addr <= 3'd0;  // 选择IN0通道
                state <= LATCH_ADDR;
            end
            LATCH_ADDR: begin
                ale <= 1'b0;
                start <= 1'b1;  // 启动转换
                state <= START_CONV;
            end
            START_CONV: begin
                start <= 1'b0;
                if (!eoc) begin  // 等待转换结束(EOC变低)
                    state <= WAIT_EOC;
                end
            end
            WAIT_EOC: begin
                if (eoc) begin  // 转换结束(EOC变高)
                    oe <= 1'b1;  // 使能输出
                    state <= READ_DATA;
                end
            end
            READ_DATA: begin
                data_out <= adc_data;  // 读取ADC数据
                data_valid <= 1'b1;  // 标记数据有效
                oe <= 1'b0;
                state <= IDLE;  // 回到空闲状态
            end
            default: state <= IDLE;
        endcase
    end
end
endmodule
(2)数据处理模块(data_process.v

功能 :对ADC数据进行中值校准 (消除零点漂移),并将8位二进制数据转换为BCD码(便于数码管显示)。

v 复制代码
module data_process(
    input clk,          // 50MHz时钟
    input rst_n,        // 复位(低有效)
    input [7:0] adc_data,  // ADC原始数据
    input data_valid,  // 数据有效标志
    output reg [15:0] bcd_data,  // BCD码输出(格式:XX.XX)
    output reg bcd_valid  // BCD数据有效标志
);

// 中值校准变量
reg [7:0] median;  // 中值(上电时采集100次取平均)
reg [15:0] sum;   // 累加器
reg [6:0] cnt;    // 计数器

// 二进制转BCD码(移位法)
function [15:0] bin2bcd(input [7:0] bin);
    reg [15:0] bcd;
    integer i;
    begin
        bcd = 16'd0;
        for (i = 0; i < 8; i = i + 1) begin
            if (bcd[3:0] > 4'd4) bcd[3:0] = bcd[3:0] + 4'd3;
            if (bcd[7:4] > 4'd4) bcd[7:4] = bcd[7:4] + 4'd3;
            if (bcd[11:8] > 4'd4) bcd[11:8] = bcd[11:8] + 4'd3;
            bcd = bcd << 1;
            bcd[0] = bin[7 - i];
        end
        bin2bcd = bcd;
    end
endfunction

// 中值校准逻辑
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        sum <= 16'd0;
        cnt <= 7'd0;
        median <= 8'd0;
    end else if (cnt < 7'd100) begin  // 采集100次数据
        sum <= sum + adc_data;
        cnt <= cnt + 1'd1;
        if (cnt == 7'd99) begin
            median <= sum / 100;  // 计算中值
        end
    end
end

// 数据处理逻辑
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        bcd_data <= 16'd0;
        bcd_valid <= 1'b0;
    end else if (data_valid) begin
        // 中值校准(减去中值,消除零点漂移)
        reg [7:0] calibrated_data = adc_data - median;
        // 二进制转BCD码(格式:XX.XX)
        bcd_data <= bin2bcd(calibrated_data);
        bcd_valid <= 1'b1;
    end else begin
        bcd_valid <= 1'b0;
    end
end
endmodule
(3)串口发送模块(uart_tx.v

功能 :将BCD码数据通过UART协议发送至PC端,支持115200bps8-N-1格式(8位数据、无校验、1位停止位)。

v 复制代码
module uart_tx(
    input clk,          // 50MHz时钟
    input rst_n,        // 复位(低有效)
    input [7:0] tx_data,  // 待发送数据(BCD码)
    input tx_start,    // 发送使能(高有效)
    output reg txd,     // UART发送引脚(TTL电平)
    output reg tx_busy  // 发送忙标志(高有效)
);

// 波特率参数(115200bps)
localparam BAUD_RATE = 115200;
localparam CLK_FREQ = 50_000_000;
localparam BAUD_CNT = CLK_FREQ / BAUD_RATE;  // 50M / 115200 ≈ 434
localparam HALF_BAUD_CNT = BAUD_CNT / 2;    // 217(采样中点)

// 状态定义
typedef enum {IDLE, START_BIT, DATA_BITS, STOP_BIT} state_t;
state_t state;

// 内部变量
reg [15:0] baud_cnt;  // 波特率计数器
reg [3:0] bit_cnt;   // 数据位计数器(0-7)
reg [7:0] tx_reg;    // 发送数据寄存器

// 状态机逻辑
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        state <= IDLE;
        txd <= 1'b1;  // 空闲状态为高电平
        tx_busy <= 1'b0;
        baud_cnt <= 16'd0;
        bit_cnt <= 4'd0;
        tx_reg <= 8'd0;
    end else begin
        case (state)
            IDLE: begin
                txd <= 1'b1;
                tx_busy <= 1'b0;
                if (tx_start) begin  // 检测到发送使能
                    tx_reg <= tx_data;  // 加载发送数据
                    state <= START_BIT;
                    tx_busy <= 1'b1;
                end
            end
            START_BIT: begin
                txd <= 1'b0;  // 发送起始位(低电平)
                if (baud_cnt < BAUD_CNT - 1) begin
                    baud_cnt <= baud_cnt + 1'd1;
                end else begin
                    baud_cnt <= 16'd0;
                    state <= DATA_BITS;
                end
            end
            DATA_BITS: begin
                txd <= tx_reg[bit_cnt];  // 发送数据位(LSB先发)
                if (baud_cnt < BAUD_CNT - 1) begin
                    baud_cnt <= baud_cnt + 1'd1;
                end else begin
                    baud_cnt <= 16'd0;
                    if (bit_cnt < 4'd7) begin
                        bit_cnt <= bit_cnt + 1'd1;
                    end else begin
                        bit_cnt <= 4'd0;
                        state <= STOP_BIT;
                    end
                end
            end
            STOP_BIT: begin
                txd <= 1'b1;  // 发送停止位(高电平)
                if (baud_cnt < BAUD_CNT - 1) begin
                    baud_cnt <= baud_cnt + 1'd1;
                end else begin
                    baud_cnt <= 16'd0;
                    state <= IDLE;
                end
            end
            default: state <= IDLE;
        endcase
    end
end
endmodule

参考代码 基于FPGA的电压表与串口通信 www.youwenfan.com/contentcss/161143.html

四、系统测试与优化

1. 功能测试

测试项 方法 预期结果
电压采集 输入0-5V模拟电压(如1.23V) ADC数据输出对应数字量(如0x7B)
数据处理 中值校准后,转换BCD码 BCD数据输出(如0x1234,对应1.23V)
数码管显示 输入1.23V,观察数码管 显示"1.23"
串口通信 发送数据至PC,用串口调试助手接收 接收数据"1.23V"(或BCD码)

2. 优化方向

  • 精度提升 :采用12位ADC(如ADC121S101),提高电压分辨率(0.0012V);
  • 低功耗:空闲时关闭数码管扫描、降低FPGA时钟频率(如10MHz);
  • 功能扩展 :增加多通道采集 (如8路电压输入)、数据存储(如SD卡存储历史数据);
  • 抗干扰 :在ADC输入级增加RC低通滤波(1kΩ+100nF),减少高频噪声。

五、总结

本设计基于FPGA实现了电压采集、数据处理、显示驱动、串口通信一体化功能,通过ADC0809实现模拟电压到数字信号的转换,Verilog HDL完成逻辑控制与数据处理,UART协议实现远程数据传输。系统具备高精度、低功耗、易扩展特点,可广泛应用于实验室、工业设备等场景,为电压监测提供可靠的解决方案。

相关推荐
仲南音16 小时前
Xilinx FPGA——时钟IP核MMCM、PLL
fpga开发
I'm a winner1 天前
基于Xilinx FPGA的LVDS高速串行通信系统(三)--数据训练及握手机制【文末源码】
fpga开发
upper20201 天前
coremark移植坑之-nostartfiles -nostdlib参数
学习·fpga开发·coremark移植·riscv设计
Eloudy2 天前
Vivado 纯命令行构建 FPGA 项目教程
fpga开发
Rambo.xia2 天前
AXI跨时钟域与数据一致性——CDC FIFO深度不够、写后读冒险、多Master仲裁、乱序返回,出了Bug根本查不出来
fpga开发·bug
upper20202 天前
FPGA部署卷积神经网络识别MINST图片
fpga开发·卷积神经网络·minst·minst识别·部署神经网络·神经网络识别图片
你是我的解忧王子2 天前
嵌入式 ADC采样 原始数据分析上层(平均值 波动率 正态分布 线性补偿 系统误差)
fpga开发·数据挖掘·数据分析
9527华安3 天前
FPGA纯verilog代码ISP图像处理培训教程,基于IMX214,提供工程源码+视频教程+FPGA开发板
图像处理·fpga开发·isp·imx214·mipi
千寻xun3 天前
二、实战篇-NVME SSD控制之ZYNQ实现(六)-读写NVME SSD硬盘数据
fpga开发·nvme·nvme ssd
千寻xun3 天前
二、实战篇-NVME SSD控制之ZYNQ实现(三)
fpga开发·nvme ssd·nvme协议