简易电压表设计验证

前言

        电压表是测量电压的一种仪器。由永磁体、线圈等构成。电压表是个相当大的电阻器,理想的认为是断路。初中阶段实验室常用的电压表量程为0~3V和0~15V。

        传统的指针式电压表包括一个灵敏电流计,在灵敏电流计里面有一个永磁体,在电流计的两个接线柱之间串联一个由导线构成的线圈,线圈放置在永磁体的磁场中,并通过传动装置与表的指针相连。大部分电压表都分为两个量程。电压表有三个接线柱,一个负接线柱,两个正接线柱,电压表的正极与电路的正极连接,负极与电路的负极连接。

正文

一、简易电压表设计验证

        1.项目需求

        基于fpga设计一款电压表,显示数据误差不高于0.001V。

        2.技术介绍

        模数转换器即AD转换器,或简称ADC(Analog to DigitalConver),通常是指一个将模拟信号转变为数字信号的电子元件或电路。
        将经过与标准量比较处理后的模拟量转换为以二进制数值表示的离散信号。
模拟信号向数字信号的转换过程一般分为四个步骤:采样、保持、量化、编码。通常量化,编码在ADC芯片中进行,常用ADC芯片有积分型、逐次逼近型、闪烁型、流水线型

        本实验的数据采集需要借助于AD转换模块,该模块使用芯片AD9280,是一款并行8位宽,采样率32M,电压范围+5V,到-5V。

        da_in的数据范围为0000_0000到1111_1111,即0到255,表示-5到+5v,在0到127表示-5到0V,当前电压为= -精度*(127-测量值)。当前精度为10/(2^8);128到255表示0到+5V,当前电压为= 精度*(测量值-127)。当前精度为10/(2^8)。
这里测量方法选用中值法:系统上电后采集接口悬空,此时ad输入数据应为0V,对此时采集的数据取均值M,此时M对应0V,测量数据0到M即对应-5到0V,当前电压为= -精度*(M-测量值),当前精度为10/((M+1)*2);M到255表示0到+5V,当前电压为= 精度*(测量值-M)。当前精度为10/((255-M)*2)。

        3.顶层架构

        4.端口描述

clk时钟信号(50Mhz)
rst_n复位信号(低电平有效)
Clk_ad采样时钟
daAD模块接转换的数据
[2:0] sel位选信号
[7:0] seg段选信号

二、代码验证

数据计算模块

module div_volt(

	input 		  		clk			,
	input 		  		rst_n			,
	input[7:0]	  		da_in			,
					
	output 		  		da_clk		,
	output   [23:0]	data    		,
	output 				sign				//符号位

);

reg 			cnt		;//分频计数器
reg 			da_clk_o	;//四分频时钟
reg [12:0]	cnt_ad	;//数据计数器,基于采样时钟
reg [17:0] 	data_sum	;//数据累加器
reg 			sum_en	;//累加范围标准信号,1024个数据后拉高
reg [7:0] 	data_pj	;//数据M求平均

wire [27:0]	data_p	;//数据精度(-5——0V)
wire [27:0]	data_l	;//数据精度(-5——0V)

reg [27:0]	data_out	;//输出数据暂存
	
always@(posedge clk,negedge rst_n)//四分频计数器
begin
	if(rst_n == 0)
		cnt <= 1'b0;
	else
		cnt = cnt + 1'b1;
end

always@(posedge clk,negedge rst_n)//实现四分频
begin
	if(rst_n == 0)
		da_clk_o <= 1'b0;
	else
		if(cnt == 1'b1)
			da_clk_o <= ~da_clk_o;
		else
			da_clk_o <= da_clk_o;
end

assign da_clk = ~da_clk_o;//输出实现四分频,采样时钟

always@(posedge da_clk,negedge rst_n)//数据计数器
begin
	if(rst_n == 0)
		cnt_ad <= 13'd0;
	else
		if(sum_en == 1'b0)
			cnt_ad <= cnt_ad + 13'd1;
		else
			cnt_ad <= cnt_ad;
end

always@(posedge da_clk,negedge rst_n)//数据累加
begin
	if(rst_n == 0)
		data_sum <= 18'd0;
	else
		if(cnt_ad == 13'd1024)
			data_sum <= 18'd0;
		else
			data_sum <= data_sum + da_in;
end		

always@(posedge da_clk,negedge rst_n)//累加范围标志信号
begin
	if(rst_n == 0)
		sum_en <= 1'b0;
	else
		if(cnt_ad == 13'd1024)//0-1024为悬空状态下确定M的过程
			sum_en <= 1'b1;
		else
			sum_en <= sum_en ;
end

always@(posedge da_clk,negedge rst_n)//求M
begin
	if(rst_n == 0)
		data_pj <= 8'd0;
	else
		if(cnt_ad == 13'd1024)
			data_pj <= data_sum / 1024;
		else
			data_pj <= data_pj;
end

assign data_p = (sum_en == 1'b1)? 81920000/((data_pj +1)*2 ):0;//((10*2^13*1000)/(M+1)*2)

assign data_l = (sum_en == 1'b1)? 81920000/((255-data_pj +1)*2 ):0;//精度扩大2^13倍


always@(posedge da_clk,negedge rst_n)//求M
begin
	if(rst_n == 0)
		data_out <= 24'd0;
	else
		if(sum_en == 1'b1)
			if(da_in < data_pj)
				data_out <= (data_p * (data_pj - da_in)) >>13;
			else
				if(da_in > data_pj)
					data_out <= (data_l * (da_in - data_pj)) >>13;
		
end

assign sign = (da_in > data_pj)?1'b0:1'b1;

assign data = data_out;
			
endmodule

数码管驱动模块

module seg_driver(
 
	input 				clk		,
	input 				rst_n		,
	input [23:0] 		data_in	,//接收数字时钟信号
	
	output reg [2:0] 	sel		,//位选信号
	output reg [7:0]	seg			//段选信号
);
 
reg [18:0] cnt;//1MS
parameter MAX = 19'd50_000;
//20ns记50000次
//产生1ms的延时
//位选信号1ms变换一次
reg [3:0] temp;
always @(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)
		cnt <= 19'd0;
	else
		if(cnt < MAX - 1)//产生1ms的延时
			cnt <= cnt + 19'd1;
		else
			cnt <= 19'd0;
end 
 
//数码管位选信号控制逻辑
always @(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)
		sel <= 3'd0;
	else
		if(cnt == MAX - 1)//位选信号6位,1ms的延时到变化一次
			if(sel < 5)
				sel <= sel + 3'd1;
			else 
				sel <= 3'd0;
		else 
			sel <= sel;	
end 
always @(*) begin
	if(rst_n == 0)
		temp <= 4'd0;
	else
		case(sel)//位选信号到将数据输出到对应输出位上
			3'd0	:	temp <= data_in[23:20];
			3'd1	:	temp <= data_in[19:16];
			3'd2	:	temp <= data_in[15:12];
			3'd3	:	temp <= data_in[11:8];
			3'd4	:	temp <= data_in[7:4];
			3'd5	:	temp <= data_in[3:0];
			default	:	temp <= 4'd0;
		endcase
end 
always @(*) begin
	if(rst_n == 0)
		seg <= 8'hff;
	else
		case(temp)//段选信号,对应的数码管信号
			4'd0	:	seg <= 8'b1100_0000;//0
			4'd1	:	seg <= 8'b1111_1001;//1
			4'd2	:	seg <= 8'b1010_0100;//2
			4'd3	:	seg <= 8'b1011_0000;//3
			4'd4	:	seg <= 8'b1001_1001;//4
			4'd5	:	seg <= 8'b1001_0010;//5
			4'd6	:	seg <= 8'b1000_0010;//6
			4'd7	:	seg <= 8'b1111_1000;//7
			4'd8	:	seg <= 8'b1000_0000;//8
			4'd9	:	seg <= 8'b1001_0000;//9
			4'd10	:	seg <= 8'b1000_1000;//A
			4'd11	:	seg <= 8'b1000_0011;//b
			4'd12	:	seg <= 8'b1100_0110;//C
			4'd13	:	seg <= 8'b1010_0001;//d
			4'd14	:	seg <= 8'b1000_0110;//E
			4'd15	:	seg <= 8'b1000_1110;//F
			default	:	seg <= 8'hff;
		endcase 
end 
endmodule 

顶层连线

module div_volt_top(

	input 		  		clk			,
	input 		  		rst_n			,
	input[7:0]	  		da_in			,
					
	output 		  		da_clk		,
	output  [2:0] 		sel			,//位选信号
	output  [7:0]		seg			//段选信号

);

wire [23:0]data;

div_volt div_volt_inst(

	.clk		(clk	),
	.rst_n	(rst_n),
	.da_in	(da_in),
   
	.da_clk	(da_clk),
	.data    (data  ),
	.sign 	(      )

);

seg_driver seg_driver_inst(
 
	.clk		(clk		),
	.rst_n	(rst_n	),
	.data_in	(data 	),//接收数字时钟信号
    
	.sel		(sel		),//位选信号
	.seg		(seg		)	//段选信号
);
 

endmodule

仿真代码

`timescale 1ns/1ps
module div_volt_top_tb;
	
	reg 			clk	;
	reg 			rst_n	;
	reg[7:0]		da_in	;
	reg			da_en	;
	reg[7:0]		da_reg;
	
	wire [7:0]	seg	;
	wire [2:0]	sel	;
	wire 			da_clk;
	
div_volt_top div_volt_top_inst(

	.clk		(clk		),
	.rst_n	(rst_n	),
	.da_in	(da_in	),

	.da_clk	(da_clk	),
	.sel		(sel		),//位选信号
	.seg		(seg		)	//段选信号
);


initial clk =1;
always #10 clk = ~clk;


initial begin
	rst_n = 0;
	#20
	rst_n = 1;
	#100
	da_en = 0;
	#499990
	da_en = 1;
	#20000
	$stop;
end

always@(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)
		da_reg <= 8'b0;
	else
		if(da_en == 1)
			da_reg <= da_reg + 1;
		else
			da_reg <= 8'b0;
end

always@(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)
		da_in <= 8'b0;
	else
		if(da_en == 0)
			da_in <= 8'd125;
		else
			if(da_en == 1)
				da_in <= da_reg;
			else
				da_in <= da_in;
end


endmodule

三、仿真验证

运行仿真,这里可以看到在500818665ps后开始有数据输出。

调出中间数据,放大波形图进行观察

数据输出4920,在精度计数块,对数据进行了1000倍的放大,所以这里输出数据为4.92V,sign为高电平,表示该数据为负数,即-4.92V。此时输入数据为1,0V时对应输入124,输入范围为0-255,通过对比计算得到输出电压。

数据输出1249,在精度计数块,对数据进行了1000倍的放大,所以这里输出数据为1.249V,sign为低电平,表示该数据为正数,即1.249V。数据输出正确,实验成功

参考资料

等精度测量

  • 15
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张明阳.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值