这个小项目我是想试一试,如果不跟着野火的步骤:分析->波形图->编辑->仿真->debug,不用波形图纯脑补会用多久的时间,我会遇到什么问题?这个项目是控制数码管显示的,当然我没有看野火的数码管的视频。
写不写波形图的区别首先是时间上:比用波形图至少慢了4倍,这个时间主要花在了debug上,是真的痛苦。然后是代码上,不用波形图时很多波形的时序都有点想当然了,实际运行的波形跟真正要的波形不是同一个时会先天陷入教条认为自己实际输出的就是对的,要花大量时间比对,更痛苦了。
总结:老实点先写波形图。
display_d_tube: 点亮使用双级联74HC595点亮数码管的项目
/*
* @Author: LC [email protected]
* @Date: 2023-11-05 17:49:32
* @LastEditors: LC [email protected]
* @LastEditTime: 2023-11-12 13:31:54
* @FilePath: \display_d_tube\RTL\digital_tube.v
* @Description: 使用74来驱动显示数码管
*
* Copyright (c) 2023 by ${git_name_email}, All Rights Reserved.
*/
//`include "./IC_74HC595_2023_11.v"
module digital_tube (
input clk_50Mhz, rst_n,
output OE_n, shift_clock_cp, storage_clock_8div_cp, data_s
);
reg [7:0] data_disp = 8'b0; //输入到数码管所对应的io输出
reg [4:0] data_value = 5'd0; //想要显示的数值
reg [7:0] data_cs = 8'b0; //片选所对应的io输出
reg [4:0] data_num = 5'd0; //想要选定的数码管,最大支持8个管
/*
显示数字“0”,abcdef亮,状态值00111111——>0x3f
显示数字“1”,bc亮,状态值00000110——>0x06
显示数字“2”,abdeg亮,状态值01011011——>0x5b
显示数字“3”,abcdg亮,状态值01001111——>0x4f
显示数字“4”,bcfg亮,状态值01100110——>0x66
显示数字“5”,acdfg亮,状态值01101101——>0x6d
显示数字“6”,acdefg亮,状态值01111101——>0x7d
显示数字“7”,abc亮,状态值00000111——>0x07
显示数字“8”,abcdefg亮,状态值01111111——>0x7f
显示数字“9”,abcdfg亮,状态值01101111——>0x6f
*/
/* 转换成对应数码管的数值 */
always @(posedge clk_50Mhz) begin
if(rst_n == 1'b0) begin
data_disp <= 8'b0;
data_value <= 5'd0;
end else begin
case(data_value)
5'd0: data_disp <= ~8'h3f;
5'd1: data_disp <= ~8'h06;
5'd2: data_disp <= ~8'h5b;
5'd3: data_disp <= ~8'h4f;
5'd4: data_disp <= ~8'h66;
5'd5: data_disp <= ~8'h6d;
5'd6: data_disp <= ~8'h7d;
5'd7: data_disp <= ~8'h07;
5'd8: data_disp <= ~8'h7f;
5'd9: data_disp <= ~8'h6f;
default: data_disp <= ~8'h00;
endcase
end
end
/* 转换成片选对应的io输出 */
always @(posedge clk_50Mhz) begin
if(rst_n == 1'b0) begin
data_cs <= 8'b0;
data_num <= 5'd0;
end else begin
case(data_num)
5'd0: data_cs <= 8'h01;
5'd1: data_cs <= 8'h02;
5'd2: data_cs <= 8'h04;
5'd3: data_cs <= 8'h08;
5'd4: data_cs <= 8'h10;
5'd5: data_cs <= 8'h20;
5'd6: data_cs <= 8'h40;
5'd7: data_cs <= 8'h80;
default: data_cs <= 8'h00;
endcase
end
end
reg switch = 1'b0;
reg [7:0] data = 1'b0;
reg [2:0] count = 3'b0;
reg flag = 1'b1;
reg sel = 1'b0;
/* 8计数器 */
always @(posedge clk_50Mhz) begin
if(rst_n == 1'b0)begin
count <= 3'b0;
flag <= 1'b1;
end else begin
if(count == 3'b111) begin
count <= 3'b0;
flag <= 1'b1;
end else begin
count <= count + 1'b1;
flag <= 1'b0;
end
end
end
/* 根据flag依次填入片选跟显示的data */
always @(posedge clk_50Mhz) begin
if(rst_n == 1'b0)begin
switch <= 1'b0;
data <= 8'b0;
sel <= 1'b0;
end else begin
if(flag == 1'b1) begin
if(sel == 1'b0) begin //填入显示
data <= data_disp;
sel <= 1'b1;
switch <= 1'b0;
end else begin //填入片选
data <= data_cs;
sel <= 1'b0;
switch <= 1'b1;
end
end
end
end
IC_74HC595_2023_11 DT_6(
.data (data ),
.rst_n (rst_n ),
.switch (switch ),
.clk (clk_50Mhz ),
.OE_n (OE_n ),
.MR_n ( ),
.shift_clock_cp (shift_clock_cp ),
.storage_clock_8div_cp (storage_clock_8div_cp ),
.data_s (data_s )
);
endmodule
/*
* @Author: LC [email protected]
* @Date: 2023-11-05 17:50:10
* @LastEditors: lc [email protected]
* @LastEditTime: 2023-11-06 17:35:28
* @FilePath: \display_d_tube\RTL\top.v
* @Description:
*
* Copyright (c) 2023 by ${git_name_email}, All Rights Reserved.
*/
//`include "./digital_tube.v"
module top (
input clk_50Mhz, rst_n,
output OE_n, shift_clock_cp, storage_clock_8div_cp, data_s
);
reg [4:0] count = 5'b0;
reg flag = 1'b1;
/* 8计数器 */
always @(posedge clk_50Mhz) begin
if(rst_n == 1'b0)begin
count <= 5'b0;
flag <= 1'b1;
end else begin
if(count == 5'b11010) begin
count <= 5'b0;
flag <= 1'b1;
end else begin
count <= count + 1'b1;
flag <= 1'b0;
end
end
end
digital_tube u_digital_tube(
.clk_50Mhz (flag ),
.rst_n (rst_n ),
.OE_n (OE_n ),
.shift_clock_cp (shift_clock_cp ),
.storage_clock_8div_cp (storage_clock_8div_cp ),
.data_s (data_s )
);
endmodule
/*
* @Author: LC [email protected]
* @Date: 2023-11-05 17:49:02
* @LastEditors: LC [email protected]
* @LastEditTime: 2023-11-12 13:28:59
* @FilePath: \display_d_tube\RTL\IC_74HC595_2023_11.v
* @Description: 这个是74HC595的驱动元件,8bit串并行转换,最高时钟:100Mhz/8
*
* Copyright (c) 2023 by ${git_name_email}, All Rights Reserved.
*/
module IC_74HC595_2023_11 (
input wire [7:0] data,
input wire rst_n,
input wire switch, //打开串并行转换
input clk, //该时钟频率即串并转换时钟
output reg OE_n, //不改变寄存器,控制输出为高阻
output reg MR_n, //清除移位寄存器的数据
output wire shift_clock_cp, //上升沿时提取ds的电平保存到移位寄存器最高位,其余位右移,
output reg storage_clock_8div_cp, //上升沿时把移位寄存器的值保存到存储寄存器
output reg data_s //串行数据线
);
reg flag = 1'b1;
reg [2:0] count = 3'b0;
reg [7:0] data_t = 8'b0;
assign shift_clock_cp = clk;
/* 8计数器 */
always @(posedge clk) begin
if(rst_n == 1'b0) begin
count <= 3'b0;
flag <= 1'b1;
end else begin
if(count == 3'b111) begin
flag <= 1'b1;
count <= 3'b0;
end else begin
flag <= 1'b0;
count <= count + 1'b1;
end
end
end
/* 控制串行数据转移到移位寄存器 */
always @(posedge clk) begin
if(rst_n == 1'b0) begin
OE_n = 1'b1; //输出高阻
MR_n = 1'b1; //清除移位寄存器
data_t = 8'b0;
end else begin
OE_n = 1'b0;
MR_n = 1'b0;
if(flag == 1'b1) begin
data_t = data;
data_s = data_t[7];
end else begin
data_t = data_t << 1;
data_s = data_t[7];
end
end
end
reg cp_flag = 1'b0;
/* 当flag计数到达,并且允许转换,将触发把移位寄存器数据转移到存储寄存器的动作时钟 */
always @(posedge clk) begin
if(rst_n == 1'b0) begin
cp_flag <= 1'b0;
end else begin
if(flag == 1'b1) begin
if(switch == 1'b1) begin
cp_flag <= 1'b1;
end else begin
cp_flag <= 1'b0;
end
end else begin
cp_flag <= 1'b0;
end
end
end
always @(posedge clk) begin
if(rst_n == 1'b0) begin
storage_clock_8div_cp <= 1'b0;
end else begin
if(cp_flag == 1'b1) begin
storage_clock_8div_cp <= 1'b1;
end else begin
storage_clock_8div_cp <= 1'b0;
end
end
end
endmodule
/*
* @Author: lc [email protected]
* @Date: 2023-11-06 16:49:00
* @LastEditors: LC [email protected]
* @LastEditTime: 2023-11-07 01:15:06
* @FilePath: \display_d_tube\SIM\sim_DT.v
* @Description: 例化测试程序
*
* Copyright (c) 2023 by ${git_name_email}, All Rights Reserved.
*/
`timescale 10ns/10ns
//`include "../RTL/top.v"
module sim_DT ();
reg clk_50Mhz;
reg rst_n;
wire OE_n;
wire shift_clock_cp;
wire storage_clock_8div_cp;
wire data_s;
initial begin
clk_50Mhz = 1'b0;
rst_n = 1'b0;
#10000; rst_n = 1'b1;
end
always #1 clk_50Mhz = !clk_50Mhz;
top u_top(
.clk_50Mhz (clk_50Mhz ),
.rst_n (rst_n ),
.OE_n (OE_n ),
.shift_clock_cp (shift_clock_cp ),
.storage_clock_8div_cp (storage_clock_8div_cp ),
.data_s (data_s )
);
endmodule
1、在io口输出时,因为频繁的io电平变动,相当于频繁从vcc拉电流,会强烈干扰其他io口的运行,表现上就是当一个io口跳变时在上下边缘会让其他做输出的io口在该点有一个纹波。如下图:
这种影响不仅体现在fpga,也体现在mcu以及soc上。所以设计时如果是单片机,io口的翻转速度要适合,至于soc、fpga。。。改不了了。