一、系统概述
本设计基于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端,支持115200bps 、8-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协议实现远程数据传输。系统具备高精度、低功耗、易扩展特点,可广泛应用于实验室、工业设备等场景,为电压监测提供可靠的解决方案。