引言
如何利用iCE40UP5K 的FPGA平台上的ADC制作一个0-3.3V的数字电压表?来自河南工业大学的【raincorn】同学在电子森林详细分享了他寒假练所做的电压表项目,点击文章底部“阅读原文”获取源码,转载请注明出处。
1
目标
2
Σ-Δ ADC采样
AD9280是一款单芯片、8位、32 MSPS模数转换器(ADC),采用单电源供电,内置一个片内采样保持放大器和基准电压源。它采用多级差分流水线架构,数据速率达32 MSPS,在整个工作温度范围内保证无失码。
close all;clear;clc;
fs = 1e6; %sample rate is 1M
t = 0:1/fs:1e-1-1/fs; %generate the data between 0-1ms to rise the fft resulation
n = length(t);
n_index = 0:n-1;
f_index = n_index*fs/n;
% 25%
x = square(2*pi*200e3*t,25) + 1; %generate the PWM with special duty
subplot(321);stem(t,x);axis([0 2e-5 0 2]);title("Time: 25% Duty");
mag_x= 20*log10(abs(fft(x)));
subplot(322);plot(f_index(1:n/2),mag_x(1:n/2));title("Spec(dB): 25% Duty");
% 50%
x = square(2*pi*200e3*t,50) + 1; %generate the PWM with special duty
subplot(323);stem(t,x);axis([0 2e-5 0 2]);title("Time: 50% Duty");
mag_x= 20*log10(abs(fft(x)));
subplot(324);plot(f_index(1:n/2),mag_x(1:n/2));title("Spec(dB): 50% Duty");
% 75%
x = square(2*pi*200e3*t,75) + 1; %generate the PWM with special duty
subplot(325);stem(t,x);axis([0 2e-5 0 2]);title("Time: 75% Duty");
mag_x= 20*log10(abs(fft(x)));
subplot(326);plot(f_index(1:n/2),mag_x(1:n/2));title("Spec(dB): 75% Duty");
优点:便于直流分量的提取,减小滤波后直流信号出现波动。 缺点:提高时间常数,电路的响应速度降低。
优点:时间常数小,电路响应速度快。 缺点:由于截至频率提高,因此需要更大的采样率才能达到较好的效果。
wire [7:0] pwm_val;
wire sample_rdy;
ADC_top u_ADC_top(
.clk_in(clk_pwm_adc),
.rstn(sys_rst_n),
.digital_out(pwm_val),
.analog_cmp(pwm_adc_in),
.analog_out(pwm_adc_out),
.sample_rdy(sample_rdy)
);
3
BCD码生成
module bcd_8421
(
input wire sys_clk , //系统时钟,频率50MHz
input wire sys_rst_n , //复位信号,低电平有效
input wire [19:0] data , //输入需要转换的数据
output reg [3:0] unit , //个位BCD码
output reg [3:0] ten , //十位BCD码
output reg [3:0] hun , //百位BCD码
output reg [3:0] tho , //千位BCD码
output reg [3:0] t_tho , //万位BCD码
output reg [3:0] h_hun //十万位BCD码
);
//********************************************************************//
//******************** Parameter And Internal Signal *****************//
//********************************************************************//
//reg define
reg [4:0] cnt_shift ; //移位判断计数器
reg [43:0] data_shift ; //移位判断数据寄存器
reg shift_flag ; //移位判断标志信号
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//cnt_shift:从0到21循环计数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_shift <= 5'd0;
else if((cnt_shift == 5'd21) && (shift_flag == 1'b1))
cnt_shift <= 5'd0;
else if(shift_flag == 1'b1)
cnt_shift <= cnt_shift + 1'b1;
else
cnt_shift <= cnt_shift;
//data_shift:计数器为0时赋初值,计数器为1~20时进行移位判断操作
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_shift <= 44'b0;
else if(cnt_shift == 5'd0)
data_shift <= {24'b0,data};
else if((cnt_shift <= 20) && (shift_flag == 1'b0))
begin
data_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]);
end
else if((cnt_shift <= 20) && (shift_flag == 1'b1))
data_shift <= data_shift << 1;
else
data_shift <= data_shift;
//shift_flag:移位判断标志信号,用于控制移位判断的先后顺序
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
shift_flag <= 1'b0;
else
shift_flag <= ~shift_flag;
//当计数器等于20时,移位判断操作完成,对各个位数的BCD码进行赋值
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
unit <= 4'b0;
ten <= 4'b0;
hun <= 4'b0;
tho <= 4'b0;
t_tho <= 4'b0;
h_hun <= 4'b0;
end
else if(cnt_shift == 5'd21)
begin
unit <= 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];
end
endmodule
wire [15:0] dis_dat_mult = dis_dat << 7; //The voltage multed by 128(3.3/256 = 0.01289) to get a similar number
wire [(6*8-1):0] dis_dat_buff; //The buffer of dis_dat
wire [3:0] dis_ten;
wire [3:0] dis_hun;
wire [3:0] dis_tho;
wire [3:0] dis_t_tho;
assign dis_dat_buff = {4'd0,dis_t_tho,".",4'd0,dis_tho,4'd0,dis_hun,4'd0,dis_ten,"V"};
bcd_8421 u_bcd_8421(
.sys_clk(clk), //系统时钟,频率50MHz
.sys_rst_n(rst_n), //复位信号,低电平有效
.data(dis_dat_mult), //输入需要转换的数据
.unit(), //个位BCD码
.ten(dis_ten), //十位BCD码
.hun(dis_hun), //百位BCD码
.tho(dis_tho), //千位BCD码
.t_tho(dis_t_tho), //万位BCD码
.h_hun() //十万位BCD码
);
module voltmeter(
// input in_clk, //Use the internal clock source to avoid restrict
input in_rst_n,
input pwm_adc_in,
// input debug, //The debug wire is connected to switch
// output oled_csn, //The cs pin is disconnected
output oled_rst,
output oled_dcn,
output oled_clk,
output oled_dat,
output pwm_adc_out
);
wire sys_clk;
HSOSC
.CLKHF_DIV ("0b10")
) u_HSOSC (
.CLKHFEN (1'b1),
.CLKHFPU (1'b1),
.CLKHF (sys_clk)
);
wire sys_rst_n,clk_gen_locked,clk_pwm_adc;
assign sys_rst_n = in_rst_n & clk_gen_locked;
clk_gen u_clk_gen(
.ref_clk_i(sys_clk),
.rst_n_i(in_rst_n),
.lock_o(clk_gen_locked),
.outcore_o(),
.outglobal_o(clk_pwm_adc) //The pll out is connected with the global clock network
);
wire [7:0] pwm_val;
//pwm_adc u_pwm_adc(
//.sys_clk(clk_pwm_adc),
//.sys_rst_n(sys_rst_n),
//.pwm_adc_in(pwm_adc_in),
//.pwm_val(pwm_val),
//.pwm_adc_out(pwm_adc_out)
//);
wire sample_rdy;
ADC_top u_ADC_top(
.clk_in(clk_pwm_adc),
.rstn(sys_rst_n),
.digital_out(pwm_val),
.analog_cmp(pwm_adc_in),
.analog_out(pwm_adc_out),
.sample_rdy(sample_rdy)
);
oled12864 u_oled12864(
.clk(sys_clk), //The system clock
.rst_n(sys_rst_n), //The system reset
.dis_dat(pwm_val),
// .debug(debug),
.oled_csn(), //OLED ENABLE
.oled_rst(oled_rst), //OLED RESET
.oled_dcn(oled_dcn), //OLED DATA/COMMAND CONTROL
.oled_clk(oled_clk), //OLED CLOCK
.oled_dat(oled_dat) //OLED DATA
);
endmodule
5
其他
END
硬禾学堂
硬禾团队一直致力于给电子工程师和相关专业的同学,带来规范的核心技能课程,帮助大家在学习和工作的各个阶段,都能有效地提升自己的职业能力。
硬禾学堂
我们一起在电子领域探索前进
关注硬禾公众号,随时直达课堂
点击阅读原文查看更多