FPGA学习总结4:计数器/分频器设计实现

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; 

/***********************************************************************

  • 2
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FPGA分频器设计主要分为两种方式:基于计数器分频器和基于查找表的分频器。 基于计数器分频器:这种分频器使用FPGA内部的计数器实现分频功能。首先需要确定分频比例,然后将计数器的初始值设置为所需的分频比例减1,每当计数器计数到0时,产生一个分频后的时钟信号。这种分频器具有简单、灵活的优点,但其最高分频率受到FPGA内部时钟频率的限制。 基于查找表的分频器:这种分频器使用FPGA内部的查找表实现分频功能。分频器的输入是一个时钟信号,输出是分频后的时钟信号。可以通过修改查找表的内容来实现不同的分频比例。这种分频器具有高速、低功耗的优点,但其实现较为复杂。 下面是一个基于计数器分频器的VHDL代码示例: ```vhdl library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity clock_divider is Port ( clk_in : in STD_LOGIC; clk_out : out STD_LOGIC); end clock_divider; architecture Behavioral of clock_divider is signal count : integer := 0; begin process(clk_in) begin if (rising_edge(clk_in)) then count <= count + 1; if (count = 100) then clk_out <= not clk_out; count <= 0; end if; end if; end process; end Behavioral; ``` 该代码实现了一个将输入时钟信号分频100倍的分频器。其中,计数器的初始值为0,每当计数器计数到99时,产生一个分频后的时钟信号,并将计数器清零。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值