小梅哥的FPGA

本文基于小梅哥的FPGA学习所得。
推荐一个更加完善的笔记

00.FPGA基本单元

可编程逻辑块
可编程IO块
可编程内部互联

PLL、DLL
块RAM存储器
数学运算单元
高速串行I/O
PCIE、DDR等硬核控制器
嵌入式处理器硬核()

01.科学FPGA开发流程

  1. 设计定义
  2. 设计输入
  3. 分析和综合(Quartus初学)
  4. 功能仿真(modelsim-altera)
  5. 设计约束
  6. 布局布线
  7. 时序仿真(modelsim-altera)
  8. IO分配以及配置文件的生成
  9. 配置(烧结FPGA)
  10. 在线调试(…)
    在这里插入图片描述
    在这里插入图片描述

设计定义:
二选一多路器
两个输入IO,可以是高电平,也可以是低电平,
输入按键按下时,LED灯与a端口保持一致。
输入按键释放时,LED灯与b端口状态保持一致。

led_test.v

module led_test(a,b,key_in,led_out);

	input a;//输入端口A
	input b;//输入端口B
	
	input key_in;//按键输入,实现输入通道的选择
	
	output led_out;//led控制端口
	
	//当key——in == 0;led_out = a;
	
	assign led_out = (key_in == 0) ? a : b;	
endmodule
  • 编译快捷键ctrl+k
  • 模块名和信号名不要有冲突
    在这里插入图片描述

led_test_tb.v

`timescale 1ns/1ps  
module led_test_tb;

//激励信号定义,对应连接到待测模块的输入端口
	reg signal_a;
	reg signal_b;
	reg signal_c;
	
//待检测信号定义,对应连接到待测模块的输出端口
	wire led;
	
//例化待测试模块
	led_test led_test0(
		.a(signal_a),
		.b(signal_b),
		.key_in(signal_c),
		.led_out(led)
		);

//产生激励
	initial begin
		signal_a = 0;signal_b = 0;signal_c = 0;
		#100//延时100ns
		signal_a = 0;signal_b = 0;signal_c = 1;
		#100
		signal_a = 0;signal_b = 1;signal_c = 0;
		#100
		signal_a = 0;signal_b = 1;signal_c = 1;
		#100
		signal_a = 1;signal_b = 0;signal_c = 0;
		#100
		signal_a = 1;signal_b = 0;signal_c = 1;
		#100
		signal_a = 1;signal_b = 1;signal_c = 0;
		#100
		signal_a = 1;signal_b = 1;signal_c = 1;
		#200
		$stop;
	end
endmodule

功能仿真(前仿真)——RTL Simulation

在这里插入图片描述

门级仿真(时序仿真、后仿真)——Gate Level Simulation

在这里插入图片描述
与前仿真相比,存在延迟和脉冲

管脚分配pin planner

在这里插入图片描述

02.3-8译码器设计与验证

ABCout
0000000_0001
0010000_0010
0100000_0100
0110000_1000
1000001_0000
1010010_0000
1100100_0000
1111000_0000

my3_8.v

module my3_8(a,b,c,out);

	input a;//输入端口A
	input b;//输入端口B
	input c;//输入端口C
	
	output	[7:0]	out;//输出端口
	reg	 	[7:0]	out;//always块中生成的必须用reg型
	
	always@(a,b,c)begin
		case({a,b,c})
			3'b000:out = 8'b0000_0001;
			3'b001:out = 8'b0000_0010;
			3'b010:out = 8'b0000_0100;
			3'b011:out = 8'b0000_1000;
			3'b100:out = 8'b0001_0000;
			3'b100:out = 8'b0010_0000;
			3'b110:out = 8'b0100_0000;
			3'b111:out = 8'b1000_0000;
			//default: out = 8'b1000_0000;
		endcase
	end
endmodule

my3_8_tb.v

`timescale 1ns/1ps
module my3_8_tb;

	reg a;
	reg b;
	reg c;
	
	wire [7:0] out;
	
	my3_8 u1(
		.a(a),
		.b(b),
		.c(c),
		.out(out)
	);

	initial begin
			a = 0;b = 0;c = 0;
			#200
			a = 0;b = 0;c = 1;
			#200
			a = 0;b = 1;c = 0;
			#200
			a = 0;b = 1;c = 1;
			#200
			a = 1;b = 0;c = 0;
			#200
			a = 1;b = 0;c = 1;
			#200
			a = 1;b = 1;c = 0;
			#200
			a = 1;b = 1;c = 1;
			#200
			$stop;
	end
endmodule

功能仿真(前仿真)

在这里插入图片描述

门级仿真(时序仿真、后仿真)

在这里插入图片描述
在这里插入图片描述

  • 上面标记的地方有下面这种情况(竞争冒险?):
    在这里插入图片描述
    错误:modelsim只支持打开一次,如果未关闭打开则会报错如下:
    在这里插入图片描述

02. 4-16译码器(对比3-8译码器练习)

ABCDout
00000000_0000_0000_0001
00010000_0000_0000_0010
00100000_0000_0000_0100
00110000_0000_0000_1000
01000000_0000_0001_0000
01010000_0000_0010_0000
01100000_0000_0100_0000
01110000_0000_1000_0000
10000000_0001_0000_0000
10010000_0010_0000_0000
10100000_0100_0000_0000
10110000_1000_0000_0000
11000001_0000_0000_0000
11010010_0000_0000_0000
11100100_0000_0000_0000
11111000_0000_0000_0000

my4_16.v

module my4_16(a,b,c,d,out);
	
	input a;
	input b;
	input c;
	input d;
	
	output [15:0]out;
	reg    [15:0]out;
	
	always@(a,b,c,d)begin
		case({a,b,c,d})   
		4'b0000	 :out = 16'b0000_0000_0000_0001;
		4'b0001	 :out = 16'b0000_0000_0000_0010;
		4'b0010	 :out = 16'b0000_0000_0000_0100;
		4'b0011	 :out = 16'b0000_0000_0000_1000;
		4'b0100	 :out = 16'b0000_0000_0001_0000;
		4'b0101	 :out = 16'b0000_0000_0010_0000;
		4'b0110	 :out = 16'b0000_0000_0100_0000;
		4'b0111	 :out = 16'b0000_0000_1000_0000;
		4'b1000	 :out = 16'b0000_0001_0000_0000;
		4'b1001	 :out = 16'b0000_0010_0000_0000;
		4'b1010	 :out = 16'b0000_0100_0000_0000;
		4'b1011	 :out = 16'b0000_1000_0000_0000;
		4'b1100	 :out = 16'b0001_0000_0000_0000;
		4'b1101	 :out = 16'b0010_0000_0000_0000;
		4'b1110	 :out = 16'b0100_0000_0000_0000;
		4'b1111	 :out = 16'b1000_0000_0000_0000;
		endcase
	end
endmodule

my4_16_tb.v

`timescale 1ns/1ps

module my4_16_tb;
	reg a;
	reg b;
	reg c;
	reg d;
	
	wire [15:0] out;
	
	my4_16 my4_16_inst(
		.a		(a	),
		.b		(b	),
		.c		(c	),
		.d		(d	),
		.out	(out)
		);
		
	initial begin
		a = 0;b = 0;c = 0;d = 0;
		#200
		a = 0;b = 0;c = 0;d = 1;
		#200
		a = 0;b = 0;c = 1;d = 0;
		#200
		a = 0;b = 0;c = 1;d = 1;
		#200
		a = 0;b = 1;c = 0;d = 0;
		#200
		a = 0;b = 1;c = 0;d = 1;
		#200
		a = 0;b = 1;c = 1;d = 0;
		#200
		a = 0;b = 1;c = 1;d = 1;
		#200
		a = 1;b = 0;c = 0;d = 0;
		#200
		a = 1;b = 0;c = 0;d = 1;
		#200
		a = 1;b = 0;c = 1;d = 0;
		#200
		a = 1;b = 0;c = 1;d = 1;
		#200
		a = 1;b = 0;c = 0;d = 0;
		#200
		a = 1;b = 0;c = 0;d = 1;
		#200
		a = 1;b = 0;c = 1;d = 0;
		#200
		a = 1;b = 0;c = 1;d = 1;
		#200
		$stop;
	end
endmodule
  • 在仿真中,任何信号都要赋给初始值

前仿真(功能仿真)

在这里插入图片描述

在这里插入图片描述

后仿真

在这里插入图片描述

  • 后仿真和之前一样,也存在延迟和上电的高阻。

语法乱记

模块调用

综合与不可综合

task中只要没有不可综合语句(如延时#),就可以综合!
initial也未必,

时序逻辑:

时钟存储能力(reg),计数器是最简单的时序逻辑(时序逻辑中也需要组合逻辑的配合才有意义)。

03.计数器

LED,每500ms,状态翻转一次,
系统时钟为50M,对应周期为20ns
500ms = 500_000_000ns/20 = 25_000_000;

电路原理图

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

counter.v

module counter(Clk50M,Rst_n,led);

	input Clk50M;//系统时钟,50M
	input Rst_n;//全局复位,低电平复位
	
	output reg led;//led输出,always块中的变量都要声明为reg型
	
	reg [24:0] cnt;//定义计数器寄存器
	
//计数器计数进程	
	always@(posedge Clk50M or negedge Rst_n)begin
	if(Rst_n == 1'b0)
		cnt <= 25'd0;
	//else if(cnt == 25'd24_999_999)
	else if(cnt == 25'd24_999)
		cnt <= 25'd0;
	else
		cnt <= cnt + 1'b1;
	end

//led输出控制进程
	always@(posedge Clk50M or negedge Rst_n)begin
	if(Rst_n == 1'b0)
		led <= 1'b1;
	//else if(cnt == 25'd24_999_999)	
	else if(cnt == 25'd24_999)
		led <= ~led;
	else 
		led <= led;
	end

endmodule

couter_tb.v

`timescale 1ns/1ps
`define clock_period 20

module counter_tb;

	reg clk;
	reg rst_n;
	
	wire led;

	counter counter0(
		.Clk50M(clk),
		.Rst_n(rst_n),
		.led(led)
	);

	initial clk = 1;
	always #(`clock_period/2)	clk = ~clk;
	
	initial begin
		rst_n = 1'b0;
		#(`clock_period *200);
		rst_n = 1'b1;
		#2000000000;
		$stop;
	end
		
	
endmodule

前仿真(功能仿真)

在这里插入图片描述

后仿真(时序仿真、门级仿真)

在这里插入图片描述

IO管脚分配

在这里插入图片描述

04.计数器IP核调用与验证

四位计数器 (Quartus II 提供的LPM_counter IP核的使用)

  • FPGA设计方式:
    原理图(不推荐)
    Verilog HDL设计方式
    IP核输入方式

调用步骤

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

counter.v

`timescale 1 ps / 1 ps
// synopsys translate_on
module counter (
	cin,
	clock,
	cout,
	q);

	input	  cin;
	input	  clock;
	output	  cout;
	output	[3:0]  q;

	wire  sub_wire0;
	wire [3:0] sub_wire1;
	wire  cout = sub_wire0;
	wire [3:0] q = sub_wire1[3:0];

	lpm_counter	LPM_COUNTER_component (
				.cin (cin),
				.clock (clock),
				.cout (sub_wire0),
				.q (sub_wire1),
				.aclr (1'b0),
				.aload (1'b0),
				.aset (1'b0),
				.clk_en (1'b1),
				.cnt_en (1'b1),
				.data ({4{1'b0}}),
				.eq (),
				.sclr (1'b0),
				.sload (1'b0),
				.sset (1'b0),
				.updown (1'b1));
	defparam
		LPM_COUNTER_component.lpm_direction = "UP",
		LPM_COUNTER_component.lpm_modulus = 10,
		LPM_COUNTER_component.lpm_port_updown = "PORT_UNUSED",
		LPM_COUNTER_component.lpm_type = "LPM_COUNTER",
		LPM_COUNTER_component.lpm_width = 4;
		
endmodule

tb_counter.v

`timescale 1ns/1ns

`define clock_period 20

module counter_tb;

	reg cin;//进位输入
	reg clk;//计数基准时钟
	
	wire cout;//进位输出
	wire [3:0] q;

	counter counter0(
		.cin(cin),
		.clock(clk),
		.cout(cout),
		.q(q)
		);
	
	initial clk = 1;
	always #(`clock_period/2) clk = ~clk;
	
	initial begin
		repeat(5)begin
			cin = 0;
			#(`clock_period *5) cin = 1;
			#(`clock_period   ) cin = 0;
		end
		#(`clock_period *200);
		$stop;		
	end

endmodule

前仿真(功能仿真)

在这里插入图片描述

  • 把counter_tb.v中的repeat(5)改为repeat(10),出现如下的仿真结果:(记得选无符号显示)
    在这里插入图片描述
  • 这个IP核的这个学习小节中,我们开始设置了计数到10,其实我们还可以计数到满(四位计数到4’b1111),下面将重新配置
  • 在这里插入图片描述
    在这里插入图片描述
  • 这里的功能仿真如下:
    在这里插入图片描述

八位计数器(四位计数器拼接升级)

前面的例码,说的是4位的,如果说要8位的,该怎么办?

一种是:在设计代码中,将位宽设置为8位的;还有一种就是将两个四位的拼接,原理图如下:
在这里插入图片描述

功能仿真

在这里插入图片描述
在这里插入图片描述

  • 当然,肯定是直接在设计中修改为8位位宽比较方便,如果继续同这节课开始,把计数器设置回10的时候,继续仿真,就会出现如下的效果,引出BCD计数器
    在这里插入图片描述

05. BCD计数器设计与使用

158

158/100 = 1
158%100 = 5
58/10 = 5

158%10 = 8

BCD计数器
在这里插入图片描述

BCD计数器基本模块

BCD_counter.v

module BCD_counter(Clk, Cin, Rst_n, Cout, q );

	input Clk;//计数基准时钟
	input Cin;//计数器进位输入
	input Rst_n;//系统复位
	
	output reg Cout;//计数器进位输出
	output [3:0] q;//计数器输出
	
	reg 	[3:0] cnt;//定义计数器寄存器
	
//执行计数过程
	always@(posedge Clk or negedge Rst_n)
	if(Rst_n == 1'b0)
		cnt <= 4'd0;
	else if(Cin == 1'b1) begin
		if(cnt == 4'd9)
			cnt <= 4'd0;
		else 
			cnt <= cnt + 4'd1;
	end
	else
			cnt <= cnt;
	
//产生进位输出信号			
	always@(posedge Clk or negedge Rst_n)
	if(Rst_n == 1'b0)
		Cout = 1'b0;
	else if(Cin == 1'b1 && cnt == 4'd9 ) 
		Cout <= 1'b1;
	else Cout <= 1'b0;
	
	assign q = cnt;

endmodule

BCD_counter_tb.v

`timescale 1ns/1ns
`define clock_period 20
module BCD_counter_tb;

	reg clk;
	reg cin;
	reg rst_n;
	
	wire cout;
	wire [3:0]q;

	BCD_counter BCD_counter_inst(
		.Clk(clk),
		.Cin(cin), 
		.Rst_n(rst_n), 
		.Cout(cout),
		.q(q) 
	);
	
	initial clk = 1'b1;
	always #(`clock_period/2) clk = ~clk;
	
	
	initial begin
		rst_n = 1'b0;
		cin = 1'b0;
		#(`clock_period *200);
		rst_n = 1'b1;
		#(`clock_period *20);
		repeat(30)begin
			cin = 1'b1;
			#`clock_period;
			cin = 1'b0;
			#(`clock_period *5);
		end
		#(`clock_period *20);
		$stop;
	end

endmodule

功能仿真

在这里插入图片描述

BCD计数器综合(由模块组成top)

按照上节课的套路,这次按照12位输出,也就是需要例化三次counter

BCD_counter_top.v

module BCD_counter_top(Clk, Cin, Rst_n, Cout, q );

	input Clk;//计数基准时钟
	input Cin;//计数器进位输入
	input Rst_n;//系统复位
	
	output Cout;//计数器进位输出
	output [11:0] q;//计数器输出
	
	wire Cout1;
	wire Cout2;
	wire [3:0] q0,q1,q2;
	assign q = {q2,q1,q0};

	BCD_counter BCD_counter_inst0(
		.Clk(Clk),
		.Cin(Cin), 
		.Rst_n(Rst_n), 
		.Cout(Cout1),
		.q(q0) 
	);
	
	BCD_counter BCD_counter_inst1(
		.Clk(Clk),
		.Cin(Cout1), 
		.Rst_n(Rst_n), 
		.Cout(Cout2),
		.q(q1) 
	);
	
	BCD_counter BCD_counter_inst2(
		.Clk(Clk),
		.Cin(Cout2), 
		.Rst_n(Rst_n), 
		.Cout(Cout),
		.q(q2) 
	);
	
endmodule

BCD_counter_top_tb.v

`timescale 1ns/1ns
`define clock_period 20
module BCD_counter_top_tb;

	reg clk;
	reg cin;
	reg rst_n;
	
	wire cout;
	wire [11:0]q;

	BCD_counter_top BCD_counter_top_inst(
		.Clk(clk),
		.Cin(cin), 
		.Rst_n(rst_n), 
		.Cout(cout),
		.q(q) 
	);
	
	initial clk = 1'b1;
	always #(`clock_period/2) clk = ~clk;
	
	
	initial begin
		rst_n = 1'b0;
		cin = 1'b0;
		#(`clock_period *200);
		rst_n = 1'b1;
		#(`clock_period *20);
		cin = 1'b1;
		#(`clock_period *5000);
		$stop;
	end

endmodule

功能仿真(发现错误)

在这里插入图片描述
在这里插入图片描述

修改后的BCD_counter.v

module BCD_counter(Clk, Cin, Rst_n, Cout, q );

	input Clk;//计数基准时钟
	input Cin;//计数器进位输入
	input Rst_n;//系统复位
	
	output  Cout;//计数器进位输出
	output [3:0] q;//计数器输出
	
	reg 	[3:0] cnt;//定义计数器寄存器
	
//执行计数过程
	always@(posedge Clk or negedge Rst_n)
	if(Rst_n == 1'b0)
		cnt <= 4'd0;
	else if(Cin == 1'b1) begin
		if(cnt == 4'd9)
			cnt <= 4'd0;
		else 
			cnt <= cnt + 1'b1;
	end
	else
			cnt <= cnt;
	
//产生进位输出信号			
	assign Cout = (Cin == 1'b1 && cnt == 4'd9 ); 

	
	assign q = cnt;

endmodule

修改后的功能仿真

在这里插入图片描述

07.阻塞赋值与非阻塞赋值

这节课,为了讲述阻塞与非阻塞,感受一下非阻塞与阻塞之间的区别,
out <= a+b+c 设计拆分为:
d <= a+b;
out <= c+d;

当然,实际过程中,就是直接用out = a+b+c即可,不用再引入寄存器增加延迟。

block_nonblock.v(第一种)

module block_nonblock(Clk,Rst_n,a,b,c,out);

	input Clk;
	input Rst_n;
	input a;
	input b;
	input c;
	
	output reg [1:0] out;
	
	//out = a + b + c;
	
	//d = a + b;
	//out = d + c;
	
	reg [1:0]d;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		out = 2'b0;
	else begin
		d = a + b;
		out = d + c;
	end
	
endmodule

综合之后的电路原理图

在这里插入图片描述

block_nonblock.v(第二种)

module block_nonblock(Clk,Rst_n,a,b,c,out);

	input Clk;
	input Rst_n;
	input a;
	input b;
	input c;
	
	output reg [1:0] out;
	
	//out = a + b + c;
	
	//d = a + b;
	//out = d + c;
	
	reg [1:0]d;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		out = 2'b0;
	else begin
		out = d + c;
		d = a + b;
	end
	
endmodule

综合之后的电路原理图(第二种)

在这里插入图片描述

block_nonblock.v(第三种)

module block_nonblock(Clk,Rst_n,a,b,c,out);

	input Clk;
	input Rst_n;
	input a;
	input b;
	input c;
	
	output reg [1:0] out;
	
	//out = a + b + c;
	
	//d = a + b;
	//out = d + c;
	
	reg [1:0]d;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		out <= 2'b0;
	else begin
		out <= d + c;
		d <= a + b;
	end
	
endmodule

综合之后的电路原理图(第三种)

在这里插入图片描述

block_nonblock.v(第四种)

module block_nonblock(Clk,Rst_n,a,b,c,out);

	input Clk;
	input Rst_n;
	input a;
	input b;
	input c;
	
	output reg [1:0] out;
	
	//out = a + b + c;
	
	//d = a + b;
	//out = d + c;
	
	reg [1:0]d;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		out <= 2'b0;
	else begin
		d <= a + b;
		out <= d + c;
	end
	
endmodule

综合之后的电路原理图(第四种)

在这里插入图片描述

测试平台block_nonblock_tb.v

`timescale 1ns/1ns
`define clock_period 20

module block_nonblock_tb;

	reg Clock;
	reg Rst_n;
	reg a,b,c;
	
	wire [1:0]out;

	block_nonblock block_nonblock0(Clock,Rst_n,a,b,c,out);
	
	initial Clock = 1'b1;
	always #(`clock_period/2) Clock = ~Clock;
	
	initial begin
		Rst_n = 1'b0;
		a = 0;
		b = 0;
		c = 0;
		#(`clock_period*200 +1);
		#(`clock_period*200);
		Rst_n = 1'b1;
		a = 0;b = 0;c = 0;
		#(`clock_period*200);
		a = 0;b = 0;c = 1;
		#(`clock_period*200);
		a = 0;b = 1;c = 0;
		#(`clock_period*200);
		a = 0;b = 1;c = 1;
		#(`clock_period*200);
		a = 1;b = 0;c = 0;
		#(`clock_period*200);
		a = 1;b = 0;c = 1;
		#(`clock_period*200);
		a = 1;b = 1;c = 0;
		#(`clock_period*200);
		a = 1;b = 1;c = 1;
		#(`clock_period*200);
		$stop;
	end
endmodule

第四种的功能仿真

在这里插入图片描述

block_nonblock.v(在第四种的基础上添加了延迟)

`timescale 1ns/1ns
`define tp 1
module block_nonblock(Clk,Rst_n,a,b,c,out);

	input Clk;
	input Rst_n;
	input a;
	input b;
	input c;
	
	output reg [1:0] out;
	
	//out = a + b + c;
	
	//d = a + b;
	//out = d + c;
	
	reg [1:0]d;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		out <= #`tp 2'b0;
	else begin
		d <= #`tp  a + b;
		out <= #`tp  d + c;
	end
	
endmodule

对应的功能仿真

在这里插入图片描述

后仿真(这里去掉延迟,用第四种设计代码)

在这里插入图片描述
从这里可以考虑一下:时序分析常识

不推荐使用阻塞赋值的原因如下:

在这里插入图片描述
在这里插入图片描述

08.状态机的设计思想

(工作日,闹钟响起)

  • 06:00~09:00 |(起床后的整理以及工作前的准备)
    询问是否需要上班——是(工作),不是(其他)
  • 09:00~18:00|(工作)
    是否需要加班——需要加班(工作),不需要工作(回家)
  • 18:00~22:00|(下班回家、做饭、吃饭)
    是否需要休息——是(休息),不是(其他)
  • 22:00~06:00|(睡觉)

序列检测的一个例子

在这里插入图片描述

Hello.v

module Hello(Clk,Rst_n,data,led);

	input Clk;//50M
	input Rst_n;//
	
	input [7:0]data;
	
	output reg led;
	
	localparam 
		CHECk_H  = 5'b0_0001,
		CHECk_e  = 5'b0_0010,
		CHECk_la = 5'b0_0100,
		CHECk_lb = 5'b0_1000,
		CHECk_o  = 5'b1_0000;
		
	reg [4:0] state;
	
	//一段式状态机、两段式状态机、三段式状态机
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		led <= 1'b1;
		state <= CHECk_H;
	end
	else begin
		case(state)
			CHECk_H:
				if(data == "H")//这是可综合的
					state <= CHECk_e;
				else
					state <= CHECk_H;
			CHECk_e:
				if(data == "e")
					state <= CHECk_la;
				else
					state <= CHECk_H;
			CHECk_la:
				if(data == "l")
					state <= CHECk_lb;
				else 
					state <= CHECk_H;
			CHECk_lb:
				if(data == "l")
					state <= CHECk_o;
				else
					state <= CHECk_H;
			CHECk_o:
				begin
					state <= CHECk_H;
					if(data == "o")
						led <= ~led;
						else led <=led;	
				end
			default:state <= CHECk_H;
		endcase	
	end	
endmodule

Hello_tb.v

`timescale 1ns/1ns
`define clock_period 20
module Hello_tb;

	reg Clk;
	reg Rst_n;
	reg [7:0]ASCII;
	
	wire led;

	Hello Hello(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.data(ASCII),
		.led(led)
	);
	
	initial Clk = 1'b1;
	always #(`clock_period/2) Clk = ~Clk;
	
	initial begin
		Rst_n = 1'b0;
		#(`clock_period*200);
		Rst_n = 1;
		#(`clock_period*200);
		
		forever begin
			ASCII = "I";
			#(`clock_period);
			ASCII = "A";
			#(`clock_period);
			ASCII = "M";
			#(`clock_period);
			ASCII = "X";
			#(`clock_period);
			ASCII = "i";
			#(`clock_period);
			ASCII = "a";
			#(`clock_period);
			ASCII = "o";
			#(`clock_period);
			ASCII = "M";
			#(`clock_period);
			ASCII = "e";
			#(`clock_period);
			ASCII = "i";
			#(`clock_period);
			ASCII = "g";
			#(`clock_period);
			ASCII = "e";
			
			#(`clock_period);
			ASCII = "H";
			#(`clock_period);
			ASCII = "E";
			
			#(`clock_period);
			ASCII = "M";
			#(`clock_period);
			ASCII = "l";
			
			#(`clock_period);
			ASCII = "H";
			#(`clock_period);
			ASCII = "E";
			#(`clock_period);
			ASCII = "L";
			#(`clock_period);
			ASCII = "L";
			#(`clock_period);
			ASCII = "O";
			
			#(`clock_period);
			ASCII = "H";
			#(`clock_period);
			ASCII = "e";
			#(`clock_period);
			ASCII = "l";
			#(`clock_period);
			ASCII = "l";
			#(`clock_period);
			ASCII = "o";
			
			#(`clock_period);
			ASCII = "l";
		end
	end	
endmodule

功能仿真

在这里插入图片描述

门级仿真

在这里插入图片描述

  • 对比功能仿真,发现led状态并没有发生立即的翻转,而是在采集到的时钟沿后面一段时间才翻转,这是符合真实电路的。因此建议在功能仿真时,建议在testbench中加上一定的延时,和后仿真贴近。在tb中修改成如下的格式:

Rst_n = 1;
#(`clock_period*200 + 1);

添加延迟后的功能仿真

在这里插入图片描述

09.A按键消抖模式设计与验证

独立按键消抖实验

课程目标:复习状态机的设计思想
实验平台:Snow Dream starter board 核心板
在这里插入图片描述
实验现象:每次按下键0,4个LED显示状态以二进制加法格式加1,每次按下按键1,4个LED显示状态以二进制加法格式减1

独立按键的物理模型
在这里插入图片描述

知识点

  1. testbench 中随机数发生函数$random的使用;
  2. 仿真模型的概念;

未按下时空闲状态(IDLE
按下抖动滤除状态(FILTER
按下稳定状态(DOWN
释放抖动滤除状态(FILTER
在这里插入图片描述
消抖模型
在这里插入图片描述
边缘检测
在这里插入图片描述

key_filter.v

module key_filter(Clk,Rst_n,key_in,key_flag,key_state);

	input Clk;
	input Rst_n;
	input key_in;
	
	output reg key_flag;
	output reg key_state;
	
	localparam
		IDLE	  = 4'b0001,
		FILTER0 = 4'b0010,
		DOWN	  = 4'b0100,
		FILTER1 = 4'b1000;
		
	reg [3:0] state;
	reg [19:0] cnt;
	reg en_cnt;//使能计数寄存器
	//50_000_000		20ns
	//20ms=20_000_000ns ,则需要计数1_000_000即为20ms
	
	reg key_tmp0,key_tmp1;
	wire pedge,nedge;
	reg cnt_full;//计数满表示信号
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		key_tmp0 <= 1'b0;
		key_tmp1 <= 1'b0;
	end
	else begin
		key_tmp0 <= key_in;
		key_tmp1 <= key_tmp0;
	end
	
	assign nedge = !key_tmp0 & key_tmp1;
	assign pedge = key_tmp0 &(!key_tmp1);
	//assign pedge = key_tmp0 &(~key_tmp1);
	//~0110 = 1001
	//!0110 = 0000

	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		en_cnt <= 1'b0;
		state <= IDLE;
		key_flag <=1'b0;
		key_state <= 1'b1;
	end
	else begin
		case(state)
			IDLE:
				begin
					key_flag <= 1'b0;
					if(nedge)begin
						state <= FILTER0;
						en_cnt <= 1'b1;
					end
					else 
						state <= IDLE;
				end
			FILTER0:
				begin
				if(cnt_full)begin
					key_flag <=1'b1;
					key_state <= 1'b0;
					state <= DOWN;
					en_cnt <= 1'b0;
				end
				else if(pedge)begin
					state <= IDLE;
					en_cnt <= 1'b0;
				end
				else state <= FILTER0;
				end
			DOWN:
				begin
					key_flag <= 1'b0;
					if(pedge)begin
						state <= FILTER1;
						en_cnt <= 1'b1;
					end
					else
						state <= DOWN;
				end
			FILTER1:
				begin
				if(cnt_full)begin
					key_flag <=1'b1;
					key_state <= 1'b1;
					state <= IDLE;
				end
				else if(nedge)begin
					en_cnt <= 1'b0;
					state <= DOWN;
				end
				else
					state <= FILTER1;
				end	
			default:
				begin
					state <= IDLE;
					en_cnt <= 1'b0;
					key_flag <= 1'b0;
					key_state <= 1'b1;
				end
		endcase
	end
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		cnt <= 20'd0;
	else if (en_cnt)
		cnt <= cnt + 1'b1;
	else 
		cnt <= 20'd0;
		
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		cnt_full <= 1'b0;
	else if (cnt == 999_999)
		cnt_full <= 1'b1;
	else 
		cnt_full <= 1'b0;	
endmodule

综合之后得到的状态图

在这里插入图片描述

key_filter_tb.v

`timescale 1ns/1ns
`define clk_period 20

module key_filter_tb;

	reg Clk;
	reg Rst_n;
	reg key_in;
	
	wire key_flag;
	wire key_state;

	key_filter key_filter0(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.key_in(key_in),
		.key_flag(key_flag),
		.key_state(key_state)
	);
	
	initial Clk = 1'b1;
	always #(`clk_period/2) Clk = ~Clk;
	
	initial begin
		Rst_n = 1'b0;
		key_in = 1'b1;
		#(`clk_period *10) Rst_n = 1'b1;
		#(`clk_period *10 +1);
		//第一次
		key_in = 0; #1000;
		key_in = 1; #2000;
		key_in = 0; #1400;
		key_in = 1; #2600;
		key_in = 0; #1300;
		key_in = 1; #200;
		key_in = 0; #20000100;
		#50000100;
		
		key_in = 1; #2000;
		key_in = 0; #1000;
		key_in = 1; #2000;
		key_in = 0; #1400;
		key_in = 1; #2600;
		key_in = 0; #1300;
		key_in = 1; #20000100;
		#50000100;
		
		//第二次
		key_in = 0; #1000;
		key_in = 1; #2000;
		key_in = 0; #1400;
		key_in = 1; #2600;
		key_in = 0; #1300;
		key_in = 1; #200;
		key_in = 0; #20000100;
		#50000100;
		
		key_in = 1; #2000;
		key_in = 0; #1000;
		key_in = 1; #2000;
		key_in = 0; #1400;
		key_in = 1; #2600;
		key_in = 0; #1300;
		key_in = 1; #20000100;
		#50000100;
		
		//第三次
		key_in = 0; #1000;
		key_in = 1; #2000;
		key_in = 0; #1400;
		key_in = 1; #2600;
		key_in = 0; #1300;
		key_in = 1; #200;
		key_in = 0; #20000100;
		#50000100;
		
		key_in = 1; #2000;
		key_in = 0; #1000;
		key_in = 1; #2000;
		key_in = 0; #1400;
		key_in = 1; #2600;
		key_in = 0; #1300;
		key_in = 1; #20000100;
		#50000100;
		
		//第四次
		key_in = 0; #1000;
		key_in = 1; #2000;
		key_in = 0; #1400;
		key_in = 1; #2600;
		key_in = 0; #1300;
		key_in = 1; #200;
		key_in = 0; #20000100;
		#50000100;
		
		key_in = 1; #2000;
		key_in = 0; #1000;
		key_in = 1; #2000;
		key_in = 0; #1400;
		key_in = 1; #2600;
		key_in = 0; #1300;
		key_in = 1; #20000100;
		#50000100; 
		$stop;
	end
endmodule

功能仿真
  • 向上的箭头:按下抖动
  • 向下的箭头:释放抖动

在这里插入图片描述

通过$random简化测试平台

随机数发生函数

`timescale 1ns/1ns
`define clk_period 20

module key_filter_tb;

	reg Clk;
	reg Rst_n;
	reg key_in;
	
	wire key_flag;
	wire key_state;

	key_filter key_filter0(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.key_in(key_in),
		.key_flag(key_flag),
		.key_state(key_state)
	);
	
	initial Clk = 1'b1;
	always #(`clk_period/2) Clk = ~Clk;
	
	initial begin
		Rst_n = 1'b0;
		key_in = 1'b1;
		#(`clk_period *10) Rst_n = 1'b1;
		#(`clk_period *10 +1);
		press_key;
		#10000;
		press_key;
		#10000;
		press_key;
		$stop;
	end
	
	reg [15:0] myrand;
	
	task press_key;
		begin
			//按下抖动过程
			repeat(50)begin
				myrand = {$random}%65536;//0-65535;
				#myrand key_in = ~key_in;
			end
			key_in = 0;
			#50000000;
			
			//释放抖动过程
			repeat(50)begin
				myrand = {$random}%65536;//0-65535;
				#myrand key_in = ~key_in;
			end
			key_in = 1;
			#50000000;
		end
	endtask
	
endmodule

功能仿真(随机函数是起作用的)

在这里插入图片描述

仿真模型

在这里插入图片描述

key_model.v

`timescale 1ns/1ns

module key_model(key);

	output reg key;
	
	reg [15:0] myrand;
	
	initial begin
		key = 1'b1;
		press_key;
		#10000;
		press_key;
		#10000;
		press_key;
		$stop;
	end
	
	task press_key;
		begin
			//按下抖动过程
			repeat(50)begin
				myrand = {$random}%65536;//0-65535;
				#myrand key = ~key;
			end
			key = 0;
			#50000000;
			
			//释放抖动过程
			repeat(50)begin
				myrand = {$random}%65536;//0-65535;
				#myrand key = ~key;
			end
			key = 1;
			#50000000;
		end
	endtask

endmodule

key_filter_tb.v

`timescale 1ns/1ns

`define clk_period 20

module key_filter_tb;

	reg Clk;
	reg Rst_n;
	wire key_in;
	
	wire key_flag;
	wire key_state;

	key_filter key_filter0(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.key_in(key_in),
		.key_flag(key_flag),
		.key_state(key_state)
	);
	
	key_model key_model1(.key(key_in));
	
	initial Clk = 1'b1;
	always #(`clk_period/2) Clk = ~Clk;
	
	initial begin
		Rst_n = 1'b0;
		#(`clk_period *10) Rst_n = 1'b1;
		#(`clk_period *10 +1);
	end
endmodule

在这里插入图片描述

09.B按键消抖与亚稳态问题引入

  • 异步信号:它与系统没有关系的,由外部产生的
  • 模块化思想
  • 异步信号的同步,使用两级D触发器进行同步

在这里插入图片描述
在这里插入图片描述

key_led_top.v

module key_led_top(Clk,Rst_n,key_in0,key_in1,led);

	input Clk;
	input Rst_n;
	input key_in0;
	input key_in1;
	
	output [3:0] led;
	
	wire key_flag0,key_flag1;
	wire key_state0,key_state1;
	
	key_filter key_filter0(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.key_in(key_in0),
		.key_flag(key_flag0),
		.key_state(key_state0)
	);
	
	key_filter key_filter1(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.key_in(key_in1),
		.key_flag(key_flag1),
		.key_state(key_state1)
	);
	
	led_ctrl led_ctrl0(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.key_flag0(key_flag0),
		.key_flag1(key_flag1),
		.key_state0(key_state0),
		.key_state1(key_state1),
		.led(led)
	);
endmodule

key_filter.v

module key_filter(Clk,Rst_n,key_in,key_flag,key_state);

	input Clk;
	input Rst_n;
	input key_in;
	
	output reg key_flag;
	output reg key_state;
	
	localparam
		IDLE	  = 4'b0001,
		FILTER0 = 4'b0010,
		DOWN	  = 4'b0100,
		FILTER1 = 4'b1000;
		
	reg [3:0] state;
	reg [19:0] cnt;
	reg en_cnt;//使能计数寄存器
	//50_000_000		20ns
	//20ms=20_000_000ns ,则需要计数1_000_000即为20ms
	

	
//对外部输入的异步信号进行同步处理
	reg key_in_s0,key_in_s1;
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		key_in_s0 <= 1'b0;
		key_in_s1 <= 1'b0;
	end
	else begin
		key_in_s0 <= key_in;
		key_in_s1 <= key_in_s0;
	end
	
	reg key_tmp0,key_tmp1;
	wire pedge,nedge;
	reg cnt_full;//计数满表示信号
	
//使用D触发器存储两个相邻时钟上升沿外部输入信号(已经同步到系统时钟域中)的电平状态
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		key_tmp0 <= 1'b0;
		key_tmp1 <= 1'b0;
	end
	else begin
		key_tmp0 <= key_in_s1;
		key_tmp1 <= key_tmp0;
	end
	
//产生跳变沿信号	
	assign nedge = !key_tmp0 & key_tmp1;
	assign pedge = key_tmp0 &(!key_tmp1);
	//assign pedge = key_tmp0 &(~key_tmp1);
	//~0110 = 1001
	//!0110 = 0000
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		en_cnt <= 1'b0;
		state <= IDLE;
		key_flag <=1'b0;
		key_state <= 1'b1;
	end
	else begin
		case(state)
			IDLE:
				begin
					key_flag <= 1'b0;
					if(nedge)begin
						state <= FILTER0;
						en_cnt <= 1'b1;
					end
					else 
						state <= IDLE;
				end
			FILTER0:
				begin
				if(cnt_full)begin
					key_flag <=1'b1;
					key_state <= 1'b0;
					state <= DOWN;
					en_cnt <= 1'b0;
				end
				else if(pedge)begin
					state <= IDLE;
					en_cnt <= 1'b0;
				end
				else state <= FILTER0;
				end
			DOWN:
				begin
					key_flag <= 1'b0;
					if(pedge)begin
						state <= FILTER1;
						en_cnt <= 1'b1;
					end
					else
						state <= DOWN;
				end
			FILTER1:
				begin
				if(cnt_full)begin
					key_flag <=1'b1;
					key_state <= 1'b1;
					state <= IDLE;
				end
				else if(nedge)begin
					en_cnt <= 1'b0;
					state <= DOWN;
				end
				else
					state <= FILTER1;
				end	
			default:
				begin
					state <= IDLE;
					en_cnt <= 1'b0;
					key_flag <= 1'b0;
					key_state <= 1'b1;
				end
		endcase
	end
	
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		cnt <= 20'd0;
	else if (en_cnt)
		cnt <= cnt + 1'b1;
	else 
		cnt <= 20'd0;
		
	
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		cnt_full <= 1'b0;
	else if (cnt == 999_999)
		cnt_full <= 1'b1;
	else 
		cnt_full <= 1'b0;	
endmodule

led_ctrl.v

module led_ctrl(Clk,Rst_n,key_flag0,key_flag1,key_state0,key_state1,led);

	input Clk;
	input Rst_n;
	input key_flag0,key_flag1;
	
	input key_state0,key_state1;
	
	output [3:0] led;
	
	reg [3:0] led_r;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		led_r <= 4'b0000;
	else if(key_flag0 && !key_state0)
		led_r <= led_r + 1'b1;
	else if(key_flag1 && !key_state1)
		led_r <= led_r - 1'b1;
	else 
		led_r <= led_r;
		
	assign led = ~led_r;
endmodule

key_led_top_tb.v

`timescale 1ns/1ns

`define clk_period 20
module key_led_top_tb;

	reg Clk;
	reg Rst_n;
	wire key_in0,key_in1;
	reg press0,press1;
	
	wire [3:0] led;

	key_led_top key_led_top0(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.key_in0(key_in0),
		.key_in1(key_in1),
		.led(led)
	);
	
	key_model key_model0(
		.press(press0),
		.key(key_in0)
	);
	
	key_model key_model1(
		.press(press1),
		.key(key_in1)
	);
	
	initial Clk = 1'b1;
	always #(`clk_period/2) Clk = ~Clk;
	
	initial begin
		Rst_n = 1'b0;
		press0 = 0;
		press1 = 0;
		#(`clk_period *10) Rst_n = 1'b1;
		#(`clk_period *10 +1);
		
		press0 = 1;
		#(`clk_period *3) 
		press0 = 0;
		
		#80_000_000
		
		press0 = 1;
		#(`clk_period  *3) 
		press0 = 0;
		
		#80_000_000
		
		press0 = 1;
		#(`clk_period *3) 
		press0 = 0;
		
		#80_000_000
		
		press1 = 1;
		#(`clk_period *3) 
		press1 = 0;
		
		#80_000_000
		
		press1 = 1;
		#(`clk_period *3) 
		press1 = 0;
		$stop;
	end
endmodule

key_model.v

`timescale 1ns/1ns

module key_model(press,key);
	
	input press;
	output reg key;
	
	reg [15:0] myrand;
	
	initial begin
		key = 1'b1;
//		press_key;
//		#10000;
//		press_key;
//		#10000;
//		press_key;
//		$stop;
	end
	
	always@(posedge press)
		press_key;
	
	task press_key;
		begin
			//按下抖动过程
			repeat(50)begin
				myrand = {$random}%65536;//0-65535;
				#myrand key = ~key;
			end
			key = 0;
			#25000000;
			
			//释放抖动过程
			repeat(50)begin
				myrand = {$random}%65536;//0-65535;
				#myrand key = ~key;
			end
			key = 1;
			#25000000;
		end
	endtask
endmodule

功能仿真

在这里插入图片描述

10.A数码管动态扫描设计与验证

8位7段数码管驱动实验

课程目标:FPGA驱动数码管显示实验
实验平台:Snow Dream starter board 核心板 + 数码管_VGA_PS2学生模块
在这里插入图片描述

实验现象:在Quartus II 中,使用In system sources andprobes editor工具,输入需要显示在数码管上的数据,则数码管显示对应数值。
知识点

  1. 数码管动态扫描实现
  2. In system sources and probes editor(ISSP)调试工具的使用。

在这里插入图片描述

  • 数码管显示数字原理
  • 数码管动态扫描原理
  • ISSP调试工具的简单使用
    在这里插入图片描述

在这里插入图片描述
a. 4输入查找表,8位输出
b. 分频模块,从系统时钟分频得到1KHz的扫描时钟
c. 8选1多路器,选择端为当前扫描的数码管位置
d. 8位循环移位寄存器,1000_0000 ->0000_0001
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

由于代码加长,之后的代码都不附上

恰好可以不看参考代码,自己从头写一下代码,这样才有长进

HEX8.v

设计代码

HEX8_tb.v

测试平台

HEX_top.v和ISSP.v

板级验证的文件

10.B串行移位寄存器原理与结构分析

在这里插入图片描述
在这里插入图片描述
串转并
锁存器在这里插入图片描述
在这里插入图片描述

10.C串行移位寄存器驱动数码管显示设计与实现

在这里插入图片描述

11.A串口发送模块与验证

  • 实验平台:芯航线FPGA学习套件核心板、PC机

  • 实验现象:在 Quartus II中,使用 In system sources and probes editor工具,输入需要通过串口发送出去的数据,然后按下学习板上的按键O,则FPGA自动将所需要发送的数据发送出去

  • 知识点:

  • 1.UART通信协议实现

  • 2.In system sources and probes editor(ISSP)调试工具的使用

在这里插入图片描述
在这里插入图片描述

11.B例解使用串口发送多个字节的数据方案

通过串口发送模块发送“HELLO”字符串。

  • 6
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
01 试看小梅哥fpga设计思想与验证方法视频:http://bbs.elecfans.com/jishu_484523_1_1.html 02 芯航线FPGA开发平台设计初衷:http://bbs.elecfans.com/jishu_514523_1_1.html 03 芯航线FPGA学习平台介绍:http://bbs.elecfans.com/jishu_514526_1_1.html 04 芯航线FPGA学习平台焊接记录:http://bbs.elecfans.com/jishu_514914_1_1.html 05 芯航线FPGA学习平台系统调试:http://bbs.elecfans.com/jishu_515169_1_1.html 06【连载视频教程(一)】科学的开发流程:http://bbs.elecfans.com/jishu_515340_1_1.html 07【连载视频教程(二)】3-8译码器设计验证:http://bbs.elecfans.com/jishu_515468_1_1.html 08【连载视频教程(三)】二进制计数器设计验证:http://bbs.elecfans.com/jishu_515476_1_1.html 09【连载视频教程(四)】高性能计数器IP核使用:http://bbs.elecfans.com/jishu_515714_1_1.html 10【连载视频教程(五)】BCD码计数器设计验证:http://bbs.elecfans.com/jishu_515893_1_1.html 11【连载视频教程(六)】例解阻塞赋值与非阻塞赋值:http://bbs.elecfans.com/jishu_516094_1_1.html 12【连载视频教程(七)】例说状态机:http://bbs.elecfans.com/jishu_516249_1_1.html 13【连载视频教程(八)】基于状态机的独立按键消抖:http://bbs.elecfans.com/jishu_516791_1_1.html 14【连载视频教程(九)】独立按键控制LED与亚稳态问题引入:http://bbs.elecfans.com/jishu_516795_1_1.html 15【连载视频教程(十)】数码管动态扫描设计与实现:http://bbs.elecfans.com/jishu_516979_1_1.html 16【连载视频教程(十一)】UART串口发送模块设计与验证:http://bbs.elecfans.com/jishu_516984_1_1.html 17【连载视频教程(十二)】UART串口接收模块设计与验证:http://bbs.elecfans.com/jishu_518308_1_1.html 18【芯航线FPGA学习平台众筹进度帖】芯航线FPGA开发板入手测试说明:http://bbs.elecfans.com/jishu_518301_1_1.html 19【芯航线FPGA学习平台众筹进度帖】芯航线FPGA学习套件配置文件固化教程 http://bbs.elecfans.com/jishu_518816_1_1.html 20【芯航线FPGA学习平台众筹进度帖】芯航线FPGA学习套件众筹回报已发放完毕,特公布运单号 http://bbs.elecfans.com/jishu_518819_1_1.html 21【芯航线FPGA学习平台众筹进度帖】芯航线FPGA学习套件众筹总结暨抽奖结果 http://bbs.elecfans.com/jishu_520454_1_1.html 22【芯航线FPGA学习平台众筹进度帖】【有奖活动】芯航线FPGA学习平台有奖活动第一季——看教程,秀笔记,赢好礼 http://bbs.elecfans.com/jishu_520463_1_1.html 23【连载视频教程(十三)】嵌入式块RAM应用之双口RAM:http://bbs.elecfans.com/jishu_520914_1_1.html 24【连载视频教程(十四)】搭建串口收发与存取双口RAM简易应用系统: http://bbs.elecfans.com/jishu_520915_1_1.html 25【连载视频教程(十五)】ROM的搭建与Signaltap II 工具使用:http://bbs.elecfans.com/jishu_522774_1_1.html 26【连载视频教程(十六)】FIFO介绍与时序验证:http://bbs.elecfans.com/jishu_522778_1_1.html 27【连载视频教程(十七)】使用PLL进行设计+Verilog参数化设计介绍: http://bbs.elecfans.com/jishu_524442_1_1.html 28【芯航线FPGA学习平台众筹进度帖】芯航线FPGA学习套件下载器驱动安装说明 http://bbs.elecfans.com/jishu_524793_1_1.html 29【芯航线FPGA学习平台众筹进度帖】Verilog语法基础讲解之参数化设计: http://bbs.elecfans.com/jishu_528770_1_1.html 30【连载视频教程(十八)】基于线性序列机设计思想的串行DAC(TLC5620)驱动: http://bbs.elecfans.com/jishu_533944_1_1.html 31【连载视频教程(十九)】基于线性序列机设计思想的串行ADC驱动: http://bbs.elecfans.com/jishu_537056_1_1.html
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杰之行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值