verilog之定时计数--任意分频、任意宽度脉冲、复位信号产生、置位/清零、PWM波形

verilog之定时计数--任意分频、任意宽度脉冲、复位信号产生、置位/清零、PWM波形

Timer的重要性

Timer是数字电路的基础,所有器件都是在时钟节拍下工作,由于时钟节拍速率高,FPGA内部可以达到100M,有些低速的设备就需要进行分频处理,这就产生了计数的需求。不同的功能模块速率不同,自然也就需要不同的计数器。

分频器

分频器的关键是计算出源时钟频率与分频后的时钟频率的倍数关系,倍数除以2 就是计数最大值cnt。

module counter(Clk,Rst_n,Low_clock);

	input Clk;	//系统时钟
	input Rst_n;	//全局复位,低电平复位
	output reg Low_clock;	//Low_clock输出
	reg [14:0]cnt;	//定义计数器寄存器

//计数器计数进程	
	always@(posedge Clk or negedge Rst_n)
	if(Rst_n == 1'b0)
		cnt <= 15'd0;
	else if(cnt == 15'd24_999)
		cnt <= 15'd0;
	else
		cnt <= cnt + 1'b1;

//Low_clock输出控制进程
	always@(posedge Clk or negedge Rst_n)
	if(Rst_n == 1'b0)
		Low_clock<= 1'b1;
	else if(cnt == 15'd24_999)
		Low_clock<= ~Low_clock;
	else
		Low_clock<= Low_clock;
endmodule

任意时间长度复位信号的产生

在CPU系统中,有多个电压轨,主电源供电后,需要控制不同电压轨的上电时序,已确保系统正常启动。有时候为了保证供电的稳定,需要控制启动时CPU的复位时间。
设计目标就是在主电源上电后的多少ms内输出一个低电平,此后信号保持为高电平状态。


module rst_delay125ms(	
			cpld_16MHz,
			rst_pld_n_delay
);
	
input	cpld_16MHz;				
output rst_pld_n_delay ;

reg	[24:0]delay_125ms_cunt = 25'b0; //计数器上电赋初始值
reg	delay_125ms = 1'b0;

			
//power_on 10ms delay generator
always@(posedge cpld_16MHz)
	begin
		if (delay_10ms_cunt == 25'd2_000_000) //改变cunt的值即可实现任意时间长度控制
			begin
				delay_125ms_cunt <= delay_125ms_cunt;
				delay_125ms <= 1'b1;
			end
		else
			begin
				delay_125ms_cunt <= delay_125ms_cunt +1;
				delay_125ms <= 1'b0;
			end
	end

assign rst_pld_n_delay = delay_125ms? 1'b1: 1'b0;
endmodule

任意宽度脉冲----展宽

该功能实现把单个时钟周期信号展宽为需要的时钟宽度信号,一般应用在片选、使能等信号上。

此例用到了参数定义语句,方便修改需要展宽的时间宽度,
仿真中为了便于观察,把此参数设为了16.
parameter CNT_MAX = 25’d8_000; //0.5ms


module rst_delay(Clk,Rst_n,Dog_rst_i,Dog_rst_delay_o);

	input Clk;	//系统时钟,50M
	input Rst_n;	//全局复位,低电平复位
	input Dog_rst_i;
	
	output Dog_rst_delay_o;	
	
	reg [24:0]cnt;	//定义计数器寄存器
	reg EN;
	parameter CNT_MAX = 25'd8_000;  //0.5ms

	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		EN  <= 1'b0;
	else if(Dog_rst_i)
		EN  <= 1'b1;
	else if(cnt == CNT_MAX)
		EN  <= 1'b0;
	else
		EN  <= EN;

assign Dog_rst_delay_o = EN;	

//计数器计数进程	
	always@(posedge Clk or negedge Rst_n )
	if(Rst_n == 1'b0 )
		cnt <= 25'd0;
	else if(cnt == CNT_MAX)
		cnt <= 25'd0;
	else if(EN)
		cnt <= cnt + 1'b1;
		else
		cnt <= cnt;
endmodule

仿真图
在这里插入图片描述

任意宽度脉冲----压缩

脉宽展宽仅限于输入脉冲的宽度较窄的情况,如果输入信号是一个跳变,比如从低电平变到高电平,我们想通过此事件触发一个特定宽度的脉冲,那么只要把上面的程序稍作修改即可,计数器计数开始的条件改为输入脉冲,计到需要的脉宽后即停止,输出脉冲的起始时刻可以通过判断计数器的某一位来实现。

module rst_delay(Clk,Rst_n,Dog_rst_i,Dog_rst_delay_o);

	input Clk;	//系统时钟,50M
	input Rst_n;	//全局复位,低电平复位
	input Dog_rst_i;
	
	output Dog_rst_delay_o;	
	
	reg [24:0]cnt;	//定义计数器寄存器
	reg EN;
	parameter CNT_MAX = 25'd16;  //0.5ms

	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		EN  <= 1'b0;
	else if(cnt[1:0]==2'b11)  //计数器的某位作为条件触发输出跳变
		EN  <= 1'b1;
	else if(cnt == CNT_MAX)  //CNT_MAX 决定输出脉冲的宽度
		EN  <= 1'b0;
	else
		EN  <= EN;

assign Dog_rst_delay_o = EN;	
	

//计数器计数进程	
	always@(posedge Clk or negedge Rst_n )
	if(Rst_n == 1'b0 )
		cnt <= 25'd0;
	else if(cnt == CNT_MAX)
//		cnt <= 25'd0;
		cnt <= cnt;
//	else if(EN)
	else if(Dog_rst_i)   //输入跳变触发计数
		cnt <= cnt + 1'b1;
//		else
//		cnt <= cnt;


endmodule

仿真图如下:
在这里插入图片描述

置位/清零 SET/RESET

该功能主要实现两个信号控制另外一个信号,比如看门狗的打开、关闭,set/reset功能。

module rst_delay(
	Clk,
	Rst_n,
	SFTDog_open,
	SFTDog_close,
	SFTDog_en
	);

	input Clk;
	input Rst_n;	//全局复位,低电平复位
	input SFTDog_open; // 打开
	input SFTDog_close; //关闭
	output reg SFTDog_en;//功能输出
	
always@(posedge Clk )
	begin
		if(!Rst_n )
			SFTDog_en<= 1'b0;
		else if(SFTDog_open)
			SFTDog_en<= 1'b1;
		else if(!SFTDog_close)
			SFTDog_en<= 1'b0;

	end
endmodule

仿真图
在这里插入图片描述

PWM

PWM波形在很多领域都可以用得到,比如屏幕背光亮度控制、运动控制、开关电源设计等等领域。在下面的代码中首先对输入时钟进行分频,产生所需要的pwm频率;其次对分频后的时钟进行上升沿采样,采样的原理就是利用两个寄存器,分别缓冲分频信号,通过
assign pos_ege = tmp0_div_clk & !tmp1_div_clk;
可以实现上升沿的判断。
上升沿抓到后,启动pwm脉宽计数,一直计到所需要的脉宽。

 module PWM(Clk,Rst_n,pwm);



     input Clk;    //系统时钟 50MHz 20ns

     input Rst_n;    //全局复位,低电平复位

     

     output reg pwm;    //led输出

     reg div_clk;

     reg [24:0]cnt;    //定义计数器寄存器
	  reg [24:0]pwm_cnt;    //定义计数器寄存器
	  
	  reg tmp0_div_clk,tmp1_div_clk;
	  wire pos_ege;

     

     parameter CNT_MAX = 25'd2_499_999;  // 0.05s  通过修改pwm_MAX,实现不同频率。

	  parameter pwm_MAX = 25'd100;  //  0 < pwm_MAX < 2* CNT_MAX , 通过修改pwm_MAX,实现不同占空比。

 //分频计数器计数进程    

     always@(posedge Clk or negedge Rst_n)

     if(Rst_n == 1'b0)

         cnt <= 25'd0;

     else if(cnt == CNT_MAX)

         cnt <= 25'd0;

     else

         cnt <= cnt + 1'b1;



 //div clock 输出控制进程

     always@(posedge Clk or negedge Rst_n)

     if(Rst_n == 1'b0)

         div_clk <= 1'b0;

     else if(cnt == CNT_MAX)

         div_clk <= ~div_clk;
			
//=========================================================

//       posedge detect
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		tmp0_div_clk <= 1'b0;
		tmp1_div_clk <= 1'b0;	
	end
	else begin
		tmp0_div_clk <= div_clk;
		tmp1_div_clk <= tmp0_div_clk;	
	end
	
	assign pos_ege = tmp0_div_clk & !tmp1_div_clk;

			
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		pwm  <= 1'b0;
	else if(pos_ege)
		pwm  <= 1'b1;
	else if(pwm_cnt == pwm_MAX)
		pwm  <= 1'b0;



//脉宽计数器计数进程	
	always@(posedge Clk or negedge Rst_n )
	if(Rst_n == 1'b0 )
		pwm_cnt <= 25'd0;
	else if(pwm_cnt == pwm_MAX)
		pwm_cnt <= 25'd0;
	else if(pwm)
		pwm_cnt <= pwm_cnt + 1'b1;



 endmodule
 

猜你喜欢

转载自blog.csdn.net/malcolm_110/article/details/103984355
今日推荐