特权同学《Verilog边码边学》,B站教学视频链接:101 组合逻辑与时序逻辑_哔哩哔哩_bilibili
目录
一、分频时钟的工程应用
1、对FPGA系统时钟(频率较高)进行分频,产生分频时钟(频率较低)
2、分频时钟可以作为FPGA低速外设的同步时钟
-
IIC总线的时钟(≤400KHz)
-
低速SPI总线的时钟(≤1MHz)
3、对于频率较高的分频时钟,不能直接作为外设时钟或FPGA内部时钟使用,这类时钟应该由FPGA内部的PLL邓时钟管理单元产生
二、Verilog实现分频计数器
-
功能需求:输入时钟100MHz,产生一个1MHz的低频时钟
分析:
① 100MHz / 1MHz = 100,翻译一下就是每100个输入时钟周期是1个输出时钟周期
② 需要对100MHz时钟做100分频
③ 计数器循环计数周期为0-99,那么前50个输入时钟就是输出时钟的高电平,后50个时钟是输出时钟的低电平
-
代码实现:当计数器为0-49时输出高电平,计数器为50-99时输出低电平
`timescale 1ns/1ps
module vlg_design(
input clk,
input rst_n,
output reg clk_1mhz
);
//`define CNT_MAX 100
//`define CNT_MAX_DIV2 `CNT_MAX/2
localparam CNT_MAX = 8'd100; //时钟为高电平
localparam CNT_MAX_DIV2 = 8'd50; //时钟为高电平的一半
reg[7:0] cnt; // 8bit计数器
always @(posedge clk)
//同步复位,当rst_n为低电平时复位
if(!rst_n) cnt <= 8'd0;
else if(cnt < (CNT_MAX-1)) cnt <= cnt+1'b1;
else cnt <= 8'd0;
always @(posedge clk)
if(!rst_n) clk_1mhz <= 8'd0;
else if(cnt < CNT_MAX_DIV2) clk_1mhz <= 1'b1;
else clk_1mhz <= 1'b0;
endmodule
-
结果展示
三、课后题
-
功能需求:输入时钟25MHz,产生一个400KHz的低频时钟
由于25MHz/400KHz=62.5,是小数分频,由于只能在上升沿或下降沿触发,所以只能等效为输入时钟的625个周期是输出时钟的10个周期,需要满足以下公式:
先做5次62分频,再做5次63分频,得到625个输入时钟周期,之后令分频时钟在625个分频时钟内跳变20次共10个周期。
可以取公约数,最终就是先做1次62分频(前31个输入时钟周期为高电平,后31个输入时钟周期为低电平),再做1次63分频(前31个输入时钟周期为高电平,后32个输入时钟周期为低电平),得到125个输入时钟周期,之后令分频时钟在125个分频时钟内跳变4次共2个周期。
这个方法被称作”双模前置小数分频“,其最重要的核心是M分频(62)和M+1分频(63)这个相近频率。
-
代码实现
`timescale 1ns/1ps
module vlg_design(
input clk,
input rst_n,
output reg clk_400khz
);
//`define CNT_MAX 100
//`define CNT_MAX_DIV2 `CNT_MAX/2
localparam div_e = 8'd62; //62分频周期数,1个输出周期
localparam div_o = 8'd63; //63分频周期数,1个输出周期
localparam change = 8'd62; //电平转换
reg[8:0] cnt; // 8bit计数器
reg[8:0] cnt62; // 8bit计数器
reg[8:0] cnt63; // 8bit计数器
always @(posedge clk) begin
//同步复位,当rst_n为低电平时复位
if(!rst_n) begin
cnt <= 8'd0;
cnt62 <= 8'd0;
cnt63 <= 8'd0;
end
else begin
if(cnt < change) begin
cnt62 <= cnt62 + 1'b1; //当cnt<62时,cnt62从0增加至61
cnt <= cnt + 1'b1;
end
else begin
if(cnt63 == div_o - 1) cnt63 <= 8'd0;
else cnt63 <= cnt63 + 1'b1; //当cnt≥62时,cnt63从0增加至62
end
end
end
always @(posedge clk) begin
if(!rst_n) begin
clk_400khz <= 1'b0;
end
else begin
if(cnt < change) begin
if(cnt62 < 8'd31)
clk_400khz <= 1'b1;
else
clk_400khz <= 1'b0;
end
else begin
if(cnt63 < 8'd31)
clk_400khz <= 1'b1;
else
clk_400khz <= 1'b0;
end
end
end
endmodule
-
结果展示
这里取了两个周期,2T=5us,400KHz的分频时钟周期为2.5us,可以得到仿真结果是正确的。