Verilog & FPGA学习(一)

本文作者分享了购买并使用FPGA的经历,特别是Spieed的TangNano9K,重点讲述了如何生成波形时序文件,回顾了之前的学习过程,以及通过Verilog实现流水灯实验,并计划深入学习Verilog和FPGA以备战电赛。
摘要由CSDN通过智能技术生成

前言

        最近心血来潮买了一块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知识。

        智能车系列也准备开始更新了,一方面是我们已经开始准备今年暑假的智能车华北赛,也准备开个专栏来记录自己的智能车学习历程。

  • 43
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值