2024.02.28
FPGA开发流程
- 设计定义
- 设计输入(编写逻辑)
- 分析综合(Vivado、quartus)
- 功能仿真(Modelsim)
- 布局布线(Vivado、quartus)
- 分析性能(时序仿真Modelsim、静态时序分析Vivado、quartus)
- 板级调试
- OK
Vivado开发流程
- 启动Vivado
- 创建工程
- 添加源文件
MUX2
设计
module mux2(
a,
b,
sel,
out
);
input a;
input b;
input sel;
output out;
assign out = (sel==1)?a:b;
endmodule
测试
`timescale 1ns / 1ps
module mux2_tb();
reg s_a;
reg s_b;
reg sel;
wire out;
//例化
mux2 mux2_inst0(
.a(s_a),
.b(s_b),
.sel(sel),
.out(out)
);
initial begin
s_a=0;s_b=0;sel=0;
#200;
s_a=0;s_b=0;sel=1;
#200;
s_a=0;s_b=1;sel=0;
#200;
s_a=0;s_b=1;sel=1;
#200;
s_a=1;s_b=0;sel=0;
#200;
s_a=1;s_b=0;sel=1;
#200;
s_a=1;s_b=1;sel=0;
#200;
s_a=1;s_b=1;sel=1;
#200;
end
endmodule
仿真
时序仿真
3-8译码器
设计
module decoder_3_8(
a,
b,
c,
out
);
input a;
input b;
input c;
output [7:0] out;
reg [7:0]out;
//以always块描述的信号赋值,被赋值对象必须定义为reg类型
always@(*)begin
case({a,b,c})
3'b000: out= 8'b0000_0000;
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'b101: out= 8'b0010_0000;
3'b110: out= 8'b0100_0000;
3'b111: out= 8'b1000_0000;
endcase
end
//{a,b,c}变成了一个三位的信号,这种操作叫做位拼接
// always@(*)begin
case({a,b,c})
3'd0: out= 8'b0000_0000;
3'd1: out= 8'b0000_0010;
3'd2: out= 8'b0000_0100;
3'd3: out= 8'b0000_1000;
3'd4: out= 8'b0001_0000;
3'd5: out= 8'b0010_0000;
3'd6: out= 8'b0100_0000;
3'd7: out= 8'b1000_0000;
endcase
end //
endmodule
测试
`timescale 1ns / 1ps
module decoder_3_8_tb();
reg s_a;
reg s_b;
reg s_c;
wire [7:0]out;
decoder_3_8 decoder_3_8_inst0(
.a(s_a),
.b(s_b),
.c(s_c),
.out(out)
);
initial begin
s_a=0;s_b=0;s_c=0;
#200;
s_a=0;s_b=0;s_c=1;
#200;
s_a=0;s_b=1;s_c=0;
#200;
s_a=0;s_b=1;s_c=1;
#200;
s_a=1;s_b=0;s_c=0;
#200;
s_a=1;s_b=0;s_c=1;
#200;
s_a=1;s_b=1;s_c=0;
#200;
s_a=1;s_b=1;s_c=1;
#200;
end
endmodule
仿真
2024.03.01
LED灯以1s的频率闪烁
如果时钟频率是100MHz,0.5s对应的计数器值是50,000,000
设计
module led_flash(
Clk,
Reset_n,
Led
);
input Clk;
input Reset_n;
output reg Led;
reg [25:0]counter;
//<=是非阻塞赋值的意思
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
counter <= 0;
else if(counter == 24999999)
counter <= 0;
else
counter <= counter + 1'd1;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Led <= 0;
else if(counter == 24999999)
Led <= !Led;
endmodule
测试
`timescale 1ns / 1ps
module led_flash_tb();
reg Clk;
reg Reset_n;
wire Led;
led_flash led_flash_inst0(
.Clk(Clk),
.Reset_n(Reset_n),
.Led(Led)
);
initial Clk = 1;
always #10 Clk = !Clk;
initial begin
Reset_n = 0;
#201;
Reset_n = 1;
#2000000000;
$stop;
end
endmodule
仿真
让8个LED灯以每个500μs灯速率循环闪烁(跑马灯)
0.0005s = 0.5ms = 500μs
输入设计
module led_run(
Clk,
Reset_n,
Led
);
input Clk;
input Reset_n;
output reg[7:0] Led;
reg [24:0]counter;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
counter <= 0;
else if(counter == 25'd24999)
counter <= 0;
else
counter <= counter + 1'b1;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Led <= 8'b0000_0001;
else if(counter == 25'd24999)begin
if(Led == 8'b1000_0000)
Led <= 8'b0000_0001;
else
Led <= Led << 1;
end
endmodule
测试
`timescale 1ns / 1ps
module led_run_tb;
reg Clk;
reg Reset_n;
wire [7:0]Led;
led_run led_run_inst0(
.Clk(Clk),
.Reset_n(Reset_n),
.Led(Led)
);
initial Clk = 1;
always #10 Clk = ~Clk;
initial begin
Reset_n = 0;
#201;
Reset_n = 1;
#40000000;
$stop;
end
endmodule
仿真
让 LED 灯按照亮 500μs,灭 500μs的状态循环亮灭
设计
module counter_led_0(
Clk,
Reset_n,
Led
);
input Clk;
input Reset_n;
output reg[7:0] Led;
reg [25:0]counter;
parameter MCNT = 50000000;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
counter <= 0;
else if(counter == 49999999)
counter <= 0;
else
counter <= counter + 1'b1;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Led <= 0;
else if(counter == 24999999)
Led <= 1;
else if(counter == 49999999)
Led <= 0;
endmodule
测试
`timescale 1ns / 1ps
module counter_led_0_tb;
reg Clk;
reg Reset_n;
wire Led;
counter_led_0
#(
.MCNT(50000)
)
counter_led_0_inst0(
.Clk(Clk),
.Reset_n(Reset_n),
.Led(Led)
);
initial Clk = 1;
always #10 Clk = !Clk;
initial begin
Reset_n = 0;
#201;
Reset_n = 1;
#2000000000;
$stop;
end
endmodule
让 LED 灯按照亮 0.25 秒,灭 0.75 秒的状态循环亮灭
设计
module counter_led_0(
Clk,
Reset_n,
Led
);
input Clk;
input Reset_n;
output reg[7:0] Led;
reg [25:0]counter;
parameter MCNT = 50000;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
counter <= 0;
else if(counter == MCNT - 1)
counter <= 0;
else
counter <= counter + 1'b1;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Led <= 0;
else if(counter == MCNT/2 + MCNT/4 - 1)
Led <= 1;
else if(counter == MCNT - 1)
Led <= 0;
endmodule
测试
`timescale 1ns / 1ps
module counter_led_0_tb;
reg Clk;
reg Reset_n;
wire Led;
counter_led_0
#(
.MCNT(50000)
)
counter_led_0_inst0(
.Clk(Clk),
.Reset_n(Reset_n),
.Led(Led)
);
initial Clk = 1;
always #10 Clk = !Clk;
initial begin
Reset_n = 0;
#201;
Reset_n = 1;
#2000000000;
$stop;
end
endmodule
仿真
让 LED 灯按照亮 0.25 秒,灭0.5秒,亮0.75秒,灭1秒的状态循环亮灭
设计
module counter_led_1(
Clk,
Reset_n,
Led
);
input Clk;
input Reset_n;
output reg[7:0] Led;
reg [26:0]counter;
parameter MCNT = 125000000;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
counter <= 0;
else if(counter == MCNT - 1)
counter <= 0;
else
counter <= counter + 1'b1;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Led <= 1;
else if(counter == MCNT/10 - 1)
Led <= 0;
else if(counter == MCNT/10 + MCNT/5 - 1)
Led <= 1;
else if(counter == (MCNT/10 + MCNT/5)*2 - 1)
Led <= 0;
else if(counter == MCNT - 1)
Led <= 1;
endmodule
测试
`timescale 1ns / 1ns
module counter_led_1_tb;
reg Clk;
reg Reset_n;
wire Led;
counter_led_1
#(
.MCNT(50000)
)
counter_led_1_inst0(
.Clk(Clk),
.Reset_n(Reset_n),
.Led(Led)
);
initial Clk = 1;
always #10 Clk = !Clk;
initial begin
Reset_n = 0;
#201;
Reset_n = 1;
#2000000000;
$stop;
end
endmodule
仿真
让 LED 灯按照指定的亮灭模式亮灭,亮灭模式未知,由用户随机指定。以 0.25 秒为一个变化周期,8个变化状态为一个循环。
设计
module counter_led_2(
Clk,
Reset_n,
Ctrl,
Led
);
input Clk;
input Reset_n;
input [7:0]Ctrl;
output reg[7:0] Led;
reg [26:0]counter;
parameter MCNT = 100000000;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
counter <= 0;
else if(counter == MCNT -1)
counter <= 0;
else
counter <= counter + 1'b1;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Led <= 0;
else if(counter == MCNT/8 -1)
Led <= Ctrl[0];
else if(counter == MCNT*2/8 -1)
Led <= Ctrl[1];
else if(counter == MCNT*3/8 -1)
Led <= Ctrl[2];
else if(counter == MCNT*4/8 -1)
Led <= Ctrl[3];
else if(counter == MCNT*5/8 -1)
Led <= Ctrl[4];
else if(counter == MCNT*6/8 -1)
Led <= Ctrl[5];
else if(counter == MCNT*7/8 -1)
Led <= Ctrl[6];
else if(counter == MCNT*8/8 -1)
Led <= Ctrl[7];
endmodule
测试
`timescale 1ns / 1ns
module counter_led_2_tb;
reg Clk;
reg Reset_n;
reg [7:0]Ctrl;
wire Led;
counter_led_2
#(
.MCNT(100000)
)
counter_led_2_inst0(
.Clk(Clk),
.Reset_n(Reset_n),
.Ctrl(Ctrl),
.Led(Led)
);
initial Clk =1;
always #10 Clk = !Clk;
initial begin
Reset_n = 0;
Ctrl = 0;
#201;
Reset_n =1;
#2000;
Ctrl = 8'b1000_0110;
#2000000000;
$stop;
end
endmodule
仿真
2024.03.04
串口通信发送
通用异步收发传输器(UART)是一种异步收发传输器,其在数据发送时将并行数据转换成串行数据来传输,在数据接收时将接收到的串行数据转换成并行数据,可以实现全双工传输和接收。
最常见类型:数据位数、波特率大小、奇偶校验类型和停止位数。
最常见的配置是8N1。
按照一个完整的字节包括一位起始位、8 位数据位、一位停止位即总共十位数据来算,
要想完整的实现这十位数据的发送,就需要 11 个波特率时钟脉冲,第 1 个脉冲标记一次传
输的起始,第11 个脉冲标记一次传输的结束,如下所示: