英特尔FPGA实训day4

以下作为个人学习杂记,不具有严格条理层次性。

学习内容:

        今天主要进行了 对昨天呼吸灯的实验的仿真书写,波形观察分析,按键的实现,以及对数码管知识的回顾,还有就是仿真器的进一步认识,简化,还有对vscode的代码补全库的扩展,对配置引脚的保存(方便下次复用)。

今天还有个巨大收获,就是基本上理清了reg,wire,paramter的区别,使用场景等。

疑惑产生及解决:

        数码管,怎么实现亮灭变化,为什么非要弄那么多标志位,状态位,不能把对应某个状态的值进行赋予,然后省略状态标志位呀。

        解决:效果的实现,更重要的是考验功能剥离,分层能力。本次实现的数码管显示,仅仅是从0到f的16进制显示。分析后,其实就三步 数字显示,数字切换,显示定时。 则,自然的就分成了三个模块,计时模块,标志显示模块,综合实现模块。

 通过这次实验,可见,对目标任务的分层显得尤为重要,因为分层后,程序书写将更加清晰。后期维护也更方便,而且程序,模块之间的复用性也好。

而对于标志位,其实在书写过程,或读懂后,就发现是必不可少的,因为标致位有个作用是不能被替代,或者说是忽略的。标致位可以有很好的传递性,与复用性!!也正是因为标致位的存在,让模块化成为可能,让一个个阶段性成果,拼成最终任务。 而且有些地方没了标志位是无法进行的。例如,本实验如果没有num标致位进行标志各个状态,则当时钟计满0.2s时,仅可判断需要切换下一个数码管值,却不能很准确或很灵活定位是哪一个数码管值(即应该显示什么内容)。

所以这个问题是解决了的。

以下是详细内容:

仿真软件标志的认识:

仿真器,上下升沿对齐符号,这几个可以增减对齐黄线,更便于分析。

 在仿真过程出现个问题(也是老师提出的),就是莫名的出现了一小段高电平,即按键按下后,没有立刻变为我们按下后led应该呈现的电平(低电平)

 通过与下面对比发现,是因为,按键按下后,虽然应该状态切换,但是按下时刻,state仍然处于上一个状态还没来得及立刻改变。

即,先理清程序最初的设计逻辑,state是控制哪一个某一个亮灯的状态(静态),不同key按下,控制的是不同led状态配合下的动态过程(动态)。在开始运行后,不断工作的是用于状态切换的时间计数器。

 所以,这里,当按键按下的时候,实际上处于的状态并不是处于第一个00的状态,而是处于11状态。下面这代码就是(部分)不同状态对应的led电平情况。

    else if (key[0] == 0) begin
        case (state)
            2'd0: led <= 4'b0001;
            2'd1: led <= 4'b0010;
            2'd2: led <= 4'b0100;
            2'd3: led <= 4'b1000;
            default: ;
        endcase
    end

从仿真图可以看到,当模拟key0按下的时候,state为11,即状态4,也就是led=1000,所以此时会有led3短暂的高电平。

接下来就是数码管的认识:

共阴极:高电平点亮

共阳极(低电平点亮)(本次开发板中的数字)

以下是要用到的对应真值表。

具体的数码管设计过程今天比较简单,并且再文首已经提过了,就不再赘述。

接下来就是,个人感觉收获很大的地方:reg,wire,parameter的应用场景等的不同。

Q:什么时候定义为reg,什么时候wire的最新理解。

A:常常就是在通过一定计算后,或者一定运行后的数据,且后续还会用到,需要传递到其他模块,则会用reg存储,即,一般模块的输出部分

,但最终的输出一般不需要reg类型,因为不需要再存储了,直接输出就可。

 还有可以一定程度上去区分的方式是,reg类型的变量常常作为被赋值的对象,其值会经常改变。即 看到

就知道,这两个变量一定是 reg类型。

Wire 类型的,则有点与reg相反的意思,wire常常给其他变量赋值, (也可以想成两个模块的桥梁,即 变量a是上个模块的output,是reg,在下个模块就常常为wire类型)

很少被赋值,如果非要被赋值,那更多的时候,也是再原本定义的模块中,需要更新为一个新的值,然后继续作为本模块的下一个小部分,继续使用(即:不存在 被赋值后,直接输出的情况)  wire 类型,要被赋值更新的话,要用assign关键字进行修饰,然后赋值。

一般被赋值后后续还会使用。  

而参数类型 parameter  则是在要使用具体值的时候,即常值,的时候,会用这个。类似C种define一个常值

综上:reg常作为模块运行的最终产物,然后进行存储,等待传递;在模块中常作为被赋值的对象。

       Wire 常作为 引入的信号,标志,传递结果。用于判断条件,或对reg变量的赋值,而不作为输出。如果中途要更新wire的值,则用assign关键字进行修饰。

       Parameter常作为 常量。 作为条件判断,给其他变量赋值等。

下面就是今天涉及到的代码:

呼吸灯仿真程序

module breath_fsm_led_tb();

reg clk;
reg rst_n;
wire [3:0] led;
// wire led;

parameter cnt_us = 3'd4;
parameter cnt_ms = 4'd9;
parameter cnt_s = 4'd9;
parameter CYCLE = 5'd19;

always #(CYCLE/2) clk =~clk ;

initial begin
    clk = 1'b0;
    rst_n = 1'b0;//复位开始
    #(CYCLE/2);
    rst_n = 1'b1;//复位结束
    #(20000);//5*10*10*20*2
    $stop;
end

breath_fsm_led #(
.cnt_us(cnt_us),
.cnt_ms(cnt_ms),
.cnt_s(cnt_s)
) u_breath_fsm_led(
.clk(clk),
.rst_n(rst_n),

.led(led)
);

endmodule


按键控制led灯:

module key_led(
    input clk,
    input rst_n,

    input [3:0]key,
    output reg[3:0] led
);

parameter TIME = 24'd9_999_999;

reg [23:0] cnt;
reg [1:0] state;
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt <= 24'd0;
    end
    else if(cnt == TIME)begin
        cnt <=24'd0;
    end
    else begin
        cnt <= cnt + 1'd1;
    end

end

//状态切换
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        state <=2'd0;
    end
    else if (cnt == TIME)begin
        state <= state +1'd1;
    end
    else begin
        state <=state;
    end
end

//判断按键值
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        led <= 4'b0000;
    end
    else if (key[0] == 0) begin
        case (state)
            2'd0: led <= 4'b0001;
            2'd1: led <= 4'b0010;
            2'd2: led <= 4'b0100;
            2'd3: led <= 4'b1000;
            default: ;
        endcase
    end
    else if (key[1] == 0) begin
        case (state)
            2'd0: led <= 4'b1000;
            2'd1: led <= 4'b0100;
            2'd2: led <= 4'b0010;
            2'd3: led <= 4'b0001;
            default: ;
        endcase
    end
    else if (key[2] == 0) begin
        case (state)
            2'd0: led <= 4'b1111;
            2'd1: led <= 4'b0000;
            2'd2: led <= 4'b1111;
            2'd3: led <= 4'b0000;
            default: ;
        endcase
    end
    else if (key[3] == 0) begin
        case (state)
            2'd0: led <= 4'b1111;
            2'd1: led <= 4'b1111;
            2'd2: led <= 4'b1111;
            2'd3: led <= 4'b1111;
            default: ;
        endcase
    end
    else begin
        led <= 4'b0000;
    end
    

end



endmodule

按键的 仿真程序

`timescale 1ns/1ns
module key_led_tb();
reg clk;
reg rst_n;
reg [3:0] key;//自己产生的信号,用reg

wire [3:0] led; //直接传递过去的信号,用wire
parameter TIME = 4'd9;
parameter CYCLE = 5'd19 ;

always #(CYCLE/2) clk = ~clk;

initial begin
    clk = 1'b0;
    rst_n = 1'b0;
    #(CYCLE/2);
    rst_n = 1'b1;
    #(4*TIME*CYCLE);
    key = 4'b1110;
    #(4*TIME*CYCLE);
    key = 4'b1101;
    #(4*TIME*CYCLE);
    key = 4'b1011;
    #(4*TIME*CYCLE);
    key = 4'b0111;
    #(4*TIME*CYCLE);
    $stop;

end

key_led #(.TIME(TIME)) u_key_led(
.clk(clk),
.rst_n(rst_n),
.key(key),

.led(led)

);




endmodule

数码管显示十六进制数:

        时间计数文件:

        

module time_count(//到达一定时间后输出一个标识符
    input clk,
    input rst_n,
    output reg flag
);

parameter TIME = 26'd49_999_999;

reg[25:0]cnt;
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt <= 26'd0;
        flag <= 1'b1;
    end
    else if (cnt == TIME) begin
        cnt <= 26'd0;
        flag <= 1'b1;
    end
    else begin
        cnt <= cnt + 1'd1;
        flag <= 1'b0;
    end

end

endmodule

        数码管内容控制及切换

module sel_led_static(//数码显示
    input clk,
    input rst_n,
    input flag,  //计时标志位, 为1,则切换为下一个内容

    output reg[5:0]sel,//位选信号
    output reg[7:0]seg//段选信号
);

reg[3:0]num;//16进制的16种 状态标志位(指出要显示的内容)



always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        sel <= 6'b111_111;
    end
    else begin
        sel <= 6'b000_000;//共阳极数码管,低电平有效,打开六个数码管
    end
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        num <= 4'h0;
    end
    else if(flag)begin
        num <= num + 1'd1;
    end
    else begin
        num <= num;
    end
end 

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        seg <= 8'h0;
    end
    else begin
        case (num)
            4'h0:    seg<= 8'b1100_0000;//匹配到后参考共阳极真值表
	        4'h1:    seg<= 8'b1111_1001;
	        4'h2:    seg<= 8'b1010_0100;
	        4'h3:    seg<= 8'b1011_0000;
	        4'h4:    seg<= 8'b1001_1001;
	        4'h5:    seg<= 8'b1001_0010;
	        4'h6:    seg<= 8'b1000_0010;
	        4'h7:    seg<= 8'b1111_1000;
	        4'h8:    seg<= 8'b1000_0000;
	        4'h9:    seg<= 8'b1001_0000;
	        4'ha:    seg<= 8'b1000_1000;
	        4'hb:    seg<= 8'b1000_0011;
	        4'hc:    seg<= 8'b1100_0110;
	        4'hd:    seg<= 8'b1010_0001;
	        4'he:    seg<= 8'b1000_0110;
	        4'hf:    seg <= 8'b1000_1110;
	      	default :seg <= 8'b1100_0000;
		endcase
  end
   
end


endmodule

数码管显示最终实现 顶层文件

module top_sel_led_static(
    input clk,
    input rst_n,

    output [5:0] sel,
    output [7:0] seg

);
parameter TIME = 26'd24_999_999;//0.5s
wire flag_reg;

time_count #(.TIME(TIME))u_time_count(
.clk(clk),
.rst_n(rst_n),

.flag(flag_reg)
);

sel_led_static u_sel_led_static(
.clk(clk),
.rst_n(rst_n),
.flag(flag_reg),

.seg(seg),
.sel(sel)

);

endmodule

以上三个文件都是数码显示的时候必须的,并且注意的是,再编译前,记得将最后哪个文件设置为top文件

 

vscode扩展代码:

{
	// Place your snippets for verilog here. Each snippet is defined under a snippet name and has a prefix, body and 
	// description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
	// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the 
	// same ids are connected.
	// Example:
	// "Print to console": {
	// 	"prefix": "log",
	// 	"body": [
	// 		"console.log('$1');",
	// 		"$2"
	// 	],
	// 	"description": "Log output to console"
	// }
	"Jsq": {
		"prefix": "Jsq(计数器)",
		"body": [
		"always @(posedge clk or negedge rst_n)begin "
		"   if(!rst_n)begin" 
		"		cnt <= 0;"
		"	end "
		"	else if(add_cnt)begin "
		"			if(end_cnt)begin "
		"				cnt <= 0;"
		"			end" 
		"			else begin "
		"				cnt <= cnt + 1;"
		"			end "
		"	end" 
		"   else  begin"
		"       cnt <= cnt;"
		"	end" 
		"end "
		""
		"assign add_cnt = ;"
		"assign end_cnt = add_cnt && cnt == ;"
		],
		"description": "counter"
   }

   "Shixu": {
	  "prefix": "Shixu(时序逻辑电路)",
	  "body": [
		 "always @(posedge clk or negedge rst_n)begin "
		 "	if(!rst_n)begin" 
		 "		 <= 0;"
		 "	end "
		 "	else if()begin "
		 "		"
		 "	end "
		 "	else begin "
		 "		"
		 "	end "
		 "end" 
	  ],
	  "description": "shixu"
   }

  "Zuhe": {
	   "prefix": "Zuhe(组合逻辑电路)",
	   "body": [
		  "always @(*)begin "
		  "	 if()begin" 
		  "	   = 0;"
		  "	 end "
		  "	 else if()begin "
		  "		"
		  "	 end "
		  "	 else begin "
		  "		"
		  "	 end "
		  "end" 
	   ],
   "description": "Zuhe"
	}

	"Module": {
	   "prefix": "Module(模块端口定义)",
	   "body": [
	   "module module_name( "
	   "	input				clk		," 
	   "	input				rst_n	,"
	   "	input				din		,"
	   "	input		[n:0]   din		,"
	   "	input		[n:0]	din 	,"
	   "	output	reg	[n:0]	dout	,"
	   "	output	reg	[n:0]	dout	,"
	   ");								 "
	   "	//参数定义			 "
	   "						"
	   "	//中间信号定义		 "
	   "	reg		[]	signal0;"
	   "	reg		[]	signal1;"
	   "	wire	[]	signal2;"
	   "	wire	[]	signal3;"
	   "						"
	   "endmodule" 
	   ],
	   "description": "Module"
   }

   "Tb": {
	   "prefix": "Tb(testbeenth)",
	   "body": [
		  "`timescale 1ns/1ns"
		  "				" 
		  "module module_name_tb();"
		  "//激励信号定义 "
		  "reg				tb_clk  	;"
		  "reg				tb_rst_n	;"
		  "reg				tb_din0		;"
		  "reg				tb_din1		;"
		  "reg				tb_din2		;"
		  "//输出信号定义	 "
		  "wire	[n:0]		tb_dout0	;"
		  "wire	[n:0]		tb_dout1    ;"
		  "									      "
		  "//时钟周期参数定义					        "
		  "	parameter		CLOCK_CYCLE = 20;    "
		  "									      "
		  "module_name u_madule_name(			      "
		  ".clk			(tb_clk			),			      "
		  ".rst_n		(tb_rst_n		),			      "
		  ".din0		(tb_din0		),			      "
		  ".din1		(tb_din1		),			      "
		  ".dout0		(tb_dout0		),			      "
		  ".dout1		(tb_dout1		)			      "
		  ");" 
		  "//产生时钟							       		"
		  "initial 		tb_clk = 1'b0;		       		"
		  "always #(CLOCK_CYCLE/2) tb_clk = ~tb_clk;  		"
		  "									       		"
		  "//产生激励							       		"
		  "initial  begin						       		"
		  "	tb_rst_n = 1'b1;								"
		  "	tb_din0 = 0;								"
		  "	#(CLOCK_CYCLE*2);				            "
		  "	tb_rst_n = 1'b0;							"
		  "	#(CLOCK_CYCLE*20);				            "
		  "	tb_rst_n = 1'b1;							"
		  "									       		"
		  "								       			"
		  "									       		"
		  "end 									       	"
		  "endmodule 									       	"
	   ],
	   "description": "Testbeench"
	}

	"Do": {
	   "prefix": "Do",
	   "body": [
	   "#tcl脚本  自动化仿真                         "                                      

	   "#创建工作库 名为work                       "
	   "vlib work                       "
	   "                                    "
	   "#映射工作库 work 到 work                   "
	   "vmap work work                           "
	   "   "
	   "#编译testbench文件                     "
	   "vlog key_led_tb.v                       "
	   "                                                    "
	   "#若要仿真IP核必须添加该文件                                 "
	   "#vlog altera_mf.v                                   "
	   "		                                                  "
	   "#编译被仿真文件                                                "
	   "#vlog ../rtl/key_led.v                                         "
	   "#vlog ../rtl/key_filter.v                                   "
	   "#vlog ../rtl/led.v                                          "
	   "                                                           "
	   "#对IP核进行仿真                                               "
	   "#vlog ../par/ipcore/pll.v                                    "
	   "                                                             "
	   "#指定仿真顶层                                                 "
	   "vsim -novopt work.key_led_tb"
	   "                                                            "
	   "#添加testbench顶层模块中的信号到波形窗
	   "add wave -position insertpoint sim:key_led_tb//*            "
	   "															"
	   "#表示让该tb_clk信号显示黄色									"
	   "#add wave -noupdate -color Yellow /follow_led_tb/tb_clk		"
	   "                                                             "
	   "#表示让div_coef信号用十进制tb_led来显示						   "
	   "#add wave -noupdate -radix decimal /follow_led_tb/tb_led     "
	   "                                                             "
	   "#运行2000个时间单位                                           "
	   "run 2000                                                     "
	   "                                                             "
	   "#一直仿真下去                                                 "
	   "#run -all                                                    "	
	   ],
   "description": "Do"
	}

	"Zhushi": {
	   "prefix": "Zhushi(注释模板)",
	   "body": [
	   "/**************************************功能介绍***********************************"
	   "Copyright:			"                                                                                 
	   "Date     :			"                                                                                 
	   "Author   :			"                                                                                 
	   "Version  :			"
	   "Description:		"
	   "*********************************************************************************/"
	   ],
   "description": "Zhushi"
	}
}

配置步骤:

 

 

 粘贴代码(如果原文件中有个大括号,中间是注释,则把那些都删除了,再粘贴代码)

效果展示:

 (也可以自己在文件里面进行扩展,将常用的语句写入)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值