SPI接口的74HC595驱动数码管实现

摸鱼记录 Day_17 (((^-^)))

review

前边已经学习了:

数码管显示原理:数码管动态扫描显示-CSDN博客

且挖了个SPI的坑坑

1. 今日份摸鱼任务

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 学习循环移位寄存器18 串行移位寄存器原理详解_哔哩哔哩_bilibili 学习SPI接口的74HC595驱动数码管19 SPI接口的74HC595驱动数码管实验_哔哩哔哩_bilibili 了解SPI协议:SPI协议详解(图文并茂+超详细) - 知乎 (zhihu.com) SPI总线协议及SPI时序图详解 - Ady Lee - 博客园 (cnblogs.com) |

2. 循环移位寄存器

|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| |
| 四位D触发器,输入信号1001,经过四次时钟上升沿,D0-D3 1001 DATA是串行数据,在此结构下,每个上升沿到来,都会改变D0-D3的输出 为了正确输出四位的串转并数据 可在红色箭头处,添加一个使能信号,对输出进行控制 |
| |
| 此时,使用CLK、DATA、LATCH三根信号线,即可完成将串行信号转为并行信号 |

3. 74HC959 循环移位寄存器

一文搞懂74HC595芯片(附使用方法)_74hc595芯片引脚图及功能-CSDN博客

74HC595的最重要的功能就是:串行输入,并行输出。

其次,74HC595里面有2个8位寄存器:移位寄存器、存储寄存器。

|-----------------------------------------------------------------------------------------------------------------|
| 第一个从SER送入的bit将会从 Q7 出去 |
| 本篇在草稿呆了很多天,因为上图SHCP STCP的画法有一定理解上的问题 SHCP 移位寄存器的时钟输出 STCP 存储寄存器的时钟输出 但是在例程中: STCP是在数据都保存后,完成一次输出,这保证了输出数据是一个完整的 |

ACZ702 配套 EDA 扩展板设计用到了芯片 74HC595,该芯片的作用是移位寄存器,通过移位的方式,节省 FPGA 的管脚。FPGA 只需要输出 3 个管脚,即可达到发送数码管数据的目的,与数码管动态扫描显示-CSDN博客的传统段选位选方式相比节省了 IO 设计资源。

3.3V供电情况下,50MHz -----》25MHz-----》12.5MHz

4. VIO Virtual Input/Output

关于这个IP核可以看:Vivado中VIO IP核的使用_vivado vio-CSDN博客

本次实验,用于设定数码管的显示内容,具体设置如下:

|---------------------------------------------------------------------------------------------------|
| |
| |

4. SPI接口的74HC595驱动数码管实现 (((^-^)))

SPI(Serial Peripheral Interface),串行外围设备接口。

SPI 是一个同步的数据总线,用单独的数据线一个单独的时钟信号 来保证发送端和接收端的同步

可以参考:SPI协议详解(图文并茂+超详细) - 知乎 (zhihu.com)

对于74HC595,本次SPI协议,是学习SCK MOSI,无需MISO,片选默认选中

4.1 design sources

|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| hex_8 |
| module hex_8(input clk, input reset_n, input [31:0]disp_data, //8个数码管进行显示,每个显示0~F,输入格式为disp_data = 32'h12345678 output reg [7:0]sel, output reg [7:0]seg ); //[31:0]disp_data 16hex 4*8 //[7:0]sel 位选信号 //[7:0]seg 段选信号 // 1kHz分频时钟 reg [14:0]div_clk; always@(posedge clk or negedge reset_n) if(!reset_n) div_clk <= 1'b0; else if(div_clk == 24999) div_clk <= 1'b0; else div_clk <= div_clk + 1'b1; reg disp_en; always@(posedge clk or negedge reset_n) if(!reset_n) disp_en <= 1'b0; else if(div_clk == 24999) disp_en <= 1'b1; else disp_en <= 1'b0; // 位选sel reg[2:0]sel_num; always@(posedge clk or negedge reset_n) if(!reset_n) sel_num <= 3'b000; else if(disp_en) sel_num <= sel_num + 1'b1; always@(posedge clk or negedge reset_n) if(!reset_n) sel <= 8'b0000_0000; else case(sel_num) 0:sel <= 8'b0000_0001; 1:sel <= 8'b0000_0010; 2:sel <= 8'b0000_0100; 3:sel <= 8'b0000_1000; 4:sel <= 8'b0001_0000; 5:sel <= 8'b0010_0000; 6:sel <= 8'b0100_0000; 7:sel <= 8'b1000_0000; endcase // 段选seg [31:0]disp_data 16hex 4*8 reg [3:0] dis_tmp; always@(posedge clk ) case(sel_num) //高位放前面 0:dis_tmp <= disp_data[31:28]; 1:dis_tmp <= disp_data[27:24]; 2:dis_tmp <= disp_data[23:20]; 3:dis_tmp <= disp_data[19:16]; 4:dis_tmp <= disp_data[15:12]; 5:dis_tmp <= disp_data[11:8]; 6:dis_tmp <= disp_data[7:4]; 7:dis_tmp <= disp_data[3:0]; endcase always@(posedge clk ) case(dis_tmp) 0:seg <= 8'hc0; 1:seg <= 8'hf9; 2:seg <= 8'ha4; 3:seg <= 8'hb0; 4:seg <= 8'h99; 5:seg <= 8'h92; 6:seg <= 8'h82; 7:seg <= 8'hf8; 8:seg <= 8'h80; 9:seg <= 8'h90; 4'ha:seg <= 8'h88; 4'hb:seg <= 8'h83; 4'hc:seg <= 8'hc6; 4'hd:seg <= 8'ha1; 4'he:seg <= 8'h86; 4'hf:seg <= 8'h8e; endcase endmodule |
| hc595_driver //在Verilog中,不能使用数字开头命名 |
| module hc595_driver( input clk, input reset_n, input [15:0]data, input s_en, output reg sh_cp, output reg st_cp, output reg ds ); /启动信号s_en时,保存当前data reg [15:0]r_data; always@(posedge clk) if(s_en) r_data <= data; parameter CNT_MAX = 2; // 在 3.3V 状态下工作于 12.5MHz reg [7:0]divider_cnt;//分频计数器 always@(posedge clk or negedge reset_n) if(!reset_n) divider_cnt <= 0; else if(divider_cnt == CNT_MAX - 1'b1) divider_cnt <= 0; else divider_cnt <= divider_cnt + 1'b1; wire sck_plus; assign sck_plus = (divider_cnt == CNT_MAX - 1'b1); reg [5:0]SHCP_EDGE_CNT; always@(posedge clk or negedge reset_n) if(!reset_n) SHCP_EDGE_CNT <= 0; else if(sck_plus) begin if(SHCP_EDGE_CNT == 6'd32) //32 16个数据,按照SH_CP上升沿、下降沿 SHCP_EDGE_CNT <= 0; else SHCP_EDGE_CNT <= SHCP_EDGE_CNT + 1'b1; end else SHCP_EDGE_CNT <= SHCP_EDGE_CNT; always@(posedge clk or negedge reset_n) if(!reset_n) begin st_cp <= 1'b0; ds <= 1'b0; sh_cp <= 1'd0; end else begin case(SHCP_EDGE_CNT)//重点就是线性序列机这部分分析啦 //SH_CP 移位寄存器的时钟 //在SH_CP上升沿 0->1 输出数据 //在SH_CP下降沿 1->0 改变数据 0: begin sh_cp <= 0; st_cp <= 1'd0;ds <= r_data[15];end 1: begin sh_cp <= 1; st_cp <= 1'd0;end 2: begin sh_cp <= 0; ds <= r_data[14];end 3: begin sh_cp <= 1; end 4: begin sh_cp <= 0; ds <= r_data[13];end 5: begin sh_cp <= 1; end 6: begin sh_cp <= 0; ds <= r_data[12];end 7: begin sh_cp <= 1; end 8: begin sh_cp <= 0; ds <= r_data[11];end 9: begin sh_cp <= 1; end 10: begin sh_cp <= 0; ds <= r_data[10];end 11: begin sh_cp <= 1; end 12: begin sh_cp <= 0; ds <= r_data[9];end 13: begin sh_cp <= 1; end 14: begin sh_cp <= 0; ds <= r_data[8];end 15: begin sh_cp <= 1; end 16: begin sh_cp <= 0; ds <= r_data[7];end 17: begin sh_cp <= 1; end 18: begin sh_cp <= 0; ds <= r_data[6];end 19: begin sh_cp <= 1; end 20: begin sh_cp <= 0; ds <= r_data[5];end 21: begin sh_cp <= 1; end 22: begin sh_cp <= 0; ds <= r_data[4];end 23: begin sh_cp <= 1; end 24: begin sh_cp <= 0; ds <= r_data[3];end 25: begin sh_cp <= 1; end 26: begin sh_cp <= 0; ds <= r_data[2];end 27: begin sh_cp <= 1; end 28: begin sh_cp <= 0; ds <= r_data[1];end 29: begin sh_cp <= 1; end 30: begin sh_cp <= 0; ds <= r_data[0];end 31: begin sh_cp <= 1; end 32: st_cp <= 1'd1;//最后拉高一下st_cp锁存器输出 default: begin st_cp <= 1'b0; ds <= 1'b0; sh_cp <= 1'd0; end endcase end endmodule |
| hex_top |
| module hex_top( clk, reset_n, sh_cp, st_cp, ds ); input clk; //50M input reset_n; output sh_cp; output st_cp; output ds; wire [31:0]disp_data; wire [7:0] sel;//数码管位选(选择当前要显示的数码管) wire [7:0] seg;//数码管段选(当前要显示的内容) vio_0 vio_0 ( .clk(clk), .probe_out0(disp_data) ); hc595_driver hc595_driver( .clk(clk), .reset_n(reset_n), .data({seg,sel}), //将段选与位选信号拼接在一起 .s_en(1'b1), .sh_cp(sh_cp), .st_cp(st_cp), .ds(ds) ); hex8 hex8( .clk(clk), .reset_n(reset_n), .en(1'b1), .disp_data(disp_data), .sel(sel), .seg(seg) ); endmodule |

4.2 板级验证

|---------------------------------------------------------------------------------------------------|
| |
| |
| |
| |

//好啦, (((^-^)))

相关推荐
IM_DALLA2 小时前
【Verilog学习日常】—牛客网刷题—Verilog快速入门—VL21
学习·fpga开发
皇华ameya6 小时前
AMEYA360:村田电子更适合薄型设计应用场景的3.3V输入、12A输出的DCDC转换IC
fpga开发
千穹凌帝9 小时前
SpinalHDL之结构(二)
开发语言·前端·fpga开发
一口一口吃成大V15 小时前
FPGA随记——FPGA时序优化小经验
fpga开发
贾saisai16 小时前
Xilinx系FPGA学习笔记(九)DDR3学习
笔记·学习·fpga开发
redcocal20 小时前
地平线秋招
python·嵌入式硬件·算法·fpga开发·求职招聘
思尔芯S2C1 天前
高密原型验证系统解决方案(下篇)
fpga开发·soc设计·debugging·fpga原型验证·prototyping·深度调试·多fpga 调试
坚持每天写程序1 天前
xilinx vivado PULLMODE 设置思路
fpga开发
redcocal2 天前
地平线内推码 kbrfck
c++·嵌入式硬件·mcu·算法·fpga开发·求职招聘
邹莉斯3 天前
FPGA基本结构和简单原理
fpga开发·硬件工程