0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Verilog实现流水灯及与C语言的对比

FPGA之家 来源:FPGA之家 2023-05-14 14:11 次阅读

一、 软件平台与硬件平台

软件平台:

1、操作系统:Windows-8.1

2、开发套件:ISE14.7

3、仿真工具:ModelSim-10.4-SE

硬件平台:

1、FPGA型号:XC6SLX45-2CSG324

二、 原理介绍

我的开发板上有4个LED灯,原理图如下:

c466b6e8-f0aa-11ed-90ce-dac502259ad0.png

由原理图可知仅当FPGA的对应管脚输入低电平时LED才会亮,流水灯的效果可以轮流让四个对应管脚输出低电平来产生。

三、 目标任务

编写四个LED流水的Verilog代码并用ModelSim进行仿真,仿真通过以后下载到开发板进行测试,要求开发板上每个LED亮的时间为1s。

四、 设计思路与Verilog代码编写

由于每个LED亮的时间为1s,所以首先很自然想到产生一个1s的时钟用来驱动后续逻辑,有了这个1s的时钟以后,就可以在这个1s时钟的节拍下对LED的输出进行以移位操作来产生流水灯的效果。

1、1s时钟的分频逻辑

由于主时钟是50MHz,周期为20ns,所以可以利用50MHz主时钟驱动一个计数器,当计数器的值每次到达24999999时,消耗的时间为25000000*20ns=0.5s,这时把分频器的输出反转,并把计数值清0,这样分频器的输出就会每隔0.5s翻转一次,产生了一个1s的时钟。

Verilog代码如下:

//////////////////////////////////////////////////////////////////
// 功能:产生1s的时钟
//////////////////////////////////////////////////////////////////
always @(posedge I_clk or negedge I_rst_n)
begin
    if(!I_rst_n)
        begin
            R_cnt_ls        <= 32'd0 ;
            R_clk_ls_reg    <= 1'b1  ;
        end 
    else if(R_cnt_ls == 32'd24_999_999)
        begin
            R_cnt_ls        <= 32'd0          ;
            R_clk_ls_reg    <= ~R_clk_ls_reg  ;
        end
    else
        R_cnt_ls <= R_cnt_ls + 1'b1 ;
end

assign W_clk_ls = R_clk_ls_reg ;

2、移位逻辑

有了1s的时钟信号以后,就在这个1s时钟信号的驱动下对输出的LED寄存器进行移位操作产生流水效果。

Verilog代码如下:

//////////////////////////////////////////////////////////////////
// 功能:对输出寄存器进行移位产生流水效果
//////////////////////////////////////////////////////////////////
always @(posedge W_clk_ls or negedge I_rst_n)
begin
    if(!I_rst_n)
        R_led_out_reg <= 4'b0001 ;
    else if(R_led_out_reg == 4'b1000)
        R_led_out_reg <= 4'b0001 ;
    else    
        R_led_out_reg <= R_led_out_reg << 1 ;
end

assign O_led_out = ~R_led_out_reg ;

五、 ModelSim仿真

写好逻辑以后,为了确定时序是正确的,最好写一个测试文件对功能进行仿真,为了加快仿真速度,修改分频逻辑计数器的计数值为24,然后编写测试文件,测试文件中激励产生的Verilog代码如下:

initial begin
    // Initialize Inputs
    I_clk = 0;
    I_rst_n = 0;

    // Wait 100 ns for global reset to finish
    #100;
    I_rst_n = 1;
    
    // Add stimulus here

end

always #10 I_clk = ~I_clk ;

仿真的时序图如下图所示:

c4e260fe-f0aa-11ed-90ce-dac502259ad0.jpg

可以看到时序完全正确,接下来就是绑定管脚,生成bit文件下载到开发板测试了。

六、 进一步思考——C语言流水灯与Verilog流水灯区别

看完网上《Verilog那些事》系列博文以后,作者提出了一种“仿顺序操作”方法,其实以前自己写代码的时候无形之中一直在用这种思想,但是一直没有提炼出来,看完作者的介绍以后才发现确实是有那个“仿顺序”的味道。详细的博文请参考博客园博主akuei2的系列博文。这里我在总结一遍,给以后留个印象。

C语言实现流水灯的大致代码框架如下:

while(1)

{

1、让第1个LED亮,其他的灭;

2、延时1s

3、让第2个LED亮,其他的灭

4、延时1s

5、让第3个LED亮,其他的灭;

6、延时1s

7、让第4个LED亮,其他的灭

8、延时1s

}

在while(1)里面代码是一行一行的执行,最后一行执行完毕以后在回到第一行重新开始新一轮的执行。就这样产生了流水的效果。

看到这里,有人应该突然明白了吧,这不正好就是Verilog中的一个状态机么。对应的Verilog代码也可以写出来了

always @(posedge I_clk)

begin

case(R_state)

第1个状态:让第1个LED亮,其他的灭,下一状态是第2个状态;

第2个状态:延时1s,下一状态是第3个状态;

第3个状态:让第2个LED亮,其他的灭,下一状态是第4个状态;

第4个状态:延时1s,下一状态是第5个状态;

第5个状态:让第3个LED亮,其他的灭,下一状态是第6个状态;

第6个状态:延时1s,下一状态是第7个状态;

第7个状态:让第4个LED亮,其他的灭,下一状态是第8个状态;

第8个状态:延时1s,下一状态是第1个状态;

default :;

endcase

end

具体的代码如下:

//////////////////////////////////////////////////////////////////
// 功能:“仿顺序操作”
//////////////////////////////////////////////////////////////////
always @(posedge I_clk or negedge I_rst_n)
begin
    if(!I_rst_n)
        begin
            R_state  <= 3'b000 ;
            R_cnt_ls <= 32'd0  ;
        end
    else
        begin    
            case(R_state)
                C_S0:
                    begin
                        R_led_out_reg <= 4'b0001 ;
                        R_state       <= C_S1    ;
                    end
                C_S1:
                    begin
                        if(R_cnt_ls == C_CNT_1S)
                            begin
                                R_cnt_ls <= 32'd0 ;
                                R_state  <= C_S2  ;
                            end
                        else
                            R_cnt_ls <= R_cnt_ls + 1'b1 ;
                    end
                C_S2:
                    begin
                        R_led_out_reg <= 4'b0010 ;
                        R_state       <= C_S3    ;
                    end
                C_S3:
                    begin
                        if(R_cnt_ls == C_CNT_1S)
                            begin
                                R_cnt_ls <= 32'd0 ;
                                R_state  <= C_S4  ;
                            end
                        else
                            R_cnt_ls <= R_cnt_ls + 1'b1 ;
                    end
                C_S4:
                    begin
                        R_led_out_reg <= 4'b0100 ;
                        R_state       <= C_S5    ;
                    end
                C_S5:
                    begin
                        if(R_cnt_ls == C_CNT_1S)
                            begin
                                R_cnt_ls <= 32'd0 ;
                                R_state  <= C_S6  ;
                            end
                        else
                            R_cnt_ls <= R_cnt_ls + 1'b1 ;
                    end
                C_S6:
                    begin
                        R_led_out_reg <= 4'b1000 ;
                        R_state <= C_S7 ;
                    end
                C_S7:
                    begin
                        if(R_cnt_ls == C_CNT_1S)
                            begin
                                R_cnt_ls <= 32'd0 ;
                                R_state  <= C_S0  ;
                            end
                        else
                            R_cnt_ls <= R_cnt_ls + 1'b1 ;
                    end 
                default: R_state <= 3'b000 ;
            endcase 
        end                  
end

assign O_led_out = ~R_led_out_reg ;

时序图如下图:

c5178982-f0aa-11ed-90ce-dac502259ad0.jpg

时序图仍然正确,实现了流水灯的效果

七、 总结

1、所谓的“仿顺序操作”实际上就是一个状态机,通过状态的跳变实现“顺序执行”的效果。这种思想在后面写接口时序的时候还是挺管用的,今后可以多多琢磨琢磨。

2、 C语言的while(1)和Verilog语言的always @(posedge I_clk)有类似的地方,只要CPU的时钟存在,它们就一直执行下去。书上都说C语言是一种串行语言,Verilog是一种并行语言,实际上这里也能有体会:C语言里只能有1个while(1)语句,进入while(1)以后CPU就出不来了,而Verilog中可以有多个always @(posedge I_clk)语句,并且每个always @(posedge I_clk)同时运行的,这就是两种语言最大的区别吧。

八、 附录

1、分频1s产生流水灯的完整代码

module led_work_top
(
    input           I_clk       ,
    input           I_rst_n     ,
    output  [3:0]   O_led_out
);

reg  [31:0]  R_cnt_ls      ;
wire         W_clk_ls      ;
reg          R_clk_ls_reg  ;
reg  [3:0]   R_led_out_reg ;

//////////////////////////////////////////////////////////////////
// 功能:产生1s的时钟
//////////////////////////////////////////////////////////////////
always @(posedge I_clk or negedge I_rst_n)
begin
    if(!I_rst_n)
        begin
            R_cnt_ls        <= 32'd0 ;
            R_clk_ls_reg    <= 1'b1  ;
        end 
    else if(R_cnt_ls == 32'd24_999_999)
        begin
            R_cnt_ls        <= 32'd0          ;
            R_clk_ls_reg    <= ~R_clk_ls_reg  ;
        end
    else
        R_cnt_ls <= R_cnt_ls + 1'b1 ;
end

assign W_clk_ls = R_clk_ls_reg ;

//////////////////////////////////////////////////////////////////
// 功能:对输出寄存器进行移位产生流水效果
//////////////////////////////////////////////////////////////////
always @(posedge W_clk_ls or negedge I_rst_n)
begin
    if(!I_rst_n)
        R_led_out_reg <= 4'b0001 ;
    else if(R_led_out_reg == 4'b1000)
        R_led_out_reg <= 4'b0001 ;
    else    
        R_led_out_reg <= R_led_out_reg << 1 ;
end

assign O_led_out = ~R_led_out_reg ;

endmodule

2、 “仿顺序操作”产生流水灯完整代码

module led_work_top
(
    input           I_clk         ,
    input           I_rst_n       ,
    output  [3:0]   O_led_out
);
                                  
reg  [31:0]  R_cnt_ls             ;
reg  [3:0]   R_led_out_reg        ;
reg  [2:0]   R_state              ;

parameter    C_CNT_1S =   32'd49_999_999  ;

parameter    C_S0     =   3'b000  ,
             C_S1     =   3'b001  ,
             C_S2     =   3'b010  ,
             C_S3     =   3'b011  ,
             C_S4     =   3'b100  ,
             C_S5     =   3'b101  ,
             C_S6     =   3'b110  ,
             C_S7     =   3'b111  ;

//////////////////////////////////////////////////////////////////
// 功能:仿顺序操作
//////////////////////////////////////////////////////////////////
always @(posedge I_clk or negedge I_rst_n)
begin
    if(!I_rst_n)
        begin
            R_state  <= 3'b000 ;
            R_cnt_ls <= 32'd0  ;
        end
    else
        begin    
            case(R_state)
                C_S0:
                    begin
                        R_led_out_reg <= 4'b0001 ;
                        R_state       <= C_S1    ;
                    end
                C_S1:
                    begin
                        if(R_cnt_ls == C_CNT_1S)
                            begin
                                R_cnt_ls <= 32'd0 ;
                                R_state  <= C_S2  ;
                            end
                        else
                            R_cnt_ls <= R_cnt_ls + 1'b1 ;
                    end
                C_S2:
                    begin
                        R_led_out_reg <= 4'b0010 ;
                        R_state       <= C_S3    ;
                    end
                C_S3:
                    begin
                        if(R_cnt_ls == C_CNT_1S)
                            begin
                                R_cnt_ls <= 32'd0 ;
                                R_state  <= C_S4  ;
                            end
                        else
                            R_cnt_ls <= R_cnt_ls + 1'b1 ;
                    end
                C_S4:
                    begin
                        R_led_out_reg <= 4'b0100 ;
                        R_state       <= C_S5    ;
                    end
                C_S5:
                    begin
                        if(R_cnt_ls == C_CNT_1S)
                            begin
                                R_cnt_ls <= 32'd0 ;
                                R_state  <= C_S6  ;
                            end
                        else
                            R_cnt_ls <= R_cnt_ls + 1'b1 ;
                    end
                C_S6:
                    begin
                        R_led_out_reg <= 4'b1000 ;
                        R_state <= C_S7 ;
                    end
                C_S7:
                    begin
                        if(R_cnt_ls == C_CNT_1S)
                            begin
                                R_cnt_ls <= 32'd0 ;
                                R_state  <= C_S0  ;
                            end
                        else
                            R_cnt_ls <= R_cnt_ls + 1'b1 ;
                    end 
                default: R_state <= 3'b000 ;
            endcase 
        end                  
end

assign O_led_out = ~R_led_out_reg ;

endmodule

3、测试记录文件完整代码

module tb_led_work_top;

    // Inputs
    reg I_clk;
    reg I_rst_n;

    // Outputs
    wire [3:0] O_led_out;

    // Instantiate the Unit Under Test (UUT)
    led_work_top U_led_work_top (
        .I_clk(I_clk),
        .I_rst_n(I_rst_n),
        .O_led_out(O_led_out)
    );

    initial begin
        // Initialize Inputs
        I_clk = 0;
        I_rst_n = 0;

        // Wait 100 ns for global reset to finish
        #100;
        I_rst_n = 1;
        
        // Add stimulus here

    end
    
    always #5 I_clk = ~I_clk ;
      
endmodule

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FPGA
    +关注

    关注

    1625

    文章

    21648

    浏览量

    601470
  • led
    led
    +关注

    关注

    240

    文章

    23100

    浏览量

    657824
  • Verilog
    +关注

    关注

    28

    文章

    1343

    浏览量

    109949
  • C语言
    +关注

    关注

    180

    文章

    7597

    浏览量

    136023
  • 流水灯
    +关注

    关注

    21

    文章

    432

    浏览量

    59624

原文标题:【接口时序】2、Verilog实现流水灯及与C语言的对比

文章出处:【微信号:zhuyandz,微信公众号:FPGA之家】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    基于Verilog FPGA 流水灯设计_流水灯源码_明德扬资料

    LED流水广告灯工程说明在本案例中,使用常用的verilog语言完成该程序,设计并控制8个灯的花式或循环点亮;即上电后,实现左移和右移交替的流水灯
    发表于 08-02 17:56

    如何使用c语言实现LED流水灯

    单片机实验:使用c语言实现LED流水灯目的:实现一个简单的流水灯程序仿真软件:Portues编程软件:KeilPortues 原理图绘制:需
    发表于 11-30 07:52

    LED流水灯程序【C语言版】

    LED流水灯程序【C语言版】LED流水灯程序【C语言版】LED
    发表于 12-29 11:05 0次下载

    LED流水灯程序【C语言+汇编版】

    LED流水灯程序【C语言+汇编版】,感兴趣的朋友可以学习。
    发表于 12-31 10:36 0次下载

    关于C语言流水灯验证的介绍

    使用C语言编写流水灯程序。
    的头像 发表于 07-10 06:01 3212次阅读
    关于<b class='flag-5'>C</b><b class='flag-5'>语言</b>的<b class='flag-5'>流水灯</b>验证的介绍

    C语言的基础知识及流水灯实现程序免费下载

    本文档的主要内容详细介绍的是C语言的基础知识及流水灯实现程序免费下载。
    发表于 04-15 18:24 2次下载
    <b class='flag-5'>C</b><b class='flag-5'>语言</b>的基础知识及<b class='flag-5'>流水灯</b>的<b class='flag-5'>实现</b>程序免费下载

    使用单片机实现流水灯C语言程序免费下载

    本文档的主要内容详细介绍的是使用单片机实现流水灯C语言程序免费下载。
    发表于 08-15 17:32 1次下载
    使用单片机<b class='flag-5'>实现</b><b class='flag-5'>流水灯</b>的<b class='flag-5'>C</b><b class='flag-5'>语言</b>程序免费下载

    使用51单片机实现流水灯C语言的程序实例免费下载

    本文档的主要内容详细介绍的是使用51单片机实现流水灯C语言的程序实例免费下载。
    发表于 07-19 17:38 9次下载
    使用51单片机<b class='flag-5'>实现</b><b class='flag-5'>流水灯</b><b class='flag-5'>C</b><b class='flag-5'>语言</b>的程序实例免费下载

    使用51单片机实现流水灯C语言程序免费下载

    本文档的主要内容详细介绍的是使用51单片机实现流水灯C语言程序免费下载。
    发表于 05-27 08:00 2次下载
    使用51单片机<b class='flag-5'>实现</b><b class='flag-5'>流水灯</b>的<b class='flag-5'>C</b><b class='flag-5'>语言</b>程序免费下载

    LED流水灯Verilog设计实例资料合集免费下载

    本文档的主要内容详细介绍的是LED流水灯Verilog设计实例资料合集免费下载。
    发表于 04-16 18:02 20次下载
    LED<b class='flag-5'>流水灯</b>的<b class='flag-5'>Verilog</b>设计实例资料合集免费下载

    使用verilog HDL实现状态机8位流水灯的程序和工程文件免费下载

    本文档的主要内容详细介绍的是使用verilog HDL实现状态机8位流水灯的程序和工程文件免费下载。
    发表于 10-16 16:20 23次下载
    使用<b class='flag-5'>verilog</b> HDL<b class='flag-5'>实现</b>状态机8位<b class='flag-5'>流水灯</b>的程序和工程文件免费下载

    使用单片机实现24C02存储花样流水灯C语言实例免费下载

    本文档的主要内容详细介绍的是使用单片机实现24C02存储花样流水灯C语言实例免费下载。
    发表于 03-24 13:52 20次下载

    基于AT89C51的单片机简易流水灯设计(C语言

    基于AT89C51的单片机简易流水灯设计(C语言)文章目录一、功能介绍二、代码展示三、仿真四、总结(一)思考题(二)注意的问题文章目录一、功能介绍此程序是基于
    发表于 11-05 11:06 19次下载
    基于AT89<b class='flag-5'>C</b>51的单片机简易<b class='flag-5'>流水灯</b>设计(<b class='flag-5'>C</b><b class='flag-5'>语言</b>)

    单片机实验:使用c语言实现LED流水灯

    单片机实验:使用c语言实现LED流水灯目的:实现一个简单的流水灯程序仿真软件:Portues编程软件:KeilPortues 原理图绘制:需
    发表于 11-21 10:51 11次下载
    单片机实验:使用<b class='flag-5'>c</b><b class='flag-5'>语言实现</b>LED<b class='flag-5'>流水灯</b>

    C语言查询按键控制8个流水灯

    C语言查询按键控制8个流水灯一.仿真电路图注意发光二极管的方向以及接的电阻的大小。二.C语言代码
    发表于 11-21 16:51 14次下载
    <b class='flag-5'>C</b><b class='flag-5'>语言</b>查询按键控制8个<b class='flag-5'>流水灯</b>