简易项目(1)流水灯项目讲解

写在前面的话

这一节呢,我们来实现一个流水灯驱动程序的编写,当然啦,点灯不是目的,最重要的是我们通过这个流水灯代码的实现可以掌握一些重要的规范。

项目需求

我们要求流水灯模式如下:当复位键按下时,灯全部熄灭,当复位键放开以后,首先,点亮第一个灯,然后第一个灯熄灭,同时点亮第二个灯,接着,第二个灯熄灭,同时点亮第三个灯,然后,第三个灯熄灭,同时点亮第四个灯,最后第四个灯熄灭,同时点亮第一个灯,如此循环往复,实现流水。

相关技术介绍

项目需求,我相信大家已经看清楚了,那么,接下来我们该怎么做呢?写代码?NO 我们来仔细的看看项目需求,这里面涉及到了按键,LED灯,还需要我们用按键控制流水灯的启动或停止。那么,在写代码之前,我们首先应该明确按键按下和放开有什么区别、LED是低电平点亮还是高电平点亮。只有清楚外设的性能,我们才可能编写代码正确地驱动这些外设。代码体现的是我们的思路,所以在写代码之前我们必须首先理顺自己的思路,否则盲目的编写代码,一定是徒劳的。

硬件设计

下图所示为轻触按键与FPGA的连接关系示意图

由上述电路图可知,当按键放开时,FPGA端口等于接到了上拉电阻,所以检测到的为高电平。当按键按下时,FPGA端子通过按键接到了地平面,检测到的为低电平。

下图所示为LED与FPGA的连接关系示意图

由上述电路图可知,LED正极全部接到了3.3V电源。那么,只有当FPGA端口给出低电平的时候,LED才会点亮。当FPGA端给高电平时,LED熄灭。

顶层架构设计

项目需求以及项目需求中所涉及到的所有外设都已经分析清楚了,那么接下来是不是可以开始编写代码了呢?答案还是—NO!哈哈,别着急,其实对于工程师而言,编写代码真的是小菜一碟,闭着眼睛都能敲几行哦。一个项目最重要的、最终决定成败的一般来说不是代码的具体实现,而是前期的架构设计,好的架构可以化简为易,将一个很复杂的工程逐步的拆分成很多简单的子模块,不但提高了设计效率和成功率,同时也比较适合团队作战,分工合作。如果在开始设计代码之前没有一个明朗的架构,做到最后甚至可能会发现原理根本无法通过,整体架构需要重新设计,那么这样就得不偿失啦。如下图所示为我们流水灯模块的一个基本架构,虽然很简单,甚至简单到了只有一个模块,但是呢,我们一定要养成这样的一个习惯。

端口描述


端口名


功能


clk


系统时钟输入(50MHz)


rst_n


复位按键(低电平有效)


pio_led


4bit led驱动端口

代码解释

终于可以写代码了,具体代码实现步骤(先写什么,后写什么),大家可以观看梦翼师兄配套的视频。在这里,我们直接给出具体代码如下


/****************************************************

*   Engineer        :   梦翼师兄

*   QQ               :   761664056

*   The module function:流水灯

*****************************************************/

01  module led_learn(

02                      clk,   //系统时钟输入

03                      rst_n, //系统复位

04                      pio_led//LED驱动输出

05                  );

06  //系统输入

07  input clk;   //系统时钟输入

08  input rst_n; //系统复位

09  //系统输出

10  output reg [3:0]pio_led;//LED驱动输出

11  //中间寄存器定义

12  reg [1:0]state;//状态寄存器定义

13  //LED驱动逻辑

14  always@(posedge clk or negedge rst_n)

15      begin

16          if(!rst_n)

17              begin

18                  pio_led<=4‘b1111;//LED全部熄灭

19                  state<=0;//寄存器赋初值

20              end

21          else begin

22              case(state)

23                  0:begin

24                      pio_led<=4‘b0111;//第一个灯点亮

25                      state<=1;//状态跳转

26                  end

27                  1:begin

28                      pio_led<=4‘b1011;//第二个灯点亮

29                      state<=2;//状态跳转

30                  end

31                  2:begin

32                      pio_led<=4‘b1101;//第三个灯点亮

33                      state<=3;//状态跳转

34                  end

35                  3:begin

36                      pio_led<=4‘b1110;//第四个灯点亮

37                      state<=0;//状态跳转

38                  end

39                  default:state<=0;

40                  endcase

41          end

42      end

43  endmodule

这里我们应用的就是状态机的概念,第一步进行某些操作,然后跳到下一步进行其他操作,直到所有操作完成以后再返回初始状态

那么我们现在想当然写出来的逻辑是不是可以正确实现我们的目标呢?这其实还是一个大大的问号,那么接下来,我们需要做的就是进行逻辑仿真,梦翼师兄在教学过程中常说的一句话就是“对不对,只有仿真说了算”。

接下来我们编写仿真代码如下


/****************************************************

*   Engineer        :   梦翼师兄

*   QQ               :   761664056

*   The module function:流水灯测试模块

*****************************************************/

01  `timescale 1ns/1ps //时间单位和精度定义

02  module tb;

03

04  //系统输入

05  reg clk;   //系统时钟输入

06  reg rst_n; //系统复位

07  //系统输出

08  wire [3:0]pio_led;//LED驱动输出

09

10  initial

11      begin

12          clk=0;

13          rst_n=0;

14          #1000.1 rst_n=1;

15      end

16

17      always #10 clk=~clk;//50MHz时钟

18

19  led_learn led_learn(

20          .clk(clk),       //系统时钟输入

21          .rst_n(rst_n),   //系统复位

22          .pio_led(pio_led)//LED驱动输出

23        );

24  endmodule

运行仿真软件Modelsim 查看仿真波形(软件具体操作请观看梦翼师兄配套教学视频)

由仿真图,我们可以看到在每个时钟的上升沿pio_led的值发生一次切换,从第一个到第四个灯依次循环点亮,说明逻辑设计正确。

好了,波形仿真正确了,如果下载到开发板,流水灯可以实现了吗?答案还是NO!什么?梦翼师兄疯了吧,一会儿说逻辑对了,一会儿又说流水灯还不能实现,到底能不能愉快的玩耍啦?哈哈,这就是仿真和真实环境条件切换的一个误区。大家试想一下,我们现在每来一个时钟,LED就会切换一次状态,那么由于我们的时钟是50MHz,因此我们的时钟周期仅仅为20Ns,这么快的速度,人的眼睛是无法分辨的,那么在这种条件下,我们当然是看不到流水现象的。

那么如何才能看到流水呢?对,我们必须降低LED的切换速度。那么LED的切换速度和谁有关系呢?第一当然是时钟,假设时钟速度很慢,那么流水的速度自然也会很慢,第二个原因就是状态机,因为不管时钟速度如何,状态机只要控制自己的状态不要那么快切换,那么也可以实现我们的目的。

那么,首先让我们从状态机的角度去控制LED的切换速度,我们给出修改的代码如下


/****************************************************

*   Engineer        :   梦翼师兄

*   QQ               :   761664056

*   The module function:流水灯

*****************************************************/

01  module led_learn(

02                      clk,   //系统时钟输入

03                      rst_n, //系统复位

04                      pio_led//LED驱动输出

05                  );

06  //系统输入

07  input clk;   //系统时钟输入

08  input rst_n; //系统复位

09  //系统输出

10  output reg [3:0]pio_led;//LED驱动输出

11  //中间寄存器定义

12  reg [1:0]state;//状态寄存器定义

13  reg [40:0]counter;//计数寄存器

14  //LED驱动逻辑

15  always@(posedge clk or negedge rst_n)

16      begin

17          if(!rst_n)

18              begin

19                  pio_led<=4‘b1111;//LED全部熄灭

20                  state<=0;//寄存器赋初值

21                  counter<=0;//计数器赋初值

22              end

23          else begin

24              case(state)

25                  0:begin

26                      pio_led<=4‘b0111;//第一个灯点亮

27                      if(counter<12)//延时时间不够则继续计数

28                          counter<=counter+1;

29                      else

30                          begin

31                              state<=1;//状态跳转

32                              counter<=0;//计数器清零

33                          end

34                  end

35                  1:begin

36                      pio_led<=4‘b1011;//第二个灯点亮

37                      if(counter<12)//延时时间不够则继续计数

38                          counter<=counter+1;

39                      else

40                          begin

41                              state<=2;//状态跳转

42                              counter<=0;//计数器清零

43                          end

44                  end

45                  2:begin

46                      pio_led<=4‘b1101;//第三个灯点亮

47                      if(counter<12)//延时时间不够则继续计数

48                          counter<=counter+1;

49                      else

50                          begin

51                              state<=3;//状态跳转

52                              counter<=0;//计数器清零

53                          end

54                  end

55                  3:begin

56                      pio_led<=4‘b1110;//第四个灯点亮

57                      if(counter<12)//延时时间不够则继续计数

58                          counter<=counter+1;

59                      else

60                          begin

61                              state<=0;//状态跳转

62                              counter<=0;//计数器清零

63                          end

64                  end

65                  default:state<=0;

66                  endcase

67          end

68      end

69  endmodule

该段代码和上一段代码唯一的区别之处在于我们在状态机状态跳转的部分加入了延时计数器,只有累计时钟上升沿达到一定数量以后,状态才会发生跳转。这样就可以有效延长每个LED灯点亮的时间。当然啦,这里面计数值到12完全是梦翼师兄为了仿真方便而乱写的一个数,如果真的要实现流水灯,计数值应该很大才可以哦。接下来让我们看一下这段代码的仿真波形

对比两个波形图,我们可以看到加延时计数器之后,流水灯的切换速度明显变慢,可以实现我们的设计要求。通过该实验,我们同时也学到了计数器的用法。那么还剩下一种方式,那就是控制我们的频率了,我们设计代码如下


/****************************************************

*   Engineer        :   梦翼师兄

*   QQ               :   761664056

*   The module function:流水灯

*****************************************************/

01  module led_learn(

02                      clk,   //系统时钟输入

03                      rst_n, //系统复位

04                      pio_led//LED驱动输出

05                  );

06  //系统输入

07  input clk;   //系统时钟输入

08  input rst_n; //系统复位

09  //系统输出

10  output reg [3:0]pio_led;//LED驱动输出

11  //中间寄存器定义

12  reg [1:0]state;//状态寄存器定义

13  reg [40:0]counter;//计数器定义

14  reg clk_slow;//慢时钟定义

15  //时钟分频电路

16  always@(posedge clk or negedge rst_n)

17      begin

18          if(!rst_n)

19              begin

20                  counter<=0;

21                  clk_slow<=0;

22              end

23          else

24              begin

25                  if(counter<12)

26                      counter<=counter+1;

27                  else

28                      begin

29                          counter<=0;

30                          clk_slow<=~clk_slow;

31                      end

32              end

33      end

34

35  //LED驱动逻辑

36  always@(posedge clk_slow or negedge rst_n)

37      begin

38          if(!rst_n)

39              begin

40                  pio_led<=4‘b1111;//LED全部熄灭

41                  state<=0;//寄存器赋初值

42              end

43          else begin

44              case(state)

45                  0:begin

46                      pio_led<=4‘b0111;//第一个灯点亮

47                      state<=1;//状态跳转

48                  end

49                  1:begin

50                      pio_led<=4‘b1011;//第二个灯点亮

51                      state<=2;//状态跳转

52                  end

53                  2:begin

54                      pio_led<=4‘b1101;//第三个灯点亮

55                      state<=3;//状态跳转

56                  end

57                  3:begin

58                      pio_led<=4‘b1110;//第四个灯点亮

59                      state<=0;//状态跳转

60                  end

61                  default:state<=0;

62                  endcase

63          end

64      end

65  endmodule

以上代码16-33行为我们添加的计数器分频模块,通过计数器计数,利用快时钟分频得到一路慢时钟。代码36行


36  always@(posedge clk_slow or negedge rst_n)

我们用分频得到的慢时钟作为状态机的切换时钟,这样也可以有效控制状态机切换的速度。查看仿真波形如下

由仿真图可知,第一:快时钟正确生产了慢时钟 第二:LED在慢时钟的控制下进行切换,说明我们的逻辑设计正确。通过该实验,我们也可以学会分频电路的设计方法。这也是梦翼师兄的初衷,尽可能通过一个实验项目多学东西,后面我们就可以利用这些知识点来解决其他问题啦。

原文地址:https://www.cnblogs.com/mengyi1989/p/11517606.html

时间: 2024-08-29 06:46:48

简易项目(1)流水灯项目讲解的相关文章

一个简易的发布电影票的项目

原文:一个简易的发布电影票的项目 源代码下载地址:http://www.zuidaima.com/share/1601881858886656.htm 在首页(index.html)页面上,按照影片发表时间显示所有影片 点击index.html页面右边的影片类型链接,在页面左边显示对应影片 根据影片的名称进行搜索 当鼠标悬停到影片的图片上,显示影片的详细信息 发布新影片(不要求实现上传图片功能) 发布新影片时可以使用struts2组件上传图片 提供数据库脚本 分层实现 使用struts2框架和j

永远的流水灯(Verilog)

1. 为了更好地学习FPGA和深入理解Verilog语法,首先从最简单的流水灯做起.虽然简单,但是也包含了不少知识.通过这次实验项目,可以了解开发软件的使用及Verilog的编程方法,熟悉模块化设计的方法. 2. 该项目主要实现的功能为: (1)10位的流水灯 (2)中间两个led灯每隔100ms闪烁一次 (3)两边的led灯每隔100ms流动一下,从中间向两边流水. 3.  具体实现如下 (1)首先定义一个时间计数寄存器counter,每当达到预定的100ms时,计数寄存器就清零,否则的话寄存

Qt利用代码实现流水灯的效果

用代码实现流水灯的效果 其实很想实现这种流水灯的效果了,看起来挺酷的,用处也很多,只是开始没有思路不知道怎么去实现,于是在我的超市收银项目中就采用了图片加载的方式进行显示,效果如下图所示: 由于是动态图片,显示的时候就要用到QMovie进行加载,简单的代码如下所示: QMovie *move = new QMovie(":/images/splash.gif"); QLabel *label = new QLabel("",0); label->setWind

流水灯之并行操作

流水灯 功能描述: 10个led灯 从第一个和最后一个led灯开始从两边向中间闪烁,闪烁频率为0.5s一次 项目实现 首先定义一个计时器 计数器的名字为count1,如果复位或者count1==2.5s时复位,否则count1加1,开发板晶振50M 当计数达到TIME=2.5s/(1/50M)-1=124_999_999次数的时候,即为2.5s具体代码为:[email protected](posedge CLK or negedge RSTn)   if(!RSTn)    Count1<=2

STM32f103之流水灯

       这几天打算复习下stm32有关的硬件资源,就想着从最开始做起,熟悉下当初所学的知识.学习stm32最初都基本是从流水灯开始的,今天就开始点亮流水灯.        首先,必须明白流水灯的硬件原理,以下是原理图: 它由8个管脚控制,因此首先必须进行初始化8个引脚. //初始化PE8...PE15为输出口.并使能这八个口的时钟 //LED IO初始化 void LED_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2P

流水灯系列

流水灯 电路仿真图 /****************************** 项目名称:项目1彩灯控制器 任务名称:任务3流水灯控制 任务描述:P1口控制8个LED,编程实现8个LED依次亮灭并循环. *****************************/ #include<reg51.h> #include<intrins.h> void delay(int i) { int k,j; for(k=0;k<i;k++) for(j=0;j<100;j++)

第一个FPGA工程—LED流水灯

这一章我们来实现第一个FPGA工程-LED流水灯.我们将通过流水灯例程向大家介绍一次完整的FPGA开发流程,从新建工程,代码设计,综合实现,管脚约束,下载FPGA程序.掌握本章内容,大家就算正式的开始入门FPGA开发了. 1.1.1.电路说明 1.1.2.新建工程 第一步:从开始菜单启动Quartus II 13.1(64 bit) ,如下图. 第二步:菜单栏选择File->New Project Wizard,新建工程. 第三步:弹出新建工程对话框,点击Next,下一步. 第三步:如下图,依次

51流水灯实验

  课程名称:_单片机原理与应用 专业班级: 嵌入式14103班 姓    名:_赵存档       _ __ 学    号:_14160310317    __     2015-- 2016   学年第  1 学期     实验项目( 一 ) — 预习报告 项目 名称 LED高低电平交替闪烁程序 实验 目的 及 要求 1. 正确安装keil软件 2. 在 Proteus 的环境下,设计硬件原理图: 3.在keil 集成环境下设计C语言程序: 4. 在 Proteus 的环境下,将硬件原理图与

LED流水灯(一)

7个寄存器 是R1-R16.(当然,里面有很多是分几个模式的,所以总共有37个)类似于单片机的R0-R7. GPXCON,GPXDAT等等是另外的寄存器,应该叫,特殊功能寄存器,类似于单片机的P0,P1,TCON,等等. GPXCON:是X管脚的控制寄存器,控制它们的模式,比如输出模式,输入模式……GPXDAT:是X管脚的数据寄存器,存储它们的数据, GPIO ,通用的输入输出,其引脚可供编程使用,对于简单的外部设备,比如控制一个LED 灯的亮灭,自然 只需要一位 信号就够了. 使用传统的 串行