FPGA之简易电压表设计
文章目录
- 前言
- 一、ADC
- 1.什么是ADC
- 2.ADC转换过程
- 3.ADC种类
- ADC主要技术指标
- 二、ADC模块设计
- 1.ADC计算
- 2.端口和寄存器设计
- 3.RTL代码
- 三、数码管设计代码
- 1.二进制数转十进制数
- 2.数码管显示代码
- 四、顶层文件设计
- 1.顶层设计代码
- 2.RTL视图
- 五、仿真测试模块
- 1.仿真测试模块代码
- 2.仿真波形图
- 六、上板验证
前言
使用FPGA开发板及板载AD模块设计一个测量范围为-5V~5V的电压表,并使用数码管显示出来
一、ADC
1.什么是ADC
模/数转换器即 A/D 转换器,或简称 ADC(Analog to Digital Conver),通常是指一个将模拟信号转变为数字信号的电子元件或电路。常见的模/数转换器将经过与标准量比较处理后的模拟量转换为以二进制数值表示的离散信号。
2.ADC转换过程
模拟信号与数字信号的转换过程一般分为四个步骤:采样、保持、量化、编码。前两个步骤在采样-保持电路中完成,后两步则在 ADC 芯片中完成。
3.ADC种类
常用的 ADC 可分为积分型、逐次逼近型、并行比较型/串并行型、Σ -Δ调制型、电容阵列逐次比较型以及压频变换型。
ADC主要技术指标
ADC 的主要技术指标包括:分辨率、转换速率、量化误差、满刻度误差、线性度。
- 分辨率指输出数字量变化一个最低有效位(LSB)所需的输入模拟电压的变化量。
- 转换速率是指完成一次从模拟转换到数字的 AD 转换所需要的时间的倒数。积分型AD 的转换时间是毫秒级属低速 AD,逐次比较型 AD 是微秒级属中速 AD,全并行/串并行型 AD 可达到纳秒级。采样时间则是另外一个概念,是指两次转换的间隔。为了保证转换的正确完成,采样速率(Sample Rate)必须小于或等于转换速率。因此有人习惯上将转换速率在数值上等同于采样速率也是可以接受的。
- 量化误差是由于 AD 的有限分辩率而引起的误差,即有限分辩率 AD 的阶梯状转移特性曲线与无限分辩率 AD(理想 AD)的转移特性曲线(直线)之间的最大偏差。通常是 1个或半个最小数字量的模拟变化量,表示为 1LSB、1/2LSB。
- 满刻度误差是满刻度输出时对应的输入信号与理想输入信号值之差。
- 线性度指实际转换器的转移函数与理想直线的最大偏移。
二、ADC模块设计
1.ADC计算
- 使用的 ADC 芯片位宽为 8 位,板卡模拟电压输入范围为-5v~+5v,即电压表测量范围,最大值和最小值压降为 10v,分辨率为 10/28。
- 使用定义中值的测量方法:在电压表上电后未接入测量电压时,取 ADC 芯片采集的最初的若干测量值,取平均,作为测量中值 data_median,与实际测量值 0V 对应。
当 ADC 芯片采集后的电压数值 ad_data 位于 0 - data_median 范围内,表示测量电压位于-5V ~ 0V 范围内,分辨率为 10/((data_median + 1) * 2),换算为电压值:Vin = - ((10 /((data_median + 1) * 2)) * (data_median -ad_data));当 ADC芯片采集后的电压数值 ad_data 位于 data_median - 255 范围内,表示测量电压位于 0V ~ 5V范围内,分辨率为 10/((255 - data_median + 1) * 2),换算为电压值:Vin = ((10 /((255 -data_median + 1) * 2)) * (ad_data - data_median))。
2.端口和寄存器设计
- clk_sample:将系统是时钟四分频,变为12.5MHz时钟给AD芯片
- median_en:中值使能信号
- cnt_median:中值数据累加计数器
- data_sum_m:1024次中值数据累加总和
- data_median:中值数据
- data_p、data_n:根据中值计算出的正向电压AD和负向电压AD的分辨率(放大2^13*1000倍)
- volt_reg:处理后的稳定数据
3.RTL代码
module dac(input wire clk,input wire rst_n,input wire [7:0]ad_data,output wire ad_clk,output wire sign,output wire [15:0]volt
);parameter CNT_DATA_MAX=11'd1024;reg [1:0]cnt_clk;reg clk_sample;reg median_en;reg [10:0]cnt_median;reg [18:0]data_sum_m;reg [7:0]data_median;reg [27:0]volt_reg;wire [27:0]data_p;wire [27:0]data_n;assign ad_clk=~clk_sample;assign sign=(ad_data<data_median)? 1'b1:1'b0;//将系统时钟四分频,变为12.5MHz时钟给ad芯片always @(posedge clk or negedge rst_n)if(!rst_n)begincnt_clk<=1'b0;clk_sample<=1'b0;endelse begincnt_clk<=cnt_clk+1'b1;if(cnt_clk==2'b1)begincnt_clk<=2'b0;clk_sample<=~clk_sample;endend//中值使能信号always @(posedge clk or negedge rst_n)if(!rst_n)median_en<=1'b0;else if(cnt_median==CNT_DATA_MAX)median_en<=1'b1;elsemedian_en<=median_en;//中值数据累加计数器always @(posedge clk or negedge rst_n)if(!rst_n)cnt_median<=1'b0;else if(!median_en)cnt_median<=cnt_median+1'b1;//1024次中值数据累加总和always @(posedge clk or negedge rst_n)if(!rst_n)data_sum_m<=1'b0;else if(cnt_median==CNT_DATA_MAX)data_sum_m<=1'b0;elsedata_sum_m<=data_sum_m+ad_data;//中值数据always @(posedge clk or negedge rst_n)if(!rst_n)data_median<=1'b0;else if(cnt_median==CNT_DATA_MAX)data_median<=data_sum_m/CNT_DATA_MAX;elsedata_median<=data_median;//根据中值计算出的正向电压AD和负向电压AD的分辨率(放大2^13*1000倍)assign data_p=(median_en==1'b1)?8192_0000/((255-data_median)*2):0;assign data_n=(median_en==1'b1)?8192_0000/((data_median+1)*2):0;//处理后的稳定数据always @(posedge clk or negedge rst_n)if(!rst_n)volt_reg<=1'b0;else if(median_en)if((ad_data>(data_median-3)) && (ad_data<(data_median+3)))volt_reg<=1'b0;else if(ad_data<data_median)volt_reg<=(data_n*(data_median-ad_data)) >> 13;else if(ad_data>data_median)volt_reg<=(data_p*(ad_data-data_median)) >> 13;elsevolt_reg<=1'b0;assign volt=volt_reg;endmodule
三、数码管设计代码
1.二进制数转十进制数
module bcd_8421(input wire clk,input wire rst_n,input wire [19:0]data,output reg [3:0]unit,output reg [3:0]ten,output reg [3:0]hun,output reg [3:0]tho,output reg [3:0]t_tho,output reg [3:0]h_hun);reg [4:0]cnt_shift;reg [43:0]data_shift;reg shift_flag;always @(posedge clk or negedge rst_n)if(!rst_n)cnt_shift<=1'b0;else if(cnt_shift==5'd21 && shift_flag)cnt_shift<=1'b0;else if(shift_flag)cnt_shift<=cnt_shift+1'b1;elsecnt_shift<=cnt_shift;always @(posedge clk or negedge rst_n)if(!rst_n)data_shift<=1'b0;else if(!cnt_shift)data_shift<={24'd0,data};else if(cnt_shift<=20 && (!shift_flag))begindata_shift[23:20]<=(data_shift[23:20]>4)? (data_shift[23:20]+2'd3):(data_shift[23:20]);data_shift[27:24]<=(data_shift[27:24]>4)? (data_shift[27:24]+2'd3):(data_shift[27:24]);data_shift[31:28]<=(data_shift[31:28]>4)? (data_shift[31:28]+2'd3):(data_shift[31:28]);data_shift[35:32]<=(data_shift[35:32]>4)? (data_shift[35:32]+2'd3):(data_shift[35:32]);data_shift[39:36]<=(data_shift[39:36]>4)? (data_shift[39:36]+2'd3):(data_shift[39:36]);data_shift[43:40]<=(data_shift[43:40]>4)? (data_shift[43:40]+2'd3):(data_shift[43:40]);endelse if(cnt_shift<=5'd20 && shift_flag)data_shift<=data_shift<<1;elsedata_shift<=data_shift;always @(posedge clk or negedge rst_n)if(!rst_n)shift_flag<=1'b0;elseshift_flag<=~shift_flag;always @(posedge clk or negedge rst_n)if(!rst_n)beginunit<=1'b0;ten<=1'b0;hun<=1'b0;tho<=1'b0;t_tho<=1'b0;h_hun<=1'b0;endelse if(cnt_shift==5'd21)beginunit<=data_shift[23:20];ten<=data_shift[27:24];hun<=data_shift[31:28];tho<=data_shift[35:32];t_tho<=data_shift[39:36];h_hun<=data_shift[43:40];endendmodule
2.数码管显示代码
module seg
#(parameter CNT_MAX=16'd49999
)
(input wire clk,input wire rst_n,input wire [5:0]point,input wire [19:0]data,input wire seg_en,input wire sign,output reg [5:0]sel,output reg [7:0]seg);wire [3:0]unit;wire [3:0]ten;wire [3:0]hun;wire [3:0]tho;wire [3:0]t_tho;wire [3:0]h_hun;bcd_8421 bcd_8421(.clk(clk),.rst_n(rst_n),.data(data),.unit(unit),.ten(ten),.hun(hun),.tho(tho),.t_tho(t_tho),.h_hun(h_hun));reg [23:0]data_reg;reg [15:0]cnt_1ms;reg flag_1ms;reg [2:0]cnt_sel;reg [5:0]sel_reg;reg [3:0]data_disp;reg dot_disp;//控制数码管显示always @(posedge clk or negedge rst_n)if(!rst_n)data_reg<=1'b0;//若显示的十万位为非零数据或需要显示小数点,六个数码管全显示else if(h_hun || point[5])data_reg<={h_hun,t_tho,tho,hun,ten,unit};//若显示的万位数为非零数据或需要显示小数点,数值显示在5个数码管上else if((t_tho || point[4]) && sign)//显示负号data_reg<={4'd10,t_tho,tho,hun,ten,unit};//定义4'd10为显示负号else if((t_tho || point[4]) && !sign)data_reg<={4'd11,t_tho,tho,hun,ten,unit};//定义4‘d11为不显示//若显示的千位数为非零数据或需要显示小数点,数值显示在4个数码管上else if((tho || point[3]) && sign)data_reg<={4'd11,4'd10,tho,hun,ten,unit};else if((tho || point[3]) && !sign)data_reg<={4'd11,4'd11,tho,hun,ten,unit};//若显示的百位数为非零数据或需要显示小数点,数值显示在3个数码管上else if((hun || point[2]) && sign)data_reg<={4'd11,4'd11,4'd10,hun,ten,unit};else if((hun || point[2]) && !sign)data_reg<={4'd11,4'd11,4'd11,hun,ten,unit};//若显示的十位数为非零数据或需要显示小数点,数值显示在2个数码管上else if((ten || point[2]) && sign)data_reg<={4'd11,4'd11,4'd11,4'd10,ten,unit};else if((ten || point[2]) && !sign)data_reg<={4'd11,4'd11,4'd11,4'd11,ten,unit};//若显示的个位数为非零数据或需要显示小数点,数值显示在1个数码管上else if((unit || point[1]) && sign)data_reg<={4'd11,4'd11,4'd11,4'd11,4'd10,unit};else data_reg<={4'd11,4'd11,4'd11,4'd11,4'd11,unit};//计数器计数1msalways @(posedge clk or negedge rst_n)if(!rst_n)cnt_1ms<=1'b0;else if(cnt_1ms==CNT_MAX)cnt_1ms<=1'b0;else cnt_1ms<=cnt_1ms+1'b1;//计数标志位always @(posedge clk or negedge rst_n)if(!rst_n)flag_1ms<=1'b0;else if(cnt_1ms==CNT_MAX-1'b1)flag_1ms<=1'b1;elseflag_1ms<=1'b0;//cnt_sel:从0到5的循环,用于选择当前显示的数码管always @(posedge clk or negedge rst_n)if(!rst_n)cnt_sel<=1'b0;else if(cnt_sel==3'b101 && flag_1ms)cnt_sel<=1'b0;else if(flag_1ms)cnt_sel<=cnt_sel+1'b1;elsecnt_sel<=cnt_sel;//数码管位选信号寄存器always @(posedge clk or negedge rst_n)if(!rst_n)sel_reg<=6'b000_000;else if(!cnt_sel && flag_1ms)sel_reg<=6'b000_001;else if(flag_1ms)sel_reg<=sel_reg<<1;elsesel_reg<=sel_reg;//控制数码管的位选信号,使六个数码管轮流显示always @(posedge clk or negedge rst_n)if(!rst_n)data_disp<=1'b0;else if(seg_en && flag_1ms)case(cnt_sel)3'd0:data_disp<=data_reg[3:0];3'd1:data_disp<=data_reg[7:4];3'd2:data_disp<=data_reg[11:8];3'd3:data_disp<=data_reg[15:12];3'd4:data_disp<=data_reg[19:16];3'd5:data_disp<=data_reg[23:20];default:data_disp<=1'b0;endcaseelsedata_disp<=data_disp;//dot_disp:小数点低电平点亮,需对小数点有效信号取反always @(posedge clk or negedge rst_n)if(!rst_n)dot_disp<=1'b1;else if(flag_1ms)dot_disp<=~point[cnt_sel];elsedot_disp<=dot_disp;//控制数码管段选信号,显示数字always @(posedge clk or negedge rst_n)if(!rst_n)seg<=8'b1111_1111;elsecase(data_disp)4'd0:seg<={dot_disp,7'b100_0000};4'd1:seg<={dot_disp,7'b111_1001};4'd2:seg<={dot_disp,7'b010_0100};4'd3:seg<={dot_disp,7'b011_0000};4'd4:seg<={dot_disp,7'b001_1001};4'd5:seg<={dot_disp,7'b001_0010};4'd6:seg<={dot_disp,7'b000_0010};4'd7:seg<={dot_disp,7'b111_1000};4'd8:seg<={dot_disp,7'b000_0000};4'd9:seg<={dot_disp,7'b001_0000};4'd10:seg<=8'b1011_1111;4'd11:seg<=8'b1111_1111;default:seg<=8'b1100_0000;endcase//sel:数码管位选信号赋值always @(posedge clk or negedge rst_n)if(!rst_n)sel<=6'b000_000;elsesel<=~sel_reg;
endmodule
四、顶层文件设计
1.顶层设计代码
module dig_top(input wire clk,input wire rst_n,input wire[7:0]ad_data,output wire ad_clk,output wire [5:0]sel,output wire [7:0]seg
);wire [15:0]volt;wire sign;seg seg_inst(.clk(clk),.rst_n(rst_n),.point(6'b001000),.data(volt),.seg_en(1'b1),.sign(sign),.sel(sel),.seg(seg));dac dac_inst(.clk(clk),.rst_n(rst_n),.ad_data(ad_data),.ad_clk(ad_clk),.sign(sign),.volt(volt));
endmodule
2.RTL视图
五、仿真测试模块
1.仿真测试模块代码
`timescale 1ns/1ns
`define clk_period 20module dig_top_tb;reg clk;reg rst_n;reg[7:0]ad_data;reg data_en;reg [7:0]ad_data_reg;wire ad_clk;wire [5:0]sel;wire [7:0]seg;dig_top dig_top_inst(.clk(clk),.rst_n(rst_n),.ad_data(ad_data),.ad_clk(ad_clk),.sel(sel),.seg(seg));initial clk=1'b1;always #(`clk_period/2) clk=~clk;initial beginrst_n = 1'b0;clk = 1'b0;#200;rst_n = 1'b1;data_en = 1'b0;#499990;data_en=1'b1;endalways@(posedge clk or negedge rst_n)if(rst_n == 1'b0)ad_data_reg <= 8'd0;else if(data_en == 1'b1)ad_data_reg <= ad_data_reg + 1'b1;elsead_data_reg <= 8'd0;always@(posedge clk or negedge rst_n)if(rst_n == 1'b0)ad_data <= 8'd0;else if(data_en == 1'b0)ad_data <= 8'd125;else if(data_en == 1'b1)ad_data <= ad_data_reg;elsead_data <= ad_data;
endmodule
2.仿真波形图
六、上板验证
在没有接入电压时,显示为0.00
接入板载IO口中3.3V电压,在误差允许范围内,设计成功。
FPGA之简易电压表设计相关推荐
- 基于FPGA的简易DDS信号发生器的设计与验证
基于FPGA的简易DDS信号发生器的设计与验证 一,理论介绍 补充:举例理解 二,代码实现 1,实验目标 2,MATLAB代码 3,verilog代码及实现思路 一,理论介绍 DDS 是直接数字式频率 ...
- 基于FPGA的简易DDS信号发生器的设计(一)
写这篇文章的本意不是为了探讨AD9767怎么使用,因为9767的控制实在是太简单了,准备好数据直接输出即可,和网上大多数的并行DA输出基本上一模一样,更麻烦的反而是硬件方面.发文的原因是最近一位很细心 ...
- 基于FPGA的电子计算器设计(上)
今天给大侠带来基于FPGA的电子计算器设计,由于篇幅较长,分三篇.今天带来第一篇,上篇,话不多说,上货. 导读 本篇介绍了一个简单计算器的设计,基于 FPGA 硬件描述语言 Verilog HDL,系 ...
- 单片机c语言数字频率计的课程设计,基于单片机的简易数字频率计设计报告(最终版)最新版...
<基于单片机的简易数字频率计设计报告.doc>由会员分享,可免费在线阅读全文,更多与<基于单片机的简易数字频率计设计报告(最终版)>相关文档资源请在帮帮文库(www.woc88 ...
- 基于89C52的可调电压表设计(简洁版)
基于89C52的可调电压表设计(简洁版) 1. 功能与指标 2. 设计方案与工作原理 3. 硬件模块 3.1 ADC模数转换[^1] 3.2 89c52数据处理 3.3 LCD1602显示 4 程序代 ...
- 基于FPGA的简易数字频率计+上板测试(小梅哥AC620FPGA开发板)
基于FPGA的简易数字频率计+上板测试(小梅哥AC620FPGA开发板 目录 主要架构 1.计数模块 2.数码显示模块 3.控制信号模块 4.分频模块 例化模块 上板测试图 附:74HC595移位寄存 ...
- CPLD/FPGA的UART接口设计之系统时钟(晶振)和波特率关系
UART(UniversalAsynchronous ReceiverTransmitter,通用异步收发器)是一种广泛使用的异步串行数据通信协议.目前大多数MCU.串口通信IC等芯片或模块均支持UA ...
- 用matlab编程简单电子琴,基于MATLAB的数字信号发生器及简易电子琴设计论文.doc...
基于MATLAB的数字信号发生器及简易电子琴设计论文 基于MATLAB的数字信号发生器及简易电子琴设计 摘 要 数字信号发生器是一种基于软硬件结合实现的函数波形产生仪器.在工程实践中需要检测和分析的各 ...
- 基于FPGA的IIR滤波器设计
基于FPGA的IIR滤波器设计,使用VHDL语言. 本设计是毕设,包括论文 下面是论文目录截图: 各模块VHDL程序 时序控制模块程序 library ieee; use ieee.std_logic ...
最新文章
- Python读取文件夹下的所有文件,并获得文件中的2-10行的信息
- git怎么读_【杂谈】怎么使用有三AI完成系统性学习并赚钱
- bert 多义词_BERT之后,GLUE基准升级为SuperGLUE:难度更大
- HTTP 相应头相关
- 关于 Apple Metal API 的一些想法
- Java基础-自增自减运算符练习题
- acm集训训练赛(二)D题【并查集】
- 创建 macvlan 网络 - 每天5分钟玩转 Docker 容器技术(55)
- 前端实现序列帧_canvas实现序列帧动画的案例
- stm32f4 dma da正弦波发生器 keil5 hal库 CubeMX
- 电脑录屏的html文件,如何在电脑录制网页视频及网页录音?
- Tbase 源码 (六)
- 随机森林 matlab
- 三亚自由行游记,探秘这座美丽小岛
- 微信红包“昙花一现”?看传统企业中兴如何玩转“微信红包”
- 联想惠普谁才是pc的最后王者
- 【爬虫修炼和实战】二、从requests开始——爬取喜马拉雅全站音频数据(基础篇)
- 职场常用的办公软件,操作很方便
- 转载 学写钢笔字应该注意些什么
- Excel技巧--数据不能按照1-100来排列
热门文章
- python同或与异或_python中 “与,或,异或”与C语言的不同
- HTML——实现富文本编辑器wangEditor的使用
- ​插件化DPI在商用WIFI中的价值
- 如何理解函数式中纯函数
- 中研股份通过注册:拟募资4.6亿 谢怀杰家族控制46%股权
- Excel VBA属性、方法、事件大全——Part11(Complete List of Excel VBA attribute/method and event)
- 关于string头文件
- hp 服务器ipmi协议,HP DL380 G6 服务器IPMI Interface在Windows 2003 下怎么安驱动?_电脑_天涯问答_天涯社区...
- Android锁屏、重启、关机开发!简单直接
- 万字总结八大排序算法(图文详解)