【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
相关推荐
千寻xun2 小时前
三、实战篇-NVME SSD控制之FPGA实现(一)
fpga开发·nvme ssd·nvme协议
a1117763 小时前
2FA 验证码生成器(github登录验证 app)
笔记·学习
我的xiaodoujiao3 小时前
API 接口自动化测试详细图文教程学习系列32--Allure测试报告2
python·学习·测试工具·pytest
你想知道什么?5 小时前
线性回归-学习笔记
笔记·学习·线性回归
鱼毓屿御5 小时前
从「只会聊」到「边想边做」的跃迁
前端·学习·react.js
XMAIPC_Robot5 小时前
软硬协同实时控制|RK3588业务调度+FPGA硬件时序,ethercat实现半导体设备微秒级响应(125us)
linux·arm开发·人工智能·fpga开发
AOwhisky6 小时前
Python 学习笔记(第十五期)——运维自动化(下·后篇):堡垒机实战——paramiko高阶篇
运维·python·学习·云原生·自动化·运维开发
upper20206 小时前
从零开始设计riscv cpu记录之七
fpga开发·riscv·riscv设计·btb·分支预测
minglie18 小时前
zynq中linux系统的自动登录和免密登录
学习
茯苓gao8 小时前
嵌入式开发笔记:Qt信号槽机制深度解析——从原理到实战的全方位指南
开发语言·笔记·嵌入式硬件·qt·学习