HC595.v
/**
https://docs.wokwi.com/zh-CN/parts/wokwi-74hc595
**/
`timescale 1ns / 1ps
module HC595 (
input wire i_clk, // 全局时钟,用于同步操作
input wire i_rst_n, // 复位信号,清除所有寄存器
input wire DS, // 串行数据输入(DS)
input wire SHCP, // 移位时钟(SHCP),用于移位操作
input wire STCP, // 存储时钟(STCP),用于锁存数据
output reg [7:0] Q, // 8 位并行输出(Q)
output reg Q7S // 串行输出(从移位寄存器)
);
reg [7:0] r_shift_reg; // 8 位移位寄存器
// 移位操作:每当 SHCP 上升沿时,将串行数据输入到移位寄存器
always @(posedge SHCP or posedge i_rst_n) begin
if (!i_rst_n) begin
r_shift_reg <= 8'b0; // 复位时清零移位寄存器
end else begin
r_shift_reg <= {r_shift_reg[6:0], DS}; // 左移并输入串行数据
end
end
// 存储操作:每当 STCP 上升沿时,将移位寄存器的内容传递到并行输出寄存器
always @(posedge STCP or posedge i_rst_n) begin
if (!i_rst_n) begin
Q <= 8'b0; // 复位时清空并行输出
end else begin
Q <= r_shift_reg; // 将移位寄存器的内容输出到并行输出
end
end
// 串行输出:移位寄存器的最右边位(r_shift_reg[7])作为串行输出
always @(posedge i_clk) begin
Q7S <= r_shift_reg[7]; // 串行输出为移位寄存器的最右边位
end
endmodule
hc595_drive.v
`timescale 1ns / 1ps
module hc595_drive (
input wire i_clk, // 全局时钟
input wire i_rst_n, // 低电平复位
input wire i_start, // 启动信号
input wire [7:0] i_data, // 8 位数据输入
output reg o_shcp, // 移位时钟
output reg o_stcp, // 存储时钟
output reg o_ds, // 串行数据输出
output reg o_done // 传输完成信号
);
// 状态编码
localparam S_IDLE = 3'd0,
S_LOAD = 3'd1,
S_SHIFT_LOW = 3'd2,
S_SHIFT_HIGH = 3'd3,
S_LATCH_LOW = 3'd4,
S_LATCH_HIGH = 3'd5,
S_DONE = 3'd6;
reg [2:0] state;
reg [3: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_shcp <= 1'b0;
o_stcp <= 1'b0;
o_ds <= 1'b0;
o_done <= 1'b0;
r_bit_cnt <= 4'd0;
r_shift_reg <= 8'd0;
state <= S_IDLE;
end else begin
case (state)
S_IDLE: begin
o_done <= 1'b0;
o_shcp <= 1'b0;
o_stcp <= 1'b0;
if (i_start) begin
state <= S_LOAD;
end
end
S_LOAD: begin
r_shift_reg <= i_data;
r_bit_cnt <= 4'd0;
state <= S_SHIFT_LOW;
end
S_SHIFT_LOW: begin
o_ds <= r_shift_reg[7];
o_shcp <= 1'b0;
state <= S_SHIFT_HIGH;
end
S_SHIFT_HIGH: begin
o_shcp <= 1'b1;
r_shift_reg <= {r_shift_reg[6:0], 1'b0}; // 左移
r_bit_cnt <= r_bit_cnt + 1;
if (r_bit_cnt == 4'd7)
state <= S_LATCH_LOW;
else
state <= S_SHIFT_LOW;
end
S_LATCH_LOW: begin
o_stcp <= 1'b0;
state <= S_LATCH_HIGH;
end
S_LATCH_HIGH: begin
o_stcp <= 1'b1;
state <= S_DONE;
end
S_DONE: begin
o_stcp <= 1'b0;
o_shcp <= 1'b0;
o_done <= 1'b1;
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] dat;
wire SHCP;
wire STCP;
wire DS;
wire done;
wire [7:0] Q;
wire Q7S;
// 实例化 HC595
HC595 u_hc595 (
.i_clk(clk),
.i_rst_n(rst_n),
.DS(DS),
.SHCP(SHCP),
.STCP(STCP),
.Q(Q),
.Q7S(Q7S)
);
// 实例化驱动模块
hc595_drive u_hc595_drive (
.i_clk(clk),
.i_rst_n(rst_n),
.i_start(start),
.i_data(dat),
.o_shcp(SHCP),
.o_stcp(STCP),
.o_ds(DS),
.o_done(done)
);
// 生成时钟
initial clk = 0;
always #5 clk = ~clk; // 100MHz
initial begin
// 初始化
rst_n = 0;
start = 0;
dat = 8'h00;
#20;
rst_n = 1;
#20;
// 写入 0x38
dat = 8'h38;
start = 1;
#10;
start = 0;
// 等待传输完成
wait(done == 1);
#10;
$display("Q_OUT after 0x38 = %b", Q);
// 写入 0x46
dat = 8'h46;
start = 1;
#10;
start = 0;
wait(done == 1);
#10;
$display("Q_OUT after 0x46 = %b", Q);
#50;
$finish;
end
endmodule
wokwi
main.ino
#include <Arduino.h>
#define datapin 2
#define clockpin 3
#define latchpin 4
#define HC595_SCLK(x) digitalWrite(clockpin, x)
#define HC595_RCLK(x) digitalWrite(latchpin, x)
#define HC595_SDAT(x) digitalWrite(datapin, x)
void hc595_drive(unsigned char dat_h)
{
unsigned char i;
unsigned char dat_temp;
HC595_SCLK(0);
HC595_RCLK(0);
dat_temp = dat_h;
for (i = 0; i<8; i++)
{
HC595_SDAT(dat_temp >= 0x80);
HC595_SCLK(0);
delay(1);
HC595_SCLK(1);
delay(1);
dat_temp = dat_temp << 1;
}
HC595_RCLK(0);
delay(1);
HC595_RCLK(1);
delay(1);
HC595_SCLK(0);
HC595_RCLK(0);
HC595_SDAT(0);
}
void hc595_init()
{
pinMode(datapin, OUTPUT);
pinMode(clockpin, OUTPUT);
pinMode(latchpin, OUTPUT);
}
void setup()
{
hc595_init();
hc595_drive(0x01);
}
void loop()
{
}
diagram.json
{
"version": 1,
"author": "Uri Shaked",
"editor": "wokwi",
"parts": [
{ "type": "wokwi-arduino-uno", "id": "uno", "top": 231, "left": -135, "attrs": {} },
{
"type": "wokwi-74hc595",
"id": "sr1",
"top": 94.66,
"left": 178.9,
"rotate": 270,
"attrs": {}
},
{
"type": "wokwi-led-bar-graph",
"id": "bargraph1",
"top": 72,
"left": 321.6,
"attrs": { "color": "lime" }
},
{ "type": "wokwi-gnd", "id": "gnd1", "top": 182.4, "left": 345, "attrs": {} }
],
"connections": [
[ "sr1:DS", "uno:2", "blue", [ "h-75.6", "h0", "v115.2" ] ],
[ "sr1:STCP", "uno:4", "purple", [ "h-56.4", "v0", "h-61.5" ] ],
[ "sr1:SHCP", "uno:3", "gray", [ "h-75.6", "v0", "h-32.8" ] ],
[ "sr1:Q0", "bargraph1:A1", "green", [ "h-18", "v28.8", "h67.2", "v-86.4" ] ],
[ "sr1:Q1", "bargraph1:A2", "green", [ "h38.4", "v-57.6" ] ],
[ "sr1:Q2", "bargraph1:A3", "green", [ "h28.8", "v-38.4" ] ],
[ "sr1:Q3", "bargraph1:A4", "green", [ "h9.6", "v-19.2" ] ],
[ "sr1:Q4", "bargraph1:A5", "green", [ "h0" ] ],
[ "sr1:Q5", "bargraph1:A6", "green", [ "h9.6", "v-48", "h67.2", "v67.2" ] ],
[ "sr1:Q6", "bargraph1:A7", "green", [ "h57.6", "v48" ] ],
[ "sr1:Q7", "bargraph1:A8", "green", [ "h48", "v57.6" ] ],
[ "bargraph1:C1", "bargraph1:C2", "green", [ "v0" ] ],
[ "bargraph1:C3", "bargraph1:C4", "green", [ "h0" ] ],
[ "bargraph1:C5", "bargraph1:C6", "green", [ "h0" ] ],
[ "bargraph1:C7", "bargraph1:C8", "green", [ "h0" ] ],
[ "bargraph1:C9", "bargraph1:C10", "green", [ "h0" ] ],
[ "bargraph1:C8", "bargraph1:C9", "green", [ "h0" ] ],
[ "bargraph1:C2", "bargraph1:C3", "green", [ "h0" ] ],
[ "bargraph1:C4", "bargraph1:C5", "green", [ "h0" ] ],
[ "bargraph1:C6", "bargraph1:C7", "green", [ "h0" ] ],
[ "gnd1:GND", "bargraph1:C10", "black", [ "v0" ] ]
],
"dependencies": {}
}
hc595_drive.c
void hc595_drive(unsigned char dat_h)
{
unsigned char i;
unsigned char dat_temp;
HC595_SCLK = 0;
HC595_RCLK = 0;
dat_temp = dat_h;
for (i = 0; i<8; i++)
{
if (dat_temp >= 0x80)HC595_SDAT = 1;
else HC595_SDAT = 0;
HC595_SCLK = 0;
_delay(1);
HC595_SCLK = 1;
_delay(1);
dat_temp = dat_temp << 1;
}
HC595_RCLK = 0;
_delay(1);
HC595_RCLK = 1;
_delay(1);
HC595_SCLK = 0;
HC595_RCLK = 0;
HC595_SDAT = 0;
}
arduino
#include <Arduino.h>
int datapin = 2;
int clockpin = 3;
int latchpin = 4;
#define HC595_SCLK(x) digitalWrite(3, x)
#define HC595_RCLK(x) digitalWrite(4, x)
#define HC595_SDAT(x) digitalWrite(2, x)
void hc595_drive(unsigned char dat_h)
{
unsigned char i;
unsigned char dat_temp;
HC595_SCLK(0);
HC595_RCLK(0);
dat_temp = dat_h;
for (i = 0; i<8; i++)
{
HC595_SDAT(dat_temp >= 0x80);
HC595_SCLK(0);
delay(1);
HC595_SCLK(1);
delay(1);
dat_temp = dat_temp << 1;
}
HC595_RCLK(0);
delay(1);
HC595_RCLK(1);
delay(1);
HC595_SCLK(0);
HC595_RCLK(0);
HC595_SDAT(0);
}
void setup()
{
pinMode(datapin, OUTPUT);
pinMode(clockpin, OUTPUT);
pinMode(latchpin, OUTPUT);
hc595_drive(0x01);
}
void loop()
{
}
diagram.json
{
"version": 1,
"author": "Uri Shaked",
"editor": "wokwi",
"parts": [
{ "type": "wokwi-arduino-uno", "id": "uno", "top": 231, "left": -135, "attrs": {} },
{
"type": "wokwi-74hc595",
"id": "sr1",
"top": 94.66,
"left": 178.9,
"rotate": 270,
"attrs": {}
},
{
"type": "wokwi-led-bar-graph",
"id": "bargraph1",
"top": 72,
"left": 321.6,
"attrs": { "color": "lime" }
},
{ "type": "wokwi-gnd", "id": "gnd1", "top": 182.4, "left": 345, "attrs": {} }
],
"connections": [
[ "sr1:DS", "uno:2", "blue", [ "h-75.6", "h0", "v115.2" ] ],
[ "sr1:STCP", "uno:4", "purple", [ "h-56.4", "v0", "h-61.5" ] ],
[ "sr1:SHCP", "uno:3", "gray", [ "h4", "v30", "h-66" ] ],
[ "sr1:Q0", "bargraph1:A1", "green", [ "h-18", "v28.8", "h67.2", "v-86.4" ] ],
[ "sr1:Q1", "bargraph1:A2", "green", [ "h38.4", "v-57.6" ] ],
[ "sr1:Q2", "bargraph1:A3", "green", [ "h28.8", "v-38.4" ] ],
[ "sr1:Q3", "bargraph1:A4", "green", [ "h9.6", "v-19.2" ] ],
[ "sr1:Q4", "bargraph1:A5", "green", [ "h0" ] ],
[ "sr1:Q5", "bargraph1:A6", "green", [ "h9.6", "v-48", "h67.2", "v67.2" ] ],
[ "sr1:Q6", "bargraph1:A7", "green", [ "h57.6", "v48" ] ],
[ "sr1:Q7", "bargraph1:A8", "green", [ "h48", "v57.6" ] ],
[ "bargraph1:C1", "bargraph1:C2", "green", [ "v0" ] ],
[ "bargraph1:C3", "bargraph1:C4", "green", [ "h0" ] ],
[ "bargraph1:C5", "bargraph1:C6", "green", [ "h0" ] ],
[ "bargraph1:C7", "bargraph1:C8", "green", [ "h0" ] ],
[ "bargraph1:C9", "bargraph1:C10", "green", [ "h0" ] ],
[ "bargraph1:C8", "bargraph1:C9", "green", [ "h0" ] ],
[ "bargraph1:C2", "bargraph1:C3", "green", [ "h0" ] ],
[ "bargraph1:C4", "bargraph1:C5", "green", [ "h0" ] ],
[ "bargraph1:C6", "bargraph1:C7", "green", [ "h0" ] ],
[ "gnd1:GND", "bargraph1:C10", "black", [ "v0" ] ]
],
"dependencies": {}
}
···