数电实验6:可控分频器设计
一、实验目的
- 学习 ModelSim 仿真方法。
- 巩固 Verilog HDL 时序电路设计。
二、基本实验内容
- FPGA 开发板上有一个 50MHz 的高频时钟。设计一个可控分频器,clk_in 为分频器时钟输入, sel为选择开关, clk_out为分频器信号输出。当sel=0时,fclk_out=sn[2:0]Hz;当 sel=1 时, fclk_out=sn[4:0] Hz。
- clk_out 的占空比 D=28%;(D=tH/T, tH 为高电平时间, T 为周期)
- 说明。 sn 为学号, sn[2:0]表示取十进制学号的后 3 位, sn[4:0]表示取十进制学号的后 5 位,若学号后 3 位为 0 则学号后 5 位按 32768 取值。例如,学号 sn=2017112345,sn[2:0]=345; sn=2017100000, sn[2:0]=768.
- 实验测试
- 用导线将 clk_out 接入实验箱的 CH0 逻辑分析仪通道, 测试 clk_out 实际输出频率及占空比, 若与要求不相符(误差须小于 1‰), 修改电路程序使之符合要求。
三、提高性实验内容(选做)
- 增加占空比调节功能,每按一下“+”键,占空比增加 10%;每按一下“-”键,占空比减少 1%;
- 使输出信号的占空比按正弦波规律自动变化,正弦波频率为 300Hz;
- 其他
四、预习实验
- 写出设计思路。
- 由于 FPGA 只能进行整数计数来分频, 会存在除不尽的情况而只能四舍五入取整数,
请根据实际分频系数计算因为取整导致的理论误差。 - 自学 ModelSim 仿真方法, 用 ModelSim 对实验电路进行仿真(需使用标尺功能测
量输出信号频率/周期、占空比),并将仿真代码及仿真结果截图打印。 - 自行安排所用引脚, 列出引脚锁定分配表(信号名->主板器件名->引脚号)
五、实验报告要求
- 列出程序代码(有详细注释)。
- 列出通电测试结果。
- 列出实验过程出现的问题及解决措施。
- 附源程序
六、内容讲解(基础实验内容)
我们以学号为2017112345为例讲解本次实验。
首先,先将基本框架写出来。
module controlled_frequency
(
input wire clk_in ,
input wire reset_n ,
input wire sel ,
output wire clk_out
);
endmodule
sn[2:0] = 345,sn[4:0] = 12345 。输入时钟clk_in的频率为50MHz,周期T0 = 20ns。当输出时钟的频率为345Hz时,周期为T1 ≈ 144927T0,占空比为28%,则高电平时间为T1H = 40580T0 ;当输出时钟的频率为12345Hz时,周期T2 ≈ 4050T0,高电平时间T2H = 1134T0;因此我们首先需要一个计数器,并且对各个计数值进行编码。sel = 0 ,输出时钟频率为345Hz时,计数器从0到144926循环计数,并且在0 ~ 40579内,clk_out保持高电平,剩下的时间保持低电平;sel = 1,输出时钟频率为12345Hz时,计数器从0到4049循环计数,并且在0 ~ 1133内,clk_out保持高电平,剩下时间保持低电平。代码如下
module controlled_frequency
(
input wire clk_in ,
input wire reset_n ,
input wire sel ,
output wire clk_out
);
//以学号2017112345为例
parameter CNT_CLK1 = 20'd144926 ;//频率为345Hz时钟计数(从0开始):144927 - 1
parameter CNT_CLK2 = 20'd4049 ;//频率为12345Hz时钟计数(从0开始):4050 - 1
parameter CNT_CLK1_HIGH = 20'd40579 ;//345Hz时钟高电平计数(从0开始):40580 - 1
parameter CNT_CLK2_HIGH = 20'd1133 ;//12345Hz时钟高电平计数(从0开始):1134 - 1
reg [19:0] CNT ;
//CNT的计数逻辑
always@(posedge clk_in, negedge reset_n)
begin
if(!reset_n)
CNT <= 20'd0;
else if((sel == 1'b0) && (CNT >= CNT_CLK1))//输出时钟频率345Hz
CNT <= 20'd0;
else if((sel == 1'b1) && (CNT >= CNT_CLK2))//输出时钟频率为12345Hz
CNT <= 20'd0;
else
CNT <= CNT + 1'b1;
end
//clk_out的逻辑
assign clk_out = ( (sel == 0 && CNT <= CNT_CLK1_HIGH) ||
(sel == 1 && CNT <= CNT_CLK2_HIGH) )? 1'b1:1'b0;
endmodule
在更换频率时(sel从0变为1),计数器计数可能会大于CNT_CLK2(4049),需要将计数器清零,因此我们计数器清零的条件是 CNT >= CNT_CLK2。
七、testbench及仿真结果
1.testbench
`timescale 10ns/1ns//时间单位10ns,时间精度1ns
module tb_controlled_frequency();
reg clk_in ;
reg reset_n ;
reg sel ;
wire clk_out ;
initial
begin
clk_in <= 1'b1;
reset_n <= 1'b0;
sel <= 1'b0;
# 5 reset_n <= 1'b1;
# 1500000 sel <= 1'b1;
end
always #1 clk_in = ~clk_in;//时钟周期为20ns
controlled_frequency controlled_frequency_inst//实例化
(
.clk_in (clk_in ),
.reset_n (reset_n ),
.sel (sel ),
.clk_out (clk_out )
);
endmodule
2.仿真结果
sel = 0,CNT从0开始计数,clk_out为高电平。
计数到40579,clk_out变为低电平,保持低电平到144926,计数器清零,clk_out又变为高电平。
sel = 1时
CNT从0计数到1133,clk_out保持高电平,在1134后保持低电平。
计数到4049后,计数器清零,clk_out又变为高电平。
欢迎在评论区留言,感谢您的关注与支持!