FPGA 输入捕获 串口数据上传

顶层模块



module top_jishuqi(
    //system clock
    input                  sys_clk  ,    // 时钟信号
    input                  sys_rst_n,    // 复位信号

    //cymometer interface
    input                  clk_fx   ,    // 被测信号
    output                 clk_out  ,    // 模拟的输出时钟 这里由b3输出
    //user interface
    output          [5:0]  sel      ,    // 数码管位选
    output          [7:0]  seg_led  ,      // 数码管段选
    

    output    uart_txd               //UART发送端口
);

//parameter define
parameter    CLK_FS = 26'd50000000;      // 基准时钟频率值 fsclk

//wire define
wire    [19:0]       data_fx;            // 被测信号测量值



//parameter define
parameter  CLK_FREQ = 50000000;       //定义系统时钟频率
parameter  UART_BPS = 115200;         //定义串口波特率 修改波特率时候可以直接在这里修改

//*****************************************************
//**                    main code
//*****************************************************

//例化等精度频率计模块
cymometer #(.CLK_FS(CLK_FS)              // 基准时钟频率值
) u_cymometer(
    //system clock
    .clk_fs      (sys_clk  ),            // 基准时钟信号
    .rst_n       (sys_rst_n),            // 复位信号
    //cymometer interface
    .clk_fx      (clk_fx   ),            // 被测时钟信号
    .data_fx     (data_fx  )             // 测量的被测时钟频率数值
);
    
//例化测试时钟模块,产生测试时钟
clk_test #(.DIV_N(12'd2000)                // 分频系数 100分频
) u_clk_test(
    //源时钟
    .clk_in      (sys_clk  ),            // 输入时钟
    .rst_n       (sys_rst_n),            // 复位信号
    //分频后的时钟
    .clk_out     (clk_out  )             // 测试时钟
);

//例化数码管显示模块
seg_led u_seg_led(
    //module clock
    .clk         (sys_clk  ),            // 数码管驱动模块的驱动时钟
    .rst_n       (sys_rst_n),            // 复位信号
    //seg_led interface
    .sel         (sel      ),            // 数码管位选
    .seg_led     (seg_led  ),            // 数码管段选
    //user interface
    .data        (data_fx  ),            // 被测频率值
    .point       (6'd0     ),            // 数码管显示的点控制
    .en          (1'b1     ),            // 数码管驱动使能信号
    .sign        (1'b0     )             // 控制符号位显示
);


   
usart #(                          //串口发送模块
    .CLK_FREQ       (CLK_FREQ),       //设置系统时钟频率
    .UART_BPS       (UART_BPS))       //设置串口发送波特率
u_uart_send(                 
    .sys_clk        (sys_clk),
    .sys_rst_n      (sys_rst_n),
    .data           (data_fx), 

    .uart_txd       (uart_txd)//发送端口
    );

endmodule

测试信号产生模块


//系统时钟位50M 100分频后为0.5Mhz
module clk_test #(parameter DIV_N = 12'd2000)// = 7'd1000)    //分频系数
    (
     //源时钟
     input        clk_in     ,                 // 输入时钟
     input        rst_n      ,                 // 复位信号
     //分频后的时钟
     output  reg  clk_out                      // 输出时钟
);

//reg define
reg [31:0] cnt;                                 // 时钟分频计数

//*****************************************************
//**                    main code
//*****************************************************

//时钟分频
always @(posedge clk_in or negedge rst_n) begin
    if(rst_n == 1'b0) begin
        cnt     <= 0;
        clk_out <= 0;
    end
    else begin
        if(cnt == DIV_N/2 - 1'b1) begin//周期1/2时 电平反转
            cnt     <= 10'd0;
            clk_out <= ~clk_out;
        end
        else
            cnt <= cnt + 1'b1;
    end
end

endmodule

输入捕获


module cymometer
   #(parameter    CLK_FS = 26'd50_000_000) // 基准时钟频率值
    (   //system clock
        input                 clk_fs ,     // 基准时钟信号
        input                 rst_n  ,     // 复位信号

        //cymometer interface
        input                 clk_fx ,     // 被测时钟信号
        output   reg [19:0]   data_fx      // 测量的被测时钟频率值输出
);

//parameter define
localparam   MAX       =  6'd32;           // 定义fs_cnt、fx_cnt的最大位宽
localparam   GATE_TIME = 16'd5_000;        // 门控时间设置

//reg define
reg                gate        ;           // 门控信号
reg                gate_fs     ;           // 同步到基准时钟的门控信号
reg                gate_fs_r   ;           // 用于同步gate信号的寄存器
reg                gate_fs_d0  ;           // 用于采集基准时钟下gate下降沿
reg                gate_fs_d1  ;           // 
reg                gate_fx_d0  ;           // 用于采集被测时钟下gate下降沿
reg                gate_fx_d1  ;           // 
reg    [   15:0]   gate_cnt    ;           // 门控计数
reg    [MAX-1:0]   fs_cnt      ;           // 门控时间内基准时钟的计数值
reg    [MAX-1:0]   fs_cnt_temp ;           // fs_cnt 临时值
reg    [MAX-1:0]   fx_cnt      ;           // 门控时间内被测时钟的计数值
reg    [MAX-1:0]   fx_cnt_temp ;           // fx_cnt 临时值

//wire define
wire               neg_gate_fs;            // 基准时钟下门控信号下降沿
wire               neg_gate_fx;            // 被测时钟下门控信号下降沿

//*****************************************************
//**                    main code
//*****************************************************

//边沿检测,捕获信号下降沿
assign neg_gate_fs = gate_fs_d1 & (~gate_fs_d0);
assign neg_gate_fx = gate_fx_d1 & (~gate_fx_d0);

//门控信号计数器,使用被测时钟计数
always @(posedge clk_fx or negedge rst_n) begin
    if(!rst_n)
        gate_cnt <= 16'd0; 
    else if(gate_cnt == GATE_TIME + 5'd20)//对5000+20个被测信号的周期进行计数
        gate_cnt <= 16'd0;
    else
        gate_cnt <= gate_cnt + 1'b1;
end

//门控信号,拉高时间为GATE_TIME个实测时钟周期,创造一个门控信号
always @(posedge clk_fx or negedge rst_n) begin
    if(!rst_n)
        gate <= 1'b0;
    else if(gate_cnt < 4'd10)//创造一个门控信号
        gate <= 1'b0;     
    else if(gate_cnt < GATE_TIME + 4'd10)
        gate <= 1'b1;
    else if(gate_cnt <= GATE_TIME + 5'd20)
        gate <= 1'b0;
    else 
        gate <= 1'b0;
end

//将门控信号同步到基准时钟下,得到基准时钟下的门控信号
always @(posedge clk_fs or negedge rst_n) begin//注意这里是clk_fs
    if(!rst_n) begin
        gate_fs_r <= 1'b0;
        gate_fs   <= 1'b0;
    end
    else begin
        gate_fs_r <= gate;
        gate_fs   <= gate_fs_r;
    end
end

//打拍,采门控信号的下降沿(被测时钟下)
always @(posedge clk_fx or negedge rst_n) begin
    if(!rst_n) begin
        gate_fx_d0 <= 1'b0;
        gate_fx_d1 <= 1'b0;
    end
    else begin
        gate_fx_d0 <= gate;
        gate_fx_d1 <= gate_fx_d0;
    end
end

//打拍,采门控信号的下降沿(基准时钟下)
always @(posedge clk_fs or negedge rst_n) begin
    if(!rst_n) begin
        gate_fs_d0 <= 1'b0;
        gate_fs_d1 <= 1'b0;
    end
    else begin
        gate_fs_d0 <= gate_fs;
        gate_fs_d1 <= gate_fs_d0;
    end
end

//门控时间内对被测时钟计数
always @(posedge clk_fx or negedge rst_n) begin
    if(!rst_n) begin
        fx_cnt_temp <= 32'd0;
        fx_cnt <= 32'd0;
    end
    else if(gate)
        fx_cnt_temp <= fx_cnt_temp + 1'b1;
    else if(neg_gate_fx) begin
        fx_cnt_temp <= 32'd0;
        fx_cnt   <= fx_cnt_temp;
    end
end

//门控时间内对基准时钟计数
always @(posedge clk_fs or negedge rst_n) begin
    if(!rst_n) begin
        fs_cnt_temp <= 32'd0;
        fs_cnt <= 32'd0;
    end
    else if(gate_fs)
        fs_cnt_temp <= fs_cnt_temp + 1'b1;
    else if(neg_gate_fs) begin
        fs_cnt_temp <= 32'd0;
        fs_cnt <= fs_cnt_temp;
    end
end

//计算被测信号频率
always @(posedge clk_fs or negedge rst_n) begin
    if(!rst_n) begin
        data_fx <= 20'd0;
    end
    else if(gate_fs == 1'b0)
        data_fx <= (CLK_FS/fs_cnt)*(fx_cnt);
end

endmodule 

数码管显示

//****************************************Copyright (c)***********************************//
//技术支持:www.openedv.com
//淘宝店铺:http://openedv.taobao.com
//关注微信公众平台微信号:"正点原子",免费获取FPGA & STM32资料。
//版权所有,盗版必究。
//Copyright(C) 正点原子 2018-2028
//All rights reserved
//----------------------------------------------------------------------------------------
// File name:           seg_led
// Last modified Date:  2018/3/13 9:03:06
// Last Version:        V1.0
// Descriptions:        数码管动态显示模块
//----------------------------------------------------------------------------------------
// Created by:          正点原子
// Created date:        2018/3/13 9:03:09
// Version:             V1.0
// Descriptions:        The original version
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//

module seg_led(
    //module clock
    input                   clk    ,        // 时钟信号
    input                   rst_n  ,        // 复位信号

    //seg_led interface
    output   reg  [5:0]     sel    ,        // 动态显示被选中的数码管
    output   reg  [7:0]     seg_led,        // 一个数码管中亮的灯,包含小数点

    //user interface
    input         [19:0]    data   ,        // 6个数码管要显示的数值
    input         [5:0]     point  ,        // 小数点具体显示的位置,从高到低,高电平有效
    input                   en     ,        // 数码管使能信号
    input                   sign            // 符号位(高电平显示“-”号)
);

//parameter define
localparam  MAX_NUM    = 13'd5000  ;        // 1ms计数值
localparam  CLK_DIVIDE =  4'd10    ;        // 时钟分频

//reg define
reg    [12:0]             cnt0     ;        // 1ms计数
reg                       flag     ;        // 1ms计满标志信号
reg    [2:0]              cnt      ;        // 切换显示数码管用
reg    [3:0]              num1     ;        // 送给要显示的数码管,要亮的灯
reg                       point1   ;        // 要显示的小数点
reg    [23:0]             num      ;        // 24位bcd码用寄存器
reg    [ 3:0]             clk_cnt  ;        // 时钟计数
reg                       dri_clk  ;        // 驱动数码管操作的驱动时钟

//wire define
wire   [3:0]              data0    ;        // 十万位数
wire   [3:0]              data1    ;        // 万位数
wire   [3:0]              data2    ;        // 千位数
wire   [3:0]              data3    ;        // 百位数
wire   [3:0]              data4    ;        // 十位数
wire   [3:0]              data5    ;        // 个位数

//*****************************************************
//**                    main code
//*****************************************************

assign  data5 = data / 17'd100000;           // 十万位数
assign  data4 = data / 14'd10000 % 4'd10;    // 万位数
assign  data3 = data / 10'd1000 % 4'd10 ;    // 千位数
assign  data2 = data /  7'd100 % 4'd10  ;    // 百位数
assign  data1 = data /  4'd10 % 4'd10   ;    // 十位数
assign  data0 = data %  4'd10;               // 个位数

//生成数码管的驱动时钟用于驱动数码管的操作
always @(posedge clk or negedge rst_n) begin
   if(!rst_n) begin
       dri_clk <= 1'b1;
       clk_cnt <= 4'd0;
   end
   else if(clk_cnt == CLK_DIVIDE/2 - 1'd1) begin
       clk_cnt <= 4'd0;
       dri_clk <= ~dri_clk;
   end
   else
       clk_cnt <= clk_cnt + 1'b1;
end

//将20位2进制数转换为8421bcd码
always @ (posedge dri_clk or negedge rst_n) begin
    if (!rst_n)
        num <= 24'b0;
    else begin
        if (data5 || point[5]) begin
            num[23:20] <= data5;
            num[19:16] <= data4;
            num[15:12] <= data3;
            num[11:8]  <= data2;
            num[ 7:4]  <= data1;
            num[ 3:0]  <= data0;
        end
        else begin
            if (data4 || point[4]) begin
                num[19:0]   <= {data4,data3,data2,data1,data0};
                if(sign)
                    num[23:20] <= 4'd11;
                else
                    num[23:20] <= 4'd10;
            end
            else begin
                if (data3 || point[3]) begin
                    num[15: 0] <= {data3,data2,data1,data0};
                    num[23:20] <= 4'd10;
                    if(sign)
                        num[19:16] <= 4'd11;
                    else
                        num[19:16] <= 4'd10;
                end
                else begin
                    if (data2 || point[2]) begin
                        num[11: 0] <= {data2,data1,data0};
                        num[23:16] <= {2{4'd10}};
                        if(sign)
                            num[15:12] <= 4'd11;
                        else
                            num[15:12] <= 4'd10;
                    end
                    else begin
                        if (data1 || point[1]) begin
                            num[ 7: 0] <= {data1,data0};
                            num[23:12] <= {3{4'd10}};
                            if(sign)
                                num[11:8]  <= 4'd11;
                            else
                                num[11:8] <=  4'd10;
                        end
                        else begin
                            num[3:0] <= data0;
                            if(sign)
                                num[23:4] <= {{4{4'd10}},4'd11};
                            else
                                num[23:4] <= {5{4'd10}};
                        end
                    end
                end
            end
        end
    end
end

//计数1ms
always @ (posedge dri_clk or negedge rst_n) begin
    if (rst_n == 1'b0) begin
        flag <=  1'b0;
        cnt0 <= 13'b0;
     end
    else if (cnt0 < MAX_NUM - 1'b1) begin
        flag <= 1'b0;
        cnt0 <= cnt0 + 1'b1;
     end
    else begin
        flag <=  1'b1;
        cnt0 <= 13'b0;
     end
end

//计数器,用来计数6个状态(因为有6个灯)
always @ (posedge dri_clk or negedge rst_n) begin
    if (rst_n == 1'b0)
        cnt <= 3'b0;
    else if(flag) begin
        if(cnt < 3'd5)
            cnt <= cnt + 1'b1;
        else
            cnt <= 3'b0;
    end
end
//6个数码管轮流显示,完成刷新( 从右到左)
always @ (posedge dri_clk or negedge rst_n) begin
    if(!rst_n) begin
        sel  <= 6'b000000;
        num1 <= 4'b0;
    end
    else begin
        if(en) begin
            case (cnt)
                3'd0 :begin
                    sel    <= 6'b111110;
                    num1   <= num[3:0] ;
                    point1 <= ~point[0] ;
                end
                3'd1 :begin
                    sel    <= 6'b111101;
                    num1   <= num[7:4] ;
                    point1 <= ~point[1] ;
                end
                3'd2 :begin
                    sel    <= 6'b111011;
                    num1   <= num[11:8];
                    point1 <= ~point[2] ;
                end
                3'd3 :begin
                    sel    <= 6'b110111;
                    num1   <= num[15:12];
                    point1 <= ~point[3]  ;
                end
                3'd4 :begin
                    sel    <= 6'b101111;
                    num1   <= num[19:16];
                    point1 <= ~point[4];
                end
                3'd5 :begin
                    sel    <= 6'b011111;
                    num1   <= num[23:20];
                    point1 <= ~point[5];
                end
                default :begin
                    sel    <= 6'b000000;
                    num1   <= 4'b0;
                    point1 <= 1'b1;
                end
            endcase
        end
        else
            sel <= 6'b111111;
    end
end

//数码管显示数据
always @ (posedge dri_clk or negedge rst_n) begin
    if (!rst_n)
        seg_led <= 7'h40;
    else begin
        case (num1)
            4'd0 : seg_led <= {point1,7'b1000000};
            4'd1 : seg_led <= {point1,7'b1111001};
            4'd2 : seg_led <= {point1,7'b0100100};
            4'd3 : seg_led <= {point1,7'b0110000};
            4'd4 : seg_led <= {point1,7'b0011001};
            4'd5 : seg_led <= {point1,7'b0010010};
            4'd6 : seg_led <= {point1,7'b0000010};
            4'd7 : seg_led <= {point1,7'b1111000};
            4'd8 : seg_led <= {point1,7'b0000000};
            4'd9 : seg_led <= {point1,7'b0010000};
            4'd10: seg_led <= 8'b11111111;
            4'd11: seg_led <= 8'b10111111;
            default : seg_led <= {point1,7'b1000000};
        endcase
    end
end

endmodule

串口数据上传


module usart(
    input	      sys_clk,                  //系统时钟
    input         sys_rst_n,                //系统复位,低电平有效

    input        [19:0]    data   , 
    output  reg   uart_txd               //UART发送端口

    );
    
    
    
reg [7:0] data_wei [5:0];
reg[19:0] data0;

    
//parameter define
parameter  CLK_FREQ = 50000000;             //系统时钟频率
parameter  UART_BPS = 9600;                 //串口波特率
localparam BPS_CNT  = CLK_FREQ/UART_BPS;    //为得到指定波特率,对系统时钟计数BPS_CNT次

reg[31:0] i;
reg [ 31:0] Data_Count;
reg [7:0] arry [Data_Len-1:0];
parameter [ 31:0] Data_Len=32'd14;//修改此处

//reg define
reg        usart_down;
reg        uart_en_d0; 
reg        uart_en_d1;  
reg [15:0] clk_cnt;                         //系统时钟计数器
reg [ 3:0] tx_cnt;                          //发送数据计数器
reg        tx_flag;                         //发送过程标志信号'b
reg [7:0]  tx_data;
reg        first;
reg init=1;


always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin
        if (init)begin
            for(i=0; i<Data_Len; i=i+1'b1) begin    
            case(i)
              0: arry[0] <= "F";
              1: arry[1] <= "r";
              2: arry[2] <= "e"; 
              3: arry[3] <= ":"; 
              
              10: arry[10] <= "H"; 
              11: arry[11] <= "z"; 
              12: arry[12] <= "\n"; 
              13: arry[13] <= "\r"; 
              endcase 
                init<=0;
              end
              
        end
     end
end
      
//*****************************************************
//**                    main code
//*****************************************************
//捕获uart_en上升沿,得到一个时钟周期的脉冲信号
assign en_flag = (~uart_en_d1) & uart_en_d0;


always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin
    end 
    else begin//创造usart_down的第一个上升沿 first实现
   
 arry[4] <=    data / 17'd100000+"0";           // 十万位
 arry[5] <=    data / 14'd10000 % 4'd10 +"0";    // 万位数
 arry[6] <=  data / 10'd1000 % 4'd10 +"0";    // 千位数  arry[4] <= "a";
 arry[7] <=  data /  7'd100 % 4'd10 +"0" ;    // 百位数  arry[5] <= "g";
 arry[8] <=  data /  4'd10 % 4'd10  +"0" ;    // 十位数  arry[6] <= "y";
 arry[9] <=  data %  4'd10 +"0" ;               // 个位数  arry[7] <= "i";

    end  
    
end


always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin
        usart_down <= 1'b0;   
        first <= 1'b1; 
    end 
    else if (first)begin//创造usart_down的第一个上升沿 first实现
        usart_down <= 1;
        first <= 0;    
    end  
    else if(tx_cnt == 4'd0) begin                                      
        usart_down <= 1;      
    end
    else 
        usart_down <= 0; 
end


//usart_down的边沿检测
always @(posedge sys_clk or negedge sys_rst_n) begin 
    if (!sys_rst_n) begin 
        uart_en_d0 <= 1'b0;
        uart_en_d1 <= 1'b0;          
    end
    else begin
        uart_en_d0  <= usart_down;                   
        uart_en_d1  <= uart_en_d0;
    end   
end



//当脉冲信号en_flag到达时,寄存待发送的数据,并进入发送过程          
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin                                  
        tx_flag <= 1'b0;
        tx_data <= arry[0];
        Data_Count <= 4'b0; 
    end 
    else if(en_flag) begin                 //检测到发送使能上升沿                      
        tx_flag <= 1'b1;                //进入发送过程,标志位tx_flag拉高
        tx_data <= arry[Data_Count];            //寄存待发送的数据
    end
    else  if((tx_cnt == 4'd10)&&(clk_cnt == BPS_CNT/2))
    begin                               //计数到停止位中间时,停止发送过程
        tx_flag <= 1'b0;                //发送过程结束,标志位tx_flag拉低
        Data_Count<=Data_Count+4'b1;
    if (Data_Count==Data_Len)
        Data_Count<=32'b0;      
    end
end



//进入发送过程后,启动系统时钟计数器与发送数据计数器
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin                             
        clk_cnt <= 16'd0;                                  
        tx_cnt  <= 4'd0;
    end                                                      
    else if (tx_flag) begin                 //处于发送过程
        if (clk_cnt < BPS_CNT - 1) begin
            clk_cnt <= clk_cnt + 1'b1;
            tx_cnt  <= tx_cnt;
        end
        else begin
            clk_cnt <= 16'd0;               //对系统时钟计数达一个波特率周期后清零
            tx_cnt  <= tx_cnt + 1'b1;       //此时发送数据计数器加1
        end
    end
    else begin                              //发送过程结束
        clk_cnt <= 16'd0;
        tx_cnt  <= 4'd0;
    end
end



//根据发送数据计数器来给uart发送端口赋值
always @(posedge sys_clk or negedge sys_rst_n) begin        
    if (!sys_rst_n)  
        uart_txd <= 1'b1;        
    else if (tx_flag)
        case(tx_cnt)
            4'd0: uart_txd <= 1'b0;         //起始位 
            4'd1: uart_txd <= tx_data[0];   //数据位最低位
            4'd2: uart_txd <= tx_data[1];
            4'd3: uart_txd <= tx_data[2];
            4'd4: uart_txd <= tx_data[3];
            4'd5: uart_txd <= tx_data[4];
            4'd6: uart_txd <= tx_data[5];
            4'd7: uart_txd <= tx_data[6];
            4'd8: uart_txd <= tx_data[7];   //数据位最高位
            4'd9: uart_txd <= 1'b1;         //停止位
            default: ;
        endcase
    else 
        uart_txd <= 1'b1;                   //空闲时发送端口为高电平
end

endmodule	          
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值