Veirlog 学习记录(6),数字频率计的设计与实现

FPGA的课程的大作业,我们选的是数字频率计设计。下面分享一下代码,还有工程文件,还有自己写的论文(里面会有更加详细的介绍),希望可以对你有所启发。

工程文件github地址

开发环境:Vivado 2015.4+Modelsim(仅用于仿真波形)
开发板:赛灵思公司 xc7a100tcsg324-1

总体设计要求:

  • 可测量脉冲信号的频率
  • 被测信号由100MHz的系统时钟分频获得,频率为学号*1000 Hz
  • 测量结果在6位数码管上显示,高位若是零则不显示该位
  • 采用连续测量方式,每4秒为1个周期,其中1秒用于测量,3秒用于显示

总体设计框图:

在这里插入图片描述

子模块设计:

- 分频模块:

结构图:
在这里插入图片描述代码如下:

module div(
    input clk_100mhz, //系统给定的时钟频率
    output clk_190hz, //数码管的动态扫描频率
    output reg clk_1Hz, //控制模块的驱动频率
    output reg fin  //输出待测试信号的频率
    );
	reg [9:0] cnt0;
	reg [30:0] cnt;
	reg [18:0] cnt1;
	
	always @(posedge clk_100mhz)
		cnt1 = cnt1 + 1;
	assign clk_190hz = cnt1[18];
	always @(posedge clk_100mhz)
		if(cnt == 50000000) begin
			cnt = 0;
			clk_1Hz = ~clk_1Hz;
		    end
		else
			cnt = cnt + 1;
	always @(posedge clk_100mhz)
		if(cnt0 == 499) begin  //生成的测试信号的频率为100KHz
			cnt0 = 0;
			fin = ~fin;
		end
		else
			cnt0 = cnt0 + 1;

endmodule

被测频率本来要求是学号*1000Hz,但是我的学号无法被整除,所以无法度量频率计的的精度,更无法进行误差分析。所以才选取了100KHz作为测试频率。

- 控制模块

结构图:
在这里插入图片描述
code:

module control(clk_1Hz, rst, count_en, latch_en, clear);  
  input clk_1Hz;  
  input rst;  //复位信号
  output count_en;  //计数使能
  output latch_en;  //锁存使能
  output clear;  //清零信号
  reg [2:0] state; //状态信号,用于控制各种使能信号  
  reg count_en;  
  reg latch_en;  
  reg clear;
       
  always @(posedge clk_1Hz or negedge rst)  
  if(!rst)   //复位信号有效  
    begin    //各种使能信号清零  
      state <= 3'b000;  
      count_en <= 1'b0;  
      latch_en <=1'b0;  
      clear <= 1'b0;  
    end  
     else    //遇到基准信号的下一个上升沿,状态变化一次,每次变化后状态持续1s  
    begin
      case(state)  
        3'b000:   
            begin //第一个上升沿到达,开始计数,计数1个基准信号周期内待测信号的上升沿个数,此个数即为待测信号的频率  
            count_en <= 1'b1;  //计数使能信号有效  
            latch_en <= 1'b0;  
            clear <= 1'b0;  
            state <= 3'b001;  
          end  
        3'b001:  
          begin  //第二个上升沿到达,计数完成,锁存使能信号有效,测得频率锁存至锁存器中  
            count_en <= 1'b0;  
            latch_en <=1'b1;  
            clear <= 1'b0;  
            state <= 3'b010;  
          end
        3'b010:  
          begin  //第三个上升沿到达,计数完成,锁存使能信号有效,测得频率锁存至锁存器中  
            count_en <= 1'b0;  
            latch_en <=1'b1;  
            clear <= 1'b0;  
            state <= 3'b011;  
          end
        3'b011:  
          begin  //第四个上升沿到达,计数完成,锁存使能信号有效,测得频率锁存至锁存器中  
            count_en <= 1'b0;  
            latch_en <=1'b1;  
            clear <= 1'b0;  
            state <= 3'b100;  
          end
        3'b100:   
          begin //第五个上升沿到达,清零使能信号有效,计数器清零,为下一次计数做准备  
            count_en <= 1'b0;
            clear <= 1'b1;   
            latch_en <=1'b1;   
            state <= 3'b000; //状态清零,进入下一次测量  
          end  
        default:  
          begin  
            count_en <= 1'b0;  
            latch_en <=1'b0;  
            clear <= 1'b0;  
            state <= 3'b000;  
          end     
      endcase        
    end  
    
    
endmodule

- 计数模块

结构图:
在这里插入图片描述
code:

module counter_10(en_in, rst, clear, fin, en_out, q);  
  input en_in; //输入使能信号  
  input rst;   //复位信号  
  input clear; //清零信号  
  input fin;   //待测信号  
  output en_out; //输出使能,用于控制下一个计数器的状态,当输出使能有效时,下一个模10计数器计数加1  
  output [3:0] q; //计数器的输出,4位BCD码输出  
    
  reg en_out;  
  reg [3:0] q;  
    
  always@ (posedge fin or negedge rst) //输入待测信号的上升沿作为敏感信号  
  if(!rst) //复位信号有效,计数器输出清零  
      begin  
        en_out <= 1'b0;  
        q <= 4'b0;  
      end  
    else if(en_in) //进位输入使能信号有效  
      begin  
        if(q == 4'b1001) //若q = 4'b1001的话,q清零,同时进位输出使能有效,即en_out 赋值为1'b1  
          begin  
            q <= 4'b0;  
            en_out <= 1'b1;  
          end  
             else //若q未达到4'b1001时,每到达待测信号的一个上升沿,q加1,同时输出进位清零  
          begin  
            q <= q + 1'b1;  
            en_out <=1'b0;  
          end  
      end   
    else if(clear) //若清零信号有效,计数器清零,用于为下一次测量准备  
      begin  
        q <= 4'b0;  
        en_out <= 1'b0;  
      end  
    else  
    begin  
    q <= q;  
    en_out <=1'b0;  
    end   
    
endmodule

锁存模块

结构图:
在这里插入图片描述
code:

module latch(clk_1Hz, latch_en, rst, q0, q1, q2, q3, q4, q5, q6, q7,  
            d0, d1, d2, d3, d4, d5, d6, d7);            
  input clk_1Hz, latch_en, rst;  
  input[3:0] q0, q1, q2, q3, q4, q5, q6, q7;  
  output[3:0] d0, d1, d2, d3, d4, d5, d6, d7;  
  reg[3:0] d0, d1, d2, d3, d4, d5, d6, d7;  
  always@ (posedge clk_1Hz or negedge rst)  
  if(!rst) //复位信号有效时输出清零  
    begin  
      d0 <= 4'b0; d1 <= 4'b0; d2 <= 4'b0; d3 <= 4'b0; d4 <= 4'b0;  
      d5 <= 4'b0; d6 <= 4'b0; d7 <= 4'b0;  
    end  
  else if(latch_en) //锁存信号有效时,将计数器的输出信号锁存至锁存器  
    begin  
      d0 <= q0; d1 <= q1; d2 <= q2; d3 <= q3; d4 <= q4;  
      d5 <= q5; d6 <= q6; d7 <= q7;  
    end  
     else  //上面两种情况均未发生时,输入不变  
    begin  
      d0 <= d0; d1 <= d1; d2 <= d2; d3 <= d3; d4 <= d4;  
      d5 <= d5; d6 <= d6; d7 <= d7;  
    end  
  
endmodule

显示模块

结构图:
在这里插入图片描述
code:

module IP_seg_disp(
    input clk_190hz,
    input [3:0] d0,d1,d2,d3,d4,d5,d6,d7
    output reg [7:0] duan,
    output reg [7:0] wei
    );

    reg [3:0] disp;
    reg [2:0] smg_ctl;
    
    always @ ( posedge clk_190hz)
        smg_ctl = smg_ctl + 1'b1;
	 always @ (*)
        case ( smg_ctl )
        3'b000:begin
            wei = 8'b11111110;
            disp = d0 [3:0];
        end
        3'b001:begin
            wei = 8'b11111101;
            disp = d1 [3:0];
        end
        3'b010:begin
            wei = 8'b11111011;
            disp = d2 [3:0];
        end
        3'b011:begin
            wei = 8'b11110111;
            disp = d3 [3:0];
        end
        3'b100:begin
            wei = 8'b11101111;
            disp = d4 [3:0];
        end
        3'b101:begin
            wei = 8'b11011111;
            disp = d5 [3:0];
         end
        3'b110:begin
            wei = 8'b10111111;
            disp = d6 [3:0];
            if( disp==0 ) //如果高位数值为0,则不显示该位
               disp <=4'b1111;
            end
        3'b111:begin
            wei = 8'b01111111;
            disp = d7 [3:0];
            if( disp==0 )
                disp <=4'b1111
        end          
        default:;
        endcase

    always @ ( * )
        case (disp)
        4'b0000:duan = 8'b11000000;
        4'b0001:duan = 8'b11111001;
        4'b0010:duan = 8'b10100100;
        4'b0011:duan = 8'b10110000;
        4'b0100:duan = 8'b10011001;
        4'b0101:duan = 8'b10010010;
        4'b0110:duan = 8'b10000010;
        4'b0111:duan = 8'b11111000;
        4'b1000:duan = 8'b10000000;
        4'b1001:duan = 8'b10010000;
        4'b1010:duan = 8'b10001000;
        4'b1011:duan = 8'b10000011;
        4'b1100:duan = 8'b11000110;
        4'b1101:duan = 8'b10100001;
        4'b1110:duan = 8'b10000110;
        4'b1111:duan = 8'b11111111;
        default:duan = 8'b11000000; 
        endcase
endmodule

顶层模块

code:

module freDetect(clk_100mhz,rst,duan,wei);  
  input clk_100mhz;  
  input rst; //复位信号  
  output [7:0] duan; 
  output [7:0] wei;  
  wire[3:0] q0, q1, q2, q3, q4, q5, q6, q7;   //中间数据  
  wire[3:0] d0, d1, d2, d3, d4, d5, d6, d7;
  wire fin;
  wire clk_1Hz;
  wire clk_190hz;
//分频模块实例
  div u_div( 
             .clk_1Hz(clk_1Hz),
             .clk_190hz(clk_190hz),
             .clk_100mhz(clk_100mhz),
             .fin(fin)
                ); 
  //显示模块实例             
  IP_seg_disp u_IP_seg_disp( .clk_190hz(clk_190hz), .d0(d0), 
                           .d1(d1),  .d2(d2),  .d3(d3), .d4(d4), 
                           .d5(d5),  .d6(d6),  .d7(d7),
                           .duan(duan), .wei(wei) 
);
  //控制模块实例  
  control u_control(.clk_1Hz(clk_1Hz), .rst(rst), .count_en(count_en),  
                    .latch_en(latch_en), .clear(clear));  
    
  //计数器模块实例  
  counter_10 counter0(.en_in(count_en), .clear(clear), .rst(rst),  
                      .fin(fin), .en_out(en_out0), .q(q0));  
  counter_10 counter1(.en_in(en_out0), .clear(clear), .rst(rst),  
                      .fin(fin), .en_out(en_out1), .q(q1));  
  counter_10 counter2(.en_in(en_out1), .clear(clear), .rst(rst),  
                      .fin(fin), .en_out(en_out2), .q(q2));  
  counter_10 counter3(.en_in(en_out2), .clear(clear), .rst(rst),  
                      .fin(fin), .en_out(en_out3), .q(q3));  
  counter_10 counter4(.en_in(en_out3), .clear(clear), .rst(rst),  
                      .fin(fin), .en_out(en_out4), .q(q4));  
  counter_10 counter5(.en_in(en_out4), .clear(clear), .rst(rst),  
                      .fin(fin), .en_out(en_out5), .q(q5));  
  counter_10 counter6(.en_in(en_out5), .clear(clear), .rst(rst),  
                      .fin(fin), .en_out(en_out6), .q(q6));  
  counter_10 counter7(.en_in(en_out6), .clear(clear), .rst(rst),  
                      .fin(fin), .en_out(en_out7), .q(q7));  
    
  //锁存器模块实例  
  latch u_latch(.clk_1Hz(clk_1Hz), .rst(rst), .latch_en(latch_en),  
                .q0(q0), .q1(q1), .q2(q2), .q3(q3), .q4(q4), .q5(q5),  
                .q6(q6), .q7(q7), .d0(d0), .d1(d1), .d2(d2), .d3(d3),  
                .d4(d4), .d5(d5), .d6(d6), .d7(d7));  
     
endmodule

测试文件:

module freDetect_tb;  
  parameter CLK_1HZ_DELAY = 50000000; //用于生成1Hz基准信号  
  parameter FIN_DELAY = 500;     //用于生成100KHz待测信号  
  reg clk_1Hz;  
  reg fin;  
  reg rst;  //复位
  wire[3:0] d0, d1, d2, d3, d4, d5, d6, d7;  
  initial  
    begin  
      rst =1'b0;  
      #1 rst = 1'b1;  
    end 
  initial  
    begin  
      fin = 1'b0;  
      forever  
      #FIN_DELAY fin = ~fin;  
    end 
  initial  
    begin  
      clk_1Hz = 1'b0;  
      forever  
      #CLK_1HZ_DELAY clk_1Hz = ~clk_1Hz;  
    end
    freDetect freDetect1(.clk_1Hz(clk_1Hz), .rst(rst), .fin(fin),  
    .d0(d0), .d1(d1), .d2(d2), .d3(d3), .d4(d4), .d5(d5), .d6(d6), .d7(d7));  
endmodule

波形仿真结果如图所示:
在这里插入图片描述
实验结果:

两张图片分别为 测量计数时和复位时和显示计数时:
测量计数时和复位时的显示显示计数时

我也写了几篇关于Veirlog的文章,感兴趣的同学可以去看看。该模块链接如下:
https://blog.csdn.net/weixin_43877139/article/category/8778400

©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页