目 录
摘要 1
一系统概述 3
二单元电路的设计与分析 4
三电路的安装与调试 19
四结束语 21
附件1:元器件清单 22
附件2:原理图 23
参考文献 23
摘要
本次多种数字信号源设计使用Quartus 13.1的门电路模块图以及Verilog HDL模块混合,仿真验证使用Modelsim 2020.4,FPGA型号为EP4CE10E22C8。
主要设计分为顶层采样参数设计、多分频器模块设计、状态控制计数器设计、可选择自循环式ROM设计、波形分辨计数器设计、以及DA和电压比较模块设计。
最终实现的功能有:
-
按键预置四种标准波形
-
按键预置9档频率
-
数码管显示波形的设置参数
-
LED显示实测波形种类
整体的执行原则为:先原理图,再代码,再仿真,最后实际搭建电路,调试直到产生预期现象,本文也是按照此逻辑组织阐述的。
关键词 Verilog HDL,数字信号源
Abstract
This multiple digital signal source design uses Quartus 13.1 gate circuit block diagram and Verilog HDL module, simulation verification uses Modelsim 2020.4, FPGA type is EP4CE10E22C8.
The main design is divided into top-level sampling parameter design, multi-frequency divider module design, state control counter design, optional self-circulating ROM design, waveform resolution counter design, and DA and voltage comparison circuit design.
The functions finally we realized are:
-
Press the button to preset four standard waveforms
-
Press the button to preset 9 levels of frequency
-
Display the parameters of current waveform through the digital tube
-
LED display the type of measured waveform
Keyword
Verilog HDL, Multiple Digital Signal Source.
1.
系统概述
1.
总体原理框图
数字电路部分如下图:
| | | --- |
模拟电路部分如下图:
| | | --- |
1.
总体工作流程
1.
部分名词解释
数码管:该数码管自带译码器,使用时DCBA输入8421BCD码即可
频率可控分频器:通过频率控制字译码实现变模
循环自增ROM:内置计数器,可按照选择状态读取并输出对应存储位置的数据
1.
数字部分
按下频率控制按钮 ,十进制计数器跳转到下一状态,得到对应的数字码,该码通过译码器,选通对应的数码管段,并改变分频器的分频值,使得循环自增ROM的基频改变,从而输出波形的频率改变。
按下模式控制按钮 ,四进制计数器跳转到下一状态,得到对应状态的高位地址,这样就改变了在ROM中读取的波形数据类型。
1.
模拟部分
D7-D0共8位数据,对应引脚连接到DAC0832的DI7-DI0位,DAC0832此时输出电流信号,将电流负出端接地,另一端引到一个OP07。
再将此时的电压输出解接OP07反相,再接入参考电压为+5V的比较电路中,这样不同的波形达到+5V的时间不同,产生的电压比较器的输出波形也必然为占空比不同的方波,可以实现波形检测的目的。
1.
单元电路的设计与分析
1.
顶层参数设计
在我们使用的FPGA中,系统时钟信号从PIN24管脚引出,频率为20MHz,而我们目标要求的波形频率为1kHz,所以我们这里设预期输出正弦波在采样前的表达式为:
我们设采样序列数为n,采样频率为 ,那么采样后得到的函数表达式为:
若我们设ROM中,分配给每个种类波形的存储空间数为1k个,那么对于每个高位地址而言,将有24个地址存储值为0(或任意数,因为这段空间在切换基址时以及在顺序读取时都是被跳过的),那么,一个波形数据的完整地址表示为:
这样我们有以下约束:
于是有 ,这样,当我们使用可变频率分频器使得输出采样频率改变为它的1/2,1/4,1/8,...倍时,对应波形的周期也会改变为它的2,4,8,...而这在示波器上是容易观察验证的。
1.
多分频器模块设计
在这里我们先给出多分频器的门级电路设计:
| | | --- |
代码如下:
| //将时钟分频为2^(1~9)+0:20module n_divider ( input [3:0] n, input clk, output reg opt); reg [9:0] div; reg [8:0] pulse; always @(*) begin case(n) 4'd0: div=10'd20; 4'd1: div=10'd2; 4'd2: div=10'd4; 4'd3: div=10'd8; 4'd4: div=10'd16; 4'd5: div=10'd32; 4'd6: div=10'd64; 4'd7: div=10'd128; 4'd8: div=10'd256; 4'd9: div=10'd512; default: div=10'd2; endcase pulse=div/10'd2; end reg [8:0] count=0; always @(posedge clk) begin if (count==div-1) begin count<=0; end else begin count<=count+1'b1; end if ((count >= 0) && (count<pulse)) opt<=1; else opt<=0; endendmodule | | --- |
可以看出,此模块实现的方法为:
首先,利用一个10*10bit的ROM存储与分频数对应的计数次数,0为默认,这样分频得到1MHz的时钟信号,1-9对应分频得到的时钟信号为20/(2^n)MHz的频率,通过译码得到对应的计数值后,除以2,可得当前的高电平计数值,因为时钟信号的默认占空比为0.5,这之后,再实现一个特殊的变模计数器,它的模等于计数次数,每个时钟触发一次,自动判断当前的计数个数是否超过占空计数个数,若超过,则将输出信号置一,否则置0。
我们编写Modelsim测试程序如下:
| `timescale 1us/1psmodule test_tb; reg clk; reg [3:0] n; wire opt; test t1(clk,n,opt); initial begin n=1; #10000 n=3; #10000 $stop; end initial begin clk=0; forever begin #5 clk=~clk; end endendmodule | | --- |
该程序实现的功能为:输入一个0.1MHz的时钟信号,每隔10ms改变一次分频数,这样我们只需测试得到的输出是否与我们的分频数对应即可验证我们程序的功能,验证结果如下:
| | | --- |
可以看出,该模块设计正常。
1.
状态控制计数器设计
我们先给出状态控制计数器的门级电路设计:
它们的实现代码分别给出如下:
| //btn1周期增加,显示几表示 基频/2^n//共1+九档频率 0默认为20分频module counter_10 ( btn1,q); input btn1; output reg[3:0] q; initial begin q=4'h0; end always @(posedge btn1) begin if(q==9) q= (4'h0); else q=(q+1'b1); end endmodule | | --- | | module counter_4 ( btn, otp, ); input btn; output reg[1:0] otp; initial begin otp=2'b00; end always @(posedge btn) begin otp<=(otp+1'b1)%4; endendmodule |
该代码实现的功能很简单,即我们只需要让该计数值在模之内递增即可。
我们编写10进制程序的测试文件如下:
| `timescale 1us/1psmodule test_tb;reg btn1;wire [3:0] q;test t1(btn1,q);initial beginbtn1=0;repeat(18) #5 btn1=~btn1; repeat(18) #5 btn1=~btn1; #20 $stop;end
endmodule | | --- |
该测试文件模拟按下18次按键,我们只需观察输出值的变化是否在0-9之间递增变化即可验证模块功能。
将文件加载到Modelsim中,运行结果如下:
| | | --- |
我们可看出,该计数器工作正常。
1.
变模式自循环ROM设计
1.
说明
该ROM中,地址的高2位无法由计数器改变,时钟上升沿到来时,1000进制计数器自动改变一次状态,如此可实现名称中的功能。
1.
数据生成
我们使用matlab编程,并在程序中直接将其转换为8位数据,给出程序如下:
| Sample_sin=round(127+128*sin(w*T));Sample_square=[linspace(0,0,DataLength/2),255*linspace(1,1,DataLength/2)]; rise1=2*10^3*T(1:DataLength/2);Sample_iso=round(255*[rise1 rise1(end