【Verilog学习日常】—牛客网刷题—Verilog企业真题—VL76

任意奇数倍时钟分频

描述

编写一个模块,对输入的时钟信号clk_in,实现任意奇数分频,要求分频之后的时钟信号占空比为50%。模块应包含一个参数,用于指定分频的倍数。

模块的接口信号图如下:

要求:使用Verilog HDL语言实现,并编写testbench验证模块的功能。

输入描述:

clk_in:输入时钟信号

rst_n:复位信号,低电平有效

输出描述:

clk_out:分频之后的时钟信号

解题思路

理解题意

根据题目要求,将输入的时钟信号进行任意奇数分频,并要求占空比为50%;以5分频为例:

由上图所示,clk_in为原始时钟,clk_out为五分频后的输出时钟。其中,clk_out与clk_in经过同一个时钟上升沿,在clk_in经过2.5周期时clk_out触发下降沿;++clk_out的一个完整的时钟周期长度等于clk_in五个时钟周期的长度++;

解题思路

①设置计数器,计数0~4;

代码如下:

cpp 复制代码
//时钟上升沿采样计数
always @(posedge clk_in or negedge rst_n) begin
	if (!rst_n) cnt <= 'b0;
	else if (cnt == dividor-1) cnt <= 'b0;
	else cnt <= cnt + 'd1;
end
②设置两个电平信号edge_rise和edge_fall;

其中,edge_rise为时钟上升沿触发,edge_fall为时钟下降沿触发,其中电平信号edge_rise和edge_fall将原时钟clk_in的5个时钟周期分为两个部分(++即先经过2个时钟周期(第2个时钟周期)发生电平切换,再经过2个时钟周期(第4个时钟周期)再发生一次电平切换++);其波形如下所示:

由波形图可以发现,将++edge_rise的波形图向右平移半个时钟周期就可得到edge_fall的波形图++;

edge_rise波形与edge_fall波形进行异或就可得到原始时钟的五分频电路;

代码如下:

cpp 复制代码
//电平信号edge_rise
always @(posedge clk_in or negedge rst_n) begin
	if (!rst_n) egde_rise <= 'b0;
	else if (cnt == (dividor-1>>1))		egde_rise <= ~egde_rise; //(dividor-1)/2 = 2
	else if (cnt == dividor-1)	egde_rise <= ~egde_rise; //dividor-1 = 4
	else egde_rise <= egde_rise;
end
//电平信号edge_fall
always @(negedge clk_in or negedge rst_n) begin
	if (!rst_n) egde_fall <= 'b0;
	else if (cnt == (dividor-1>>1))		egde_fall <= ~egde_fall; //(dividor-1)/2 = 2
	else if (cnt == dividor-1)	egde_fall <= ~egde_fall; //dividor-1 = 4
	else egde_fall <= egde_fall;
end

assign clk_out = egde_rise | egde_fall; 

PS:对于任意奇数N倍时钟分频,则电平信号edge_rise和edge_fall将原时钟clk_in的N个时钟周期 先经过**(N-1)/2时钟周期(第(N-1)/2个时钟周期**)发生电平切换,再经过**(N-1)/2**个时钟周期(第N-1个时钟周期)发生电平切换;

③完整代码如下;
cpp 复制代码
`timescale 1ns/1ns

module clk_divider
    #(parameter dividor = 5)
( 	input clk_in,
	input rst_n,
	output clk_out
);
parameter cnt_width = $clog2(dividor); //$clog2()为取对数操作
reg [cnt_width:0] cnt;
reg egde_rise, egde_fall;

//时钟上升沿采样计数
always @(posedge clk_in or negedge rst_n) begin
	if (!rst_n) cnt <= 'b0;
	else if (cnt == dividor-1) cnt <= 'b0;
	else cnt <= cnt + 'd1;
end

always @(posedge clk_in or negedge rst_n) begin
	if (!rst_n) egde_rise <= 'b0;
	else if (cnt == (dividor-1>>1))		egde_rise <= ~egde_rise; //(dividor-1)/2 = 2
	else if (cnt == dividor-1)	egde_rise <= ~egde_rise; //dividor-1 = 4
	else egde_rise <= egde_rise;
end

always @(negedge clk_in or negedge rst_n) begin
	if (!rst_n) egde_fall <= 'b0;
	else if (cnt == (dividor-1>>1))		egde_fall <= ~egde_fall; //(dividor-1)/2 = 2
	else if (cnt == dividor-1)	egde_fall <= ~egde_fall; //dividor-1 = 4
	else egde_fall <= egde_fall;
end

assign clk_out = egde_rise | egde_fall; 


endmodule
相关推荐
西岸行者5 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
ZPC82105 天前
docker 镜像备份
人工智能·算法·fpga开发·机器人
ZPC82105 天前
docker 使用GUI ROS2
人工智能·算法·fpga开发·机器人
悠哉悠哉愿意5 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码5 天前
嵌入式学习路线
学习
毛小茛5 天前
计算机系统概论——校验码
学习
babe小鑫6 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms6 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下6 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。6 天前
2026.2.25监控学习
学习