跳转至

效果

video https://cdn.jsdmirror.com/gh/zikwq/Blog_Pic/7c9063c655c66e08db9fad2814949158.mp4

储备知识

  1. FFT IP核的调用。用来求出AD输入波形的峰峰值
  2. RAM、ROM IP核的调用,存储波形和文字信息
  3. VGA视频传输协议的时序设计
  4. DAC芯片的时序设计。DDS 信号发生器的设计,产生不同的测试波形
  5. PLL IP核的调用,产生不同频率的时钟
  6. Seg 6位数码管的动态驱动设计,显示频率信息

dds发生器的概述:

使用dac芯片实现一个dds信号发生器的方法,首先需要请阅读一下该芯片的精度,我用的是开发板自带的dac芯片,分辨率精度是8为,那么我是使用一个计数器,从0计数到255也就是2的8次方减一。当到达255的时候输出最高电压5v,当计数到0的时候,输出0v。以此类推实现一个dds信号发生器的锯齿波、三角波等简单的波形。 与此同时,还需要关注芯片支持的最高频率,对我们的系统时钟进行分频处理得到芯片输入时钟。再深一步就是考虑处理时序的建立时间、保持时间等,这些信息也是需要参考芯片手册的信息进行实现

adc芯片概述:

在使用adc设计一款电压显示器的时候。需要查看adc的芯片手册,看一下里面这款芯片的最高时钟频率是多少,再使用我们的FPGA系统时钟进行分频处理输出时钟信号连接到adc

因为fpga不擅长进行浮点数的运算,我们将采集的电压值根据芯片手册中介绍的这款芯片电压分辨率和我们的精度要求进行选择合适的倍数相乘,将浮点数转换成整数进行运算

例如adc的时钟信号是10mhz,单个时钟周期的时间是100ns,所以当我们实际连接到adc芯片的电压输入接口的时候,数值会在100ns变换一次,因为实际的电压信号不稳定,我们的读数会一直闪烁无法有效读取数值。这时候我们就要再fpga中设置一个取均值的方法,设置采集1024个点后取均值后再除以我们之前乘上的倍数就会得到真是的电压值。数据更新频率将会从100ns一个延长到100*1024ns一次,也就是102400ns即0.0001024s。

最后将数据转换成10进制数显示在seg数码管中,接下来我们设计的seg显示模块,这个才是实际中控制数据显示频率的部分,我们在这个模块中再次对时钟进行分频,通常得到一个时钟周期为1ms的时钟频率用来控制显示的频率。

程序

程序比较乱,没有进行优化,有时间去整理一下 数码管

module seg(
    input clk,
    input rst_n,
    input  [19:0] tenvalue,
    output reg [7:0] segdata,
    output reg [2:0] segcs
);

reg [24:0] count1ms;
reg [2:0] number = 3'b0;
reg clk1ms = 1'b0;

parameter sample=2'b00,
          display=2'b01;

//-----------数码管驱动时钟-----------
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        clk1ms <= 1'b0;
        count1ms <= 0;
    end else begin
        if (count1ms >= 25'd50000) begin // 1ms的计数器
            clk1ms <= ~clk1ms;
            count1ms <= 0;
        end else begin
            count1ms <= count1ms + 1'b1;
        end
    end
end

//-----------数码管译码-----------
function [7:0] leddata;
    input [3:0] datain;
    begin
        case (datain)
            4'd0: leddata = 8'b11000000; // 0
            4'd1: leddata = 8'b11111001; // 1
            4'd2: leddata = 8'b10100100; // 2
            4'd3: leddata = 8'b10110000; // 3
            4'd4: leddata = 8'b10011001; // 4
            4'd5: leddata = 8'b10010010; // 5
            4'd6: leddata = 8'b10000010; // 6
            4'd7: leddata = 8'b11111000; // 7
            4'd8: leddata = 8'b10000000; // 8
            4'd9: leddata = 8'b10010000; // 9
            4'd10: leddata = 8'b10111111; // -
            4'd11: leddata = 8'b01111111; // .
            default: leddata = 8'b11111111;
        endcase
    end
endfunction

//-----------数码管扫描-----------
always @(posedge clk1ms or negedge rst_n) begin
    if (!rst_n) begin
        number <= 3'd0;
    end else begin
        if (number == 3'd5) begin
            number <= 3'd0;
        end else begin
            number <= number + 1;
        end

        case (number)
            3'd0: begin
                segdata <= leddata(tenvalue % 10); // 个位
                segcs <= 3'b101;
            end
            3'd1: begin
                segdata <= leddata((tenvalue / 10) % 10); // 十位
                segcs <= 3'b100;
            end
            3'd2: begin
                segdata <= leddata((tenvalue / 100) % 10); // 百位
                segcs <= 3'b011;
            end 
            4'd3: begin
                segdata <= leddata((tenvalue / 1000) % 10); // 千位          
                segcs <= 3'b010;
            end
            4'd4: begin
                segdata <= leddata((tenvalue / 10000) % 10); // 万位         
                segcs <= 3'b001;
            end
            4'd5: begin
                segdata <= leddata((tenvalue / 100000) % 10); // 十万位           
                segcs <= 3'b000;
            end
            default: begin
                segdata <= 8'b11111111; // 或者其他默认值
                segcs <= 3'b111; // 或者其他默认值
            end
        endcase
    end
end

endmodule

`timescale  1ns/1ns

module  freq_meter_calc
(
    input   wire            sys_clk     ,   
    input   wire            sys_rst_n   ,   
    input   wire            clk_test    ,   //待检测时钟
    output  reg     [19:0]  freq            //待检测时钟频率
);
parameter   CNT_GATE_S_MAX  =   28'd37_499_999  ,   //软件闸门计数器计数最大值  1.5s
            CNT_RISE_MAX    =   28'd6_250_000   ;   //软件闸门拉高计数值,   1.25s
parameter   CLK_STAND_FREQ  =   28'd100_000_000 ;   //标准时钟时钟频率,    100Mhz

wire            clk_stand           ;   
wire            gate_a_flag_s       ;   
wire            gate_a_flag_t       ;   

reg     [27:0]  cnt_gate_s          ;   
reg             gate_s              ;   
reg             gate_a              ;   
reg             gate_a_test         ;   
reg             gate_a_stand        ;   
reg             gate_a_stand_reg    ;
reg             gate_a_test_reg     ;   
reg     [47:0]  cnt_clk_stand       ;   
reg     [47:0]  cnt_clk_stand_reg   ;   
reg     [47:0]  cnt_clk_test        ;   
reg     [47:0]  cnt_clk_test_reg    ;   
reg             calc_flag           ;   
reg     [63:0]  freq_reg            ;
reg             calc_flag_reg       ;

//step1:按照原理生成软件闸门、实际闸门
//cnt_gate_s:软件闸门计数器
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_gate_s  <=  28'd0;
    else    if(cnt_gate_s == CNT_GATE_S_MAX)
        cnt_gate_s  <=  28'd0;
    else
        cnt_gate_s  <=  cnt_gate_s + 1'b1;

//gate_s:软件闸门
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gate_s  <=  1'b0;
    else    if((cnt_gate_s>= CNT_RISE_MAX)
                && (cnt_gate_s <= (CNT_GATE_S_MAX - CNT_RISE_MAX)))
        gate_s  <=  1'b1;
    else
        gate_s  <=  1'b0;

//gate_a:实际闸门
always@(posedge clk_test or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gate_a  <=  1'b0;
    else
        gate_a  <=  gate_s;

//step2:得到待测信号的周期数 X
always@(posedge clk_test or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gate_a_test  <=  1'b0;
    else
        gate_a_test  <=  gate_a;        

//gate_a_test:实际闸门打一拍(待检测时钟下)
always@(posedge clk_test or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gate_a_test_reg <=  1'b0;
    else
        gate_a_test_reg <=  gate_a_test;    

//cnt_clk_test:待检测时钟周期计数器,计数实际闸门下待检测时钟周期数。  x++
always@(posedge clk_test or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_clk_test    <=  48'd0;
    else    if(gate_a_test == 1'b0)
        cnt_clk_test    <=  48'd0;
    else    if(gate_a_test == 1'b1)
        cnt_clk_test    <=  cnt_clk_test + 1'b1;

//gate_a_flag_t:实际闸门下降沿(待检测时钟下)
assign  gate_a_flag_t = ((gate_a_test_reg == 1'b1) && (gate_a_test == 1'b0))
                        ? 1'b1 : 1'b0;

//cnt_clk_test_reg:实际闸门下待检测时钟周期数,  x
always@(posedge clk_test or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_clk_test_reg   <=  32'd0;
    else    if(gate_a_flag_t == 1'b1)
        cnt_clk_test_reg   <=  cnt_clk_test;    

//step3:得到标准信号的周期数 y        
//使用PLL ipcore生成100Mhz信号
clk_gen clk_gen_inst
(
    .areset    (~sys_rst_n ),
    .inclk0  (sys_clk    ),

    .c0 (clk_stand  )
);  


//gate_a_stand:实际闸门打一拍(标准时钟下)
always@(posedge clk_stand or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gate_a_stand    <=  1'b0;
    else
        gate_a_stand    <=  gate_a_test;

always@(posedge clk_stand or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gate_a_stand_reg    <=  1'b0;
    else
        gate_a_stand_reg    <=  gate_a_stand;

//gate_a_flag_s:实际闸门下降沿(标准时钟下)
assign  gate_a_flag_s = ((gate_a_stand_reg == 1'b1) && (gate_a_stand == 1'b0))
                        ? 1'b1 : 1'b0;

//cnt_clk_stand:标准时钟周期计数器,计数实际闸门下标准时钟周期数。  y++
always@(posedge clk_stand or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_clk_stand   <=  48'd0;
    else    if(gate_a_stand == 1'b0)
        cnt_clk_stand   <=  48'd0;
    else    if(gate_a_stand == 1'b1)
        cnt_clk_stand   <=  cnt_clk_stand + 1'b1;

//cnt_clk_stand_reg:实际闸门下标志时钟周期数
always@(posedge clk_stand or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_clk_stand_reg   <=  32'd0;
    else    if(gate_a_flag_s == 1'b1)
        cnt_clk_stand_reg   <=  cnt_clk_stand;

//step4: 利用公式进行频率计算     
//calc_flag:待检测时钟时钟频率计算标志信号
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        calc_flag   <=  1'b0;
    else    if(cnt_gate_s == (CNT_GATE_S_MAX - 1'b1))
        calc_flag   <=  1'b1;
    else
        calc_flag   <=  1'b0;

//freq:待检测时钟信号时钟频率
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        freq_reg    <=  64'd0;
    else    if(calc_flag == 1'b1)
        freq_reg    <=  (CLK_STAND_FREQ * cnt_clk_test_reg / cnt_clk_stand_reg );    //   (100MHZ*X)/Y 

 //calc_flag_reg:待检测时钟频率输出标志信号
 always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        calc_flag_reg <= 1'b0;
    else
        calc_flag_reg <= calc_flag;

 //freq:待检测时钟信号时钟频率
 always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        freq <= 19'd0;
    else if(calc_flag_reg == 1'b1)
        freq <= (CLK_STAND_FREQ * cnt_clk_test_reg / (cnt_clk_stand_reg) );  

endmodule

按键控制模块,控制波形选择

`timescale  1ns/1ns
/////////////////////////////////////////////////////////////////////////
// Author        : EmbedFire
// Create Date   : 2019/07/10
// Module Name   : key_control
// Project Name  : top_dds
// Target Devices: Altera EP4CE10F17C8N
// Tool Versions : Quartus 13.0
// Description   : 按键控制模块,控制波形选择
// 
// Revision      : V1.0
// Additional Comments:
// 
// 实验平台: 野火_征途Pro_FPGA开发板
// 公司    : http://www.embedfire.com
// 论坛    : http://www.firebbs.cn
// 淘宝    : https://fire-stm32.taobao.com
////////////////////////////////////////////////////////////////////////

module  key_control
(
    input   wire            sys_clk     ,   //系统时钟,50MHz
    input   wire            sys_rst_n   ,   //复位信号,低电平有效
    input   wire    [3:0]   key         ,   //输入4位按键

    output  reg     [3:0]   wave_select     //输出波形选择

);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter   sin_wave    =   4'b0001,    //正弦波
            squ_wave    =   4'b0010,    //方波
            tri_wave    =   4'b0100,    //三角波
            saw_wave    =   4'b1000;    //锯齿波

parameter   CNT_MAX =   20'd999_999;    //计数器计数最大值

//wire  define
wire            key3    ;   //按键3
wire            key2    ;   //按键2
wire            key1    ;   //按键1
wire            key0    ;   //按键0





//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//wave:按键状态对应波形
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        wave_select   <=  4'b0000;
    else    if(key0 == 1'b1)
        wave_select   <=  sin_wave;
    else    if(key1 == 1'b1)
        wave_select   <=  squ_wave;// 锯齿波
    else    if(key2 == 1'b1)
        wave_select   <=  tri_wave;// 三角波
    else    if(key3 == 1'b1)
        wave_select   <=  saw_wave;
    else
        wave_select   <=  wave_select;

//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------- key_fifter_inst3 --------------
key_filter 
#(
    .CNT_MAX      (CNT_MAX  )       //计数器计数最大值
)
key_filter_inst3
(
    .sys_clk      (sys_clk  )   ,   //系统时钟50Mhz
    .sys_rst_n    (sys_rst_n)   ,   //全局复位
    .key_in       (key[3]   )   ,   //按键输入信号

    .key_flag     (key3     )       //按键消抖后标志信号
);

//------------- key_fifter_inst2 --------------
key_filter 
#(
    .CNT_MAX      (CNT_MAX  )       //计数器计数最大值
)
key_filter_inst2
(
    .sys_clk      (sys_clk  )   ,   //系统时钟50Mhz
    .sys_rst_n    (sys_rst_n)   ,   //全局复位
    .key_in       (key[2]   )   ,   //按键输入信号

    .key_flag     (key2     )       //按键消抖后标志信号
);

//------------- key_fifter_inst1 --------------
key_filter 
#(
    .CNT_MAX      (CNT_MAX  )       //计数器计数最大值
)
key_filter_inst1
(
    .sys_clk      (sys_clk  )   ,   //系统时钟50Mhz
    .sys_rst_n    (sys_rst_n)   ,   //全局复位
    .key_in       (key[1]   )   ,   //按键输入信号

    .key_flag     (key1     )       //按键消抖后标志信号
);

//------------- key_fifter_inst0 --------------
key_filter 
#(
    .CNT_MAX      (CNT_MAX  )       //计数器计数最大值
)
key_filter_inst0
(
    .sys_clk      (sys_clk  )   ,   //系统时钟50Mhz
    .sys_rst_n    (sys_rst_n)   ,   //全局复位
    .key_in       (key[0]   )   ,   //按键输入信号

    .key_flag     (key0     )       //按键消抖后标志信号
);

endmodule

dds发生器

module  dds
(
    input   wire            sys_clk     ,   //系统时钟,50MHz
    input   wire            sys_rst_n   ,   //复位信号,低电平有效
    input   wire    [3:0]   wave_select ,   //输出波形选择

    output  wire    [7:0]   data_out        //波形输出
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter   sin_wave    =   4'b0001     ,   //正弦波
            squ_wave    =   4'b0010     ,   //方波
            tri_wave    =   4'b0100     ,   //三角波
            saw_wave    =   4'b1000     ;   //锯齿波
parameter   FREQ_CTRL   =   32'd42949   ,   //相位累加器单次累加值
            PHASE_CTRL  =   12'd1024    ;   //相位偏移量

//reg   define
reg     [31:0]  fre_add     ;   //相位累加器
reg     [11:0]  rom_addr_reg;   //相位调制后的相位码
reg     [13:0]  rom_addr    ;   //ROM读地址

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//fre_add:相位累加器
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        fre_add <=  32'd0;
    else
        fre_add <=  fre_add + FREQ_CTRL;

//rom_addr:ROM读地址
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        begin
            rom_addr        <=  14'd0;
            rom_addr_reg    <=  11'd0;
        end
    else
    case(wave_select)
        sin_wave:
            begin
                rom_addr_reg    <=  fre_add[31:20] + PHASE_CTRL;
                rom_addr        <=  rom_addr_reg;
            end     //正弦波
        squ_wave:
            begin
                rom_addr_reg    <=  fre_add[31:20] + PHASE_CTRL;
                rom_addr        <=  rom_addr_reg + 14'd4096;
            end     //方波
        tri_wave:
            begin
                rom_addr_reg    <=  fre_add[31:20] + PHASE_CTRL;
                rom_addr        <=  rom_addr_reg + 14'd8192;
            end     //三角波
        saw_wave:
        begin
                rom_addr_reg    <=  fre_add[31:20] + PHASE_CTRL;
                rom_addr        <=  rom_addr_reg + 14'd12288;
            end     //锯齿波
        default:
            begin
                rom_addr_reg    <=  fre_add[31:20] + PHASE_CTRL;
                rom_addr        <=  rom_addr_reg;
            end     //正弦波
    endcase

//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------------------- rom_wave_inst ------------------------
rom_wave    rom_wave_inst
(
    .address    (rom_addr   ),  //ROM读地址
    .clock      (sys_clk    ),  //读时钟

    .q          (data_out   )   //读出波形数据
);

endmodule

按键消抖

`timescale  1ns/1ns
////////////////////////////////////////////////////////////////////////
// Author        : EmbedFire
// Create Date   : 2019/03/15
// Module Name   : key_filter
// Project Name  : top_dds
// Target Devices: Altera EP4CE10F17C8N
// Tool Versions : Quartus 13.0
// Description   : 按键消抖模块
//
// Revision      : V1.0
// Additional Comments:
// 
// 实验平台: 野火_征途Pro_FPGA开发板
// 公司    : http://www.embedfire.com
// 论坛    : http://www.firebbs.cn
// 淘宝    : https://fire-stm32.taobao.com
////////////////////////////////////////////////////////////////////////

module  key_filter
#(
    parameter CNT_MAX = 20'd999_999 //计数器计数最大值
)
(
    input   wire    sys_clk     ,   //系统时钟50Mhz
    input   wire    sys_rst_n   ,   //全局复位
    input   wire    key_in      ,   //按键输入信号

    output  reg     key_flag        //key_flag为1时表示消抖后检测到按键被按下
                                    //key_flag为0时表示没有检测到按键被按下
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//reg   define
reg     [19:0]  cnt_20ms    ;   //计数器

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//

//cnt_20ms:如果时钟的上升沿检测到外部按键输入的值为低电平时,计数器开始计数
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_20ms <= 20'b0;
    else    if(key_in == 1'b1)
        cnt_20ms <= 20'b0;
    else    if(cnt_20ms == CNT_MAX && key_in == 1'b0)
        cnt_20ms <= cnt_20ms;
    else
        cnt_20ms <= cnt_20ms + 1'b1;

//key_flag:当计数满20ms后产生按键有效标志位
//且key_flag在999_999时拉高,维持一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        key_flag <= 1'b0;
    else    if(cnt_20ms == CNT_MAX - 1'b1)
        key_flag <= 1'b1;
    else
        key_flag <= 1'b0;

endmodule

模拟输出

module serial_output
(
    input  wire       sys_clk    ,  // 系统时钟
    input  wire       sys_rst_n  ,  // 复位信号,低电平有效
    input  wire [7:0] dac_data   ,  // 8位并行数据输入
    output reg        serial_out     // 串行数据输出
);

// 寄存器和参数定义
reg [2:0] bit_count;       // 位计数器,用于追踪当前正在输出的位
reg [7:0] data_reg;        // 数据寄存器,用于暂存dac_data

// 时钟上升沿触发的逻辑
always @(posedge sys_clk or negedge sys_rst_n) begin
    if (!sys_rst_n) begin
        // 复位逻辑
        bit_count  <= 3'b0;
        data_reg   <= 8'b0;
        serial_out <= 1'b0;
    end else begin
        // 串行输出逻辑
        if (bit_count == 3'b111) begin
            // 如果所有位都已输出,则重新加载数据并重置计数器
            bit_count <= 3'b0;
            data_reg  <= dac_data;
        end else begin
            // 输出当前最高位,并将数据左移一位
            serial_out <= data_reg[7];
            data_reg   <= data_reg << 1;
            bit_count  <= bit_count + 1;
        end
    end
end

endmodule

tlc5620_driver

module tlc5620_driver
(
    input CLOCK_50,
    input RST_N,
    //
    input da_enable,
    input da_range, // 0, 1倍参考电压; 1, 2倍参考电压
    input [7:0] da0_data, // 0~255
    input [7:0] da1_data, // 0~255
    input [7:0] da2_data, // 0~255
    input [7:0] da3_data, // 0~255
    // 
    output reg SCK,
    output reg SDI,
    output reg LOAD
);

function integer log2(input integer n);
    integer i;
    for(i=0; 2**i <=n; i=i+1) log2=i+1;
endfunction

/**************************************
* 生成140ns的tick时钟
**************************************/
reg [log2(7):1]cnt_140ns;
always@(posedge CLOCK_50, negedge RST_N) 
    if(!RST_N) cnt_140ns <= 0;
    else begin
        if(cnt_140ns < 6) 
            cnt_140ns <= cnt_140ns + 1'b1;
        else cnt_140ns <= 0;
    end
wire tick_140ns = (cnt_140ns == 6) ? 1 : 0;

/**************************************
* 根据tick时钟生成da基准计数器
**************************************/
reg [log2(48):1] da_ref_cnt; // [0,47]
always@(posedge CLOCK_50, negedge RST_N)
    if(!RST_N) da_ref_cnt <= 0;
    else begin
        if(!da_enable) da_ref_cnt <= 0;
        else begin
            if(tick_140ns) begin
                if(da_ref_cnt < 47) 
                    da_ref_cnt <= da_ref_cnt + 1'b1;
                else da_ref_cnt <= 0;
            end
        end
    end
wire tick_6720ns = (da_ref_cnt == 47) ? 1 : 0;

reg [1:0] da_sel_cnt;
always@(posedge CLOCK_50, negedge RST_N)
    if(!RST_N) da_sel_cnt <= 2'b0;
    else if (tick_6720ns) begin
        if(da_sel_cnt < 3)
            da_sel_cnt <= da_sel_cnt + 1'b1;
        else da_sel_cnt <= 2'b0;
    end

/**************************************
* 根据基准计数器生成串行信号
**************************************/
reg [7:0] da_data;
always@(posedge CLOCK_50, negedge RST_N)
    if(!RST_N) da_data <= 8'b0;
    else begin
        case(da_sel_cnt)
            2'b00: da_data <= da0_data;
            2'b01: da_data <= da1_data;
            2'b10: da_data <= da2_data;
            2'b11: da_data <= da3_data;
        endcase
    end

always@(posedge CLOCK_50, negedge RST_N)
    if(!RST_N) begin
        SCK <= 0;
        SDI <= 0;
        LOAD <= 0;
    end
    else begin
        if(tick_140ns) begin
            // 生成SCK信号
            case(da_ref_cnt)
                2,6,10,14,18,22,26,30,34,38,42: SCK <= 1;
                4,8,12,16,20,24,28,32,36,40,44: SCK <= 0;
                default : ; // 缺省不操作
            endcase
            // 生成LOAD信号
            case(da_ref_cnt)
                0: LOAD <= 1;
                46: LOAD <= 0;
                default : ; // 缺省不操作
            endcase
            // 送入串型数据
            case(da_ref_cnt)
                3,4: SDI <= da_sel_cnt[1];
                7,8: SDI <= da_sel_cnt[0];
                11,12: SDI <= da_range;
                15,16: SDI <= da_data[7];
                19,20: SDI <= da_data[6];
                23,24: SDI <= da_data[5];
                27,28: SDI <= da_data[4];
                31,32: SDI <= da_data[3];
                35,36: SDI <= da_data[2];
                39,40: SDI <= da_data[1];
                43,44: SDI <= da_data[0];
                default : SDI <= 1'b1;
            endcase
        end
    end

endmodule

top_dds

module top_dds
(
    input   wire            sys_clk     ,   // 系统时钟,50MHz
    input   wire            sys_rst_n   ,   // 复位信号,低电平有效
    input   wire    [3:0]   key         ,   // 输入4位按键
    input                   key_add     ,       // 减少脉冲频率按键
    input                   key_low     ,       // 增加脉冲频率按键

    // TLC5620的引脚
    output  wire            da_clk      ,   // 时钟信号
    output  wire            da_data     ,   // 数据信号
    output  wire            da_ldac     ,   // LDAC信号
    output  wire            da_load        // LOAD信号



);

// 定义计数器的最大值
reg [15:0] counter = 16'd999; // 初始值

// 消抖后的按键状态
wire key_add_flag;
wire key_low_flag;
// 消抖后的按键状态
parameter   CNT_MAX =   20'd999_999;    //计数器计数最大值

always @(posedge sys_clk or negedge sys_rst_n) begin
    if (!sys_rst_n) begin
        // 当复位信号为低时,重置计数器和步进信号
            counter <= 16'd999;
    end else begin
        // 根据按键状态调整counter的值
        if (!key_add_flag) begin
                counter <= counter + 16'd100;
        end else if (!key_low_flag) begin
                counter <= counter - 16'd100;
        end
    end
end
/**************************************
* 生成20ms的tick时钟
**************************************/
reg [15:0] cnt_20ms;
always@(posedge sys_clk, negedge sys_rst_n) 
    if(!sys_rst_n) cnt_20ms <= 0;
    else begin
        if(cnt_20ms < 16'd999) 
            cnt_20ms <= cnt_20ms + 1'b1;
        else cnt_20ms <= 0;
    end
wire tick_20ms = (cnt_20ms == 16'd999) ? 1 : 0;
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//wire  define
wire    [3:0]   wave_select ;   // 波形选择
wire    [7:0]   dac_data    ;   // 输入DAC模块波形数据



/**************************************
* 锯齿波;
**************************************/
reg [7:0] da0_data;
always@(posedge sys_clk, negedge sys_rst_n) 
    if(!sys_rst_n) da0_data <= 0;
    else if(tick_20ms) begin
        if(da0_data < 126) 
            da0_data <= da0_data + 1'b1;
        else da0_data <= 0; 
    end

/**************************************
* 三角波;
**************************************/
reg da1_highest_level_flag;
reg [7:0] da1_data;

always@(posedge sys_clk, negedge sys_rst_n) 
    if(!sys_rst_n) begin
        da1_data <= 0;
        da1_highest_level_flag <= 0;
    end else if(tick_20ms) begin
        if(da1_data == 126) 
            da1_highest_level_flag <= 1;
        else if(da1_data == 0)
            da1_highest_level_flag <= 0;

        if(da1_highest_level_flag)
            da1_data <= da1_data - 1'b1;
        else
            da1_data <= da1_data + 1'b1;
    end

//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//-------------------------- dds_inst -----------------------------
dds     dds_inst
(
    .sys_clk        (sys_clk    ),   // 系统时钟,50MHz
    .sys_rst_n      (sys_rst_n  ),   // 复位信号,低电平有效
    .wave_select    (wave_select),   // 输出波形选择

    .data_out       (dac_data   )    // 波形输出
);

//----------------------- key_control_inst ------------------------
key_control key_control_inst
(
    .sys_clk        (sys_clk    ),   // 系统时钟,50MHz
    .sys_rst_n      (sys_rst_n  ),   // 复位信号,低电平有效
    .key            (key        ),   // 输入4位按键

    .wave_select    (wave_select)    // 输出波形选择
);

//----------------------- tlc5620_driver_inst ------------------------
tlc5620_driver tlc5620_driver_inst
(
    .CLOCK_50(sys_clk),     // 系统时钟
    .RST_N(sys_rst_n),      // 复位信号
    .da_enable(1'b1),       // 使能信号,始终使能
    .da_range(1'b0),        // 输出范围选择,根据需要设置
    .da0_data(dac_data),    // 将dac_data连接到DA0通道
    .da1_data(da0_data),        // 其他通道暂时不使用,置为0
    .da2_data(da1_data),        // 其他通道暂时不使用,置为0
    .da3_data(8'b0),        // 其他通道暂时不使用,置为0
    .SCK(da_clk),           // 连接到外部引脚
    .SDI(da_data),          // 连接到外部引脚
    .LOAD(da_load)          // 连接到外部引脚
);

// TLC5620的LDAC信号通常需要保持低电平以更新输出电压
assign da_ldac = 1'b0;
//------------- key_low --------------
key_filter 
#(
    .CNT_MAX      (CNT_MAX  )       //计数器计数最大值
)
key_filter_inst5
(
    .sys_clk      (sys_clk  )   ,   //系统时钟50Mhz
    .sys_rst_n    (sys_rst_n)   ,   //全局复位
    .key_in       (key_low   )   ,   //按键输入信号

    .key_flag     (key_low_flag     )       //按键消抖后标志信号
);
//------------- key_add --------------
key_filter 
#(
    .CNT_MAX      (CNT_MAX  )       //计数器计数最大值
)
key_filter_inst4
(
    .sys_clk      (sys_clk  )   ,   //系统时钟50Mhz
    .sys_rst_n    (sys_rst_n)   ,   //全局复位
    .key_in       (key_add   )   ,   //按键输入信号

    .key_flag     (key_add_flag     )       //按键消抖后标志信号
);




endmodule

Vga_Module

//---------------------------------------------------------------------------
//--    文件名     :   A4_Vga.v
//--    作者      :   ZIRCON
//--    描述      :   VGA显示彩条
//--    修订历史    :   2014-1-1
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
//-- VGA 800*600@60 
//-- VGA_DATA[7:0] red2,red1,red0,green2,green1,green0,blue1,blue0
//-- VGA CLOCK 40MHz.
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
//-- Horizonal timing information
//-- Sync pluse   128  a
//-- back porch   88   b
//-- active       800  c
//-- front porch  40   d
//-- All line     1056 e
//-- Vertical timing information
//-- sync pluse   4    o
//-- back porch   23   p
//-- active time  600  q
//-- front porch  1    r
//-- All lines    628  s
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
//-- Horizonal timing information
`define HSYNC_A   16'd128  // 128
`define HSYNC_B   16'd216  // 128 + 88
`define HSYNC_C   16'd1016 // 128 + 88 + 800
`define HSYNC_D   16'd1056 // 128 + 88 + 800 + 40
//-- Vertical  timing information
`define VSYNC_O   16'd4    // 4 
`define VSYNC_P   16'd27   // 4 + 23
`define VSYNC_Q   16'd627  // 4 + 23 + 600
`define VSYNC_R   16'd628  // 4 + 23 + 600 + 1
//---------------------------------------------------------------------------

module Vga_Module
(
    //输入端口
    CLK_40M,RST_N,vga_freq,vga_fengzhi,
    //输出端口
    VSYNC,HSYNC,VGA_DATA,vga_x,vga_y,ad_to_vga_data
);

//---------------------------------------------------------------------------
//--    外部端口声明
//---------------------------------------------------------------------------
input               CLK_40M;                    //时钟的端口
input               RST_N;                  //复位的端口,低电平复位
input       [7:0]       ad_to_vga_data;     //VGA中显示的波形数据
input   [31:0]  vga_freq;               //VGA中显示的频率值
input   [31:0]  vga_fengzhi;            //VGA中显示的峰峰值
output              VSYNC;                  //VGA垂直同步端口
output              HSYNC;                  //VGA水平同步端口
output      [ 7:0]  VGA_DATA;               //VGA数据端口
output  [15:0]  vga_x;                  //VGA的x坐标
output  [15:0]  vga_y;                  //VGA的y坐标
//---------------------------------------------------------------------------
//--    内部端口声明
//---------------------------------------------------------------------------
reg         [15:0]  hsync_cnt;              //水平扫描计数器
reg         [15:0]  hsync_cnt_n;            //hsync_cnt的下一个状态
reg         [15:0]  vsync_cnt;              //垂直扫描计数器
reg         [15:0]  vsync_cnt_n;            //vsync_cnt的下一个状态
reg         [ 7:0]  VGA_DATA;               //RGB端口总线
reg         [ 7:0]  VGA_DATA_N;             //VGA_DATA的下一个状态
reg                     VSYNC;                  //垂直同步端口    
reg                 VSYNC_N;                    //VSYNC的下一个状态
reg                     HSYNC;                  //水平同步端口
reg                 HSYNC_N;                    //HSYNC的下一个状态
reg                     vga_data_en;            //RGB传输使能信号     
reg                     vga_data_en_n;          //vga_data_en的下一个状态
wire        [15:0]  rom_font_data;          //字库的数据位
reg         [15:0]  rom_font_addr;          //字库的地址位
reg         [15:0]  rom_font_addr_n;        //rom_font_addr的下一个状态

//---------------------------------------------------------------------------
//--    逻辑功能实现  
//---------------------------------------------------------------------------
//时序电路,用来给hsync_cnt寄存器赋值
always @ (posedge CLK_40M or negedge RST_N)
begin
    if(!RST_N)                                  //判断复位
        hsync_cnt <= 16'b0;                 //初始化hsync_cnt值
    else
        hsync_cnt <= hsync_cnt_n;           //用来给hsync_cnt赋值
end

//组合电路,水平扫描
always @ (*)
begin
    if(hsync_cnt == `HSYNC_D)               //判断水平扫描时序
        hsync_cnt_n = 16'b0;                    //如果水平扫描完毕,计数器将会被清零
    else
        hsync_cnt_n = hsync_cnt + 1'b1; //如果水平没有扫描完毕,计数器继续累加
end

//时序电路,用来给vsync_cnt寄存器赋值
always @ (posedge CLK_40M or negedge RST_N)
begin
    if(!RST_N)                                  //判断复位
        vsync_cnt <= 16'b0;                 //给行扫描赋值
    else
        vsync_cnt <= vsync_cnt_n;           //给行扫描赋值
end

//组合电路,垂直扫描
always @ (*)
begin
    if((vsync_cnt == `VSYNC_R) && (hsync_cnt == `HSYNC_D))//判断垂直扫描时序
        vsync_cnt_n = 16'b0;                    //如果垂直扫描完毕,计数器将会被清零
    else if(hsync_cnt == `HSYNC_D)      //判断水平扫描时序
        vsync_cnt_n = vsync_cnt + 1'b1; //如果水平扫描完毕,计数器继续累加
    else
        vsync_cnt_n = vsync_cnt;            //否则,计数器将保持不变
end

//时序电路,用来给HSYNC寄存器赋值
always @ (posedge CLK_40M or negedge RST_N)
begin
    if(!RST_N)                                  //判断复位
        HSYNC <= 1'b0;                          //初始化HSYNC值
    else
        HSYNC <= HSYNC_N;                       //用来给HSYNC赋值
end

//组合电路,将HSYNC_A区域置0,HSYNC_B+HSYNC_C+HSYNC_D置1
always @ (*)
begin   
    if(hsync_cnt < `HSYNC_A)                //判断水平扫描时序
        HSYNC_N = 1'b0;                     //如果在HSYNC_A区域,那么置0
    else
        HSYNC_N = 1'b1;                     //如果不在HSYNC_A区域,那么置1
end

//时序电路,用来给VSYNC寄存器赋值
always @ (posedge CLK_40M or negedge RST_N)
begin
    if(!RST_N)                                  //判断复位
        VSYNC <= 1'b0;                          //初始化VSYNC值
    else
        VSYNC <= VSYNC_N;                       //用来给VSYNC赋值
end

//组合电路,将VSYNC_A区域置0,VSYNC_P+VSYNC_Q+VSYNC_R置1
always @ (*)
begin   
    if(vsync_cnt < `VSYNC_O)                //判断水平扫描时序
        VSYNC_N = 1'b0;                     //如果在VSYNC_O区域,那么置0
    else
        VSYNC_N = 1'b1;                     //如果不在VSYNC_O区域,那么置1
end

//时序电路,用来给vga_data_en寄存器赋值
always @ (posedge CLK_40M or negedge RST_N)
begin
    if(!RST_N)                                  //判断复位
        vga_data_en <= 1'b0;                    //初始化vga_data_en值
    else
        vga_data_en <= vga_data_en_n;       //用来给vga_data_en赋值
end

//组合电路,判断显示有效区(列像素>216&&列像素<1017&&行像素>27&&行像素<627)
always @ (*)
begin
    if((hsync_cnt > `HSYNC_B && hsync_cnt <`HSYNC_C) && 
        (vsync_cnt > `VSYNC_P && vsync_cnt < `VSYNC_Q))
        vga_data_en_n = 1'b1;               //如果在显示区域就给使能数据信号置1
    else
        vga_data_en_n = 1'b0;               //如果不在显示区域就给使能数据信号置0
end


//时序电路,用来给VGA_DATA寄存器赋值
always @ (posedge CLK_40M or negedge RST_N)
begin
    if(!RST_N)                                  //判断复位
        VGA_DATA <= 8'h0;                       //初始化VGA_DATA值
    else
        VGA_DATA <= VGA_DATA_N;             //用来给VGA_DATA赋值
end

//例化ROM字库模块
ROM_Font_Module ROM_Font_Init
(
    .address        (rom_font_addr ),       //字库的地址位
    .clock          (CLK_40M        ),      //字库的时钟
    .q              (rom_font_data )        //字库的数据位
);

//判断数字显示的位置
assign rom_5v_en = (vga_y >= 10'd90) && (vga_y <= 10'd106) && (vga_x >= 10'd98) && (vga_x <= 10'd116);
assign rom_4_375v_en = (vga_y >= 10'd122) && (vga_y <= 10'd138) && (vga_x >= 10'd66) && (vga_x <= 10'd116);
assign rom_3_75v_en = (vga_y >= 10'd154) && (vga_y <= 10'd170) && (vga_x >= 10'd74) && (vga_x <= 10'd116);
assign rom_3_125v_en = (vga_y >= 10'd186) && (vga_y <= 10'd203) && (vga_x >= 10'd66) && (vga_x <= 10'd116);
assign rom_2_5v_en = (vga_y >= 10'd218) && (vga_y <= 10'd234) && (vga_x >= 10'd82) && (vga_x <= 10'd116);

assign rom_1_875v_en = (vga_y >= 10'd250) && (vga_y <= 10'd266) && (vga_x >= 10'd66) && (vga_x <= 10'd116);
assign rom_1_25v_en = (vga_y >= 10'd282) && (vga_y <= 10'd298) && (vga_x >= 10'd74) && (vga_x <= 10'd116);
assign rom_0_625v_en = (vga_y >= 10'd314) && (vga_y <= 10'd330) && (vga_x >= 10'd66) && (vga_x <= 10'd116);
assign rom_0v_en = (vga_y >= 10'd346) && (vga_y <= 10'd362) && (vga_x >= 10'd98) && (vga_x <= 10'd116);

assign rom_pinlv_en = (vga_y > 10'd490) && (vga_y < 10'd507) && (vga_x >= 10'd130) && (vga_x <= 10'd176);
assign rom_500hz_en = (vga_y >= 10'd490) && (vga_y <= 10'd506) && (vga_x >= 10'd180) && (vga_x <= 10'd220);
assign rom_333hz_en = (vga_y >= 10'd490) && (vga_y <= 10'd506) && (vga_x >= 10'd180) && (vga_x <= 10'd220);
assign rom_833hz_en = (vga_y >= 10'd490) && (vga_y <= 10'd506) && (vga_x >= 10'd180) && (vga_x <= 10'd220);
assign rom_166hz_en = (vga_y >= 10'd490) && (vga_y <= 10'd506) && (vga_x >= 10'd180) && (vga_x <= 10'd220);
assign rom_666hz_en = (vga_y >= 10'd490) && (vga_y <= 10'd506) && (vga_x >= 10'd180) && (vga_x <= 10'd220);
assign rom_1khz_en = (vga_y >= 10'd490) && (vga_y <= 10'd506) && (vga_x >= 10'd180) && (vga_x <= 10'd212);

assign rom_2000hz_en = (vga_y >= 10'd490) && (vga_y <= 10'd506) && (vga_x >= 10'd180) && (vga_x <= 10'd214);
assign rom_1833hz_en = (vga_y >= 10'd490) && (vga_y <= 10'd506) && (vga_x >= 10'd180) && (vga_x <= 10'd230);
assign rom_1666hz_en = (vga_y >= 10'd490) && (vga_y <= 10'd506) && (vga_x >= 10'd180) && (vga_x <= 10'd230);
assign rom_1500hz_en = (vga_y >= 10'd490) && (vga_y <= 10'd506) && (vga_x >= 10'd180) && (vga_x <= 10'd230);
assign rom_1333hz_en = (vga_y >= 10'd490) && (vga_y <= 10'd506) && (vga_x >= 10'd180) && (vga_x <= 10'd230);
assign rom_1166hz_en = (vga_y >= 10'd490) && (vga_y <= 10'd506) && (vga_x >= 10'd180) && (vga_x <= 10'd230);

assign rom_26v_en = (vga_y >= 10'd490) && (vga_y <= 10'd506) && (vga_x >= 10'd482) & (vga_x <= 10'd516);
assign rom_25v_en = (vga_y >= 10'd490) && (vga_y <= 10'd506) && (vga_x >= 10'd482) & (vga_x <= 10'd516);
assign rom_24v_en = (vga_y >= 10'd490) && (vga_y <= 10'd506) && (vga_x >= 10'd482) & (vga_x <= 10'd516);
assign rom_23v_en = (vga_y >= 10'd490) && (vga_y <= 10'd506) && (vga_x >= 10'd482) & (vga_x <= 10'd516);
assign rom_22v_en = (vga_y >= 10'd490) && (vga_y <= 10'd506) && (vga_x >= 10'd482) & (vga_x <= 10'd516);
assign rom_21v_en = (vga_y >= 10'd490) && (vga_y <= 10'd506) && (vga_x >= 10'd482) & (vga_x <= 10'd516);
assign rom_20v_en = (vga_y >= 10'd490) && (vga_y <= 10'd506) && (vga_x >= 10'd482) & (vga_x <= 10'd516);
assign rom_fengzhi_0v_en = (vga_y >= 10'd490) & (vga_y <= 10'd506) && (vga_x >= 10'd482) & (vga_x <= 10'd500);
assign rom_fengzhi_en = (vga_y >= 10'd490) & (vga_y <= 10'd506) & (vga_x >= 10'd416) & (vga_x <= 10'd482);


//时序电路,用来给rom_font_addr寄存器赋值
always @ (posedge CLK_40M or negedge RST_N)
begin
    if(!RST_N) 
        rom_font_addr <= 8'd0;
    else
        rom_font_addr <= rom_font_addr_n;
end

//组合电路,用于生成字库的地址位
always @ (*)
begin
    if(rom_5v_en)
    begin
        if(vga_x == 10'd98) 
            rom_font_addr_n = 8'h28;
        else if(vga_x == 10'd106)
            rom_font_addr_n = 8'h58;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_4_375v_en)
    begin
        if(vga_x == 10'd66) 
            rom_font_addr_n = 8'h20;
        else if(vga_x == 10'd74)
            rom_font_addr_n = 8'h50;
        else if(vga_x == 10'd82)
            rom_font_addr_n = 8'h18;
        else if(vga_x == 10'd90)
            rom_font_addr_n = 8'h38;
        else if(vga_x == 10'd98)
            rom_font_addr_n = 8'h28;
        else if(vga_x == 10'd106)
            rom_font_addr_n = 8'h58;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_3_75v_en)
    begin
        if(vga_x == 10'd74) 
            rom_font_addr_n = 8'h18;
        else if(vga_x == 10'd82)
            rom_font_addr_n = 8'h50;
        else if(vga_x == 10'd90)
            rom_font_addr_n = 8'h38;
        else if(vga_x == 10'd98)
            rom_font_addr_n = 8'h28;
        else if(vga_x == 10'd106)
            rom_font_addr_n = 8'h58;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_3_125v_en)
    begin
        if(vga_x == 10'd66) 
            rom_font_addr_n = 8'h18;
        else if(vga_x == 10'd74)
            rom_font_addr_n = 8'h50;
        else if(vga_x == 10'd82)
            rom_font_addr_n = 8'h8;
        else if(vga_x == 10'd90)
            rom_font_addr_n = 8'h10;
        else if(vga_x == 10'd98)
            rom_font_addr_n = 8'h28;
        else if(vga_x == 10'd106)
            rom_font_addr_n = 8'h58;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_2_5v_en)
    begin
        if(vga_x == 10'd82)
            rom_font_addr_n = 8'h10;
        else if(vga_x == 10'd90)
            rom_font_addr_n = 8'h50;
        else if(vga_x == 10'd98)
            rom_font_addr_n = 8'h28;
        else if(vga_x == 10'd106)
            rom_font_addr_n = 8'h58;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_1_875v_en)
    begin
        if(vga_x == 10'd66) 
            rom_font_addr_n = 8'h8;
        else if(vga_x == 10'd74)
            rom_font_addr_n = 8'h50;
        else if(vga_x == 10'd82)
            rom_font_addr_n = 8'h40;
        else if(vga_x == 10'd90)
            rom_font_addr_n = 8'h38;
        else if(vga_x == 10'd98)
            rom_font_addr_n = 8'h28;
        else if(vga_x == 10'd106)
            rom_font_addr_n = 8'h58;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_1_25v_en)
    begin
        if(vga_x == 10'd74) 
            rom_font_addr_n = 8'h8;
        else if(vga_x == 10'd82)
            rom_font_addr_n = 8'h50;
        else if(vga_x == 10'd90)
            rom_font_addr_n = 8'h10;
        else if(vga_x == 10'd98)
            rom_font_addr_n = 8'h28;
        else if(vga_x == 10'd106)
            rom_font_addr_n = 8'h58;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_0_625v_en)
    begin
        if(vga_x == 10'd66) 
            rom_font_addr_n = 8'h0;
        else if(vga_x == 10'd74)
            rom_font_addr_n = 8'h50;
        else if(vga_x == 10'd82)
            rom_font_addr_n = 8'h30;
        else if(vga_x == 10'd90)
            rom_font_addr_n = 8'h10;
        else if(vga_x == 10'd98)
            rom_font_addr_n = 8'h28;
        else if(vga_x == 10'd106)
            rom_font_addr_n = 8'h58;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_0v_en)
    begin
        if(vga_x == 10'd98) 
            rom_font_addr_n = 8'h0;
        else if(vga_x == 10'd106)
            rom_font_addr_n = 8'h58;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end

    else if(rom_166hz_en && (vga_freq == 10'd166))
    begin
        if(vga_x == 10'd180)
            rom_font_addr_n = 8'h8;
        else if(vga_x == 10'd188)
            rom_font_addr_n = 8'h30;
        else if(vga_x == 10'd196)
            rom_font_addr_n = 8'h30;
        else if(vga_x == 10'd204)
            rom_font_addr_n = 8'h90;
        else if(vga_x == 10'd212)
            rom_font_addr_n = 8'h98;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_333hz_en && (vga_freq == 10'd333))
    begin
        if(vga_x == 10'd180)
            rom_font_addr_n = 8'h18;
        else if(vga_x == 10'd188)
            rom_font_addr_n = 8'h18;
        else if(vga_x == 10'd196)
            rom_font_addr_n = 8'h18;
        else if(vga_x == 10'd204)
            rom_font_addr_n = 8'h90;
        else if(vga_x == 10'd212)
            rom_font_addr_n = 8'h98;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_500hz_en && (vga_freq == 10'd500))
    begin
        if(vga_x == 10'd180)
            rom_font_addr_n = 8'h28;
        else if(vga_x == 10'd188)
            rom_font_addr_n = 8'h0;
        else if(vga_x == 10'd196)
            rom_font_addr_n = 8'h0;
        else if(vga_x == 10'd204)
            rom_font_addr_n = 8'h90;
        else if(vga_x == 10'd212)
            rom_font_addr_n = 8'h98;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_666hz_en && (vga_freq == 10'd666))
    begin
        if(vga_x == 10'd180)
            rom_font_addr_n = 8'h30;
        else if(vga_x == 10'd188)
            rom_font_addr_n = 8'h30;
        else if(vga_x == 10'd196)
            rom_font_addr_n = 8'h30;
        else if(vga_x == 10'd204)
            rom_font_addr_n = 8'h90;
        else if(vga_x == 10'd212)
            rom_font_addr_n = 8'h98;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_833hz_en && (vga_freq == 10'd833))
    begin
        if(vga_x == 10'd180)
            rom_font_addr_n = 8'h40;
        else if(vga_x == 10'd188)
            rom_font_addr_n = 8'h18;
        else if(vga_x == 10'd196)
            rom_font_addr_n = 8'h18;
        else if(vga_x == 10'd204)
            rom_font_addr_n = 8'h90;
        else if(vga_x == 10'd212)
            rom_font_addr_n = 8'h98;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_1khz_en && (vga_freq == 10'd1000))
    begin
        if(vga_x == 10'd180)
            rom_font_addr_n = 8'h8;
        else if(vga_x == 10'd188)
            rom_font_addr_n = 12'h0a0;
        else if(vga_x == 10'd196)
            rom_font_addr_n = 8'h90;
        else if(vga_x == 10'd204)
            rom_font_addr_n = 8'h98;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_1166hz_en && (vga_freq == 32'd1166))
    begin
        if(vga_x == 10'd180)
            rom_font_addr_n = 8'h8;
        else if(vga_x == 10'd188)
            rom_font_addr_n = 10'h8;
        else if(vga_x == 10'd196)
            rom_font_addr_n = 8'h30;
        else if(vga_x == 10'd204)
            rom_font_addr_n = 8'h30;
        else if(vga_x == 10'd212)
            rom_font_addr_n = 8'h90;
        else if(vga_x == 10'd220)
            rom_font_addr_n = 8'h98;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_1333hz_en && (vga_freq == 32'd1333))
    begin
        if(vga_x == 10'd180)
            rom_font_addr_n = 8'h8;
        else if(vga_x == 10'd188)
            rom_font_addr_n = 10'h18;
        else if(vga_x == 10'd196)
            rom_font_addr_n = 8'h18;
        else if(vga_x == 10'd204)
            rom_font_addr_n = 8'h18;
        else if(vga_x == 10'd212)
            rom_font_addr_n = 8'h90;
        else if(vga_x == 10'd220)
            rom_font_addr_n = 8'h98;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_1500hz_en && (vga_freq == 32'd1500))
    begin
        if(vga_x == 10'd180)
            rom_font_addr_n = 8'h8;
        else if(vga_x == 10'd188)
            rom_font_addr_n = 10'h28;
        else if(vga_x == 10'd196)
            rom_font_addr_n = 8'h0;
        else if(vga_x == 10'd204)
            rom_font_addr_n = 8'h0;
        else if(vga_x == 10'd212)
            rom_font_addr_n = 8'h90;
        else if(vga_x == 10'd220)
            rom_font_addr_n = 8'h98;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_1666hz_en && (vga_freq == 32'd1666))
    begin
        if(vga_x == 10'd180)
            rom_font_addr_n = 8'h8;
        else if(vga_x == 10'd188)
            rom_font_addr_n = 10'h30;
        else if(vga_x == 10'd196)
            rom_font_addr_n = 8'h30;
        else if(vga_x == 10'd204)
            rom_font_addr_n = 8'h30;
        else if(vga_x == 10'd212)
            rom_font_addr_n = 8'h90;
        else if(vga_x == 10'd220)
            rom_font_addr_n = 8'h98;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_1833hz_en && (vga_freq == 32'd1833))
    begin
        if(vga_x == 10'd180)
            rom_font_addr_n = 8'h8;
        else if(vga_x == 10'd188)
            rom_font_addr_n = 10'h40;
        else if(vga_x == 10'd196)
            rom_font_addr_n = 8'h18;
        else if(vga_x == 10'd204)
            rom_font_addr_n = 8'h18;
        else if(vga_x == 10'd212)
            rom_font_addr_n = 8'h90;
        else if(vga_x == 10'd220)
            rom_font_addr_n = 8'h98;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_2000hz_en && (vga_freq == 32'd2000))
    begin
        if(vga_x == 10'd180)
            rom_font_addr_n = 8'h10;
        else if(vga_x == 10'd188)
            rom_font_addr_n = 12'h0a0;
        else if(vga_x == 10'd196)
            rom_font_addr_n = 8'h90;
        else if(vga_x == 10'd204)
            rom_font_addr_n = 8'h98;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if((rom_26v_en) && (vga_fengzhi == 10'd26))
    begin
        if(vga_x == 10'd482)
            rom_font_addr_n = 8'h10;
        else if(vga_x == 10'd490)
            rom_font_addr_n = 8'h50;
        else if(vga_x == 10'd498)
            rom_font_addr_n = 8'h30;
        else if(vga_x == 10'd506)
            rom_font_addr_n = 8'h58;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if((rom_25v_en) && (vga_fengzhi == 10'd25))
    begin
        if(vga_x == 10'd482)
            rom_font_addr_n = 8'h10;
        else if(vga_x == 10'd490)
            rom_font_addr_n = 8'h50;
        else if(vga_x == 10'd498)
            rom_font_addr_n = 8'h28;
        else if(vga_x == 10'd506)
            rom_font_addr_n = 8'h58;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if((rom_24v_en) && (vga_fengzhi == 10'd24))
    begin
        if(vga_x == 10'd482)
            rom_font_addr_n = 8'h10;
        else if(vga_x == 10'd490)
            rom_font_addr_n = 8'h50;
        else if(vga_x == 10'd498)
            rom_font_addr_n = 8'h20;
        else if(vga_x == 10'd506)
            rom_font_addr_n = 8'h58;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if((rom_23v_en) && (vga_fengzhi == 10'd23))
    begin
        if(vga_x == 10'd482)
            rom_font_addr_n = 8'h10;
        else if(vga_x == 10'd490)
            rom_font_addr_n = 8'h50;
        else if(vga_x == 10'd498)
            rom_font_addr_n = 8'h18;
        else if(vga_x == 10'd506)
            rom_font_addr_n = 8'h58;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if((rom_22v_en) && (vga_fengzhi == 10'd22))
    begin
        if(vga_x == 10'd482)
            rom_font_addr_n = 8'h10;
        else if(vga_x == 10'd490)
            rom_font_addr_n = 8'h50;
        else if(vga_x == 10'd498)
            rom_font_addr_n = 8'h10;
        else if(vga_x == 10'd506)
            rom_font_addr_n = 8'h58;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if((rom_21v_en) && (vga_fengzhi == 10'd21))
    begin
        if(vga_x == 10'd482)
            rom_font_addr_n = 8'h10;
        else if(vga_x == 10'd490)
            rom_font_addr_n = 8'h50;
        else if(vga_x == 10'd498)
            rom_font_addr_n = 8'h8;
        else if(vga_x == 10'd506)
            rom_font_addr_n = 8'h58;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if((rom_20v_en) && (vga_fengzhi == 10'd20))
    begin
        if(vga_x == 10'd482)
            rom_font_addr_n = 8'h10;
        else if(vga_x == 10'd490)
            rom_font_addr_n = 8'h50;
        else if(vga_x == 10'd498)
            rom_font_addr_n = 8'h0;
        else if(vga_x == 10'd506)
            rom_font_addr_n = 8'h58;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if((rom_fengzhi_0v_en) && (vga_fengzhi == 10'd0))
    begin
        if(vga_x == 10'd482)
            rom_font_addr_n = 8'h0;
        else if(vga_x == 10'd490)
            rom_font_addr_n = 8'h58;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_pinlv_en)
    begin
        if(vga_x == 10'd130)
            rom_font_addr_n = 8'h60;
        else if(vga_x == 10'd146)
            rom_font_addr_n = 8'h70;
        else if(vga_x == 10'd162)
            rom_font_addr_n = 8'h80;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else if(rom_fengzhi_en)
    begin
        if(vga_x == 10'd416)
            rom_font_addr_n = 8'ha8;
        else if(vga_x == 10'd432)
            rom_font_addr_n = 8'hb8;
        else if(vga_x == 10'd448)
            rom_font_addr_n = 8'hc8;
        else if(vga_x == 10'd464)
            rom_font_addr_n = 8'hd8;
        else 
            rom_font_addr_n = rom_font_addr + 1'b1;
    end
    else
        rom_font_addr_n <= 15'b0;;
end

//组合电路,判断字符显示的位置并进行显示
always @ (*)
begin
    if(vga_data_en)
    begin
        if( (vga_x >= 10'd128 && vga_x <= 10'd704) && (vga_y >= 10'd96 && vga_y <= 10'd480) )
            begin
                if(vga_y - 10'd97 == (ad_to_vga_data )) //显示波形
                        VGA_DATA_N = 10'd253;
                else if((10'd0 == (vga_y % 10'd5)) && (10'd0 == (vga_x % 10'd32)))  //画虚线
                        VGA_DATA_N = 10'd208;
                else if((10'd0 == (vga_y % 10'd32)) && (10'd0 == (vga_x % 10'd5)))  //画虚线
                        VGA_DATA_N = 10'd208;
                else if((vga_y == 10'd96 || vga_y == 10'd480) && (vga_x >= 10'd96 && vga_x <= 10'd704)) //上下线
                        VGA_DATA_N = 10'd208;
                else if((vga_x == 10'd128 || vga_x == 704) && (vga_y >= 96 && vga_y <= 480)) //左右线
                        VGA_DATA_N = 10'd208;
                else if(vga_y == 10'd352 && vga_x >= 10'd96 && vga_x <= 10'd704)  //X轴
                        VGA_DATA_N = 10'he0;
                else if(vga_x == 416 && vga_y >= 10'd96 && vga_y <= 10'd480)     //Y轴
                        VGA_DATA_N = 10'he0;    
                else    
                        VGA_DATA_N = 8'h08;         
            end
        else if(rom_5v_en)  //在屏幕上显示5V
            begin
                if(rom_font_data[10'd106 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if(rom_4_375v_en)  //在屏幕上显示4.375V
            begin
                if(rom_font_data[10'd138 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if(rom_3_75v_en)   //在屏幕上显示3.75V
            begin
                if(rom_font_data[10'd170 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if(rom_3_125v_en)  //在屏幕上显示3.125V
            begin
                if(rom_font_data[10'd202 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if(rom_2_5v_en) //在屏幕上显示2.5V
            begin
                if(rom_font_data[10'd234 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if(rom_1_875v_en) //在屏幕上显示1.875V
            begin
                if(rom_font_data[10'd266 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if(rom_1_25v_en) //在屏幕上显示1.25V
            begin
                if(rom_font_data[10'd298 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if(rom_0_625v_en) //在屏幕上显示0.625V
            begin
                if(rom_font_data[10'd330 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if(rom_0v_en) //在屏幕上显示0V
            begin
                if(rom_font_data[10'd362 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if(rom_pinlv_en) //在屏幕上显示频率两个字
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if((rom_500hz_en) && (vga_freq == 10'd500)) //在屏幕上显示500hz
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end 
        else if((rom_333hz_en) && (vga_freq == 10'd333)) //在屏幕上显示333hz
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if((rom_166hz_en) && (vga_freq == 10'd166)) //在屏幕上显示166hz
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if((rom_666hz_en) && (vga_freq == 10'd666)) //在屏幕上显示666hz
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if((rom_833hz_en) && (vga_freq == 10'd833)) //在屏幕上显示833hz
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if((rom_1khz_en) && (vga_freq == 32'd1000)) //在屏幕上显示1khz
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if((rom_1166hz_en) && (vga_freq == 32'd1166)) //在屏幕上显示1166hz
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if((rom_1333hz_en) && (vga_freq == 32'd1333)) //在屏幕上显示1333hz
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if((rom_1500hz_en) && (vga_freq == 32'd1500)) //在屏幕上显示1500hz
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if((rom_1666hz_en) && (vga_freq == 32'd1666)) //在屏幕上显示1666hz
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if((rom_1833hz_en) && (vga_freq == 32'd1833)) //在屏幕上显示1833hz
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if((rom_2000hz_en) && (vga_freq == 32'd2000)) //在屏幕上显示2khz
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end

        else if((rom_fengzhi_en)) //在屏幕上显示峰峰值3个字
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if((rom_26v_en) && (vga_fengzhi == 10'd26)) //在屏幕上显示2.6V
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if((rom_25v_en) && (vga_fengzhi == 10'd25)) //在屏幕上显示2.5V
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if((rom_24v_en) && (vga_fengzhi == 10'd24)) //在屏幕上显示2.4V
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if((rom_23v_en) && (vga_fengzhi == 10'd23)) //在屏幕上显示2.3V
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if((rom_22v_en) && (vga_fengzhi == 10'd22)) //在屏幕上显示2.2V
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if((rom_21v_en) && (vga_fengzhi == 10'd21)) //在屏幕上显示2.1V
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if((rom_20v_en) && (vga_fengzhi == 10'd20)) //在屏幕上显示2.0V
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else if((rom_fengzhi_0v_en) && (vga_fengzhi == 10'd0)) //在屏幕上显示0V
            begin
                if(rom_font_data[10'd506 - vga_y])
                    VGA_DATA_N = 10'd253;
                else
                    VGA_DATA_N = 8'h03;
            end
        else
            VGA_DATA_N = 8'h03;                             
    end
    else
        VGA_DATA_N = 8'h0;  
end

assign vga_x = hsync_cnt - `HSYNC_B;
assign vga_y = vsync_cnt - `VSYNC_P;


endmodule




FFT_Control_Module ```verilog FFT_Control_Module.v //--------------------------------------------------------------------------- //-- 文件名 : FFT_Control_Module.v //-- 作者 : ZIRCON //-- 描述 : FFT控制模块 //-- 修订历史 : 2017-01-01 //--------------------------------------------------------------------------- module FFT_Control_Module ( //输入端口 CLK_50M,RST_N,data_real_in_int, //输出端口 fft_real_out_int,fft_imag_out_int,fft_bit_cnt, ,vga_fengzhi );

//--------------------------------------------------------------------------- //-- 外部端口声明 //--------------------------------------------------------------------------- input CLK_50M; //时钟端口 input RST_N; //复位端口 input [ 9:0] data_real_in_int; //输入波形数据 output [31:0] vga_fengzhi; //VGA中显示的峰峰值 output [ 9:0] fft_bit_cnt; //FFT位计数器 output [ 9:0] fft_real_out_int; //FFT实数的输出 output [ 9:0] fft_imag_out_int; //FFT虚数的输出

//--------------------------------------------------------------------------- //-- 内部端口声明 //--------------------------------------------------------------------------- wire sink_sop; //输入流的开始信号 wire sink_eop; //输入流的结束信号 wire inverse; //FFT控制信号,1:IFFT,0:FFT wire [ 1:0] sink_error; //输入错误信号 wire source_ready; //输出源准备信号
wire sink_ready; //输入的准备信号 wire [ 1:0] source_error; //输出源的错误信号
wire source_sop; //输出源流的开始信号 wire source_eop; //输出源流的结束信号 reg end_test; //结束测试信号 reg end_test_n; //end_test的下一个状态 wire source_valid; //输出源的有效信号 wire [ 5:0] source_exp; //输出源的指数信号
wire [ 9:0] source_real; //输出源的实部信号 wire [ 9:0] source_imag; //输出源的虚部信号 reg fft_start; //FFT开始转换信号 reg fft_start_n; //fft_start的下一个状态 wire end_input; //停止输入信号 wire end_output; //停止输出信号 reg [ 9:0] fft_bit_cnt; //FFT位计数器 reg [ 9:0] fft_bit_cnt_n; //fft_bit_cnt的下一个状态 reg [ 9:0] sink_real; //输入的实部信号 reg [ 9:0] sink_real_n; //sink_real的下一个状态 reg [ 9:0] sink_imag; //输入的虚部信号 reg [ 9:0] sink_imag_n; //sink_imag的下一个状态 reg sink_valid; //输入的有效信号 reg sink_valid_n; //sink_valid的下一个状态 reg [ 9:0] fft_real_out_int; //FFT输出的实部信号 reg [ 9:0] fft_real_out_int_n; //fft_real_out_int的下一个状态 reg [ 9:0] fft_imag_out_int; //FFT输出的虚部信号 reg [ 9:0] fft_imag_out_int_n; //fft_imag_out_int的下一个状态 reg [ 5:0] exponent_out_int; //FFT输出的指数信号
reg [ 5:0] exponent_out_int_n; //exponent_out_int的下一个状态 reg [31:0] fft_real_image_data; //FFT输出的数据信号 reg [31:0] fft_real_image_data_n;//fft_real_image_data的下一个状态 wire [15:0] sqrt_data_out; //平方根处理后的数据信号 reg [ 9:0] data_max; //数据的最大值 reg [ 9:0] data_max_n; //data_max的下一个状态 reg [ 9:0] data_max2; //数据的次大值 reg [ 9:0] data_max2_n; //data_max2的下一个状态 reg [ 9:0] max_cnt; //最大值的位置 reg [ 9:0] max_cnt_n; //max_cnt的下一个状态 reg [ 9:0] max_cnt2; //次大值的位置 reg [ 9:0] max_cnt2_n; //max_cnt2的下一个状态 reg [15:0] fengzhi_max; //峰峰值的最大值 reg [15:0] fengzhi_max_n; //fengzhi_max的下一个状态 reg [15:0] fengzhi_min; //峰峰值的最小值 reg [15:0] fengzhi_min_n; //fengzhi_min的下一个状态

parameter data_imag_in_int = 10'b0; //输入数据的虚部置0 parameter fftpts_array = 255; //FFT的点数

//--------------------------------------------------------------------------- //-- 逻辑功能实现
//--------------------------------------------------------------------------- / FFT控制信号,1:IFFT,0:FFT / assign inverse = 1'b0; / 输入错误信号 / assign sink_error = 2'b0; / 源准备信号 / assign source_ready = 1'b1; / 输入开始进行FFT转换运算 / assign fft_ready_valid = (sink_valid && sink_ready);

/ 时序电路,用来给fft_start寄存器赋值 / always @ (posedge CLK_50M or negedge RST_N) begin if(!RST_N) fft_start <= 1'b1; else fft_start <= fft_start_n; end

/ 组合电路,FFT开始转换信号 / always @ (*) begin if(fft_ready_valid) fft_start_n = 1'b0; else fft_start_n = 1'b1; end

/ 时序电路,用来给fft_bit_cnt寄存器赋值 / always @ (posedge CLK_50M or negedge RST_N) begin if(!RST_N) fft_bit_cnt <= 10'b0; else fft_bit_cnt <= fft_bit_cnt_n; end

/ 组合电路,FFT位计数器 / always @ (*) begin if(fft_ready_valid && (fft_bit_cnt == fftpts_array)) fft_bit_cnt_n = 1'b0;
else if(fft_ready_valid) fft_bit_cnt_n = fft_bit_cnt + 1'b1; else fft_bit_cnt_n = fft_bit_cnt; end

/ 停止输出信号 / assign end_output = (source_eop && source_valid && source_ready) ? 1'b1 : 1'b0; / 停止输入信号 / assign end_input = (sink_eop && sink_valid && sink_ready) ? 1'b1 : 1'b0; / 输入流的开始 / assign sink_sop = (fft_bit_cnt == 1'b0) ? 1'b1 : 1'b0 ; / 输入流的结束 / assign sink_eop = (fft_bit_cnt == fftpts_array) ? 1'b1 : 1'b0;

/ 时序电路,用来给end_test寄存器赋值 / always @ (posedge CLK_50M or negedge RST_N) begin if(!RST_N) end_test <= 1'b0; else end_test <= end_test_n; end

/ 组合电路,结束测试信号 / always @ (*) begin if(end_input) end_test_n = 1'b1; else end_test_n = end_test; end

/ 时序电路,用来给sink_real寄存器赋值 / always @ (posedge CLK_50M or negedge RST_N) begin if(!RST_N) sink_real <= 10'b0; else sink_real <= sink_real_n; end

/ 组合电路,输入的实部信号 / always @ (*) begin if(end_test || end_input) sink_real_n = 10'b0; else if (fft_ready_valid || (fft_start & !(sink_valid && sink_ready == 1'b0))) sink_real_n = data_real_in_int; else sink_real_n = sink_real; end

/ 时序电路,用来给sink_imag寄存器赋值 / always @ (posedge CLK_50M or negedge RST_N) begin if(!RST_N) sink_imag <= 10'b0; else sink_imag <= sink_imag_n; end

/ 组合电路,输入的虚部信号 / always @ (*) begin if(end_test || end_input) sink_imag_n = 10'b0; else if (fft_ready_valid || (fft_start & !(sink_valid && sink_ready == 1'b0))) sink_imag_n = data_imag_in_int; else sink_imag_n = sink_imag; end

/ 时序电路,用来给sink_valid寄存器赋值 / always @ (posedge CLK_50M or negedge RST_N) begin if(!RST_N) sink_valid <= 1'b0; else sink_valid <= sink_valid_n; end

/ 组合电路,输入的有效信号 / always @ (*) begin if(end_test || end_input) sink_valid_n = 1'b0; else if (fft_ready_valid || (fft_start & !(sink_valid && sink_ready == 1'b0))) sink_valid_n = 1'b1; else sink_valid_n = 1'b1; end

/ 时序电路,用来给fft_real_out_int寄存器赋值 / always @ (posedge CLK_50M or negedge RST_N) begin if(!RST_N) fft_real_out_int <= 10'b0; else fft_real_out_int <= fft_real_out_int_n; end

/ 组合电路,FFT输出的实部信号 / always @ (*) begin if(source_valid && source_ready) fft_real_out_int_n = source_real[9] ? (~source_real[9:0]+1) : source_real; else fft_real_out_int_n = fft_real_out_int; end

/ 时序电路,用来给fft_imag_out_int寄存器赋值 / always @ (posedge CLK_50M or negedge RST_N) begin if(!RST_N) fft_imag_out_int <= 10'b0; else fft_imag_out_int <= fft_imag_out_int_n; end

/ 组合电路,FFT输出的虚部信号 / always @ (*) begin if(source_valid && source_ready) fft_imag_out_int_n = source_imag[9] ? (~source_imag[9:0]+1) : source_imag; else fft_imag_out_int_n = fft_imag_out_int; end

/ 时序电路,用来给exponent_out_int寄存器赋值 / always @ (posedge CLK_50M or negedge RST_N) begin if(!RST_N) exponent_out_int <= 10'b0; else exponent_out_int <= exponent_out_int_n; end

/ 组合电路,用于生成FFT输出的指数信号 / always @ (*) begin if(source_valid && source_ready) exponent_out_int_n = source_exp; else exponent_out_int_n = exponent_out_int; end

/ 时序电路,用来给fft_real_image_data寄存器赋值 / always @ (posedge CLK_50M or negedge RST_N) begin if(!RST_N) fft_real_image_data <= 32'b0; else fft_real_image_data <= fft_real_image_data_n; end

/ 组合电路,用于生成FFT输出的数据信号 / always @ () begin if(source_valid && source_ready) fft_real_image_data_n = fft_real_out_intfft_real_out_int + fft_imag_out_int*fft_imag_out_int; else fft_real_image_data_n = fft_real_image_data; end

/ 平方根模块 / SQRT_Module SQRT_Init ( .radical (fft_real_image_data ), //FFT输出的数据信号 .q (sqrt_data_out ) //平方根处理后的数据信号 );

/ 时序电路,用来给max_cnt2寄存器赋值 / always @ (posedge CLK_50M or negedge RST_N) begin if(!RST_N) max_cnt2 <= 10'b0; else max_cnt2 <= max_cnt2_n; end

/ 组合电路,用于生成次大值的位置 / always @ (*) begin if(sqrt_data_out > data_max) max_cnt2_n = max_cnt2 + 1'b1; else if((sqrt_data_out > data_max2) && (sqrt_data_out != data_max)) max_cnt2_n = max_cnt2 + 1'b1; else if(max_cnt2 >= 10'd256) max_cnt2_n = 10'b0; else max_cnt2_n = max_cnt2 + 1'b1;; end

/ 时序电路,用来给fengzhi_max寄存器赋值 / always @ (posedge CLK_50M or negedge RST_N) begin if(!RST_N) fengzhi_max <= 16'b0; else fengzhi_max <= fengzhi_max_n; end

/ 组合电路,用于生成峰峰值的最大值 / always @ (*) begin if(data_real_in_int > fengzhi_max) fengzhi_max_n = data_real_in_int; else fengzhi_max_n = fengzhi_max; end

/ 时序电路,用来给fengzhi_max寄存器赋值 / always @ (posedge CLK_50M or negedge RST_N) begin if(!RST_N) fengzhi_min <= 16'd255; else fengzhi_min <= fengzhi_min_n; end

/ 组合电路,用于求出峰峰值的最小值 / always @ (*) begin if(fengzhi_min > data_real_in_int) fengzhi_min_n = data_real_in_int; else fengzhi_min_n = fengzhi_min; end

/ 组合电路,生成VGA中显示的频率值 / / 组合电路,生成VGA中显示的峰峰值 / assign vga_fengzhi = ((fengzhi_max - fengzhi_min) * 10'd50) >> 8'd8; //((data_max3 * 10'd100) >> 8'd8) + 10'd2;

/ FFT IP核模块例化 /
fft fft_init ( .clk (CLK_50M ), //时钟端口 .reset_n (RST_N ), //复位端口 .inverse (inverse ), //FFT控制信号,1:IFFT,0:FFT .sink_valid (sink_valid ), //输入的有效信号 .sink_sop (sink_sop ), //输入流的开始信号 .sink_eop (sink_eop ), //输入流的结束信号 .sink_real (sink_real ), //输入的实部信号 .sink_imag (sink_imag ), //输入的虚部信号 .sink_error (sink_error ), //输入错误信号 .source_ready (source_ready ), //输出源准备信号 .sink_ready (sink_ready ), //输入的准备信号
.source_error (source_error ), //输出源的错误信号
.source_sop (source_sop ), //输出源流的开始信号 .source_eop (source_eop ), //输出源流的结束信号 .source_valid (source_valid ), //输出源的有效信号 .source_exp (source_exp ), //输出源的指数信号
.source_real (source_real ), //输出源的实部信号 .source_imag (source_imag ) //输出源的虚部信号 );

endmodule

Ad_Module
```verilog
//---------------------------------------------------------------------------
//--    文件名     :   Ad_Module.v
//--    作者      :   ZIRCON
//--    描述      :   AD模块
//--    修订历史    :   2014-1-1
//---------------------------------------------------------------------------

`define AD_CLK_TIME         10'd45  //1.1M, 909ns,909 / (1 / 50M) = 45 =0x2D
`define AD_CLK_TIME_HALF    10'd22  //909ns / 2 = 454.5ns 45 / 2 = 22   

module Ad_Module
(   
    //Input
    CLK_50M,RST_N,
    //Output
    AD_CS,AD_CLK,AD_DATA,data_out
);

//---------------------------------------------------------------------------
//--    外部端口声明
//---------------------------------------------------------------------------
input                   CLK_50M;                //时钟的端口,开发板用的50M晶振
input                   RST_N;              //复位的端口,低电平复位
input                   AD_DATA;                //AD数据端口
output              AD_CS;              //AD片选端口
output              AD_CLK;             //AD时钟端口,最大不超过1.1MHz
output  [ 7:0]  data_out;           //AD模数转换完成的数据输出


//---------------------------------------------------------------------------
//--    内部端口声明
//---------------------------------------------------------------------------
reg                 AD_CS;              //AD片选信号端口
reg                 AD_CS_N;                //AD_CS的下一个状态
reg                 AD_CLK;             //AD时钟,最大不超过1.1MHz
reg                 AD_CLK_N;           //AD_CLK的下一个状态

reg     [ 2:0]  ad_fsm_cs;          //状态机的当前状态
reg     [ 2:0]  ad_fsm_ns;          //状态机的下一个状态

reg     [ 5:0]  time_cnt;           //用于记录一个时钟所用时间的定时器
reg     [ 5:0]  time_cnt_n;         //time_cnt的下一个状态
reg     [ 5:0]  bit_cnt;                //用来记录时钟周期个数的计数器
reg     [ 5:0]  bit_cnt_n;          //bit_cnt的下一个状态

reg     [ 7:0]  data_out;           //用来保存稳定的AD数据
reg     [ 7:0]  data_out_n;         //data_out的下一个状态
reg     [ 7:0]  ad_data_reg;        //用于保存数据的移位寄存器
reg     [ 7:0]  ad_data_reg_n;      //ad_data_reg_n的下一个状态

parameter   FSM_IDLE            = 3'h0; //状态机的初始状态;
parameter   FSM_READY       = 3'h1; //满足CS有效时的第一个1.4us的延时状态
parameter   FSM_DATA            = 3'h2; //读取8个数据状态
parameter   FSM_WAIT_CONV   = 3'h3; //等待转换状态,等待17us;
parameter   FSM_END         = 3'h4; //结束的状态

//---------------------------------------------------------------------------
//--    逻辑功能实现  
//---------------------------------------------------------------------------
//时序电路,用来给ad_fsm_cs寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)                              //判断复位
        ad_fsm_cs <= 1'b0;              //初始化ad_fsm_cs值
    else
        ad_fsm_cs <= ad_fsm_ns;         //用来给ad_fsm_ns赋值
end

//组合电路,用来实现状态机
always @ (*)
begin
    case(ad_fsm_cs)                     //判断状态机的当前状态
        FSM_IDLE:
                                                //3 x 0.909us = 2.727us用于初始化延时 
            if((bit_cnt == 6'd2 ) && (time_cnt == `AD_CLK_TIME))
                ad_fsm_ns = FSM_READY;  //如果空闲状态完成就进入延时状态
            else
                ad_fsm_ns = ad_fsm_cs;  //否则保持原状态不变
        FSM_READY:
                                                //2 x 0.909us = 1.818us用于延迟1.4us
            if((bit_cnt == 6'd1 ) && (time_cnt == `AD_CLK_TIME))
                ad_fsm_ns = FSM_DATA;   //如果延时状态完成就进入读取数据状态
            else
                ad_fsm_ns = ad_fsm_cs;  //否则保持原状态不变 
        FSM_DATA:
                                                //读取数据8位,1~8个时钟脉冲
            if((bit_cnt == 6'd8 ) && (time_cnt == `AD_CLK_TIME))
                ad_fsm_ns = FSM_WAIT_CONV;//如果读取数据状态完成就进入等待状态
            else
                ad_fsm_ns = ad_fsm_cs;  //否则保持原状态不变     
        FSM_WAIT_CONV:
                                                //19 x 0.909us = 17.271us用于延迟17us
            if((bit_cnt == 6'd18) && (time_cnt == `AD_CLK_TIME))
                ad_fsm_ns = FSM_END;        //如果等待状态完成就进入读取状态
            else
                ad_fsm_ns = ad_fsm_cs;  //否则保持原状态不变  
        FSM_END:                                
            ad_fsm_ns = FSM_READY;      //完成一次数据转换,进入下一次转换
        default:ad_fsm_ns = FSM_IDLE;               
    endcase
end

//时序电路,用来给time_cnt寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)                              //判断复位
        time_cnt <= 6'h0;                   //初始化time_cnt值
    else
        time_cnt <= time_cnt_n;         //用来给time_cnt赋值
end

//组合电路,实现0.909us的定时计数器
always @ (*)
begin
    if(time_cnt == `AD_CLK_TIME)        //判断0.909us时间
        time_cnt_n = 6'h0;              //如果到达0.909us,定时器清零
    else
        time_cnt_n = time_cnt + 6'h1;   //如果未到0.909us,定时器继续加1
end

//时序电路,用来给bit_cnt寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)                              //判断复位
        bit_cnt <= 6'h0;                    //初始化bit_cnt值
    else
        bit_cnt <= bit_cnt_n;           //用来给bit_cnt赋值
end

//组合电路,用来记录时钟周期个数的计数器
always @ (*)
begin
    if(ad_fsm_cs != ad_fsm_ns)          //判断状态机的当前状态
        bit_cnt_n = 6'h0;                   //如果当前的状态不等于下一个状态,计时器就清零
    else if(time_cnt == `AD_CLK_TIME_HALF)//判断0.4545us时间
        bit_cnt_n = bit_cnt + 6'h1; //如果到达0.4545us,计数器就加1
    else
        bit_cnt_n = bit_cnt;                //否则计数器保持不变
end

//时序电路,用来给AD_CLK寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)                              //判断复位
        AD_CLK <= 1'h0;                 //初始化AD_CLK值
    else
        AD_CLK <= AD_CLK_N;             //用来给AD_CLK赋值
end

//组合电路,用来生成AD的时钟波形
always @ (*)
begin
    if(ad_fsm_cs != FSM_DATA)           //判断状态机的当前状态
        AD_CLK_N = 1'h0;                    //如果当前的状态不等于读取数据状态,AD_CLK_N就置0
    else if(time_cnt == `AD_CLK_TIME_HALF)//判断0.4545us时间
        AD_CLK_N = 1'h1;                    //如果到达0.4545us,ADC_CLK_N就置1
    else if(time_cnt == `AD_CLK_TIME)//判断0.909us时间
        AD_CLK_N = 1'h0;                    //如果到达0.909us,AD_CLK_N就置0
    else
        AD_CLK_N = AD_CLK;              //否则保持不变
end

//时序电路,用来给AD_CS寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)                              //判断复位
        AD_CS <= 1'h0;                      //初始化AD_CS值
    else
        AD_CS <= AD_CS_N;                   //用来给AD_CS赋值
end

//组合电路,用来生成AD的片选波形
always @ (*)
begin
    if((ad_fsm_cs == FSM_DATA) || (ad_fsm_cs == FSM_READY))//判断状态机的当前状态
        AD_CS_N = 1'h0;//如果当前的状态等于读取数据状态或等于延时1.4us状态,AD_CS_N就置0
    else
        AD_CS_N = 1'h1;//如果当前的状态不等于读取数据状态或不等于延时1.4us状态,AD_CS_N就置1
end

//时序电路,用来给ad_data_reg寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)                              //判断复位
        ad_data_reg <= 8'h0;                //初始化ad_data_reg值
    else
        ad_data_reg <= ad_data_reg_n;   //用来给ad_data_reg赋值
end

//组合电路,将AD线上的数据保存到移位寄存器中
always @(*)
begin
    if((ad_fsm_cs == FSM_DATA) && (!AD_CLK) && (AD_CLK_N))//判断每一个时钟的上升沿
        ad_data_reg_n = {ad_data_reg[6:0],AD_DATA};//将数据存入移位寄存器中,高位优先
    else
        ad_data_reg_n = ad_data_reg;    //否则保持不变
end

//时序电路,用来给data_out寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)                              //判断复位
        data_out <= 8'h0;                   //初始化data_out值
    else
        data_out <= data_out_n;         //用来给data_out赋值
end

//组合电路,将移位寄存器中的数据存入data_out中,可用于输出
always @ (*)
begin
    if(ad_fsm_cs == FSM_END)            //判断复位
        data_out_n = ad_data_reg;       //初始化data_out值
    else
        data_out_n = data_out;          //用来给data_out赋值
end

endmodule



顶层模块


module A4_Oscilloscope_Top
(
    //时钟和复位端口
    input CLK_50M,
    input RST_N,
    //AD外设端口
    output AD_CS,
    output AD_CLK,
    input AD_DATA,
    //DA外设端口
    output da_clk  ,
    output da_data ,
    output da_ldac ,
    output da_load ,
    input    [3:0]  key   ,
    //VGA外设端口
    output VGA_HSYNC,
    output VGA_VSYNC,
    output  [ 7:0]  VGA_DATA,
    input key_add     ,       // 减少脉冲频率按键
   input key_low     ,        // 增加脉冲频率按键
    //seg
    input  wire clk_test,
    output wire clk_out , //生成的待检测时钟
   output wire [7:0]segdata,
   output wire [2:0]segcs
);


//---------------------------------------------------------------------------
//--    内部端口声明
//---------------------------------------------------------------------------
wire                    clk_40m;                //PLL生成的40M时钟

wire        [ 7:0]  in_ad_data;         //AD模数转换完成的数据输出
wire        [15:0]  vga_x;              //VGA的x坐标
wire        [31:0]  vga_fengzhi;        //VGA中显示的峰峰值
wire        [ 7:0]  ad_to_vga_data; //VGA中显示的波形数据

//---------------------------------------------------------------------------
//--    逻辑功能实现  
//---------------------------------------------------------------------------
// 实例化DA模块
top_dds top_dds_inst
(
    .sys_clk   (CLK_50M)  ,   // 系统时钟,50MHz
    .sys_rst_n (RST_N)  ,   // 复位信号,低电平有效
    .key       (key)  ,   // 输入4位按键
    .key_add   (key_add)  ,   // 输入按键
    .key_low   (key_low)  ,   // 输入按键

    .da_clk    (da_clk) ,   // 时钟信号
    .da_data   (da_data) ,   // 数据信号
    .da_ldac   (da_ldac) ,   // LDAC信号
    .da_load   (da_load) ,    // LOAD信号


);



//例化AD模块
Ad_Module           Ad_Init
(
   .CLK_50M         (CLK_50M            ),  //时钟端口
   .RST_N           (RST_N          ),  //复位端口
    .AD_CS          (AD_CS          ),  //AD片选端口
    .AD_CLK         (AD_CLK         ),  //AD时钟,最大不超过1.1MHz
    .AD_DATA            (AD_DATA            ),  //AD数据端口
    .data_out       (in_ad_data     )   //AD模数转换完成的数据输出
);  

Data_Process        Data_Process_Init
(
    .CLK_50M            (CLK_50M            ),  //系统时钟50MHz
    .CLK_40M            (clk_40m            ),  //PLL生成的40MHz时钟
   .RST_N           (RST_N          ),  //复位端口
    .AD_CS          (AD_CS          ),  //AD片选端口
    .in_ad_data     (in_ad_data     ), //AD模数转换完成的数据输出
    .vga_x          (vga_x          ),  //VGA的x坐标
    .vga_fengzhi    (vga_fengzhi    ), //VGA中显示的峰峰值
    .ad_to_vga_data(ad_to_vga_data) //VGA中显示的波形数据

);

//例化PLL模块
PLL_Module          PLL_Module_Init 
(
    .inclk0             (CLK_50M        ),  //系统时钟50MHz
    .c0                 (clk_40m        )   //PLL生成的40MHz时钟
);

//例化VGA模块
Vga_Module          VGA_Init
(
    .RST_N          (RST_N          ),  //复位端口
    .CLK_40M            (clk_40m            ),  //PLL生成的40MHz时钟
    .VSYNC          (VGA_VSYNC      ),  //VGA垂直同步端口
    .HSYNC          (VGA_HSYNC      ),  //VGA水平同步端口
    .VGA_DATA       (VGA_DATA       ),  //VGA数据端口
    .vga_x          (vga_x          ), //VGA的x坐标
    .ad_to_vga_data(ad_to_vga_data), //VGA中显示的波形数据
    .vga_freq       (20'd500        ), //VGA中显示的频率值
    .vga_fengzhi    (vga_fengzhi    )  //VGA中显示的峰峰值

);

//wire  define
wire    [19:0]  freq    ;   //计算得到的待检测信号时钟频率
//------------- freq_meter_calc_inst --------------
freq_meter_calc freq_meter_calc_inst
(
    .sys_clk    (clk_40m    ),   //系统时钟,频率50MHz
    .sys_rst_n  (RST_N  ),   //复位信号,低电平有效
    .clk_test   (da_data   ),   //待检测时钟

    .freq       (freq       )    //待检测时钟频率  
);
seg seg_inst (
    .clk(clk_40m),
    .rst_n(RST_N),
    .tenvalue(20'd500),  // 这里连接没有问题
    .segdata(segdata),
    .segcs(segcs)
);
endmodule




Data_Process

module Data_Process
(
    //输入端口
    CLK_50M,CLK_40M,RST_N,AD_CS,in_ad_data,vga_x
    //输出端口
    ,vga_fengzhi,ad_to_vga_data
);

//---------------------------------------------------------------------------
//--    外部端口声明
//---------------------------------------------------------------------------
input                   CLK_50M;                    //时钟端口,开发板用的50M晶振
input                   CLK_40M;                    //PLL生成的40M时钟
input                   RST_N;                  //复位端口,低电平复位
input                   AD_CS;                  //AD片选信号端口
input       [ 7:0]  in_ad_data;             //AD模数转换完成的数据输出
input       [15:0]  vga_x;                  //VGA的x坐标
output  [31:0]  vga_fengzhi;            //VGA中显示的峰峰值
output  [ 7:0]  ad_to_vga_data;     //VGA中显示的波形数据

//---------------------------------------------------------------------------
//--    内部端口声明
//---------------------------------------------------------------------------
reg     [ 1:0]  detect_edge;            //记录AD_CS的开始脉冲,即第一个上降沿
wire        [ 1:0]  detect_edge_n;          //detect_edge的下一个状态
reg                 posedge_reg;            //上升沿标志
wire                    posedge_reg_n;          //posedge_reg的下一个状态
reg         [15:0]  ad_to_vga_addr;     //读取AD到VGA的地址
reg         [15:0]  ad_to_vga_addr_n;       //ad_to_vga_addr的下一个状态
reg         [15:0]  ad_to_fft_addr;     //读取AD到FFT的地址
reg         [15:0]  ad_to_fft_addr_n;       //ad_to_fft_addr的下一个状态
reg     [26:0]  time_cnt;               //定时计数器
reg     [26:0]  time_cnt_n;             //time_cnt的下一个状态

reg                     fft_rst_flag;           //FFT模块复位标志位
reg                     fft_rst_flag_n;     //fft_rst_flag标志位
wire        [ 9:0]  fft_bit_cnt;            //FFT位计数器
wire        [ 9:0]  fft_real_out_int;       //FFT实数的输出
wire        [ 9:0]  fft_imag_out_int;       //FFT虚数的输出
wire        [ 9:0]  ad_to_fft_data;     //FFT中用到的AD数据
wire        [31:0]  vga_freq;               //VGA中显示的频率值
wire        [31:0]  vga_fengzhi;            //VGA中显示的峰峰值

//设置定时器的时间为1s,计算方法为  (1*10^6)ns / (1/50)ns  50MHz为开发板晶振
parameter SET_TIME_1S = 27'd50_000_000; 

//---------------------------------------------------------------------------
//--    逻辑功能实现  
//---------------------------------------------------------------------------
//时序电路,用来给detect_edge寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)                                  //判断复位
        detect_edge <= 2'b11;               //初始化detect_edge值
    else
        detect_edge <= detect_edge_n;       //用来给detect_edge赋值
end

//组合电路,检测上升沿
assign detect_edge_n = {detect_edge[0] , AD_CS};    //接收AD_CS的时钟信号

//时序电路,用来给posedge_reg寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)                                  //判断复位
        posedge_reg <= 1'b0;                    //初始化posedge_reg值
    else
        posedge_reg <= posedge_reg_n;       //用来给posedge_reg赋值
end

//组合电路,判断上升沿,如果detect_edge等于01,posedge_reg_n就置1
assign posedge_reg_n = (detect_edge == 2'b01) ? 1'b1 : 1'b0; 

//时序电路,用来给ad_to_vga_addr寄存器赋值
always @ (posedge posedge_reg or negedge RST_N)
begin
    if(!RST_N)                                  //判断复位
        ad_to_vga_addr <= 1'b0;             //初始化ad_to_vga_addr
    else
        ad_to_vga_addr <= ad_to_vga_addr_n;//给ad_to_vga_addr赋值
end

//组合电路,用于生成RAM_AD_TO_VGA的地址
always @ (*)
begin
    if(ad_to_vga_addr < 16'd800)            //判断地址
        ad_to_vga_addr_n = ad_to_vga_addr + 1'b1;//地址累加
    else
        ad_to_vga_addr_n <= 0;              //地址清零
end

//例化双口RAM_AD_TO_VGA模块
RAM_AD_TO_VGA   AD_TO_VGA_Init
(
    .wrclock    (CLK_50M                ),  //写时钟
    .wraddress  (ad_to_vga_addr         ),  //写地址
    .wren       (posedge_reg            ),  //写使能
    .data       (10'd255 - in_ad_data), //写数据

    .rdclock    (CLK_40M                ),  //读时钟
    .rdaddress  (vga_x - 16'd100        ),  //读地址
    .q          (ad_to_vga_data     )   //读数据
);

//时序电路,用来给ad_to_vga_addr寄存器赋值
always @ (posedge posedge_reg or negedge RST_N)
begin
    if(!RST_N)                                  //判断复位
        ad_to_fft_addr <= 1'b0;             //初始化ad_to_fft_addr
    else
        ad_to_fft_addr <= ad_to_fft_addr_n;//给ad_to_fft_addr赋值
end

//组合电路,用于生成RAM_AD_TO_FFT的地址
always @ (*)
begin
    if(ad_to_fft_addr < 16'd256)            //判断地址
        ad_to_fft_addr_n = ad_to_fft_addr + 1'b1;//地址累加
    else
        ad_to_fft_addr_n <= 0;              //地址清零
end
//例化双口RAM_AD_TO_FFT模块
RAM_AD_TO_FFT   AD_TO_FFT_Init
(
    .wrclock    (CLK_50M            ),      //写时钟
    .wraddress  (ad_to_fft_addr     ),      //写地址
    .wren       (posedge_reg        ),      //写使能
    .data       (in_ad_data         ),      //写数据

    .rdclock    (CLK_50M                ),      //读时钟
    .rdaddress  (fft_bit_cnt        ),      //读地址
    .q          (ad_to_fft_data )       //读数据
);

//时序电路,用来给time_cnt寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)  
begin
    if(!RST_N)                                  //判断复位
        time_cnt  <=  27'h0;                    //初始化time_cnt值
    else
        time_cnt  <=  time_cnt_n;           //用来给time_cnt赋值
end

//组合电路,实现1s的定时计数器
always @ (*)  
begin
    if(time_cnt == SET_TIME_1S)         //判断1s时间
        time_cnt_n = 27'h0;                 //如果到达1s,定时计数器将会被清零
    else
        time_cnt_n = time_cnt + 27'h1;  //如果未到1s,定时计数器将会继续累加
end

//时序电路,用来给fft_rst_flag寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)  
begin
    if(!RST_N)                                  //判断复位
        fft_rst_flag <= 1'b0;               //初始化fft_rst_flag值
    else
        fft_rst_flag <= fft_rst_flag_n; //用来给fft_rst_flag赋值
end

//组合电路,用来生成FFT模块复位标志位
always @ (*)
begin
    if(time_cnt == SET_TIME_1S)         //判断时间
        fft_rst_flag_n = 1'b0;              //FFT模块复位标志位置0
    else
        fft_rst_flag_n = 1'b1;              //FFT模块复位标志位置1
end

//例化FFT控制模块
FFT_Control_Module  FFT_Control_Init
(
    .CLK_50M                (CLK_50M                ), //时钟端口,开发板用的50M晶振
    .RST_N              (fft_rst_flag       ),  //FFT模块复位标志位
    .data_real_in_int   (ad_to_fft_data ), //FFT中用到的AD数据
    .fft_real_out_int   (fft_real_out_int   ),  //FFT实数的输出
    .fft_imag_out_int   (fft_imag_out_int   ), //FFT虚数的输出
    .fft_bit_cnt        (fft_bit_cnt        ), //FFT位计数器
    .vga_fengzhi        (vga_fengzhi        )  //VGA中显示的峰峰值
);

endmodule