赞
踩
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
我们实现的是FPGA图片对应的部分。相当于写的是一个驱动,
电路逻辑示意图,不是详细的电路图。
74HC595,8位串行移位寄存器。
LATCH有上升沿的信号时,上面的REG0到3会将DFF0到3的信号存储起来,并输出到OUTPUT0到3对应的D0-D3的信号口上。
逻辑信号示意图。
表示了4位的移位寄存器。
需要4个时钟周期,移位4次。输出4位并行数据。
同理8位的移位寄存器。
需要8个时钟周期,移位8次。输出8位并行数据。
74HC595芯片的内容
QH’当成了移位的端口输出。
移位时钟SRCLK,锁定时钟RCLK。
两个并联的情况。
移位时钟SRCLK,锁定时钟RCLK。这样并联之后就可以实现16位的并行输出
只需要将这16位的信号分别接给8位8段数码管的ser(选择)接口和seg接口,就能任意控制某个数码管的某一段。
两个47HC595芯片可以实现,3个信号线传输16位信号的功能。
数码管74HC595的电路。和上面的原理是一致的。
上面是一个级联,因为QH接到了SER那里。
第一个U11QA-QH接到了数码管的HEX_SEL0-7也就是位选信号端,后边U12QA-QH接到了数码管的HEX_A-DP也就是段选信号端。
输入的信号其实就是DIO 对应的SER,RCLK,SCLK对应的SRCLK。
最终的工作不是去实现74HC595本来的功能,而是去驱动数码管管。
模块功能:
将两个8位的SEL[7:0],SEG[7:0],通过DIO(SER),SCLK,RCLK。输出给两片级联的74HC595芯片。
将两个8位的第一级接SEL和第二级接SEG恰好稳定,出现输出在两片47HC595芯片的QA-QH上。
对应的信号传输时序图。
对应的功能表
在写代码的时候对应的时序逻辑顺序十分重要。
在verilog中的信号名称不能以数字作为开头。
DIO不能在SRCLK的高电平变化,有一段时间的延迟,如上面的时间延迟表。
RCLK的上升沿一定不会出现在SRCLK的上升沿的。
思路:用线性序列机的方式实现
最小时钟单位取SRCLK的一半。
移位的时候,先移动高位再移动低位。
上一轮的结束本身就意味着下一轮的开始,
就是根据时序图来写代码,根据不同的时间来进行具体的操作。其中不同的时间主要是依靠计数器来进行计时。
不同的时间对应不同的操作。
代码如下(示例):
`timescale 1ns / 1ps module HC595( Clk, Reset_n, SEG, SEL, DIO, SRCLK, RCLK ); input Clk; input Reset_n; input [7:0]SEG; input [7:0]SEL; output reg DIO; output reg SRCLK; output reg RCLK; parameter CLOCK_FREQ = 50_000_000; parameter SRCLK_FREQ = 12_500_000; //期望的SRCLK的频率 parameter MCNT = CLOCK_FREQ/(SRCLK_FREQ * 2) - 1; 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; always@(posedge Clk or negedge Reset_n) if(!Reset_n) cnt <= 0; else if(div_cnt == MCNT) cnt <= cnt +1'd1; 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 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_tb; reg Clk; reg Reset_n; reg SEG; reg SEL; wire DIO; wire SRCLK; wire RCLK; HC595 HC595_driver( .Clk(Clk), .Reset_n(Reset_n), .SEG(SEG), .SEL(SEL), .DIO(DIO), .SRCLK(SRCLK), .RCLK(RCLK) ); 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
在测试激励程序中最好能让你的输出两轮以上,这样子方便观察计数器的问题。只跑一轮是有可能出问题的。
这里往前推传的是低位数据而不是高位的数据,SEL对的方式是按照上升沿往前推。
从这里往前对的是SEG的值。SEL的第一位同时也是SEG的最后一位。
提问,74HC595是在上升沿寄存DIO的值,为什么DIO的值是在下降沿才去变化。
答:信号在上升沿被采样,那么就让他在下降沿去变化。这样的话,变化的时刻就比采样的时刻整整差了半个时钟周期,就能保证当芯片采样数据的时候,数据就早已经变化并且稳定了。
在对应的文件夹找到之前的hex8.v数码管模块的文件,并且手动拷贝到HC595的文件夹下。
点击添加或者创建设计文件
选择对应文件添加并finish。
`timescale 1ns / 1ps module hex8_hc595_test( Clk, Reset_n, SW, DIO, SRCLK, RCLK ); input Clk; input [1:0]SW; input Reset_n; output DIO; output SRCLK; output RCLK; wire [7:0]SEG,SEL; reg [31:0]Disp_Data; //例化内容 HC595 HC595_driver( .Clk(Clk), .Reset_n(Reset_n), .SEG(SEG), .SEL(SEL), .DIO(DIO), .SRCLK(SRCLK), .RCLK(RCLK) ); hex8 hex8( .Clk(Clk), .Reset_n(Reset_n), .Disp_Data(Disp_Data), .SEL(SEL), .SEG(SEG) ); always@(*) case(SW) 0:Disp_Data <= 32'h01234567; 1:Disp_Data <= 32'h89abcdef; 2:Disp_Data <= 32'h02468ace; 3:Disp_Data <= 32'h13579bdf; endcase endmodule
实现效果,对应的拨码开关控制对应的输出。
通过Vivado软件对驱动74HC595芯片进行数码管动态显示做了仿真验证。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。