一、 软件平台与硬件平台

  软件平台:

  1、操作系统:Windows-8.1

  2、开发套件:ISE14.7

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

  硬件平台:

  1、FPGA型号:XC6SLX45-2CSG324

二、 原理介绍

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

  

  

  由原理图可知仅当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)
beginif(!I_rst_n)beginR_cnt_ls        <= 32'd0 ; R_clk_ls_reg    <= 1'b1  ;end else if(R_cnt_ls == 32'd24_999_999)beginR_cnt_ls        <= 32'd0          ;R_clk_ls_reg    <= ~R_clk_ls_reg  ;  endelseR_cnt_ls <= R_cnt_ls + 1'b1 ;
endassign W_clk_ls = R_clk_ls_reg ;

  2、移位逻辑

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

  Verilog代码如下:

//
// 功能:对输出寄存器进行移位产生流水效果
//
always @(posedge W_clk_ls or negedge I_rst_n)
beginif(!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 ;
endassign O_led_out = ~R_led_out_reg ;

五、 ModelSim仿真

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

initial begin// Initialize InputsI_clk = 0;I_rst_n = 0;// Wait 100 ns for global reset to finish#100;I_rst_n = 1;// Add stimulus hereendalways #10 I_clk = ~I_clk ;

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

可以看到时序完全正确,接下来就是绑定管脚,生成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)
beginif(!I_rst_n)beginR_state  <= 3'b000 ; R_cnt_ls <= 32'd0  ;endelsebegin    case(R_state)C_S0:beginR_led_out_reg <= 4'b0001 ;R_state       <= C_S1    ;  endC_S1:beginif(R_cnt_ls == C_CNT_1S)beginR_cnt_ls <= 32'd0 ;R_state  <= C_S2  ;endelseR_cnt_ls <= R_cnt_ls + 1'b1 ;                endC_S2:beginR_led_out_reg <= 4'b0010 ;R_state       <= C_S3    ;  endC_S3:beginif(R_cnt_ls == C_CNT_1S)beginR_cnt_ls <= 32'd0 ;R_state  <= C_S4  ;endelseR_cnt_ls <= R_cnt_ls + 1'b1 ;                endC_S4:beginR_led_out_reg <= 4'b0100 ;R_state       <= C_S5    ;  endC_S5:beginif(R_cnt_ls == C_CNT_1S)beginR_cnt_ls <= 32'd0 ;R_state  <= C_S6  ;endelseR_cnt_ls <= R_cnt_ls + 1'b1 ;                endC_S6:beginR_led_out_reg <= 4'b1000 ;R_state <= C_S7 ;  endC_S7:beginif(R_cnt_ls == C_CNT_1S)beginR_cnt_ls <= 32'd0 ;R_state  <= C_S0  ;endelseR_cnt_ls <= R_cnt_ls + 1'b1 ;                end default: R_state <= 3'b000 ;                                                                               endcase end
endassign O_led_out = ~R_led_out_reg ;

  时序图如下图:

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

七、 总结

  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)
beginif(!I_rst_n)beginR_cnt_ls        <= 32'd0 ; R_clk_ls_reg    <= 1'b1  ;end else if(R_cnt_ls == 32'd24_999_999)beginR_cnt_ls        <= 32'd0          ;R_clk_ls_reg    <= ~R_clk_ls_reg  ;  endelseR_cnt_ls <= R_cnt_ls + 1'b1 ;
endassign W_clk_ls = R_clk_ls_reg ;//
// 功能:对输出寄存器进行移位产生流水效果
//
always @(posedge W_clk_ls or negedge I_rst_n)
beginif(!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 ;
endassign 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)
beginif(!I_rst_n)beginR_state  <= 3'b000 ; R_cnt_ls <= 32'd0  ;endelsebegin    case(R_state)C_S0:beginR_led_out_reg <= 4'b0001 ;R_state       <= C_S1    ;  endC_S1:beginif(R_cnt_ls == C_CNT_1S)beginR_cnt_ls <= 32'd0 ;R_state  <= C_S2  ;endelseR_cnt_ls <= R_cnt_ls + 1'b1 ;                endC_S2:beginR_led_out_reg <= 4'b0010 ;R_state       <= C_S3    ;  endC_S3:beginif(R_cnt_ls == C_CNT_1S)beginR_cnt_ls <= 32'd0 ;R_state  <= C_S4  ;endelseR_cnt_ls <= R_cnt_ls + 1'b1 ;                endC_S4:beginR_led_out_reg <= 4'b0100 ;R_state       <= C_S5    ;  endC_S5:beginif(R_cnt_ls == C_CNT_1S)beginR_cnt_ls <= 32'd0 ;R_state  <= C_S6  ;endelseR_cnt_ls <= R_cnt_ls + 1'b1 ;                endC_S6:beginR_led_out_reg <= 4'b1000 ;R_state <= C_S7 ;  endC_S7:beginif(R_cnt_ls == C_CNT_1S)beginR_cnt_ls <= 32'd0 ;R_state  <= C_S0  ;endelseR_cnt_ls <= R_cnt_ls + 1'b1 ;                end default: R_state <= 3'b000 ;                                                                               endcase end
endassign O_led_out = ~R_led_out_reg ;endmodule

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

module tb_led_work_top;// Inputsreg I_clk;reg I_rst_n;// Outputswire [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 InputsI_clk = 0;I_rst_n = 0;// Wait 100 ns for global reset to finish#100;I_rst_n = 1;// Add stimulus hereendalways #5 I_clk = ~I_clk ;endmodule

欢迎关注我的公众号:FPGA之禅

转载于:https://www.cnblogs.com/liujinggang/p/9463589.html

【接口时序】2、Verilog实现流水灯及与C语言的对比相关推荐

  1. 8盏流水灯反向闪烁c语言,课程设计(论文)_利用8255A芯片实现流水灯闪烁设计.doc...

    课程设计(论文)_利用8255A芯片实现流水灯闪烁设计 利用8255A芯片实现流水灯闪烁设计 27 - 目录 摘要··········································· ...

  2. 流水灯实验报告c语言,PLC流水灯实验报告.pdf

    PLC流水灯实验报告 基于WinPAC 的流水灯实验 实验目的 1.掌握PLC编程的基本流程,学会在ISaGRAF环境下编程和仿真. 2.学会在ISAGRAF创建工程.下载程序.调试方法. 3.掌握L ...

  3. 单片机流水灯全亮c语言程序,终极流水灯单片机C语言程序.doc

    终极流水灯单片机C语言程序 #include #include #define uint unsigned int sbit beep=P2^3; void ji_ou(); void sx(); v ...

  4. pic单片机流水灯循环右移c语言,PIC单片机LED流水灯程序

    PIC 单片机 LED流水灯程序 ;************************************************************* include ;*********** ...

  5. STC89C52RC单片机例程实现_流水灯1_模块化(C语言实现)

    主函数main:main.c #include <reg51.h> #include "Delay.h"//Delay.h 头文件申明void main() {whil ...

  6. STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解

    文章目录 一.寄存器原理 1.什么是寄存器 2.如何访问寄存器 二.GPIO端口的初始化设置 1.时钟配置 (1)找到时钟使能寄存器映射基地址 (2)找到端口偏移地址以及对应端口所在位置 (3)使能对 ...

  7. 米联客 ZYNQ/SOC精品教程 S01-CH04 VIVADO创建工程之流水灯

    软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! ...

  8. c语言流水灯定时器延时,实现流水灯以间隔500ms的时间闪烁(系统定时器SysTick实现的精确延时)...

    /** ****************************************************************************** * @file main.c * ...

  9. FPGA学习笔记(1)简单的时序逻辑电路——流水灯

    FPGA学习笔记(1)简单的时序逻辑电路--流水灯 编程语言为Verilog HDL 原理 (1)设计一个计数器,使开发板上的4个LED状态每500ms翻转一次.开发板上的晶振输出时钟频率为50MHz ...

最新文章

  1. NIS、NFS 與 Autofs 整合應用
  2. 深入浅出 - Android系统移植与平台开发(十)- Android编译系统与定制Android平台系统(瘋耔修改篇二)...
  3. Kubernetes 集群升级指南:从理论到实践
  4. MyBatis 实践 -动态SQL/关联查询
  5. 结构型模式—享元模式
  6. IE6的Bug: 绝对定位遇到浮动后消失
  7. [转]Android中pendingIntent的深入理解
  8. java-设计模式(结构型)-【代理模式】
  9. JSP中contentType和pageEncoding的区别
  10. 设计模式的主要设计原则简介
  11. java 播放m4a 文件_Javasound没有通过JAAD(SPI)播放.m4a文件
  12. Neural Style Transfer
  13. ORCAD 16.6使用说明及技巧
  14. Android 启动问题——黑屏 死机 解决方法
  15. 硅谷丛林的故事 EDA篇
  16. 组合导航+多传感器融合算法
  17. layui js 自定义打印功能实现
  18. 【业务安全-03】业务逻辑漏洞之暴力破解(Burte Force)
  19. 如何利用百度经验引流?百度经验精准引流的方法
  20. 智慧磐石工程项目系统组成

热门文章

  1. IMG图片和文字同一行显示,图片和文字居中显示
  2. [机器学习笔记]Note13--异常检测
  3. java空值转datetime,解决Java (Spring boot) 读取数据库字段,datetime 格式为null,抛出异常 Zero date value prohibited...
  4. 巧妙解决element-ui下拉框选项过多的问题
  5. Ubuntu 无法应用原保存的显示器配置
  6. hdu 2196 computer
  7. python爬虫:两种方法模拟登录博客园
  8. 驱动思想之机制和策略
  9. PHP企业级开发环境配置全攻略-IDE+SVN++(转)
  10. C# MVC的博客开发(三)注册