-

效果

模块框图
模块框图

储备知识

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

程序

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

seg.v
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
freq_meter_calc.v
`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
key_control.v
`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.v
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
key_filter.v
`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
serial_output.v
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.v
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.v
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.v
//--------------------------------------------------------------------------- //-- 文件名 : 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.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_int*fft_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.v
//--------------------------------------------------------------------------- //-- 文件名 : 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
A4_Oscilloscope_Top.v
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.v
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

本站由 John Doe 使用 Stellar 1.28.1 主题创建。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

本"页面"访问 次 | 👀总访问 次 | 🥷总访客