FPGA 07 基础 多功能定时器模块_FPGA

FPGA 07 基础 多功能定时器模块

FPGA 07 基础 多功能定时器模块_FPGA_02

模块名称: timer

主要功能 :通过配置输入端口有3个重要参数:来设置定时器模块实现 一次计数(定时)还是循环计数(定时)功能

​ CNT_ENABLE : 定时器使能开关(一次计数时,发送一个时钟周期的高电平脉冲信号,循环定时时,直接拉高)

​ MODE : =0 单次定时器计数 =1 循环定时计数

​ CNT_ARR[31:0] : 计数器重装载值,每次计数器的计数值计数到该位置以后,重新开始计数

​ 输出有两个信号:

​ Full_flag : 计数器计满标志信号.

​ ARR[31:0] : 实时(当前)计数器的计数值

实现(设计)流程:

​ 1、使用一个always 语句,判断是在 单次计数模式 还是循环计数模式,判断进入使能模式下后,

在循环模式下:判断是否 CNT_ENABLE =1 ,是的条件下,进行正常计数,到达最大值是计数器清零,重新开始计数。

在单次计数模式下: 我们为了让计数器进行单次的计数,设置了一个计数寄存器标志信号(oneshot),当标志信号位 1 时,计数器正常机器,计数器清零保持该状态。

​ 2、标志信号(oneshot)使用一个always块语句来判断,当MODE =0 时,如果CNT_ENABLE =1 ,设置 oneshot =1 ,如果计数器但前值==(CNT_ARR[31:0] 定时装载值-1),oneshot =0 ,停止计数,其余时刻保持该状态即可。

优势: 一个模块可以实现两个功能,模块复用的时候可以更加的方便。

  • timer.v 文件
//通用定时器模块
//描述:
//通过定义 timer 里面的 input 的数值
// 得到 output 里面的数值,这样就可以得到我们想要的输出(2个 分别是 CNT_NOW 和 Full_Flag 两个输出信号)
// 时钟和复位信号是输入信号,一般由系统给定
// CNT_ARR、MODE、CNT_ENABLE 可以自己给定固定值或者通过外部的输入给定一个值(信号)
module timer(
	Clk ,  	//时钟
	Rst_n , 	//复位信号
	
	CNT_ARR , //定时器重装载值(类似与32的重装载值)
	MODE  ,	// Mode : 1  循环定时   Mode : 0 单次定时
	
	CNT_ENABLE , //CNT_ENABLE : 1 定时器计数器使能,开始计数
					 //CNT_ENABLE : 0 定时器计数不使能,停止计数
 	
	CNT_NOW , 	//实时定时器计数器
	
	Full_Flag   //计数完成标志位
);

//  定义:
	input Clk ;
	input Rst_n;
	
	input [31:0]CNT_ARR ;  //通用32位定时计数器
	input MODE 	;
	input CNT_ENABLE;
	
	output [31:0]CNT_NOW ; //当前32位定时计数器的值
	output reg Full_Flag ; //计数完成标志位
	
	
	//自己模块定义的信号
	reg [31:0]cnt; 	//定义一个32位的计数器
	reg oneshot ; 		//定义一个 单次计数值计满 触发信号
	wire Full_Flag_r; //Full_Flag_r 用于延时Full_Flag 的一个周期
	
	assign CNT_NOW = cnt;  //定时器的值
	assign Full_Flag_r = (CNT_NOW == CNT_ARR - 1)?1'b1:1'b0;

	//第1个 always 块
	always@(posedge Clk)
		Full_Flag <= Full_Flag_r;
		
	//第2个 always 块
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)   //复位信号到来,数据清零(qingling)
		cnt <=0;
	else if(MODE == 1'b1)begin	//判断是否是循环模式
		if((CNT_ENABLE == 1'b1) && (cnt < CNT_ARR)) //判断CNT_ENABLE 是否启动,且计数值是否小于重装载值
			cnt <= cnt + 1'b1;		//cnt++
		else								//否则数据清零
			cnt <= 0;
	end
	else if(!MODE)begin	//判断是否是单次计数模式
		if(oneshot)			//oneshot信号为1,表示满足一次计数条件
			cnt <= cnt + 1'b1;
		else
			cnt <= 0;
	end
	//第3个 always 块
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)	//复位信号清零
		oneshot <= 1'b0;
	else if(!MODE)
	begin			//判断是在一次计数模式下
		if(CNT_ENABLE == 1'b1)	//判断CNT_ENABLE 是否启动
			oneshot <= 1'b1;
		else if(CNT_NOW == CNT_ARR - 1) //判断计数值是否等于重转载值
			oneshot <= 1'b0;
			else	//保持不变
			oneshot <= oneshot;
	end
	else//在循环模式下,oneshot =0 ;
		oneshot <= 1'b0;
		
		
endmodule

 
  • timer_tb.v 文件
`timescale 1ns/1ns
`define clk_period 20
// 定时器定时模块测试源文件
module timer_tb; // 定义的测试模块的名称,一般命名 是后面加 _tb,表示这是测试模块

//  测试模块的输入输出 定义: input 类型 -->  reg 类型替换
//  output 类型 -->  wire 类型替换
	reg Clk ;
	reg Rst_n;

	reg [31:0]CNT_ARR ;  //通用32位定时计数器
	reg MODE 	;
	reg CNT_ENABLE;
	
	wire [31:0]CNT_NOW ; //当前32位定时计数器的值
	wire Full_Flag ; //计数完成标志位
	
timer timer0(
	.Clk(Clk) ,  					//时钟
	.Rst_n(Rst_n) , 				//复位信号
	.CNT_ARR(CNT_ARR) , 			//定时器重装载值(类似与32的重装载值)
	.MODE(MODE)  ,					// Mode : 1  循环定时   Mode : 0 单次定时
	.CNT_ENABLE(CNT_ENABLE) , 	//CNT_ENABLE : 1 定时器计数器使能,开始计数 //CNT_ENABLE : 0 定时器计数不使能,停止计数			
	.CNT_NOW(CNT_NOW) , 			//实时定时器计数器
	.Full_Flag(Full_Flag)   	//计数完成标志位
);

/*********** 定义初始化测试信号 ************/
	initial Clk = 1;	//定义时钟信号
	always #(`clk_period/2) Clk = ~Clk;
	
	initial begin  //执行一次,叫 initial  加入 begin
		//初始化所有输入信号
		Rst_n = 0;	
		CNT_ARR = 0;
		MODE = 0;
		CNT_ENABLE = 0;
		#(`clk_period*20 + 1);
		//复位信号 		Rst_n = 1; 模块正式开始工作
		Rst_n = 1;
		#(`clk_period*20);
		
		
		//设置预设值为1000,模式为循环定时模式
		CNT_ARR = 1000;
		MODE = 1;
		#(`clk_period*20); //设置为循环模式,延时20个时钟周期 
		CNT_ENABLE = 1;	 //开始启动计数定时器
		#(`clk_period*12000);
		CNT_ENABLE = 0;	//关闭计数定时器
		#(`clk_period*20);
		
		//设置预设值为600,模式为循环定时模式
		CNT_ARR = 600;
		MODE = 1;
		#(`clk_period*20);
		CNT_ENABLE = 1;
		#(`clk_period*8000);
		CNT_ENABLE = 0;
		#(`clk_period*20);	
		
		//设置预设值为1000,模式为单次定时模式
		CNT_ARR = 1000;
		MODE = 0;
		#(`clk_period*20); // CNT_ENABLE = 1; #(`clk_period)	CNT_ENABLE = 0; 表示给定的是一个脉冲信号,进入的是单次计数模式
		CNT_ENABLE = 1;
		#(`clk_period);
		CNT_ENABLE = 0;
		#(`clk_period*1200);
		
		//设置预设值为600,模式为单次定时模式
		CNT_ARR = 600;
		MODE = 0;
		#(`clk_period*20); // CNT_ENABLE = 1; #(`clk_period)	CNT_ENABLE = 0; 表示给定的是一个脉冲信号,进入的是单次计数模式
		CNT_ENABLE = 1;
		#(`clk_period);
		CNT_ENABLE = 0;
		#(`clk_period*1200);
		
		$stop;
	
	end

endmodule