枯藤老树昏鸦,小桥流水人家。 — — — —《天净沙.秋思》马致远
文章目录
- 前言
- 一、实验内容
- 二、实验平台
- 三、设计思路与方案
- 四、RTL代码设计
- 五、仿真测试程序设计
- 六、电路与仿真结果
- 七、管脚规划
- 八、板子上电演示
- 总结
前言
大四毕业后白嫖了电子创新实验室的一块FPGA,这块板子适合做数电实验,为了物尽其用,趁这个暑假搭配特权同学做的《深入浅出玩转FPGA》视频学习入门一下,用它整点活。
一、实验内容
让板载的8颗LED灯每隔1秒依次点亮,全亮后又每隔1秒依次熄灭,循环。
二、实验平台
RTL代码编写平台:Vivado 2019.1
FPGA开发板:Xilinx BASYS3
芯片型号:Artix家族 xc7a35tcpg236-1
三、设计思路与方案
1.总体构想
如下图所示,我的构想由计时模块和类38线译码器模块组合而成,时钟和复位信号输入,8颗LED灯作为输出,计时模块处理LED灯亮灭的时序逻辑,产生1Hz方波进行计数,由于计数值为0~7共8位,所以联想到38译码器,这样可以通过3位二进制数作为地址输出给后级模块去控制8颗LED灯(模拟成8位二进制数),LED状态的刷新受到计时模块时钟的控制。
2.计时模块设计
查看BASYS3开发板的原理图可知,系统时钟由DSC1033CC1-100.0000T晶振产生,为100Mhz,如下图所示。
为了达到“每隔1秒亮一次”,需要利用系统时钟产生1Hz 的方波(周期为1s),通过对系统时钟上升沿的计数可以实现,由于(100MHz/100 000 000=1Hz),所以当从0计到99 999 999时就得到1Hz的频率,并且在一周期内对半周期前后的电平翻转就可以得到1Hz、占空比50%的延时时钟。
在产生了延时时钟后,需要再对这个时钟的下降沿进行计数,如下图所示,从0计数到7,每一个计数值对应了一个3位的地址,依次对应着8颗LED灯的一种亮灭状态;计数过了7后清零,并且翻转片选信号,片选信号为0时运行的是“8颗LED灯每隔1秒依次点亮”的过程,为1时运行的是“每隔1秒依次熄灭”的过程。
3.类3-8译码器的设计
模块的真值表如下图所示,地址和片选共同作用使8位LED值输出对应的电平信号,高电平点亮LED,低电平熄灭LED。
文章来源地址https://www.toymoban.com/news/detail-769199.html
四、RTL代码设计
1.计时模块leds程序
module leds(
input clk, //100Mhz系统时钟
input rst, //复位信号,高电平有效
output reg [2:0] ctrl_data, //控制数据,输出到后级译码器中
output led_clk, //1Hz时钟
output led_cs //片选信号,输出到后级译码器用于选择状态
);
reg[27:0] cnt; //计数值,用于产生1Hz信号
parameter cnt_max = 28'd99_999_999; //计数最大值
parameter cnt_half = 28'd49_999_999; //计数中值
reg led_clk_r; //1Hz方波时钟
reg led_cs_r; //片选信号
/****产生1Hz的方波****/
always @ (posedge clk or posedge rst)
begin
if(rst) cnt <= 28'd0;
else if(cnt < cnt_max) cnt <= cnt+1'b1;
else cnt <= 28'd0;
end
always @ (posedge clk or posedge rst)
begin
if(rst) led_clk_r <= 1'b0;
else if(cnt < cnt_half) led_clk_r <= 1'b0;
else led_clk_r <= 1'b1;
end
assign led_clk = led_clk_r;
/****在1Hz方波时钟信号下计数****/
always @ (negedge led_clk or posedge rst)
begin
if(rst)
begin
ctrl_data <= 3'd0;
led_cs_r <= 1'b0;
end
else if(ctrl_data < 3'd7) ctrl_data <= ctrl_data+1'b1;
else
begin
ctrl_data <= 3'd0;
led_cs_r <= ~led_cs_r;
end
end
assign led_cs = led_cs_r;
endmodule
2.译码模块code程序
module code(
input clk, //100Mhz系统时钟
input rst, //复位信号,高电平有效
output reg [7:0] leds_out //输出8个LED信号
);
wire [2:0] ctrl; //前级输入的控制地址
wire cs; //前级输入的片选信号
/****leds模块例化语句****/
leds myleds(
.clk(clk),
.rst(rst),
.ctrl_data(ctrl),
.led_cs(cs)
);
/****类3-8线译码器的设计****/
always @ (ctrl or cs or rst)
begin
if(rst) leds_out = 8'b0000_0000;
else
begin
if(!cs)
begin
case(ctrl)
3'b000: leds_out = 8'b0000_0001;
3'b001: leds_out = 8'b0000_0011;
3'b010: leds_out = 8'b0000_0111;
3'b011: leds_out = 8'b0000_1111;
3'b100: leds_out = 8'b0001_1111;
3'b101: leds_out = 8'b0011_1111;
3'b110: leds_out = 8'b0111_1111;
3'b111: leds_out = 8'b1111_1111;
endcase
end
else
begin
case(ctrl)
3'b000: leds_out = 8'b1111_1110;
3'b001: leds_out = 8'b1111_1100;
3'b010: leds_out = 8'b1111_1000;
3'b011: leds_out = 8'b1111_0000;
3'b100: leds_out = 8'b1110_0000;
3'b101: leds_out = 8'b1100_0000;
3'b110: leds_out = 8'b1000_0000;
3'b111: leds_out = 8'b0000_0000;
endcase
end
end
end
endmodule
五、仿真测试程序设计
注意,板子上的按钮为摁下接到高电平,松开接到低电平,原理图如下所示,这里我们用到的是5个中的1个,在后续小节会讲到如何分配管脚,所以在设计仿真测试程序时要让rst信号由低电平跳上高电平然后过一点点时间再拉低。
1.leds计时模块仿真测试程序
module leds_sim;
reg clk;
reg rst;
wire [2:0] ctrl_data;
wire led_clk;
wire led_cs;
leds text_leds(
.clk(clk),
.rst(rst),
.ctrl_data(ctrl_data),
.led_clk(led_clk),
.led_cs(led_cs)
);
initial begin
clk = 0;
rst = 0;
#1000 rst = 1;
#1000 rst = 0;
end
always #5 clk = ~clk; //输出100Mhz方波信号,每隔5ns翻转一次电平
endmodule
2.计时&译码仿真测试程序
module cod_sim;
reg clk;
reg rst;
wire [7:0] leds_out;
code text_code(
.clk(clk),
.rst(rst),
.leds_out(leds_out)
);
initial begin
clk = 0;
rst = 0;
#1000 rst = 1;
#1000 rst = 0;
end
always #5 clk = ~clk;
endmodule
六、电路与仿真结果
下图为leds计时模块的行为仿真结果。
下图为leds&code总模块的仿真结果。
下图为综合后总模块的RTL原理图。
七、管脚规划
由下图所示,100Mhz系统时钟输入到了W5引脚中,所以我们给clk引脚配置为W5。
rst复位引脚我们配置为T17,原理图如下图所示。
8颗LED灯管脚号如下图所示,从右往左位数依次升高。
总的管脚配置文件如下所示。
set_property PACKAGE_PIN T17 [get_ports rst]
set_property PACKAGE_PIN U16 [get_ports {leds_out[0]}]
set_property PACKAGE_PIN E19 [get_ports {leds_out[1]}]
set_property PACKAGE_PIN U19 [get_ports {leds_out[2]}]
set_property PACKAGE_PIN V19 [get_ports {leds_out[3]}]
set_property PACKAGE_PIN W18 [get_ports {leds_out[4]}]
set_property PACKAGE_PIN U15 [get_ports {leds_out[5]}]
set_property PACKAGE_PIN U14 [get_ports {leds_out[6]}]
set_property PACKAGE_PIN V14 [get_ports {leds_out[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds_out[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds_out[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds_out[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds_out[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds_out[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds_out[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds_out[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds_out[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports rst]
set_property PACKAGE_PIN W5 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
八、板子上电演示
仿真、综合、布局布线、分配管脚后,可以生成bit文件,通过USB线给开发板上电,vivado连上器件xc7a35tcpg236-1后将bit文件烧录至开发板。
实验运行视频如下所示。
QQ视频20230709170724
总结
文章来源:https://www.toymoban.com/news/detail-769199.html
到了这里,关于实验(二)基于BASYS3平台的FPGA流水灯实验的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!