一、 软件平台与硬件平台

  软件平台:

  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)
begin
if(!I_rst_n)
begin
R_cnt_ls <= 'd0 ;
R_clk_ls_reg <= 'b1 ;
end
else if(R_cnt_ls == 'd24_999_999)
begin
R_cnt_ls <= 'd0 ;
R_clk_ls_reg <= ~R_clk_ls_reg ;
end
else
R_cnt_ls <= R_cnt_ls + '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 <= 'b0001 ;
else if(R_led_out_reg == 'b1000)
R_led_out_reg <= 'b0001 ;
else
R_led_out_reg <= R_led_out_reg << ;
end assign O_led_out = ~R_led_out_reg ;

五、 ModelSim仿真

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

initial begin
// Initialize Inputs
I_clk = ;
I_rst_n = ; // Wait 100 ns for global reset to finish
#;
I_rst_n = ; // Add stimulus here end always # 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)
begin
if(!I_rst_n)
begin
R_state <= 'b000 ;
R_cnt_ls <= 'd0 ;
end
else
begin
case(R_state)
C_S0:
begin
R_led_out_reg <= 'b0001 ;
R_state <= C_S1 ;
end
C_S1:
begin
if(R_cnt_ls == C_CNT_1S)
begin
R_cnt_ls <= 'd0 ;
R_state <= C_S2 ;
end
else
R_cnt_ls <= R_cnt_ls + 'b1 ;
end
C_S2:
begin
R_led_out_reg <= 'b0010 ;
R_state <= C_S3 ;
end
C_S3:
begin
if(R_cnt_ls == C_CNT_1S)
begin
R_cnt_ls <= 'd0 ;
R_state <= C_S4 ;
end
else
R_cnt_ls <= R_cnt_ls + 'b1 ;
end
C_S4:
begin
R_led_out_reg <= 'b0100 ;
R_state <= C_S5 ;
end
C_S5:
begin
if(R_cnt_ls == C_CNT_1S)
begin
R_cnt_ls <= 'd0 ;
R_state <= C_S6 ;
end
else
R_cnt_ls <= R_cnt_ls + 'b1 ;
end
C_S6:
begin
R_led_out_reg <= 'b1000 ;
R_state <= C_S7 ;
end
C_S7:
begin
if(R_cnt_ls == C_CNT_1S)
begin
R_cnt_ls <= 'd0 ;
R_state <= C_S0 ;
end
else
R_cnt_ls <= R_cnt_ls + 'b1 ;
end
default: R_state <= 'b000 ;
endcase
end
end assign 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 [:] O_led_out
); reg [:] R_cnt_ls ;
wire W_clk_ls ;
reg R_clk_ls_reg ;
reg [:] R_led_out_reg ; //////////////////////////////////////////////////////////////////
// 功能:产生1s的时钟
//////////////////////////////////////////////////////////////////
always @(posedge I_clk or negedge I_rst_n)
begin
if(!I_rst_n)
begin
R_cnt_ls <= 'd0 ;
R_clk_ls_reg <= 'b1 ;
end
else if(R_cnt_ls == 'd24_999_999)
begin
R_cnt_ls <= 'd0 ;
R_clk_ls_reg <= ~R_clk_ls_reg ;
end
else
R_cnt_ls <= R_cnt_ls + '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 <= 'b0001 ;
else if(R_led_out_reg == 'b1000)
R_led_out_reg <= 'b0001 ;
else
R_led_out_reg <= R_led_out_reg << ;
end assign O_led_out = ~R_led_out_reg ; endmodule

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

module led_work_top
(
input I_clk ,
input I_rst_n ,
output [:] O_led_out
); reg [:] R_cnt_ls ;
reg [:] R_led_out_reg ;
reg [:] R_state ; parameter C_CNT_1S = 'd49_999_999 ; parameter C_S0 = 'b000 ,
C_S1 = 'b001 ,
C_S2 = 'b010 ,
C_S3 = 'b011 ,
C_S4 = 'b100 ,
C_S5 = 'b101 ,
C_S6 = 'b110 ,
C_S7 = 'b111 ; //////////////////////////////////////////////////////////////////
// 功能:仿顺序操作
//////////////////////////////////////////////////////////////////
always @(posedge I_clk or negedge I_rst_n)
begin
if(!I_rst_n)
begin
R_state <= 'b000 ;
R_cnt_ls <= 'd0 ;
end
else
begin
case(R_state)
C_S0:
begin
R_led_out_reg <= 'b0001 ;
R_state <= C_S1 ;
end
C_S1:
begin
if(R_cnt_ls == C_CNT_1S)
begin
R_cnt_ls <= 'd0 ;
R_state <= C_S2 ;
end
else
R_cnt_ls <= R_cnt_ls + 'b1 ;
end
C_S2:
begin
R_led_out_reg <= 'b0010 ;
R_state <= C_S3 ;
end
C_S3:
begin
if(R_cnt_ls == C_CNT_1S)
begin
R_cnt_ls <= 'd0 ;
R_state <= C_S4 ;
end
else
R_cnt_ls <= R_cnt_ls + 'b1 ;
end
C_S4:
begin
R_led_out_reg <= 'b0100 ;
R_state <= C_S5 ;
end
C_S5:
begin
if(R_cnt_ls == C_CNT_1S)
begin
R_cnt_ls <= 'd0 ;
R_state <= C_S6 ;
end
else
R_cnt_ls <= R_cnt_ls + 'b1 ;
end
C_S6:
begin
R_led_out_reg <= 'b1000 ;
R_state <= C_S7 ;
end
C_S7:
begin
if(R_cnt_ls == C_CNT_1S)
begin
R_cnt_ls <= 'd0 ;
R_state <= C_S0 ;
end
else
R_cnt_ls <= R_cnt_ls + 'b1 ;
end
default: R_state <= '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 [:] 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 = ;
I_rst_n = ; // Wait 100 ns for global reset to finish
#;
I_rst_n = ; // Add stimulus here end always # I_clk = ~I_clk ; endmodule

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

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

  1. verilog 之流水灯

    1.黑金板 简易操作: 通过判断数值累加    个人观点:黑金代码质量有待提高,讲解不够详细 2.正点原子的 位置调换 led[:] <= {led[:],led[]}; 3.传统位移 led& ...

  2. 【接口时序】7、VGA接口原理与Verilog实现

    一. 软件平台与硬件平台 软件平台: 1.操作系统:Windows-8.1 2.开发套件:ISE14.7 3.仿真工具:ModelSim-10.4-SE 硬件平台: 1. FPGA型号:Xilinx公 ...

  3. 【接口时序】4、SPI总线的原理与Verilog实现

    一. 软件平台与硬件平台 软件平台: 1.操作系统:Windows-8.1 2.开发套件:ISE14.7 3.仿真工具:ModelSim-10.4-SE 硬件平台: 1. FPGA型号:Xilinx公 ...

  4. 花样流水灯的verilog实现

    LED(Light emitting diode)发光二极管将电能转化为可见光,正向电压导通,反向电压截止.对于该板子,二极管用低电压导通,其实验原理图为: 所谓流水灯,即让LED像水一样的点亮,从左 ...

  5. FPGA——流水灯(一)

    对于FPGA的结构原理,先不进行全面的了解,先能根据教程程序看得懂,写得出来跑起来.慢慢的了解程序运行的原理,各种语法的使用. 今天对流水的程序有一个认识,熟悉软件的使用,语法规则,原理.以正点原子的 ...

  6. FPGA 流水灯

    VerilogHDL那些事儿_建模篇(黑金FPGA开发板配套教程) 作者:akuei2 说明:参照该书将部分程序验证学习一遍 学习时间:2014年5月2号 主要收获: 1. 对FPGA有初步了解: 2 ...

  7. 【黑金原创教程】【FPGA那些事儿-驱动篇I 】【实验一】流水灯模块

    实验一:流水灯模块 对于发展商而言,动土仪式无疑是最重要的任务.为此,流水灯实验作为低级建模II的动土仪式再适合不过了.废话少说,我们还是开始实验吧. 图1.1 实验一建模图. 如图1.1 所示,实验 ...

  8. STM32学习笔记(二) 基于STM32-GPIO的流水灯实现

    学会了如何新建一个工程模板,下面就要开始动手实践了.像c/c++中经典的入门代码"hello world"一样,流水灯作为最简单的硬件设备在单片机领域也是入门首推.如果你已经有了一 ...

  9. 第一个FPGA工程—LED流水灯

    这一章我们来实现第一个FPGA工程-LED流水灯.我们将通过流水灯例程向大家介绍一次完整的FPGA开发流程,从新建工程,代码设计,综合实现,管脚约束,下载FPGA程序.掌握本章内容,大家就算正式的开始 ...

随机推荐

  1. python3中一句话定义函数

    import math as marea=lambda r:r**2*m.pi #定义一个计算圆的面积的函数area(8) 显示结果 201.06192982974676

  2. python——字符串问题总结

    转义符r/R使用: print (r'\n') print (R'\n') 输出: \n \n 不受转义符\n影响 python字符串格式化: print ("我叫 %s 今年 %d 岁!& ...

  3. Mybatis运行错误:信息: SQLErrorCodes loaded: [DB2, Derby, H2, HDB, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]

    Mybatis运行出现错误提示: 五月 23, 2018 12:07:22 上午 org.springframework.jdbc.support.SQLErrorCodesFactory <i ...

  4. java 自动补全

    int youNumber = 1; // 0 代表前面补充0 // 4 代表长度为4 // d 代表参数为正数型 String str = String.format("%04d" ...

  5. 【原】The Linux Command Line - Manipulation Files And Directories

    cp - Copy Files and directories mv - move/rename files and directories mkdir - create directories rm ...

  6. python re模块与正则表达式

    首先要先继承re模块: import re re.findall() 方法 # 返回值为列表 \w 表示一个字符,为数字,字母,下滑线之一, \W匹配任意非数字,字母,下划线 print(re.fin ...

  7. jQuery之必会增删改查Dom操作

    .next  .prev <button>change</button> <span class = '.demo'>aaa</span> <p ...

  8. JSON转Excel

    1.引入js (dist目录下JsonExportExcel.min.js) <script src="https://cuikangjie.github.io/JsonExportE ...

  9. Appium 学习一:环境搭建问题

    1.安装Android-sdk http://tools.android-studio.org/index.php/sdk 问题1:下载 android-sdk_r24.4.1-windows.zip ...

  10. Redis 高级特性

    Redis 数据结构 Redis 常用的数据类型主要有以下五种: String Hash List Set Sorted set Redis 内部使用一个 redisObject 对象来表示所有的 k ...