请问这个时序如何设定的 能否具体解释一下-Anlogic-安路社区-FPGA CPLD-ChipDebug

请问这个时序如何设定的 能否具体解释一下

  • `timescale  1ns/1ns
    ////////////////////////////////////////////////////////////////////////
    // Author        : EmbedFire
    // Create Date   : 2019/04/01
    // Module Name   : i2c_ctrl
    // Project Name  : ad
    // Target Devices: Altera EP4CE10F17C8N
    // Tool Versions : Quartus 13.0
    // Description   : i2c_ctrl
    // 
    // Revision      : V1.0
    // Additional Comments:
    // 
    // 实验平台: 野火_征途Pro_FPGA开发板
    // 公司    : http://www.embedfire.com
    // 论坛    : http://www.firebbs.cn
    // 淘宝    : https://fire-stm32.taobao.com
    ////////////////////////////////////////////////////////////////////////
    
    module  i2c_ctrl
    #(
        parameter   DEVICE_ADDR     =   7'b1010_000     ,   //i2c设备地址
        parameter   SYS_CLK_FREQ    =   26'd50_000_000  ,   //输入系统时钟频率
        parameter   SCL_FREQ        =   18'd250_000         //i2c设备scl时钟频率
    )
    (
        input   wire            sys_clk     ,   //输入系统时钟,50MHz
        input   wire            sys_rst_n   ,   //输入复位信号,低电平有效
        input   wire            wr_en       ,   //输入写使能信号
        input   wire            rd_en       ,   //输入读使能信号
        input   wire            i2c_start   ,   //输入i2c触发信号
        input   wire            addr_num    ,   //输入i2c字节地址字节数
        input   wire    [15:0]  byte_addr   ,   //输入i2c字节地址
        input   wire    [7:0]   wr_data     ,   //输入i2c设备数据
    
        output  reg             i2c_clk     ,   //i2c驱动时钟
        output  reg             i2c_end     ,   //i2c一次读/写操作完成
        output  reg     [7:0]   rd_data     ,   //输出i2c设备读取数据
        output  reg             i2c_scl     ,   //输出至i2c设备的串行时钟信号scl
        inout   wire            i2c_sda         //输出至i2c设备的串行数据信号sda
    );
    
    //************************************************************************//
    //******************** Parameter and Internal Signal *********************//
    //************************************************************************//
    // parameter define
    localparam  CNT_CLK_MAX     =   (SYS_CLK_FREQ/SCL_FREQ) >> 2'd3   ;   //cnt_clk计数器计数最大值 0-24   移位运算符号右移三位是二进制下右移三位
    
    localparam  CNT_START_MAX   =   8'd100; //cnt_start计数器计数最大值
    
    localparam  IDLE            =   4'd00,  //初始状态
                START_1         =   4'd01,  //开始状态1
                SEND_D_ADDR     =   4'd02,  //设备地址写入状态 + 控制写
                ACK_1           =   4'd03,  //应答状态1
                SEND_B_ADDR_H   =   4'd04,  //字节地址高八位写入状态
                ACK_2           =   4'd05,  //应答状态2
                SEND_B_ADDR_L   =   4'd06,  //字节地址低八位写入状态
                ACK_3           =   4'd07,  //应答状态3
                WR_DATA         =   4'd08,  //写数据状态
                ACK_4           =   4'd09,  //应答状态4
                START_2         =   4'd10,  //开始状态2
                SEND_RD_ADDR    =   4'd11,  //设备地址写入状态 + 控制读
                ACK_5           =   4'd12,  //应答状态5
                RD_DATA         =   4'd13,  //读数据状态
                N_ACK           =   4'd14,  //非应答状态
                STOP            =   4'd15;  //结束状态
    
    // wire  define
    wire            sda_in          ;   //sda输入数据寄存
    wire            sda_en          ;   //sda数据写入使能信号
    
    // reg   define
    reg     [7:0]   cnt_clk         ;   //系统时钟计数器,控制生成clk_i2c时钟信号
    reg     [3:0]   state           ;   //状态机状态
    reg             cnt_i2c_clk_en  ;   //cnt_i2c_clk计数器使能信号
    reg     [1:0]   cnt_i2c_clk     ;   //clk_i2c时钟计数器,控制生成cnt_bit信号
    reg     [2:0]   cnt_bit         ;   //sda比特计数器
    reg             ack             ;   //应答信号
    reg             i2c_sda_reg     ;   //sda数据缓存
    reg     [7:0]   rd_data_reg     ;   //自i2c设备读出数据
    
    //************************************************************************//
    //******************************* Main Code ******************************//
    //************************************************************************//
    // cnt_clk:系统时钟计数器(0-24)循环,控制生成clk_i2c时钟信号
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            cnt_clk <=  8'd0;
        else    if(cnt_clk == CNT_CLK_MAX - 1'b1)
            cnt_clk <=  8'd0;
        else
            cnt_clk <=  cnt_clk + 1'b1;
    
    // i2c_clk:i2c驱动时钟
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            i2c_clk <=  1'b1;
        else    if(cnt_clk == CNT_CLK_MAX - 1'b1)
            i2c_clk <=  ~i2c_clk;
    
    // cnt_i2c_clk_en:cnt_i2c_clk计数器使能信号
    always@(posedge i2c_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            cnt_i2c_clk_en  <=  1'b0;
        else    if((state == STOP) && (cnt_bit == 3'd3) &&(cnt_i2c_clk == 3))
            cnt_i2c_clk_en  <=  1'b0;
        else    if(i2c_start == 1'b1)
            cnt_i2c_clk_en  <=  1'b1;
    
    // cnt_i2c_clk(0-3):i2c_clk时钟计数器循环,控制生成cnt_bit信号
    always@(posedge i2c_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            cnt_i2c_clk <=  2'd0;
        else    if(cnt_i2c_clk_en == 1'b1)
            cnt_i2c_clk <=  cnt_i2c_clk + 1'b1;
    
    // cnt_bit:sda比特计数器
    always@(posedge i2c_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            cnt_bit <=  3'd0;
        else    if((state == IDLE) || (state == START_1) || (state == START_2)
                    || (state == ACK_1) || (state == ACK_2) || (state == ACK_3)
                    || (state == ACK_4) || (state == ACK_5) || (state == N_ACK))
            cnt_bit <=  3'd0;
        else    if((cnt_bit == 3'd7) && (cnt_i2c_clk == 2'd3))
            cnt_bit <=  3'd0;
        else    if((cnt_i2c_clk == 2'd3) && (state != IDLE))
            cnt_bit <=  cnt_bit + 1'b1;
    
    // state:状态机状态跳转
    always@(posedge i2c_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            state   <=  IDLE;
        else    case(state)
            IDLE:
                if(i2c_start == 1'b1)
                    state   <=  START_1;
                else
                    state   <=  state;
            START_1:
                if(cnt_i2c_clk == 3)
                    state   <=  SEND_D_ADDR;
                else
                    state   <=  state;
            SEND_D_ADDR:
                if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3))
                    state   <=  ACK_1;
                else
                    state   <=  state;
            ACK_1:
                if((cnt_i2c_clk == 3) && (ack == 1'b0))
                    begin
                        if(addr_num == 1'b1)
                            state   <=  SEND_B_ADDR_H;
                        else
                            state   <=  SEND_B_ADDR_L;
                    end
                 else
                    state   <=  state;
            SEND_B_ADDR_H:
                if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3))
                    state   <=  ACK_2;
                else
                    state   <=  state;
            ACK_2:
                if((cnt_i2c_clk == 3) && (ack == 1'b0))
                    state   <=  SEND_B_ADDR_L;
                else
                    state   <=  state;
            SEND_B_ADDR_L:
                if((cnt_bit == 3'd7) && (cnt_i2c_clk == 3))
                    state   <=  ACK_3;
                else
                    state   <=  state;
            ACK_3:
                if((cnt_i2c_clk == 3) && (ack == 1'b0))
                    begin
                        if(wr_en == 1'b1)
                            state   <=  WR_DATA;
                        else    if(rd_en == 1'b1)
                            state   <=  START_2;
                        else
                            state   <=  state;
                    end
                 else
                    state   <=  state;
            WR_DATA:
                if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3))
                    state   <=  ACK_4;
                else
                    state   <=  state;
            ACK_4:
                if((cnt_i2c_clk == 3) && (ack == 1'b0))
                    state   <=  STOP;
                else
                    state   <=  state;
            START_2:
                if(cnt_i2c_clk == 3)
                    state   <=  SEND_RD_ADDR;
                else
                    state   <=  state;
            SEND_RD_ADDR:
                if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3))
                    state   <=  ACK_5;
                else
                    state   <=  state;
            ACK_5:
                if((cnt_i2c_clk == 3) && (ack == 1'b0))
                    state   <=  RD_DATA;
                else
                    state   <=  state;
            RD_DATA:
                if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3))
                    state   <=  N_ACK;
                else
                    state   <=  state;
            N_ACK:
                if(cnt_i2c_clk == 3)
                    state   <=  STOP;
                else
                    state   <=  state;
            STOP:
                if((cnt_bit == 3'd3) &&(cnt_i2c_clk == 3))
                    state   <=  IDLE;
                else
                    state   <=  state;
            default:    state   <=  IDLE;
        endcase
    
    // ack:应答信号
    always@(*)
        case    (state)
            IDLE,START_1,SEND_D_ADDR,SEND_B_ADDR_H,SEND_B_ADDR_L,
            WR_DATA,START_2,SEND_RD_ADDR,RD_DATA,N_ACK:
                ack <=  1'b1;
            ACK_1,ACK_2,ACK_3,ACK_4,ACK_5:
                if(cnt_i2c_clk == 2'd0)
                    ack <=  sda_in;
                else
                    ack <=  ack;
            default:    ack <=  1'b1;
        endcase
    
    // i2c_scl:输出至i2c设备的串行时钟信号scl
    always@(*)
        case    (state)
            IDLE:
                i2c_scl <=  1'b1;
            START_1:
                if(cnt_i2c_clk == 2'd3)
                    i2c_scl <=  1'b0;
                else
                    i2c_scl <=  1'b1;
            SEND_D_ADDR,ACK_1,SEND_B_ADDR_H,ACK_2,SEND_B_ADDR_L,
            ACK_3,WR_DATA,ACK_4,START_2,SEND_RD_ADDR,ACK_5,RD_DATA,N_ACK:
                if((cnt_i2c_clk == 2'd1) || (cnt_i2c_clk == 2'd2))
                    i2c_scl <=  1'b1;
                else
                    i2c_scl <=  1'b0;
            STOP:
                if((cnt_bit == 3'd0) &&(cnt_i2c_clk == 2'd0))
                    i2c_scl <=  1'b0;
                else
                    i2c_scl <=  1'b1;
            default:    i2c_scl <=  1'b1;
        endcase
    
    // i2c_sda_reg:sda数据缓存
    always@(*)
        case    (state)
            IDLE:
                begin
                    i2c_sda_reg <=  1'b1;
                    rd_data_reg <=  8'd0;
                end
            START_1:
                if(cnt_i2c_clk <= 2'd0)
                    i2c_sda_reg <=  1'b1;
                else
                    i2c_sda_reg <=  1'b0;
            SEND_D_ADDR:
                if(cnt_bit <= 3'd6)
                    i2c_sda_reg <=  DEVICE_ADDR[6 - cnt_bit];
                else
                    i2c_sda_reg <=  1'b0;
            ACK_1:
                i2c_sda_reg <=  1'b1;
            SEND_B_ADDR_H:
                i2c_sda_reg <=  byte_addr[15 - cnt_bit];/* 高八位写入状态 */
            ACK_2:
                i2c_sda_reg <=  1'b1;
            SEND_B_ADDR_L:
                i2c_sda_reg <=  byte_addr[7 - cnt_bit];/* 低八位写入状态 */
            ACK_3:
                i2c_sda_reg <=  1'b1;
            WR_DATA:
                i2c_sda_reg <=  wr_data[7 - cnt_bit];
            ACK_4:
                i2c_sda_reg <=  1'b1;
            START_2:
                if(cnt_i2c_clk <= 2'd1)
                    i2c_sda_reg <=  1'b1;
                else
                    i2c_sda_reg <=  1'b0;
            SEND_RD_ADDR:
                if(cnt_bit <= 3'd6)
                    i2c_sda_reg <=  DEVICE_ADDR[6 - cnt_bit];
                else
                    i2c_sda_reg <=  1'b1;
            ACK_5:
                i2c_sda_reg <=  1'b1;
            RD_DATA:
                if(cnt_i2c_clk  == 2'd2)
                    rd_data_reg[7 - cnt_bit]    <=  sda_in;
                else
                    rd_data_reg <=  rd_data_reg;
            N_ACK:
                i2c_sda_reg <=  1'b1;
            STOP:
                if((cnt_bit == 3'd0) && (cnt_i2c_clk < 2'd3))
                    i2c_sda_reg <=  1'b0;
                else
                    i2c_sda_reg <=  1'b1;
            default:
                begin
                    i2c_sda_reg <=  1'b1;
                    rd_data_reg <=  rd_data_reg;
                end
        endcase
    
    // rd_data:自i2c设备读出数据
    always@(posedge i2c_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            rd_data <=  8'd0;
        else    if((state == RD_DATA) && (cnt_bit == 3'd7) && (cnt_i2c_clk == 2'd3))
            rd_data <=  rd_data_reg;
    
    // i2c_end:一次读/写结束信号
    always@(posedge i2c_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            i2c_end <=  1'b0;
        else    if((state == STOP) && (cnt_bit == 3'd3) &&(cnt_i2c_clk == 3))
            i2c_end <=  1'b1;
        else
            i2c_end <=  1'b0;
    
    // sda_in:sda输入数据寄存
    assign  sda_in = i2c_sda;
    // sda_en:sda数据写入使能信号
    assign  sda_en = ((state == RD_DATA) || (state == ACK_1) || (state == ACK_2)
                        || (state == ACK_3) || (state == ACK_4) || (state == ACK_5))
                        ? 1'b0 : 1'b1;
    // i2c_sda:输出至i2c设备的串行数据信号sda  1'bz高阻态 
    /* 高阻态的应用主要是在总线结构上,一般总线上会挂有多个设备,当主设备和其中一个
    从设备间建立通信的时候,其它的从设备IO一般是高阻态,这样就不会影响正在通信的设备。 */
    assign  i2c_sda = (sda_en == 1'b1) ? i2c_sda_reg : 1'bz;
    
    endmodule
    `timescale  1ns/1ns
    ////////////////////////////////////////////////////////////////////////
    // Author        : EmbedFire
    // Create Date   : 2019/04/01
    // Module Name   : pcf8591_adda
    // Project Name  : ad
    // Target Devices: Altera EP4CE10F17C8N
    // Tool Versions : Quartus 13.0
    // Description   : AD电压测量模块
    // 
    // Revision      : V1.0
    // Additional Comments:
    // 
    // 实验平台: 野火_征途Pro_FPGA开发板
    // 公司    : http://www.embedfire.com
    // 论坛    : http://www.firebbs.cn
    // 淘宝    : https://fire-stm32.taobao.com
    ////////////////////////////////////////////////////////////////////////
    
    module  pcf8591_ad
    (
        input   wire            sys_clk     ,   //输入系统时钟,50MHz?????
        input   wire            sys_rst_n   ,   //输入复位信号,低电平有效
        input   wire            i2c_end     ,   //i2c设备一次读/写操作完成
        input   wire    [7:0]   rd_data     ,   //输出i2c设备读取数据
    
        output  reg             rd_en       ,   //输入i2c设备读使能信号
        output  reg             i2c_start   ,   //输入i2c设备触发信号
        output  reg     [15:0]  byte_addr   ,   //输入i2c设备字节地址
        output  wire    [19:0]  po_data         //数码管待显示数据
    );
    
    //************************************************************************//
    //******************** Parameter and Internal Signal *********************//
    //************************************************************************//
    //parameter     define
    parameter   CTRL_DATA   =   8'b0100_0000;   //AD/DA控制字
    parameter   CNT_WAIT_MAX=   18'd6_9999  ;   //采样间隔计数最大值
    parameter   IDLE        =   3'b001,
                AD_START    =   3'b010,
                AD_CMD      =   3'b100;
    
    //wire  define
    wire    [31:0]  data_reg/* synthesis keep */;   //数码管待显示数据缓存
    
    //reg   define
    reg     [17:0]  cnt_wait;   //采样间隔计数器
    reg     [4:0]   state   ;   //状态机状态变量
    reg     [7:0]   ad_data ;   //AD数据
    
    //********************************************************************//
    //***************************** Main Code ****************************//
    //********************************************************************//
    //cnt_wait:采样间隔计数器
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            cnt_wait    <=  18'd0;
        else    if(state == IDLE)
            if(cnt_wait == CNT_WAIT_MAX)
                cnt_wait    <=  18'd0;
            else
                cnt_wait    <=  cnt_wait + 18'd1;
        else
            cnt_wait    <=  18'd0;
    
    //state:状态机状态变量
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            state   <=  IDLE;
        else
            case(state)
                IDLE:
                    if(cnt_wait == CNT_WAIT_MAX)
                        state   <=  AD_START;
                    else
                        state   <=  IDLE;
                AD_START:
                    state   <=  AD_CMD;
                AD_CMD:
                    if(i2c_end == 1'b1)
                        state   <=  IDLE;
                    else
                        state   <=  AD_CMD;
                default:state   <=  IDLE;
            endcase
    
    //i2c_start:输入i2c设备触发信号
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            i2c_start   <=  1'b0;
        else    if(state == AD_START)
            i2c_start   <=  1'b1;
        else
            i2c_start   <=  1'b0;
    
    //rd_en:输入i2c设备读使能信号
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            rd_en   <=  1'b0;
        else    if(state == AD_CMD)
            rd_en   <=  1'b1;
        else
            rd_en   <=  1'b0;
    
    //byte_addr:输入i2c设备字节地址
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            byte_addr   <=  16'b0;
        else
            byte_addr   <=  CTRL_DATA;
    
    //ad_data:AD数据
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            ad_data <=  8'b0;
        else    if(i2c_end == 1'b1) //(state == AD_CMD) && (i2c_end == 1'b1))
            ad_data <=  rd_data;
    
    //data_reg:数码管待显示数据缓存
    assign  data_reg = ((ad_data * 3300) >> 4'd8);///3.3v电压 二进制下右移8位/
    
    //po_data:数码管待显示数据
    assign  po_data = data_reg[19:0];
    
    endmodule
    `timescale  1ns/1ns
    ////////////////////////////////////////////////////////////////////////
    // Author        : EmbedFire
    // Create Date   : 2019/07/10
    // Module Name   : bcd_8421
    // Project Name  : top_seg_595
    // Target Devices: Altera EP4CE10F17C8N
    // Tool Versions : Quartus 13.0
    // Description   : 二进制数转BCD码
    //
    // Revision      : V1.0
    // Additional Comments:
    // 
    // 实验平台: 野火_征途系列FPGA开发板
    // 公司    : http://www.embedfire.com
    // 论坛    : http://www.firebbs.cn
    // 淘宝    : https://fire-stm32.taobao.com
    ////////////////////////////////////////////////////////////////////////
    
    module  bcd_8421
    (
        input   wire            sys_clk     ,   //系统时钟,频率50MHz
        input   wire            sys_rst_n   ,   //复位信号,低电平有效
        input   wire    [19:0]  data        ,   //输入需要转换的数据
    
        output  reg     [3:0]   unit        ,   //个位BCD码
        output  reg     [3:0]   ten         ,   //十位BCD码
        output  reg     [3:0]   hun         ,   //百位BCD码
        output  reg     [3:0]   tho         ,   //千位BCD码
        output  reg     [3:0]   t_tho       ,   //万位BCD码
        output  reg     [3:0]   h_hun           //十万位BCD码
    );
    
    //********************************************************************//
    //******************** Parameter And Internal Signal *****************//
    //********************************************************************//
    
    //reg   define
    reg     [4:0]   cnt_shift   ;   //移位判断计数器
    reg     [43:0]  data_shift  ;   //移位判断数据寄存器
    reg             shift_flag  ;   //移位判断标志信号
    
    //********************************************************************//
    //***************************** Main Code ****************************//
    //********************************************************************//
    
    //cnt_shift:从0到21循环计数
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            cnt_shift   <=  5'd0;
        else    if((cnt_shift == 5'd21) && (shift_flag == 1'b1))
            cnt_shift   <=  5'd0;
        else    if(shift_flag == 1'b1)
            cnt_shift   <=  cnt_shift + 1'b1;
        else
            cnt_shift   <=  cnt_shift;
           
    //data_shift:计数器为0时赋初值,计数器为1~20时进行移位判断操作?????
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            data_shift  <=  44'b0;
        else    if(cnt_shift == 5'd0)
            data_shift  <=  {24'b0,data};  //数据拼接
        else    if((cnt_shift <= 20) && (shift_flag == 1'b0))
            begin
                data_shift[23:20]   <=  (data_shift[23:20] > 4) ? (data_shift[23:20] + 2'd3) : (data_shift[23:20]);
                data_shift[27:24]   <=  (data_shift[27:24] > 4) ? (data_shift[27:24] + 2'd3) : (data_shift[27:24]);
                data_shift[31:28]   <=  (data_shift[31:28] > 4) ? (data_shift[31:28] + 2'd3) : (data_shift[31:28]);
                data_shift[35:32]   <=  (data_shift[35:32] > 4) ? (data_shift[35:32] + 2'd3) : (data_shift[35:32]);
                data_shift[39:36]   <=  (data_shift[39:36] > 4) ? (data_shift[39:36] + 2'd3) : (data_shift[39:36]);
                data_shift[43:40]   <=  (data_shift[43:40] > 4) ? (data_shift[43:40] + 2'd3) : (data_shift[43:40]);
            end
        else    if((cnt_shift <= 20) && (shift_flag == 1'b1))
            data_shift  <=  data_shift << 1;
        else
            data_shift  <=  data_shift;
    
    //shift_flag:移位判断标志信号,用于控制移位判断的先后顺序
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            shift_flag  <=  1'b0;
        else
            shift_flag  <=  ~shift_flag;
    
    //当计数器等于20时,移位判断操作完成,对各个位数的BCD码进行赋值   从左往右数 第一个是43
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            begin
                unit    <=  4'b0;
                ten     <=  4'b0;
                hun     <=  4'b0;
                tho     <=  4'b0;
                t_tho   <=  4'b0;
                h_hun   <=  4'b0;
            end
        else    if(cnt_shift == 5'd21)
            begin
                unit    <=  data_shift[23:20];
                ten     <=  data_shift[27:24];
                hun     <=  data_shift[31:28];
                tho     <=  data_shift[35:32];
                t_tho   <=  data_shift[39:36];
                h_hun   <=  data_shift[43:40];
            end
    
    endmodule
    `timescale  1ns/1ns
    ////////////////////////////////////////////////////////////////////////
    // Author        : EmbedFire
    // Create Date   : 2019/07/11
    // Module Name   : hc595_ctrl
    // Project Name  : seg_595_static
    // Target Devices: Altera EP4CE10F17C8N
    // Tool Versions : Quartus 13.0
    // Description   : 595控制模块
    //
    // Revision      : V1.0
    // Additional Comments:
    // 
    // 实验平台: 野火_征途Pro_FPGA开发板
    // 公司    : http://www.embedfire.com
    // 论坛    : http://www.firebbs.cn
    // 淘宝    : https://fire-stm32.taobao.com
    ////////////////////////////////////////////////////////////////////////
    module  hc595_ctrl
    (
        input   wire            sys_clk     ,   //系统时钟,频率50MHz
        input   wire            sys_rst_n   ,   //复位信号,低有效
        input   wire    [5:0]   sel         ,   //数码管位选信号          DIG6(sel[0])对应的就是开发板上最右侧数码管。
        input   wire    [7:0]   seg         ,   //数码管段选信号      
        
        output  reg             stcp        ,   //数据存储器时钟 产生STCP时钟,将移位寄存器里的数据送入存储寄存器。
        output  reg             shcp        ,   //移位寄存器时钟 产生SHCP时钟,将串行数据输入引脚DS上的数据串行移入移位寄存器。
        output  reg             ds          ,   //串行数据输入
        output  wire            oe              //使能信号,低有效??????
    );
    
    //********************************************************************//
    //****************** Parameter and Internal Signal *******************//
    //********************************************************************//
    //reg   define
    reg     [1:0]   cnt_4   ;   //分频计数器
    reg     [3:0]   cnt_bit ;   //传输位数计数器
    
    //wire  define
    wire    [13:0]  data    ;   //数码管信号寄存
    
    //********************************************************************//
    //***************************** Main Code ****************************//
    //********************************************************************//
    
    //将数码管信号寄存??? 数码管信号寄存在data中
    assign  data = {seg[0],seg[1],seg[2],seg[3],seg[4],seg[5],seg[6],seg[7],sel};
    
    //将复位取反后赋值给其即可?????????
    assign oe = ~sys_rst_n;
    
    /* STCP上升沿时移位寄存器的数据会进入数据存储寄存器,通过让OE(输出使能输入)低即可让存储寄存器的数据进行输出。 */
    
    
    //分频计数器:0~3循环计数
    always@(posedge sys_clk or  negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            cnt_4 <=  2'd0;
        else    if(cnt_4 == 2'd3)
            cnt_4 <=  2'd0;
        else
            cnt_4 <=  cnt_4 +   1'b1;
    
    //cnt_bit:每输入一位数据加一 /* 当cnt等于3时让cnt_bit计数器加1,让其从0到13循环计数,每个数值代表传输一位数据。 */
    always@(posedge sys_clk or  negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            cnt_bit   <=  4'd0;
        else    if(cnt_4 == 2'd3 && cnt_bit == 4'd13)
            cnt_bit   <=  4'd0;
        else    if(cnt_4  ==  2'd3)
            cnt_bit   <=  cnt_bit   +   1'b1;
        else
            cnt_bit   <=  cnt_bit;
    
    //stcp:14个信号传输完成之后产生一个上升沿? 
    
    always@(posedge sys_clk or  negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            stcp    <=  1'b0;
        else    if(cnt_bit == 4'd13 && cnt_4 == 2'd3)
            stcp    <=  1'b1;
        else
            stcp    <=  1'b0;
    
    //shcp:产生四分频移位时钟
    always@(posedge sys_clk or  negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            shcp    <=  1'b0;
        else    if(cnt_4 >= 4'd2)
            shcp    <=  1'b1;
        else
            shcp    <=  1'b0;
    
    //ds:将寄存器里存储的数码管信号输入即?????
    always@(posedge sys_clk or  negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            ds  <=  1'b0;
        else    if(cnt_4 == 2'd0)
            ds  <=  data[cnt_bit];
        else
            ds  <=  ds;
    
    endmodule
    `timescale  1ns/1ns
    ////////////////////////////////////////////////////////////////////////
    // Author        : EmbedFire
    // Create Date   : 2019/07/10
    // Module Name   : seg_dynamic
    // Project Name  : ad
    // 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  seg_dynamic
    (
        input   wire            sys_clk     , //系统时钟,频率50MHz
        input   wire            sys_rst_n   , //复位信号,低有效
        input   wire    [19:0]  data        , //数码管要显示的值
        input   wire    [5:0]   point       , //小数点显示,高电平有效
        input   wire            seg_en      , //数码管使能信号,高电平有效
        input   wire            sign        , //符号位,高电平显示负号
    
        output  reg     [5:0]   sel         , //数码管位选信号
        output  reg     [7:0]   seg           //数码管段选信号
    );
    
    //********************************************************************//
    //****************** Parameter and Internal Signal *******************//
    //********************************************************************//
    
    //parameter define
    parameter   CNT_MAX =   16'd49_999;  //数码管刷新时间计数最大值
    
    //wire  define
    wire    [3:0]   unit        ;   //个位数
    wire    [3:0]   ten         ;   //十位数
    wire    [3:0]   hun         ;   //百位数
    wire    [3:0]   tho         ;   //千位数
    wire    [3:0]   t_tho       ;   //万位数
    wire    [3:0]   h_hun       ;   //十万位数
    
    //reg   define
    reg     [23:0]  data_reg    ;   //待显示数据寄存器
    reg     [15:0]  cnt_1ms     ;   //1ms计数器
    reg             flag_1ms    ;   //1ms标志信号
    reg     [2:0]   cnt_sel     ;   //数码管位选计数器
    reg     [5:0]   sel_reg     ;   //位选信号
    reg     [3:0]   data_disp   ;   //当前数码管显示的数据
    reg             dot_disp    ;   //当前数码管显示的小数点
    
    //********************************************************************//
    //***************************** Main Code ****************************//
    //********************************************************************//
    
    //data_reg:控制数码管显示数据   point没用到?????
     always@(posedge sys_clk or  negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            data_reg    <=  24'b0;
    //若显示的十进制数的十万位为非零数据或需显示小数点,则六个数码管全显示
        else    if((h_hun) || (point[5]))
            data_reg    <=  {h_hun,t_tho,tho,hun,ten,unit};
    //若显示的十进制数的万位为非零数据或需显示小数点,则值显示在5个数码管上
    //打比方我们输入的十进制数据为20’d12345,我们就让数码管显示12345而不是012345
        else    if(((t_tho) || (point[4])) && (sign == 1'b1))//显示负号
            data_reg <= {4'd10,t_tho,tho,hun,ten,unit};//4'd10我们定义为显示负号
        else    if(((t_tho) || (point[4])) && (sign == 1'b0))
            data_reg <= {4'd11,t_tho,tho,hun,ten,unit};//4'd11我们定义为不显示
    //若显示的十进制数的千位为非零数据或需显示小数点,则值显示4个数码管
        else    if(((tho) || (point[3])) && (sign == 1'b1))
            data_reg <= {4'd11,4'd10,tho,hun,ten,unit};
        else    if(((tho) || (point[3])) && (sign == 1'b0))
            data_reg <= {4'd11,4'd11,tho,hun,ten,unit};
    //若显示的十进制数的百位为非零数据或需显示小数点,则值显示3个数码管
        else    if(((hun) || (point[2])) && (sign == 1'b1))
            data_reg <= {4'd11,4'd11,4'd10,hun,ten,unit};
        else    if(((hun) || (point[2])) && (sign == 1'b0))
            data_reg <= {4'd11,4'd11,4'd11,hun,ten,unit};
    //若显示的十进制数的十位为非零数据或需显示小数点,则值显示2个数码管
        else    if(((ten) || (point[1])) && (sign == 1'b1))
            data_reg <= {4'd11,4'd11,4'd11,4'd10,ten,unit};
        else    if(((ten) || (point[1])) && (sign == 1'b0))
            data_reg <= {4'd11,4'd11,4'd11,4'd11,ten,unit};
    //若显示的十进制数的个位且需显示负号
        else    if(((unit) || (point[0])) && (sign == 1'b1))
            data_reg <= {4'd11,4'd11,4'd11,4'd11,4'd10,unit};
    //若上面都不满足都只显示一位数码管
        else
            data_reg <= {4'd11,4'd11,4'd11,4'd11,4'd11,unit};
    
    //cnt_1ms:1ms循环计数
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            cnt_1ms <=  16'd0;
        else    if(cnt_1ms == CNT_MAX)
            cnt_1ms <=  16'd0;
        else
            cnt_1ms <=  cnt_1ms + 1'b1;
    
    //flag_1ms:1ms标志信号
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            flag_1ms    <=  1'b0;
        else    if(cnt_1ms == CNT_MAX - 1'b1)
            flag_1ms    <=  1'b1;
        else
            flag_1ms    <=  1'b0;
    
    //cnt_sel:从0到5循环数,用于选择当前显示的数码管
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            cnt_sel <=  3'd0;
        else    if((cnt_sel == 3'd5) && (flag_1ms == 1'b1))
            cnt_sel <=  3'd0;
        else    if(flag_1ms == 1'b1)
            cnt_sel <=  cnt_sel + 1'b1;
        else
            cnt_sel <=  cnt_sel;
    
    //数码管位选信号寄存器
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            sel_reg <=  6'b000_000;
        else    if((cnt_sel == 3'd0) && (flag_1ms == 1'b1))
            sel_reg <=  6'b000_001;
        else    if(flag_1ms == 1'b1)
            sel_reg <=  sel_reg << 1;
        else
            sel_reg <=  sel_reg;
    
    //控制数码管的位选信号,使六个数码管轮流显示
    always@(posedge sys_clk or  negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            data_disp    <=  4'b0;
        else    if((seg_en == 1'b1) && (flag_1ms == 1'b1))
            case(cnt_sel)//对应case语句里面选择对应的输出
            3'd0:   data_disp    <=  data_reg[3:0]  ;  //给第1个数码管赋个位值
            3'd1:   data_disp    <=  data_reg[7:4]  ;  //给第2个数码管赋十位值
            3'd2:   data_disp    <=  data_reg[11:8] ;  //给第3个数码管赋百位值
            3'd3:   data_disp    <=  data_reg[15:12];  //给第4个数码管赋千位值
            3'd4:   data_disp    <=  data_reg[19:16];  //给第5个数码管赋万位值
            3'd5:   data_disp    <=  data_reg[23:20];  //给第6个数码管赋十万位值
            default:data_disp    <=  4'b0        ;
            endcase
        else
            data_disp   <=  data_disp;
    
    //dot_disp:小数点低电平点亮,需对小数点有效信号取反???????
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            dot_disp    <=  1'b1;
        else    if(flag_1ms == 1'b1)
            dot_disp    <=  ~point[cnt_sel];
        else
            dot_disp    <=  dot_disp;
    
    //控制数码管段选信号,显示数字???
    always@(posedge sys_clk or  negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            seg <=  8'b1111_1111;
        else    
            case(data_disp)
                4'd0  : seg  <=  {dot_disp,7'b100_0000};    //显示数字0
                4'd1  : seg  <=  {dot_disp,7'b111_1001};    //显示数字1
                4'd2  : seg  <=  {dot_disp,7'b010_0100};    //显示数字2
                4'd3  : seg  <=  {dot_disp,7'b011_0000};    //显示数字3
                4'd4  : seg  <=  {dot_disp,7'b001_1001};    //显示数字4
                4'd5  : seg  <=  {dot_disp,7'b001_0010};    //显示数字5
                4'd6  : seg  <=  {dot_disp,7'b000_0010};    //显示数字6
                4'd7  : seg  <=  {dot_disp,7'b111_1000};    //显示数字7
                4'd8  : seg  <=  {dot_disp,7'b000_0000};    //显示数字8
                4'd9  : seg  <=  {dot_disp,7'b001_0000};    //显示数字9
                4'd10 : seg  <=  8'b1011_1111          ;    //显示负号
                4'd11 : seg  <=  8'b1111_1111          ;    //不显示任何字符
                default:seg  <=  8'b1100_0000;
            endcase
    
    //sel:数码管位选信号赋值
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            sel <=  6'b000_000;
        else
            sel <=  sel_reg;
    
    //********************************************************************//
    //*************************** Instantiation **************************//
    //********************************************************************//
    
    //---------- bsd_8421_inst ----------
    bcd_8421    bcd_8421_inst
    (
        .sys_clk     (sys_clk  ),   //系统时钟,频率50MHz
        .sys_rst_n   (sys_rst_n),   //复位信号,低电平有效
        .data        (data     ),   //输入需要转换的数据
    
        .unit        (unit     ),   //个位BCD码
        .ten         (ten      ),   //十位BCD码
        .hun         (hun      ),   //百位BCD码
        .tho         (tho      ),   //千位BCD码
        .t_tho       (t_tho    ),   //万位BCD码
        .h_hun       (h_hun    )    //十万位BCD码
    );
    
    endmodule

     

请登录后发表评论

    • ICMaker的头像-ChipDebugICMaker徽章-资深玩家-ChipDebug等级-LV3-ChipDebug版主0