FPGA初级课程第九讲 分频器
本帖最后由 lcytms 于 2016-11-9 21:21 编辑FPGA初级课程
第九讲 分频器
Hi,大家好!我是至芯科技的李老师。
今天讲课的题目是:分频器。
本节课我先简要地介绍一下分频器的物理原理,然后实际演示一下分频器驱动逻辑电路的建模与仿真,并通过仿真查看效果。
分频器这个名词或许大家都很熟悉了,运用计数器我们就能轻松地实现分频器设计。
我们打开《23至芯科技奋斗的小孩之altera 系列 第二十三篇 分频器.pdf》文件。
对于每一个的小实验,我们都可以把它看作是一个小项目,逐步的去分析,设计,调试,最后完成功能。
下面我们就开始我们的“小项目”。
项目名称:分频器
具体要求:将本地晶振分频成一定的频率。
架构图如下:
系统设计:
1. 工程的名称:div_freq。
我们首先来写一个计数器,实现10分频,将至芯科技ZX_1开发板上的50MHz系统时钟变成5MHz时钟输出。
很简单,我就让每隔5个时钟取反一次就行了。这种分频实现起来非常简单,它的特点是占空比为50%,而且是偶数次分频。
本帖最后由 lcytms 于 2016-11-9 19:15 编辑
新建工程文件夹div_freq。
新建分频模块div_freq2n.v,后面加上2n表示偶数次分频,以区别于我们后面要实现的通用分频模块div_freq.v。通用分频模块div_freq.v不局限于偶数次分频,而且占空比可调。
将分频模块div_freq2n.v设置为顶层模块。
module div_freq2n (clk, rst_n, clk_out);
input clk, rst_n;
output reg clk_out;
parameter CNT_NUM = 5;// half of 10
reg cnt;
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
cnt <= 0;
clk_out <= 1;
end
else
begin
if (cnt < CNT_NUM - 1)
begin
cnt <= cnt + 26'b1;
end
else
begin
cnt <= 0;
clk_out <= ~clk_out;
end
end
end
endmodule
本帖最后由 lcytms 于 2016-11-9 19:17 编辑
新建Testbench。编写div_freq2n_tb.v模块代码。
`timescale 1ns/1ps
module div_freq2n_tb;
reg clk, rst_n;
wire clk_out;
div_freq2n #(.CNT_NUM(5)) dut (.clk(clk), .rst_n(rst_n), .clk_out(clk_out));
initial
begin
clk = 1;
rst_n = 0;
#200.1
rst_n = 1;
#2000 $stop;
end
always #10 clk = ~clk;
endmodule
设置好仿真。
查看仿真波形。与设计要求相符。
通过修改参数CNT_NUM可以实现分频次数的调整。
本帖最后由 lcytms 于 2016-11-9 19:22 编辑
下面我们要实现的通用分频模块div_freq.v不局限于偶数次分频,而且占空比可调。
我们回到《23至芯科技奋斗的小孩之altera 系列 第二十三篇 分频器.pdf》文件。
2. 状态转移图如下图所示。
HW:高电平所占的周期数
LW:低电平所占的周期数
本帖最后由 lcytms 于 2016-11-9 19:29 编辑
新建通用分频模块div_freq.v
将通用分频模块div_freq.v设置为顶层模块。
module div_freq (clk, rst_n, clk_out);
input clk, rst_n;
output reg clk_out;
parameter HW = 50,
LW = 50; // HW + LW = 100 times
reg state;
localparam s0 = 1'b0,
s1 = 1'b1;
reg cnt;
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
cnt <= 0;
clk_out <= 1;
state <= s0;
end
else
begin
case (state)
s0 : begin // HW part
if (cnt < HW - 1)
begin
cnt <= cnt + 26'b1;
clk_out <= 1;
state <= s0;
end
else
begin
cnt <= 0;
clk_out <= 1;
state <= s1;
end
end
s1 : begin // LW part
if (cnt < LW - 1)
begin
cnt <= cnt + 26'b1;
clk_out <= 0;
state <= s1;
end
else
begin
cnt <= 0;
clk_out <= 0;
state <= s0;
end
end
default : state <= s0;
endcase
end
end
endmodule
本帖最后由 lcytms 于 2016-11-9 19:32 编辑
新建Testbench。编写div_freq_tb.v模块代码。
`timescale 1ns/1ps
module div_freq_tb;
reg clk, rst_n;
wire clk_out;
div_freq #(.HW(3), .LW(2)) dut (.clk(clk), .rst_n(rst_n), .clk_out(clk_out));
initial
begin
clk = 1;
rst_n = 0;
#200.1
rst_n = 1;
#2000 $stop;
end
always #10 clk = ~clk;
endmodule
设置好仿真。
查看仿真波形。与设计要求相符。
通过修改参数HW、LW可以实现分频次数的调整。
高电平为3个周期,低电平为2个周期。本地晶振是50MHz,我们分频出来的时钟为10MHz,并且占空比为60%。
如果本地晶振或者输出的时钟和笔者的设计不同,请自行更改设计,以保证设计的正确性。
页:
[1]
2