FPGA练习(带笔记)
Posted 贩卖星辰点点
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FPGA练习(带笔记)相关的知识,希望对你有一定的参考价值。
目录
板子型号:明德扬点拨开发板,芯片型号EP4CE6E22C8N
1.点灯
module led(
output wire led0,
output wire led1,
output wire led2,
output wire led3,
);
assign led0=0;
assign led1=0;
assign led2=0;
assign led3=0;
endmodule
2.与或非
module test(
input port_a , //input只有wire,没有reg
input port_b ,
input port_c ,
output wire port_d , //默认wire,也有reg
output wire port_e ,
output wire port_f ,
output wire port_g ,
output wire port_h
);
//赋值语句 assign,always
//assign:对wire赋值;awlways:对reg赋值;
assign port_d = port_a & port_b; //与
assign port_e = port_a | port_c; //或
assign port_f = ~port_a; //反相器
assign port_g = port_b ^ port_c; //异或
assign port_h = port_a ^~ port_c; //同或
endmodule
2.1.TestBench例化模块
`timescale 1ns/1ps //时间单位/时间精度
module tb_test;
reg test_a;
reg test_b;
reg test_c;
wire relt_d;
wire relt_e;
wire relt_f;
wire relt_g;
wire relt_h;
//initial 赋值的信号,必须定义成reg,固有的规定
//initial用于赋值,/*--*/中的initial方法=begin和end
/*initial test_a = 1; //在0时刻赋初始值
initial test_b = 0;
initial test_c = 1;*/
initial begin //其中begin和end,相当一C语言中的{}
test_a = 1;
test_b = 0;
test_c = 1;
#5
test_a = 0;
test_b = 1;
test_c = 1;
#5
test_a = 0;
test_b = 0;
test_c = 0;
end
test test_inst(
.port_a (test_a ), //input只有wire,没有reg
.port_b (test_b ),
.port_c (test_c ),
.port_d (relt_d ), //默认wire,也有reg
.port_e (relt_e ),
.port_f (relt_f ),
.port_g (relt_g ),
.port_h (relt_h )
);
endmodule
2.2.modelsim波形
3.嵌套
module switch(
input sel_a ,
input sel_b ,
input data_a ,
input data_b ,
output reg data_c
);
//wire--->assign 赋值
//assign data_c = (sel == 0) ? data_a : data_b ;
//值=(条件)?结果1:结果2 C语言
//assign 目标信号=(判断表达式)?判断表达式为真时执行 : 判断表达式为假时执行 ;
//assign data_c = (sel_a == 0) ? ((sel_b == 0) ? data_a : 0) : ((sel_b == 1)? data_b : 0) ;
//assign:对wire赋值;awlways:对reg赋值;
//()---敏感信号列表,需要将always中用到的信号全部写进去
always @(sel_a or sel_b or data_a or data_b) begin //*---可以匹配到()内部的所有信号,可以直接替换
if(sel_a == 0)
if(sel_b == 0)
data_c = data_a;
else
data_c = 0;
else //可忽略if(sel_a == 1) //sel_a==1;
if(sel_b == 1)
data_c = data_b;
else
data_c = 0;
end
endmodule
3.1.TestBench例化模块
`timescale 1ns/1ns
module tb_switch;
reg sel_a;
reg sel_b;
reg data_a;
reg data_b;
wire data_c;
initial begin
sel_a = 0;
sel_b = 0;
data_a = 0;
data_b = 1;
#5
sel_a = 1;
sel_b = 0;
data_a = 0;
data_b = 1;
#5
sel_a = 0;
sel_b = 1;
data_a = 1;
data_b = 0;
#5
sel_a = 1;
sel_b = 1;
data_a = 1;
data_b = 0;
end
switch switch_inst(
.sel_a (sel_a ) ,
.sel_b (sel_b ) ,
.data_a (data_a ) ,
.data_b (data_b ) ,
.data_c (data_c )
);
endmodule
3.2.modelsim波形
4.三八译码器
module decode(
input [2:0] pi_data , //[]表示位宽,可以理解为有多少根线
/*input pi_A1 ,
input pi_A2 ,*/
output reg [7:0] po_data
);
always @(*) begin
case(pi_data)
0: po_data = 8'b0000_0001 ; //1;
1: po_data = 8'b0000_0010 ; //2;
2: po_data = 8'b0000_0100 ; //4;
3: po_data = 8'b0000_1000 ; //8;
4: po_data = 8'b0001_0000 ; //16;
5: po_data = 8'b0010_0000 ; //32;
6: po_data = 8'b0100_0000 ; //64;
7: po_data = 8'b1000_0000 ; //128;
default:po_data = 8'b0000_0001 ;
//8'b1000_0000 8-->表示位宽,b-->表示二进制,这里的下划线只是为了方便标识二进制,对代码本身并没有影响
// d-->十进制 ;h-->十六进制 ;o-->
//直接写数字,为十进制,位宽默认为32bit
endcase
/*if(pi_data == 0)
po_data = 1;
else if(pi_data == 1)
po_data = 2;
else if(pi_data == 1)
po_data = 2;
else if(pi_data == 1)
po_data = 2;
else if(pi_data == 1)
po_data = 2;*/
end
endmodule
4.1.TestBench例化模块
`timescale 1ns/1ns
module tb_decode;
reg [2:0] pi_data ;
wire [2:0] po_data ;
initial begin
pi_data = 0;
#5
pi_data = 1;
#5
pi_data = 2;
#5
pi_data = 3;
#5
pi_data = 4;
#5
pi_data = 5;
#5
pi_data = 6;
#5
pi_data = 7;
end
decode decode_inst(
.pi_data (pi_data),
.po_data (po_data)
);
endmodule
5.LED闪烁
module flash(
input sclk , //system clock
input s_rst_n , //system reset , active low
output reg [3:0] led
);
//50MHz
//T=100/5=20ns
reg [25:0] cnt ; //counter
//50_000_000-1=49_999_999
//0-49_999_999 0
//always用时钟沿进行工作,<=赋值
always @(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
cnt <= 'd0 ;
else if(cnt == 'd49_999_999)
cnt <= 'd0 ;
else
cnt <= cnt + 1'b1 ;
end
//0--1--0--1--0
always @(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
led <= 4'b0000 ;
else if(cnt == 'd49_999_999)
led <= ~led ;
end
endmodule
5.1.TestBench例化模块
`timescale 1ns/1ns
module tb_flash;
reg sclk ;
reg s_rst_n ;
wire [3:0] led;
initial begin
sclk = 1 ;
s_rst_n <= 0 ;
#100
s_rst_n <= 1 ;
end
always #5 sclk = ~sclk ; //高低电平转换
flash flash_inst(
.sclk (sclk ) ,
.s_rst_n (s_rst_n ) ,
.led (led )
);
endmodule
5.2.modelsim波形
6.阻塞,非阻塞;组合,时序
`timescale 1ns/1ns
module tb_ex;
reg a;
reg b;
reg c;
reg d;
reg e;
reg f;
initial begin //阻塞赋值:依次顺序执行
a = 0;
b = 1;
c = a+b;
end
initial begin //非阻塞赋值:每次信号的实现,都在执行时间的最后一刻,在这之前没有信号,而这里的最后一个信号f,在modelsim中因为时间和显示的问题,会导致信号f,显示未定义
//总结一下就是,非阻塞赋值有延迟
d <= 0;
e <= 1;
f <= d+e;
end
// = 多用于组合逻辑电路
// <= 多用于数据逻辑电路
//时序逻辑和组合逻辑之间的区分,是否使用时钟沿。
endmodule
6.1.modelsim波形
7.流水灯
module shift(
input sclk ,
input s_rst_n ,
input [3:0] led
);
localparam delay_1s = 'd49 ;
reg [25:0] cnt ;
always @(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
cnt <= 'd0 ;
else if(cnt == delay_1s)
cnt <= 'd0 ;
else
cnt <= cnt+1'b1 ;
end
always @(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
led <= 4'b1110 ;
else if(cnt == delay_1s) //1110 => 110,1 循环 位移操作
led <= {led[2:0],led[3]};
end
endmodule
7.1.TestBench例化模块
`timescale 1ns/1ns
module tb_shift;
reg sclk;
reg s_res_n;
wire [3:0] led;
initial begin
sclk = 1;
s_res_n <= 0;
#100
s_res_n <= 1;
end
always #5 sclk = ~sclk ;
shift shift_inst(
.sclk (sclk ),
.s_res_n (s_res_n ),
.led (led )
);
endmodule
8.呼吸灯
module breath(
input sclk ,
input s_rst_n ,
output reg [3:0] led
);
localparam delay_2us = 'd99 ;
localparam delay_2ms = 'd999 ;
localparam delay_2s = 'd999 ;
reg [7:0] cnt_2us ;
reg [9:0] cnt_2ms ;
reg [9:0] cnt_2s ;
always @(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
cnt_2us <= 'd0;
else if(cnt_2us == delay_2us)
cnt_2us <= 'd0;
else
cnt_2us <= cnt_2us+1'b1;
end
always @(posedge sclk or negedge s_rst_n)begin
if(s_rst_n == 1'b0)
cnt_2ms <= 'd0 ;
else if(/*cnt_2ms == delay_2ms && */ cnt_2us == delay_2us)
cnt_2ms <=cnt_2ms+1'b1;
else if(cnt_2ms == delay_2ms/*cnt_2us == delay_2us*/)
cnt_2ms <= 'd0;
end
always @(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
cnt_2s <= 'd0 ;
else if(/*cnt_2s == delay_2s && cnt_2us == delay_2us && */cnt_2ms == delay_2ms)
cnt_2s <= cnt_2s+1'b1;
else if(cnt_2s == delay_2s /*&& cnt_2us == delay_2us*/)
cnt_2s <= 'd0 ;
end
always @(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
led <= 4'b1111;
else if(cnt_2s >= cnt_2ms)
led <= 4'b0000;
else
led <= 4'b1111;
end
endmodule
8.1.TestBench例化模块
`timescale 1ns/1ns
module tb_breath;
reg sclk ;
reg s_rst_n ;
wire [3:0] led;
initial begin
sclk = 1 ;
s_rst_n = 0 ;
#100
s_rst_n <= 1 ;
end
always #5 sclk = ~sclk ;
breath breath_inst(
.sclk (sclk ),
.s_rst_n (s_rst_n ),
.led (led )
);
endmodule
8.2.modelsim波形
8.3.呼吸灯原理
FPGA中,控制输出只能输出 0 或 1 ,要想实现呼吸灯只能依靠PWM波控制电压输出实现,
上边代码中,假设给led一个2s的时间,先把这2s分为1000个2ms等份,在这个基础上再把2ms再分为1000个2us等份,(这里主要是为了在开发板上方便我们观察led的变化),呼吸灯的闪烁规律是,慢慢变亮。所以在一千个ms时间段中,我们让他一段一段的变亮,规律如下图,依照这样的规律我们就可以实现呼吸灯
然后开发板上的晶振是50Hz,对应输出时间为20ms,即100us,代码中用计时器实现这个规律就是2us从0–99,然后2ms+1,2ms从0–999,2s+1,led先不亮,然后设置一个if条件,实现led灯随时间的亮灭,综上所述,就用FPGA实现了呼吸灯效果
以上是关于FPGA练习(带笔记)的主要内容,如果未能解决你的问题,请参考以下文章