1.FPGA计数器实现
实现500us LED进行翻转
1.1.verilog代码实现
/*
* @Descripttion: 计数器实例:输入频率50M,LED 500ms翻转一次
* @version:
* @Author:
* @Date: 2021-01-19 16:34:50
* @LastEditors: sueRimn
* @LastEditTime: 2021-03-30 17:07:58
*/
module bin_counter(
clk50M,
reset_n,
led_out
);
input clk50M; //????a
input reset_n; //????b
output led_out;//????out
reg led_out;
//parameter MCNT = 24_999_999; //周期20ns,500ms/20ns=25_000_000次
parameter MCNT = 24_999; //周期20ns,500ms/20ns=25_000_000次
reg [24:0]cnt; //定义计数器寄存器
//计数器计数进程
always@(posedge clk50M or negedge reset_n)
if(!reset_n)
cnt <= 25'd0;
else if(cnt == MCNT)
cnt <= 25'd0;//达到计满次数之后,计数器清零
else
cnt <= cnt + 1'b1;
always@(posedge clk50M or negedge reset_n)
if(!reset_n)
led <= 1'b1;
else if(cnt == MCNT)
led <= ~led; //达到计满次数之后,LED翻转
else
led <= led;
endmodule
1.2.testbench代码实现
`timescale 1ns / 1ps timescale ?位 /精度?
//例如 1ns/100ps,这??·在迾置延旿 #100,就代表着延旿,100*1ns?并俔??以延?? 100.1ns
`define CLOCK_PERIOD 20 //CLOCK_PERIOD:代表20ns
//defparam MCNT = 24_999;//仿真优?策?¥ᅩ将仿真?¶间缩??
module bin_counter_tb();
reg clk50M;
reg reset_n;
wire led;
bin_counter bin_counter_inst (
.clk50M (clk50M ),
.reset_n(reset_n ),
.led_out(led )
);
//添势输?¥激?¡À
initial clk50M = 1;
always #(`CLOCK_PERIOD/2) clk50M = ~clk50M;//20ns?¨期CLK信号产?
initial begin
reset_n = 1'b0; //复位信号产?
#(`CLOCK_PERIOD *200 + 1);
reset_n = 1'b1;
#2000000000;
$stop;
end
endmodule
1.3.modelsim 仿真波形查看.
2.FPGA的2^n次方分频器设计实现
关键点:计数器的位数决定n分频;例如2^4=16;计数器位数【3:0】=4位
2.1.代码实现
功能:实现2、4、8、16分频;
//****************************************************************************************
module clkdiv(
input clk, //输入系统时钟
input rst_n, //输入复位信号
output clk2,clk4,clk8 ,clk16 //输出分频时钟
);
reg cnt[3:0]; //4位计数器
wire clk2,clk4,clk8,clk16;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt<=0;
end
else
begin
cnt<=cnt+1'b1;
end
end
assign clk2=cnt[0];//二分频
assign clk4=cnt[1];//四分频
assign clk8=cnt[2]; //八分频
assign clk16=cnt[3];//十六分频
endmodule
//****************************************************************************************
源文件实现:
/*
* @Descripttion: 80M信号实现,2,4,8,16分频
* @version:
* @Author:
* @Date: 2021-01-19 16:34:50
* @LastEditors: sueRimn
* @LastEditTime: 2021-03-30 17:07:58
*/
module clkdiv(
clk, //输入系统时钟
rst_n, //输入复位信号
clk2, //输出分频时钟
clk4,
clk8,
clk16
);
input clk;
input rst_n;
output wire clk2;
output wire clk4;
output wire clk8;
output wire clk16;
reg [3:0] cnt; //4位计数器
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt<=0;
end
else
begin
cnt<=cnt+1'b1;
end
end
assign clk2=cnt[0];//二分频
assign clk4=cnt[1];//四分频
assign clk8=cnt[2]; //八分频
assign clk16=cnt[3];//十六分频
endmodule
testbench代码实现:
`timescale 1ns / 1ps //timescale 单位 /精度
//例如 1ns/100ps,这样在设置延时 #100,就代表着延时,100*1ns。并且可以延时 100.1ns
`define CLOCK_PERIOD 25 //CLOCK_PERIOD:代表25ns
module clkdiv_tb();
reg clk;
reg rst_n;
wire clk2;
wire clk4;
wire clk8;
wire clk16;
clkdiv clkdiv_inst (
.clk(clk),
.rst_n(rst_n ),
.clk2(clk2 ),
.clk4(clk4 ),
.clk8(clk8 ),
.clk16(clk16 )
);
//添加激励:进行仿真,就需要对其输入端口施加激励来观测输出端口的输出波
//添加:输入80M_CLK时钟信号激励
initial clk = 1;
always #(`CLOCK_PERIOD/2) clk = ~clk;//80M CLK周期信号产生
//添加:输入RST信号激励产生
initial begin
rst_n = 1'b0; //复位信号产生
#(`CLOCK_PERIOD *200 + 1); //低电平持续5001ns
rst_n = 1'b1;
#2000000000; //高电平持续2000ms
$stop;
end
endmodule
2.2 波形分析
modelsim 仿真波形查看:
2.3优缺点分析
缺点:幂指数越大,reg位数就越大,占用空间,优点可以同时实现多路分频;
3.FPGA的偶分频设计实现
关键点:计数器的模值决定分频数,例如2*3=6分频;计数器的模值(状态)为cnt[1:0],0/1/2
目标计数值cnt=n/2-1;(n:分频数);
功能:实现6分频;
3.1.代码实现
/********************************2的偶数次幂分频*********************/
module clkdiv(
input clk, //输入系统时钟
input rst_n, //输入复位信号
output clk_div6 //输出分频时钟
);
reg cnt[1:0]; //2位计数器
reg clkdiv6;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt<=0;
end
else if(cnt<=2)//2=6/2-1
begin
cnt<=2'b00;
clkdiv6=~clkdiv6;//实现6分频
end
else
cnt<=cnt+1;
end
endmodule
10M信号10分频实例:
/* 十分频器的实现
* @Descripttion: 偶数分频实现,计数器的模值
* @version: 目标计数值Mcnt=n/2-1;(n:分频数)
* @Author:
* @Date: 2021-01-19 16:34:50
* @LastEditors: sueRimn
* @LastEditTime: 2021-03-30 17:07:58
*/
module clkdiv(
clk, //输入系统时钟
rst_n, //输入复位信号
clk10 //输出分频时钟 十分频
);
input clk;
input rst_n;
output reg clk10;
reg [2:0] cnt; //3位计数器
parameter Mcnt = 4;//2=10/2-1
//计数器进程
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt<= 0;
clk10<= 0;
end
else if(cnt == Mcnt)
begin
cnt <= 2'b00;
clk10 = ~clk10;//实现10分频
end
else
cnt<=cnt+1;
end
endmodule
10M 10分频 testbench代码实现:
`timescale 1ns / 1ps //timescale 单位 /精度
//例如 1ns/100ps,这样在设置延时 #100,就代表着延时,100*1ns。并且可以延时 100.1ns
`define CLOCK_PERIOD 100 //CLOCK_PERIOD:代表100ns
module clkdiv_tb();
reg clk;
reg rst_n;
wire clk10;
//clk6:80M/6=13.3Mhz
clkdiv clkdiv_inst (
.clk(clk),
.rst_n(rst_n),
.clk10(clk10)
);
//添加激励:进行仿真,就需要对其输入端口施加激励来观测输出端口的输出波
//添加时钟信号激励:输入10M_CLK时钟信号激励
initial clk = 1;
always #(`CLOCK_PERIOD/2) clk = ~clk;//10M CLK周期信号产生
//添加RST信号激励:输入RST信号产生
initial begin
rst_n = 1'b0; //复位信号初始状态为低
#(`CLOCK_PERIOD *200 + 1); //低电平持续:50001ns
rst_n = 1'b1;//复位信号拉高
#2000000000; //高平持续:2s
$stop;
end
endmodule
3.2 波形分析
10M 10分频modelsim仿真波形查看:
3.3.分频器应用实例
以xilinx7系列实现一个点灯程序;输入时钟差分100M LVPECL,1HZ点灯,并且实现4分频25M,两种方式实现;
module light(
input wire sysclk_p,
input wire sysclk_n,//100M LVPECL
input CPU_SPI_CS3_rest_n,//100M
output wire clk_debug,
output reg CVP_RUN_LED
);
parameter [25:0] clk_100m_1hz_div = 26'd50000000;
reg[25:0] clk_100m_1hz_div ;
/*********************************差分转单端**************************************
wire sysclk temp;
wire sysclk;
IBUFDS sys_clk_IBUFDS_inst (
.0(sysclk_temp), // Buffer output
.I(sysclk_p),// Diff_p buffer input (connect directly to top-le
.IB(sysclk_n) // Diff n buffer input (connect directly to top-lev);
BUFG u_BUFG_inst(
.0(sysclk),// 1-bit output: Clock output
.I(sysclk temp) // 1-bit input: Clock input
);
/****************************************************************************
/*********************************点灯**************************************
always@(posedge sysclk or negedge CPU_SPI_cs3_rest_n)
begin
if(!CPU_SPI_cs3_rest_n)
begin
clk_100m_1hz_cnt <= 26'h0;
end
else if((clk_100m_1hz_cnt==clk_100m_1hz_div))
begin
clk_100m_1hz_cnt <=26'h0;
end
else
begin
clk_100m_1hz_cnt <= clk_100m_1hz_cnt +1b1:
end
end
alwayse (posedge sysclk or negedge CPU_SPI_cs3_rest_n)
begin
if(!CPU_SPI_cs3_rest_n)
begin
// CVP_RUN_LED <= 1'b1;
CVP_RUN_LED <= 1'b0:
end
else if((clk_100m_1hz_cnt==clk_100m_1hz_div))
beqin
CVP_RUN_LED <~CVP_RUN_LED:
end
else
begin
CVP_RUN_LED <= CVP_RUN_LED:
end
end
/***********************************************************************
/********************************100M4分频 ***************************************
//25M DIV method1
reg [3:0] div_25m_cnt;
wire sys_clk 25m;
always@(posedge sysclk or negedge CPU_SPI_cs3_rest_n)
begin
if(!CPU_SPI_cs3_rest_n)
begin
div_25m_cnt <= 2'b00;
end
else
begin
div_25m_cnt <=div_25m_cnt +1'b1;
end
end
assign sys_clk_25m =div_25m_cnt[1];
assign clk debug =sys_clk_25m;
/***********************************************************************
/*******************************100M4分频****************************************
//25M DIV method2
reg [3:0] div_25m_cnt;
reg sys_clk 25m;
always@(posedge sysclk or negedge CPU_SPI_cs3_rest_n)
begin
if(!CPU_SPI_cs3_rest_n)
begin
div_25m_cnt <= 3'b000;
end
else if(div_25m_cnt==1)
begin div_25m_cnt=0;
sys_clk_25m <=~ sys_clk_25m;
end
else
begin
div_25m_cnt <=div_25m_cnt +1'b1;
end
end
assign clk_debug =sys_clk_25m;
/***********************************************************************