HC165并转串

发布于:2025-07-17 ⋅ 阅读:(19) ⋅ 点赞:(0)

HC165.v

/**
 https://docs.wokwi.com/zh-CN/parts/wokwi-74hc165
**/
`timescale 1ns / 1ps
module HC165 (
    input  wire        i_clk,     // 全局系统时钟(用于串行输出寄存)
    input  wire        i_rst_n,   // 异步复位(低有效)
    input  wire        PL,        //串行输出
    input  wire        CP,     // 移位时钟(上升沿有效)
    input  wire [7:0]  D,        // 并行输入 D0~D7
    output wire        Q7         // 串行输出
);

    reg [7:0] r_shift_reg;

    // 并行加载或串行移位
    always @(posedge i_clk or negedge i_rst_n) begin
        if (!i_rst_n)
            r_shift_reg <= 8'b0;
        else if (!PL)
            r_shift_reg <= D;
        else if (CP)  // 移位操作
            r_shift_reg <= {r_shift_reg[6:0], 1'b0};
    end

    assign Q7 = r_shift_reg[7];

endmodule

hc165_drive.v

`timescale 1ns / 1ps

module hc165_drive (
    input  wire        i_clk,     // 系统时钟
    input  wire        i_rst_n,   // 异步复位(低有效)
    input  wire        i_start,   // 启动采集
    output reg [7:0]   o_data,    // 并转串采集到的数据
    output reg         o_done,    // 采集完成信号

    //接HC165
    output reg         o_pl,      // 并行加载信号(低有效)
    output reg         o_cp,      // 移位时钟信号
    input  wire        i_q7       // 串行数据输入

);

    // 状态机状态定义
    localparam S_IDLE   = 3'd0,  // 空闲状态,等待开始信号
               S_WAIT   = 3'd1,  // 并行加载等待状态,释放 PL
               S_LOAD   = 3'd2,  // 保留状态(未使用)
               S_SHIFT0 = 3'd3,  // 拉低 SCLK 准备移位
               S_SHIFT1 = 3'd4,  // 拉高 SCLK,采样 QH 数据
               S_DONE   = 3'd5;  // 移位完成,输出数据

    reg [2:0]  r_state;
    reg [2:0]  r_bit_cnt;
    reg [7:0]  r_shift_reg;

    always @(posedge i_clk or negedge i_rst_n) begin
        if (!i_rst_n) begin
            o_pl        <= 1'b1;
            o_cp      <= 1'b0;
            o_data      <= 8'd0;
            o_done      <= 1'b0;
            r_bit_cnt     <= 3'd0;
            r_shift_reg   <= 8'd0;
            r_state       <= S_IDLE;
        end else begin
            case (r_state)
                S_IDLE: begin
                    o_done <= 1'b0;
                    o_cp <= 1'b0;
                    if (i_start) begin
                        o_pl  <= 1'b0;  // 拉低加载
                        r_state <= S_WAIT;
                    end
                end

                S_WAIT: begin
                    o_pl  <= 1'b1;  // 拉高,准备移位
                    r_bit_cnt <= 0;
                    r_state <= S_SHIFT0;
                end

                S_SHIFT0: begin
                    o_cp <= 1'b0;  // 先拉低时钟
                    r_state  <= S_SHIFT1;
                end

                S_SHIFT1: begin
                    o_cp <= 1'b1;  // 上升沿触发移位
                    r_shift_reg <= {r_shift_reg[6:0], i_q7};
                    r_bit_cnt <= r_bit_cnt + 1;
                    if (r_bit_cnt == 3'd7)
                        r_state <= S_DONE;
                    else
                        r_state <= S_SHIFT0;
                end

                S_DONE: begin
                    o_cp  <= 1'b0;
                    o_data  <= r_shift_reg;
                    o_done  <= 1'b1;
                    r_state   <= S_IDLE;
                end
            endcase
        end
    end

endmodule

tb.v

`timescale 1ns / 1ps

module tb;

    reg         clk;
    reg         rst_n;
    reg         start;
    reg  [7:0]  d;
    wire  [7:0]  data_out;
    wire        pl;
    wire        cp;
    wire        q7;
    wire        done;
 

    // 实例化 hc165
    HC165 u_hc165 (
        .i_clk   (clk),
        .i_rst_n (rst_n),
        .PL      (pl),
        .CP   (cp),
        .D       (d),
        .Q7      (q7)
    );

    // 实例化驱动器
    hc165_drive u_hc165_drive (
        .i_clk   (clk),
        .i_rst_n(rst_n),
        .i_q7   (q7),
        .i_start(start),
        .o_pl   (pl),
        .o_cp(cp),
        .o_data (data_out),
        .o_done (done)
    );

    initial clk = 0;
    always #5 clk = ~clk;  // 100MHz

    initial begin
        rst_n = 0;
        start = 0;
        d = 8'b0;
        #20;
        rst_n = 1;
        #20;

        d = 8'b10101010;  // 预设要采集的数据
        start = 1;
        #10;
        start = 0;

        wait (done == 1);
        #10;
        $display("Read data: %b", data_out);
        #20;
        $finish;
    end

endmodule

网站公告

今日签到

点亮在社区的每一天
去签到