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