分析:
对于74HC595芯片,该芯片在位移时钟信号SRCLK的上升沿将串行输入数据SER(DIO)移入内部的寄存器。因此我们需要保证DIO上的数据在SRCLK上升沿前后一段时间内保持稳定
因此,FPGA要在SRCLK的下降沿改变DIO的值,在上升沿取到的就一定是稳定的值
数据锁存器时钟信号RCLK只需要在16位数据都移入之后给一个高电平,锁存即可
3.3V驱动,取SRCLK最大频率为12.5MHz,周期80ns
先移入的数据在高位输出
因此,应当先传第二片的seg,再传第一片的sel
顺序为seg7-0,sel7-0
设计文件:
`timescale 1ns / 1ps
module HC595_Driver(
Clk,
Reset_n,
SEG,
SEL,
DIO,
RCLK,
SRCLK
);
input Clk;
input Reset_n;
input [7:0]SEL;
input [7:0]SEG;
output reg DIO;
output reg RCLK;
output reg SRCLK;
parameter CLOCK_FREQ = 50_000_000;
parameter SRCLK_FREQ = 12_500_000;
parameter MCNT = CLOCK_FREQ/(SRCLK_FREQ * 2 ) - 1; //用SRCLK的半个周期进行分析,有助于找到对应的高/低电平,上升沿下降沿
reg[29:0]div_cnt;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
div_cnt <= 0;
else if(div_cnt == MCNT)
div_cnt <= 0;
else
div_cnt <= div_cnt + 1'd1;
reg[4:0]cnt; //传输16位数据,32个高低电平,2的5次方,需要5位
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
cnt <= 0;
else if(div_cnt == MCNT)
cnt <= cnt +1'd1; //每一个上升沿/下降沿都对应一个cnt值,用case语句使得不同时刻做不同的任务
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)begin
DIO <= 1'd0;
SRCLK <= 1'd0;
RCLK <= 1'd0;
end
else begin
case(cnt)
0:begin DIO <= SEG[7]; SRCLK <= 1 'd0; RCLK <= 1'd1; end //每个下降沿都要传输一次数据,总共有16个下降沿,把16个数据都能够移位寄存;每一轮的开始也是上一轮的结束,RCLK高电平锁存
1:begin SRCLK <= 1'd1; RCLK <= 1'd0; end
2:begin DIO <= SEG[6]; SRCLK <= 1'd0; end
3:begin SRCLK <= 1'd1; end
4:begin DIO <= SEG[5]; SRCLK <= 1'd0; end
5:begin SRCLK <= 1'd1; end
6:begin DIO <= SEG[4]; SRCLK <= 1'd0; end
7:begin SRCLK <= 1'd1; end
8:begin DIO <= SEG[3]; SRCLK <= 1'd0; end
9:begin SRCLK <= 1'd1; end
10:begin DIO <= SEG[2]; SRCLK <= 1'd0; end
11:begin SRCLK <= 1'd1; end
12:begin DIO <= SEG[1]; SRCLK <= 1'd0; end
13:begin SRCLK <= 1'd1; end
14:begin DIO <= SEG[0]; SRCLK <= 1'd0; end
15:begin SRCLK <= 1'd1; end
16:begin DIO <= SEL[7]; SRCLK <= 1'd0; end
17:begin SRCLK <= 1'd1; end
18:begin DIO <= SEL[6]; SRCLK <= 1'd0; end
19:begin SRCLK <= 1'd1; end
20:begin DIO <= SEL[5]; SRCLK <= 1'd0; end
21:begin SRCLK <= 1'd1; end
22:begin DIO <= SEL[4]; SRCLK <= 1'd0; end
23:begin SRCLK <= 1'd1; end
24:begin DIO <= SEL[3]; SRCLK <= 1'd0; end
25:begin SRCLK <= 1'd1; end
26:begin DIO <= SEL[2]; SRCLK <= 1'd0; end
27:begin SRCLK <= 1'd1; end
28:begin DIO <= SEL[1]; SRCLK <= 1'd0; end
29:begin SRCLK <= 1'd1; end
30:begin DIO <= SEL[0]; SRCLK <= 1'd0; end
31:begin SRCLK <= 1'd1; end
endcase
end
endmodule
仿真文件:
`timescale 1ns / 1ps
module HC595_Driver_tb();
reg Clk;
reg Reset_n;
reg [7:0]SEG;
reg [7:0]SEL;
wire DIO;
wire RCLK;
wire SRCLK;
HC595_Driver HC595_Driver(
.Clk(Clk),
.Reset_n(Reset_n),
.SEG(SEG),
.SEL(SEL),
.DIO(DIO),
.RCLK(RCLK),
.SRCLK(SRCLK)
);
initial Clk = 1;
always#10 Clk = ~Clk;
initial begin
Reset_n = 0;
SEL = 8'b0000_0001;
SEG = 8'b0101_0101;
#201
Reset_n = 1;
#5000;
SEL = 8'b0000_0010;
SEG = 8'b1010_1010;
#5000;
SEL = 8'b1010_0101;
SEG = 8'b0000_1101;
#5000;
$stop;
end
endmodule