前言
最近心血来潮买了一块fpga,来自spieed的Tang Nano 9K,基于高云半导体 GW1NR-9 FPGA芯片。
其实之前买过一块紫光的fpga,但是嫌环境配置太麻烦就搁置了,这次换了一家的fpga,环境配置很快,直接用高云的gowin编译器就能很快实现程序编写与下载。但是这两天研究了很久,还是没搞太懂波形时序文件怎么生成和观看...
先不说这个了,其实fpga我之前已经接触过一个学期了,之前学习数电的时候,有相关实验已经接触过fpga了,而且已经能实现数码管的操控之类的功能了。但是,我们的fpga程序编写其实就是“画图”,在quartus将数电各个模块,计数器,寄存器进行个画图连接再编译最后烧录到fpga里,所以说,我们用fpga其实只是单纯学习数电罢了。也没接触Verilog进行程序的编写。
数电实验fpga
关于为什么想学Verilog和fpga
关于想学Verilog以及fpga其实要追溯到半年前,也就是23年暑假,缘由还真就是电赛。今年电赛H题,是信号分离类型的题目,听说就是如果用fpga做,非常快就能将这道题完成。
于是我开始对fpga感兴趣,再加上对数电本身就有兴趣的(数电好像是我专业课最高分的科目了)(最开始接触数电是在MC的红石电路里),于是就开始学习了。
流水灯点亮实验
Tang Nano 9K给了一个流水灯的例程,于是我对例程开始探索并且进行一些小改动。以下是流水灯点亮实验的Verilog代码。
module led (
input sys_clk, // clk input
input sys_rst_n, // reset input
output reg [5:0] led // 6 LEDS pin
);
reg [23:0] counter;
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
counter <= 24'd0;
else if (counter < 24'd1349_9999) // 0.5s delay
counter <= counter + 1'b1;
else
counter <= 24'd0;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
led <= 6'b111110;
else if (counter == 24'd1349_9999) // 0.5s delay
led[5:0] <= {led[4:0],led[5]};
else
led <= led;
end
endmodule
接下来我就依照我的理解对此代码进行解析。
首先便是module和endmodule,在这里面包含着一个程序模块。module内括号的内容便是我们的输入和输出定义,不止有input和output类型,还有wire类型等,这些比较常用。我们定义了输入时钟sys_clk、输入复位信号sys_rst_n以及我们六个led的输出,这里我们用寄存器类型变量reg做一个六位数组,表示六个led输出。
出了括号,便是一个寄存器变量counter,我们用24位的长度进行存储这个数。
接下里便是两个always语句,表示一直循环执行,这个和C语言里的while很像,即符合条件遍进入括号里执行。
第一个always里有sys_clk和sys_rst_n,其中posedge表示上升沿,negedge表示下降沿,则进入这个always的条件是sys_clk信号的上升沿或者sys_rst_n信号的下降沿,即时钟上升沿,由于我们的复位按键信号常态为高电平,按下的时候变为低电平,则采用下降沿来进入。进入后,便是ifelse的判断,这也和C语言很像,在第一个if里,如果按键低电平,即按键按下时候,计数器清零,这符合复位的思想。之后便是对计数器counter的操作了,如果counter小于24'1349_9999这个数,我们看到这个数很复杂,但是依照我的理解是这样组成的:位数 + ' + 进制 + 数的大小 + _ +数的最大值,那么我们这个就是24位的十进制数1349,它的最大值为9999。我们的晶振频率是27MHz的,即输入频率的sys_clk也是27MHz,那么依照这个计数器,我们有0.5ms的延迟。
第二个always里便是对led灯进行操作了,最开始的时候,我们给led这个数组赋值为111110,即点亮led0(低电平点亮),之后,如果我们计时器计时到了,便循环左移,点亮led1,否则led不变,这样我们就可以依次循环点亮,形成流水灯。
这就是我们整个流水灯点亮实验的Verilog程序,通过烧录程序,我们最后可以在fpga上形成流水灯。
我的流水灯实验改进
以下是我对流水灯的拓展改进。
module led (
input sys_clk, // clk input
input sys_rst_n, // reset input
input sys_key,
output reg [5:0] led // 6 LEDS pin
);
reg [23:0] counter;
reg flag = 1;
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
counter <= 24'd0;
else if (counter < 24'd0600_9999) // 0.5s delay
counter <= counter + 2'b01;
else
counter <= 24'd0;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
led <= 6'b011111;
else if (counter == 24'd0600_9999) // 0.5s delay
begin
if(flag)
led[5:0] <= {led[0],led[5:1]};
else if (!flag)
led[5:0] <= {led[4:0],led[5]};
end
else
led <= led;
end
always @(posedge sys_key) begin
if (!sys_key)
flag = ~flag;
end
endmodule
我增加了一个输入按键以及调整了一下计数器的延时时间。其中通过按另外一个按键,可以实现流水灯的方向改变,这里我们采用一个reg寄存器变量flag作为标志位,在按下切换按键的时候,flag取反,进入另一个方向的流水灯。
总结
虽然不是第一次接触fpga,但是第一次接触Verilog,作为硬件描述语言,我们也应该用硬件的思想去理解。
我的打算是继续学习fpga和Verilog,并在打算今年电赛校赛上进行学习和使用。
之前写完2023电赛C题后还说不搞电赛了,但是现在还是想靠电赛也巩固一下fpga知识。文章来源:https://www.toymoban.com/news/detail-798522.html
智能车系列也准备开始更新了,一方面是我们已经开始准备今年暑假的智能车华北赛,也准备开个专栏来记录自己的智能车学习历程。文章来源地址https://www.toymoban.com/news/detail-798522.html
到了这里,关于Verilog & FPGA学习(一)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!