小梅哥课程学习——SPI接口的74HC595驱动数码管实验

发布时间 2023-03-29 17:30:05作者: 无情的造轮子
  1 //要求:对于74HC595芯片,该芯片在SH_CP(SCLK)的上升沿将DS(DIO)上的数据移入内部的寄存器。
  2 //目的:因此我们需要保证DS上的数据在SH_CP的上升沿前后一段时间,保持稳定。
  3 //手段:FPGA要在SH_CP的下降沿改变DS的值
  4 //先移入的数据,在高位输出。
  5 //SH_CP = 12.5Mhz
  6 //产生12.5Mhz的时钟有两种思路,第一种使用计数器,计数分频。(存在一个问题DS如何与SH_CP的上升沿和下降沿建立起关系)
  7 //不要将SH_CP当成一个时钟信号,而是当成一个普通信号,一个和DS、ST_CP一样的普通信号。
  8 //第二种将SH_CP和当成一个普通信号。
  9 //顶层hex8_test文件
 10  
 11 module hex8_test(
 12     clk,
 13     reset_n,
 14     sel,
 15     seg,
 16     SH_CP,
 17     ST_CP,
 18     DS
 19     );
 20     input clk;
 21     input reset_n;
 22     
 23     output [7:0] sel;
 24     output [7:0] seg;
 25     
 26     output SH_CP;
 27     output ST_CP;
 28     output DS;
 29     wire [31:0] disp_data;
 30     
 31     hex8_2 hex8_2_inst0(
 32     clk,
 33     reset_n,
 34     disp_data,
 35     sel,
 36     seg
 37     );
 38     
 39     wire [15:0] data;
 40     //先传seg,再传sel,怎么看出来的?
 41     assign data= {seg,sel};
 42     
 43     wire s_en;
 44     assign s_en = 1;
 45     hc595_driver hc595_driver_inst0(
 46     clk,
 47     reset_n,
 48     data,
 49     s_en,
 50     SH_CP,
 51     ST_CP,
 52     DS
 53     );
 54     assign disp_data = 32'h05211314;
 55     
 56 endmodule
 57 
 58 //底层hex8_2源文件
 59 
 60 module hex8_2(
 61     clk,
 62     reset_n,
 63     disp_data,
 64     sel,
 65     seg
 66     );
 67     input clk;
 68     input reset_n;
 69     input [31:0] disp_data;
 70     output reg [7:0] sel;
 71     output reg [7:0] seg;
 72     
 73 
 74     reg clk_1k;
 75     reg [15:0]div_cnt;
 76     //设置分频计数时钟
 77     always@(posedge clk or negedge reset_n)
 78     if(!reset_n)
 79         div_cnt <= 0;
 80     else if(div_cnt >= 49999)
 81         div_cnt <= 0;
 82     else
 83         div_cnt <= div_cnt + 1'b1;
 84         //这种门控时钟在绝大多数场合不允许使用
 85         //定义1ms的时钟(1khz)
 86 //    always@(posedge clk or negedge reset_n)
 87 //    if(!reset_n)
 88 //        clk_1k <= 0;
 89 //    else if(div_cnt >= 24999)
 90 //        clk_1k <= !clk_1k;
 91     
 92     //使能时钟
 93     always@(posedge clk or negedge reset_n)
 94     if(!reset_n)
 95         clk_1k <= 0;
 96     else if(div_cnt >= 49999)
 97         clk_1k <= 1;
 98     else
 99         clk_1k <= 0;
100         
101     reg [2:0] num_cnt;
102     always@(posedge clk or negedge reset_n)
103     if(!reset_n)
104         num_cnt <= 0;
105     else if(clk_1k)//这里面使用的就是使能时钟
106         num_cnt <= num_cnt + 1'b1; 
107     
108     //书写3—8译码器
109     always@(posedge clk)begin//将组合逻辑用时序的时钟,结果更加精确。
110         case(num_cnt)
111             0:sel <= 8'b0000_0001;
112             1:sel <= 8'b0000_0010;
113             2:sel <= 8'b0000_0100;
114             3:sel <= 8'b0000_1000;
115             4:sel <= 8'b0001_0000;
116             5:sel <= 8'b0010_0000;
117             6:sel <= 8'b0100_0000;
118             7:sel <= 8'b1000_0000;
119         endcase
120     end
121    
122    reg [3:0] dis_tmp;
123    always@(posedge clk)begin
124         case(num_cnt)
125             7:dis_tmp <= disp_data[31:28];
126             6:dis_tmp <= disp_data[27:24];
127             5:dis_tmp <= disp_data[23:20];
128             4:dis_tmp <= disp_data[19:16];
129             3:dis_tmp <= disp_data[15:12];
130             2:dis_tmp <= disp_data[11:8];
131             1:dis_tmp <= disp_data[7:4];
132             0:dis_tmp <= disp_data[3:0];
133         endcase
134     end
135     
136     always@(posedge clk)begin
137         case(dis_tmp)
138             0:seg <= 8'hc0;
139             1:seg <= 8'hf9;
140             2:seg <= 8'ha4;
141             3:seg <= 8'hb0;
142             4:seg <= 8'h99;
143             5:seg <= 8'h92;
144             6:seg <= 8'h82;
145             7:seg <= 8'hf8;
146             8:seg <= 8'h80;
147             9:seg <= 8'h90;
148             4'ha:seg <= 8'h88;
149             4'hb:seg <= 8'h83;
150             4'hc:seg <= 8'hc6;
151             4'hd:seg <= 8'ha1;
152             4'he:seg <= 8'h86;
153             4'hf:seg <= 8'h8e;
154         endcase
155     end
156 endmodule
157 
158 //底层hc595_driver文件
159 
160 module hc595_driver(
161     clk,
162     reset_n,
163     data,
164     s_en,
165     SH_CP,
166     ST_CP,
167     DS
168     );
169     input clk;
170     input reset_n;
171     input [15:0]data;
172     input s_en;
173     output reg SH_CP;
174     output reg ST_CP;
175     output reg DS;
176     parameter CNT_MAX = 2;
177     //这样就可以使用瞬时的数据,因为data随时可能会变化,来一个send_go(s_en)信号,就把数据寄存到r_data中。
178     reg[15:0]r_data;
179     always@(posedge clk )
180         if(s_en)
181             r_data <= data;
182     
183     //分频计数器得到
184     reg [7:0] divider_cnt;
185     always@(posedge clk or negedge reset_n)
186     if(!reset_n)
187         divider_cnt <= 0;
188     else if(divider_cnt == CNT_MAX - 1)
189         divider_cnt <=0;
190     else
191         divider_cnt <= divider_cnt +1'b1;
192         
193     wire sck_plus;
194     assign sck_plus = (divider_cnt ==CNT_MAX - 1);
195     //一个四位数码管需要发送16位数据(8位sel位选,8位seg选),两个四位数码管需要32位数据
196     reg [5:0] SHCP_EDGE_CNT;
197     always@(posedge clk or negedge reset_n)
198     if(!reset_n)
199         SHCP_EDGE_CNT <= 0;
200     else if(sck_plus)begin
201         if(SHCP_EDGE_CNT == 6'd32)
202             SHCP_EDGE_CNT <= 0;
203         else
204             SHCP_EDGE_CNT <= SHCP_EDGE_CNT + 1'b1;
205     end
206     
207     always@(posedge clk or negedge reset_n)
208     if(!reset_n)begin
209         SH_CP <= 0;
210         ST_CP <= 0;
211         DS <= 0;
212     end
213     else begin
214         case(SHCP_EDGE_CNT)
215             0:begin SH_CP <= 0;ST_CP <= 0; DS <= r_data[15]; end
216             1:SH_CP <= 1;
217             2:begin SH_CP <= 0; DS <= r_data[14];end
218             3:SH_CP <= 1;
219             4:begin SH_CP <= 0; DS <= r_data[13];end
220             5:SH_CP <= 1;
221             6:begin SH_CP <= 0; DS <= r_data[12];end
222             7:SH_CP <= 1;
223             8:begin SH_CP <= 0; DS <= r_data[11];end
224             9:SH_CP <= 1;
225             10:begin SH_CP <= 0; DS <= r_data[10];end
226             11:SH_CP <= 1;
227             12:begin SH_CP <= 0; DS <= r_data[9];end
228             13:SH_CP <= 1;
229             14:begin SH_CP <= 0; DS <= r_data[8];end
230             15:SH_CP <= 1;
231             16:begin SH_CP <= 0; DS <= r_data[7];end
232             17:SH_CP <= 1;
233             18:begin SH_CP <= 0; DS <= r_data[6];end
234             19:SH_CP <= 1;
235             20:begin SH_CP <= 0; DS <= r_data[5];end
236             21:SH_CP <= 1;
237             22:begin SH_CP <= 0; DS <= r_data[4];end
238             23:SH_CP <= 1;
239             24:begin SH_CP <= 0; DS <= r_data[3];end
240             25:SH_CP <= 1;
241             26:begin SH_CP <= 0; DS <= r_data[2];end
242             27:SH_CP <= 1;
243             28:begin SH_CP <= 0; DS <= r_data[1];end
244             29:SH_CP <= 1;
245             30:begin SH_CP <= 0; DS <= r_data[0];end
246             31:SH_CP <= 1;
247             32:ST_CP <= 1;
248             default:
249                     begin
250                         SH_CP <= 0;
251                         ST_CP <= 0;
252                         DS <= 0;
253                     end
254         endcase
255     end
256     
257     
258 endmodule
259 
260  //hex8_test.xdc文件
261  set_property PACKAGE_PIN R17 [get_ports {sel[7]}]
262 set_property PACKAGE_PIN P17 [get_ports {sel[6]}]
263 set_property PACKAGE_PIN P2 [get_ports {seg[7]}]
264 set_property PACKAGE_PIN P5 [get_ports {seg[6]}]
265 set_property PACKAGE_PIN P6 [get_ports {seg[5]}]
266 set_property PACKAGE_PIN N5 [get_ports {seg[4]}]
267 set_property PACKAGE_PIN N4 [get_ports {seg[3]}]
268 set_property PACKAGE_PIN N3 [get_ports {seg[2]}]
269 set_property PACKAGE_PIN P4 [get_ports {seg[1]}]
270 set_property PACKAGE_PIN M6 [get_ports {seg[0]}]
271 set_property PACKAGE_PIN P14 [get_ports {sel[5]}]
272 set_property PACKAGE_PIN R16 [get_ports {sel[4]}]
273 set_property PACKAGE_PIN K6 [get_ports {sel[3]}]
274 set_property PACKAGE_PIN J5 [get_ports {sel[2]}]
275 set_property PACKAGE_PIN M5 [get_ports {sel[1]}]
276 set_property PACKAGE_PIN L6 [get_ports {sel[0]}]
277 set_property IOSTANDARD LVCMOS33 [get_ports {seg[7]}]
278 set_property IOSTANDARD LVCMOS33 [get_ports {seg[6]}]
279 set_property IOSTANDARD LVCMOS33 [get_ports {seg[5]}]
280 set_property IOSTANDARD LVCMOS33 [get_ports {seg[4]}]
281 set_property IOSTANDARD LVCMOS33 [get_ports {seg[3]}]
282 set_property IOSTANDARD LVCMOS33 [get_ports {seg[2]}]
283 set_property IOSTANDARD LVCMOS33 [get_ports {seg[1]}]
284 set_property IOSTANDARD LVCMOS33 [get_ports {seg[0]}]
285 set_property IOSTANDARD LVCMOS33 [get_ports {sel[7]}]
286 set_property IOSTANDARD LVCMOS33 [get_ports {sel[6]}]
287 set_property IOSTANDARD LVCMOS33 [get_ports {sel[5]}]
288 set_property IOSTANDARD LVCMOS33 [get_ports {sel[4]}]
289 set_property IOSTANDARD LVCMOS33 [get_ports {sel[3]}]
290 set_property IOSTANDARD LVCMOS33 [get_ports {sel[2]}]
291 set_property IOSTANDARD LVCMOS33 [get_ports {sel[1]}]
292 set_property IOSTANDARD LVCMOS33 [get_ports {sel[0]}]
293 set_property IOSTANDARD LVCMOS33 [get_ports clk]
294 set_property IOSTANDARD LVCMOS33 [get_ports DS]
295 set_property IOSTANDARD LVCMOS33 [get_ports reset_n]
296 set_property IOSTANDARD LVCMOS33 [get_ports SH_CP]
297 set_property IOSTANDARD LVCMOS33 [get_ports ST_CP]
298 set_property PACKAGE_PIN Y18 [get_ports clk]
299 set_property PACKAGE_PIN B21 [get_ports reset_n]
300 set_property PACKAGE_PIN M18 [get_ports DS]
301 set_property PACKAGE_PIN F4 [get_ports SH_CP]
302 set_property PACKAGE_PIN C2 [get_ports ST_CP]
303 
304   //hc95——driver_tb仿真文件 
305   
306 `timescale 1ns / 1ps
307 module hc595_driver_tb();
308     reg clk;
309     reg reset_n;
310     reg [15:0]data;
311     reg s_en;
312     wire SH_CP;
313     wire ST_CP;
314     wire DS;
315     hc595_driver hc595_driver_inst0(
316     clk,
317     reset_n,
318     data,
319     s_en,
320     SH_CP,
321     ST_CP,
322     DS
323     );
324     
325     initial clk = 1;
326     always #10 clk = !clk;
327     
328     initial begin
329         reset_n = 0;
330         data = 16'h0000;
331         s_en = 0;
332         #201;
333         reset_n = 1;
334         #500
335         data = 16'h47a9;
336         s_en = 1;
337         #20;
338         s_en = 0;
339         #4000;
340         
341         data = 16'h5832;
342         s_en = 1;
343         #20;
344         s_en = 0;
345         #4000;
346         $stop;
347     end
348 endmodule
2023-03-29 17:24:35