(原创)基于FPGA的调光流水灯(Verilog,CPLD/FPGA)

1.Abstract

    前几天做了一个呼吸灯,觉得确实挺有意思的;可惜的是只有一个灯管亮,板子上有四个灯,要是能让这些灯有序地亮起来,那应该更有趣味了!跟传统的一样,逻辑上做成一个流水灯的样式,这种带有PWM调光的吸引样式,真可谓是超级流水灯了。

    做这个是在已做好的呼吸灯的基础上进行添加功能的,整理好了也在随笔里边,这里就直接引用出来。

    基于Verilog的PWM呼吸灯:http://www.cnblogs.com/hechengfei/p/4106538.html

2.Content

  2.1 总体设计

    PWM的原理在呼吸灯的那部分已经整理好了,这里就省去了原理分析一部分了,把做好的作为底层的一个小模块,主要关注顶层逻辑的设计了。

    要使灯顺序的流水起来,自然是一个时序逻辑,最佳的方法就是采用状态机,预先将各个状态分配好,然后让各个状态有序地切换,时序逻辑就清晰得被表达出来。板子上有4个灯,依次流水过去然后再回来,然后循环这样的逻辑;用图表示或许直观些。

FIG2.1 总体逻辑

    在途中,蓝色线表示向右流水,红色线表示向左流水。一次完整的流水执行下来,如绿色箭头指示;首先是LED0表演,完毕后,转至LED1表演,完毕后,再转至LED2表演,依次下去,直至回到LED0表演。

    根据上述的逻辑,将所有的逻辑状态分配出来;将总体逻辑平铺开,去掉多余的状态,就有8-2 = 6个状态(首尾的两个状态各重了一次)。分别用S0到S7八个状态表示(多余的两个状态直接转到S0),用状态表来说明一下。

表2.1 总体状态转换表


当前状态


转换条件


下一状态


S0


!RST 或者 !END0


S0


S0


RST&END0


S1


S1


!RST


S0


S1


RST & (!END1)


S1


S1


RST & END1


S2


S2


!RST


S0


S2


RST & (!END2)


S2


S2


RST & END2


S3


S3


!RST


S0


S3


RST & (!END3)


S3


S3


RST & END3


S4


S4


!RST


S0


S4


RST & (!END2)


S4


S4


RST & END2


S5


S5


!RST | END1


S0


S5


RST & (!END1)


S5


S6


*(Unconditional)


S0


S7


*(Unconditional)


S0

    用状态装换图表示可能更直观一些。

FIG2.2 总体状态转换图

    图中,绿色部分表示正常状态转换,红色部分表示控制信号强制转换。用状态转换图的方法虽然画得比较复杂,线比较多,但更容易理解和便于编写状态机。

    完成信号END的产生。在PWM呼吸灯中,它也是一个状态转换的实例,END信号的产生是由内部寄存器存储和操作的,用作子模块以后,最后的状态应该作为端口输出出来,以便顶层模块检测和顶层状态切换处理。顾只需要在原来的模块中添加一个END信号,在PWM一个周期输出完成以后,将此信号输出出来。

  2.2 顶层整合

    顶层的整合就是将所有模块连接起来,既可以采用Block块的方式,也可以用文本的方式。顶层块连接了控制模块和子状态控制块模块,各自逻辑描述如下。

    顶层块的描述:

module breath(LED,CLK,RST);
output [3:0] LED;

input CLK;
input RST;

wire S_END0;
wire S_END1;
wire S_END2;
wire S_END3;

wire RST_LED0;
wire RST_LED1;
wire RST_LED2;
wire RST_LED3;

breath_state M0 (.RST_LED0(RST_LED0), .RST_LED1(RST_LED1), .RST_LED2(RST_LED2), .RST_LED3(RST_LED3),
                 .S_END0(S_END0), .S_END1(S_END1), .S_END2(S_END2), .S_END3(S_END3),
                 .CLK(CLK), .RST(RST));

breath_led    M1 (.LED(LED[0]), .S_END(S_END0), .CLK(CLK), .RST(RST_LED0));
breath_led    M2 (.LED(LED[1]), .S_END(S_END1), .CLK(CLK), .RST(RST_LED1));
breath_led    M3 (.LED(LED[2]), .S_END(S_END2), .CLK(CLK), .RST(RST_LED2));
breath_led    M4 (.LED(LED[3]), .S_END(S_END3), .CLK(CLK), .RST(RST_LED3));

endmodule

    状态控制块的描述:

module breath_state(RST_LED0, RST_LED1, RST_LED2, RST_LED3,
                    S_END0, S_END1, S_END2, S_END3,
                    CLK,RST);

input S_END0;
input S_END1;
input S_END2;
input S_END3;

output reg RST_LED0 = 1‘b0;
output reg RST_LED1 = 1‘b0;
output reg RST_LED2 = 1‘b0;
output reg RST_LED3 = 1‘b0;

input CLK;
input RST;

parameter S0 = 3‘d0,
          S1 = 3‘d1,
          S2 = 3‘d2,
          S3 = 3‘d3,
          S4 = 3‘d4,
          S5 = 3‘d5,
          S6 = 3‘d6,
          S7 = 3‘d7;

reg [2:0] state = 3‘d0;

always @(posedge CLK)
begin
    if(!RST)
        begin
            state = S0;

            RST_LED0 = 1‘b0; //熄灭所有灯
            RST_LED1 = 1‘b0;
            RST_LED2 = 1‘b0;
            RST_LED3 = 1‘b0;
        end
    else
        begin
            case(state)
            S0:    begin
                    if(S_END0) begin state <= S1; end
                    else begin
                            RST_LED0 <= 1‘b1; // 仅LED0表演
                            RST_LED1 <= 1‘b0;
                            RST_LED2 <= 1‘b0;
                            RST_LED3 <= 1‘b0;
                         end
                end
            S1: begin
                    if(S_END1) begin state <= S2; end
                    else begin
                            RST_LED0 <= 1‘b0;
                            RST_LED1 <= 1‘b1;  // 仅LED1表演
                            RST_LED2 <= 1‘b0;
                            RST_LED3 <= 1‘b0;
                         end
                end
            S2: begin
                    if(S_END2) begin state <= S3; end
                    else begin
                            RST_LED0 <= 1‘b0;
                            RST_LED1 <= 1‘b0;
                            RST_LED2 <= 1‘b1; // 仅LED2表演
                            RST_LED3 <= 1‘b0;
                         end
                end
            S3: begin
                    if(S_END3) begin state <= S4; end
                    else begin
                            RST_LED0 <= 1‘b0;
                            RST_LED1 <= 1‘b0;
                            RST_LED2 <= 1‘b0;
                            RST_LED3 <= 1‘b1; // 仅LED3表演
                         end
                end
            S4: begin
                    if(S_END2) begin state <= S5; end
                    else begin
                            RST_LED0 <= 1‘b0;
                            RST_LED1 <= 1‘b0;
                            RST_LED2 <= 1‘b1; // 仅LED2表演
                            RST_LED3 <= 1‘b0;
                         end
                end
            S5: begin
                    if(S_END1) begin state <= S0; end
                    else begin
                            RST_LED0 <= 1‘b0;
                            RST_LED1 <= 1‘b1; // 仅LED1表演
                            RST_LED2 <= 1‘b0;
                            RST_LED3 <= 1‘b0;
                         end
                end
            S6: begin
                    state <= S0; // 多余状态,无条件返回
                end
            S7: begin
                    state <= S0; // 多余状态,无条件返回
                end
            endcase
        end

end

endmodule

  2.3 逻辑验证

    整理好各个模块以后,编译一下,看看生成出来的逻辑。

FIG2.3综合后的RTL视图网表

    顶层只做连接各个模块,那么在RTL视图中就是几个绿色的小方块儿表示了;排列的还是非常整齐的,对照连线,确定一下所有的线连接是正确的。再就是检查一下状态转换图。

FIG2.4 综合后的状态机视图

    对照视图下边的状态转换表,选中某根连线就可以在表格中直接高亮显示转换的初始状态,转换条件,下一状态等丰富信息。因为生成的状态机和预期的是一样的,所以就不再验证它的正确性了;配置好芯片引脚,将编程文件下载到实际电路板中,看看效果。

    因为博客中不能插入视频,所以将拍好的视频上传到专门的视频网站,生成一个链接,点击进去就可以观看了,也非常方便。

    实际效果:http://v.youku.com/v_show/id_XODMxOTY0MzQ0.html

3.Conclusion

    对于时序逻辑,采用状态机的方法至关重要!逻辑的设计需要非常清晰,对于状态机的设计,可以先画出状态转换图,然后再进行编写文件;对于逻辑还不清晰的地方,需要认真在草稿纸上画画。

    关于编码的规范;对逻辑设计我也是刚刚起步,才学不到一年,更加关注的是逻辑综合后电路的正确性,所以没有对编码进行统一的规范;这方面我也会多多去学习,尽量将文件写的好一点,通用一点。

    写一点感受。逻辑设计和编写程序确实有很大的差别,也是各有所长吧;逻辑电路从大的范围来讲,分为组合逻辑和时序逻辑,有各自实现的方式,对于一个要求实现的逻辑,首先要做的就是把它完全分析清楚,将它们的波形都给画出来,然后再考虑哪部分使用组合逻辑,哪部分使用时序逻辑,最后就是将这些小块块连接起来做整合,设计采用的是自顶向下,而实现的方法可以是自下而上。相对逻辑设计,编程就显得不那么精准了,但是灵活性很高,特别适合做复杂的事情,而且总体看来它就是一个时序的,写好的指令是一步步往下走的,对硬件的理解要求不会太高,从而将注意力转移到如何实现上来。我觉得没有必要将它们严格的区分开来,也没有必要将它们混为一谈来对待,它们各自有优缺点,使用的时候只是转变一下逻辑而已。

4.Reference

[1] Verilog 数字系统设计教程(第二版) 夏宇闻

[2] Verilog HDL 高级数字设计(第二版) Michael D.Ciletti

5. Platform

1).Quartus II Version 9.1 Build 222

2).Microsoft Office Visio Professional 2003 SP3

6.Attachment

工程附录文件:http://i.cnblogs.com/Files.aspx

时间: 2024-11-09 14:29:27

(原创)基于FPGA的调光流水灯(Verilog,CPLD/FPGA)的相关文章

(原创)基于MCU的频率可调,占空比可调的PWM实现(MCU,MCS-51/MSP430)

1.Abstract     做这个是受朋友之邀,用在控制电机转动的方面.他刚好在一家好的单位实习,手头工作比较多,无暇分身,所以找我帮忙做个模型.要求很明晰,PWM的频率在0~1KHz范围内,占空比0~99%范围内,二者均可调.抄下指标以后,回到实验室,细细分析以后,决定用MCU来实现一下,毕竟只分析,无实际结果也不是一个好的交代. 2.Content   2.1 理论分析     归根结底来说,是一个时序逻辑,即PWM输出波形是随着时间的推移而变化.用时序图的方式解释更明晰些. FIG2.1

FPGA的EPCS 配置的2种方法 FPGA下载程序的方法(EPCS)

使用主动串行配置模式对Cyclone FPGA进行配置前,必须将配置文件写入串行配置器件EPCS.将配置文件写入EPCS的方法有三种: (1)在Quartus II的Programmer中,通过专门与EPCS连接的AS下载接口下载.pof文件到EPCS.不同之处在于将下载线连接到AS接口而不是JTAG接口,选择编程文件时是*.pof而不是*.sof. (2)在Quartus II的Programmer中,使用JTAG接口通过FPGA中间通道间接对EPCS进行编程. (3)使用Nios II ID

《FPGA全程进阶---实战演练》第一章之FPGA介绍

1 什么是FPGA FPGA也即是Field Programmable Gate Array的缩写,翻译成中文就是现场可编程门阵列.FPGA是在PAL.GAL.CPLD等可编程器件的基础上发展起来的新型高性能产物,是作为专用集成电路(ASIC)领域中的一种半定制电路出现的,既解决了定制电路的不足,又克服了原有可编程器件门电路数有限的缺点.图1.1是Altera Cyclone V芯片. 图1.1 Altera Cyclone芯片 说到这里,不得不提ASIC,即专用集成电路(Application

(原创)用Verilog实现一个参数化的呼吸灯(Verilog,CPLD/FPGA)

1.Abstract     观察到一个有趣的现象,每当把Apple笔记本合上的时候,那个白色的呼吸灯就会反复地由暗渐明,然后又由明渐暗,乍一看就像Apple笔记本在打盹休息一样,十分可爱!于是突发奇想,要不用Verilog也写一个吧,资源也不需要太多,一个LED灯就可以了.为了使用方便,可以把它做成参数化的,可以根据时常进行参数调节:深睡.浅睡跟清醒的时候呼吸频率似乎是不一样的-     下面就来分析和实践一下. 2.Content   2.1 理论分析     根据上述描述的现象,仔细分析一

FPGA -- 实验一:闪烁灯(1)

第一个实验就简单的实现一个灯闪烁的程序(主要也是为了回顾一下语法,仿真以及下载的流程) 基本思路是:利用计数器去计数0.5s,然后每隔0.5s改变以下LED输出引脚的电平状态 硬件电路如下:(与FPGA中的对应连接,在代码注释中给出) 1.在上次建立的那个设计文件里输入以下内容 (这个实验主要做一个演示,以后建工程等步骤不再赘述) 1 /********************************************* 2 *文件名:led.v 3 *功能:实现开发板上LED灯闪烁(闪烁

(原创)defparam的应用(Verilog,CPLD/FPGA)

1.Abstract     在同一个模块被多次例化的时候,改变参数构建不同的硬件实体是一个很好的选择.特别是今天帮一个朋友调试一个比较复杂的逻辑,深有体会.这个也是一个小技巧,回来也查了许多资料,强化了一下这方面的知识.前几天也做了一个这样的例子,可以拿过来作为验证一下. 2.Content   2.1 语法说明     defparam 的语法说明如下:     defparam ParameterName = Constant Expression,     ParameterName =

[原创]基于51单片机的红外遥控课程设计

[注]: 一眨眼,大学接近尾声,具有找工作需要,所以把大学做的电子设计“劣作”放上来.希望考研失意,还能赶上“好工作”的春招班车.如果大伙有什么工作推荐也可以联系我哦,因为一年考研少接触了这方面,所以难免有些生疏.但请相信我!给我机会我会很认真学的! 邮箱:[email protected] 转载请注明出处呀! 基于51单片机的红外遥控课程设计 目录 第一章 设计简介... 3 第二章 系统方案... 3 一.设计方案对比... 3 二.方案设计... 4 第三章 硬件设计... 5 一.红外遥

[原创]基于VueJs的前后端分离框架搭建之完全攻略

首先请原谅本文标题取的有点大,但并非为了哗众取宠.本文取这个标题主要有3个原因,这也是写作本文的初衷: (1)目前国内几乎搜索不到全面讲解如何搭建前后端分离框架的文章,讲前后端分离框架思想的就更少了,而笔者希望在本文中能够全面.详细地阐述我们团队在前后端分离的摸索中所得到的搭建思路.最佳实践以及架构思想: (2)我们团队所搭建的前后端分离框架,并非只是将网上传播的知识碎片简单拼装,而是一开始就从全局出发,按照整个系统对前后端分离框架的最高期望进行设计,到目前为止,可以说我们的框架完全实现了对我们

基于verilog的FPGA编程经验总结(XILINX ISE工具)

1.用ISE仿真的时候.所用变量一定要初始化. ISE默认初始量为"XXXXX", 而Quarters是默认为"00000"的, 其实实际上, 下到FPGA里后也是默认为0的,只是可以说ISE严谨得令人DT吧.比如说用一个累加器, result = A+B+result ,必须保证在某一刻A, B, result都为定值时, 之后的数据才不会一直为"XXXXX"; 2.所有的中间线(就是module间用来传递参数的信号)都要用wire定义一下.