经典模式流水灯实验的个人总结和思考

举报
李锐博恩 发表于 2021/07/15 08:55:25 2021/07/15
【摘要】 问题叙述: 当拨码开关SW3处于OFF时, LED停止不动,只有一个LED处于点亮,并且点亮的LED不会变化;而SW3处于ON状态时,流水灯处于流动状态。导航按键S2被按下后,LED流动方向是从上到下(D9到D2方向);导航按键S3被按下后,LED流动方向是从下到上(D2到D9)。 这里面用到了拨码开关,按键,以及led灯,那么我把这三种外设的电路图给出来,并简...

问题叙述:

当拨码开关SW3处于OFF时, LED停止不动,只有一个LED处于点亮,并且点亮的LED不会变化;而SW3处于ON状态时,流水灯处于流动状态。导航按键S2被按下后,LED流动方向是从上到下(D9D2方向);导航按键S3被按下后,LED流动方向是从下到上(D2D9)。

这里面用到了拨码开关,按键,以及led灯,那么我把这三种外设的电路图给出来,并简单解释:

拨码开关:

拨码开关处于“ON”状态时,SW0输出低电平;当拨码开关处于“OFF”状态时,SW0输出高电平

led灯:

可见,低电平led灯亮;

按键:

独立按键一般有2组管脚,这2组管脚在按键未被按下时是断开的,在按键被按下时则是导通的

基于此原理,我们一般会把按键的一个管脚接地,另一个管脚上拉到VCC,并且也连接到GPIO。这样,在按键未被按下时,GPIO的连接状态为上拉到VCC,则键值为1;按键被按下时,GPIO虽然还是上拉到VCC,但同时被导通的另一个管脚拉到地了,所以它的键值实际上是0


其他没什么好说的,就是按键这个问题,既然用到了按键,就要对按键的消抖问题进行处理,本实验也不例外,在用Verilog HDL语言设计硬件电路时,必须考虑按键抖动的问题:

关于按键抖动的消除,上篇博文如果明白了的话,稍加改动,就可以直接拿过来用了。

贴出博文地址:《按键消抖与LED控制》实验的个人思考与总结

一开始,我也没想到把上篇博文中的按键抖动代码拿过来改动,准备过一遍实验,参考特权同学的代码,可是发现,代码我看不懂,这样的话,马克思大概是说过这么一句话,忘了,大概意思是需求是催生生产力。特权同学的代码看了好久,就是不明白为什么?我得自己找办法呀,于是突然想到了为什么非要用你的代码呢?我改一下上篇博文的按键消抖的代码,再添加一些控制led等的东西不就好了。于是产生了如下的Verilog HDL设计代码:


      `timescale 1ns / 1ps
      //
      // Company: 
      // Engineer: 
      // 
      // Create Date: 19:47:47 08/16/2018 
      // Design Name: 
      // Module Name: led_flow 
      // Project Name: 
      // Target Devices: 
      // Tool versions: 
      // Description: 
      //
      // Dependencies: 
      //
      // Revision: 
      // Revision 0.01 - File Created
      // Additional Comments: 
      //
      //
      module led_flow(
       clk,rst_n,
      			switch,
      			sw1_n,sw2_n,
       led
       );
      input   clk;	//主时钟信号,50MHz
      input   rst_n;	//复位信号,低有效
      input switch;  //switch表示拨码开关,低电平表示on,高电平表示off
      input   sw1_n,sw2_n; 	//2个独立按键,低表示按下
      output[7:0]  led;	//8个发光二极管
      reg [7:0] led;
      //---------------------------------------------------------------------------
      reg[1:0] key_rst;
      always @(posedge clk  or negedge rst_n)
      if (!rst_n) key_rst <= 2'b11;
      else key_rst <= {sw2_n,sw1_n};
      reg[1:0] key_rst_r; //每个时钟周期的上升沿将low_sw信号锁存到low_sw_r中
      always @ ( posedge clk  or negedge rst_n )
      if (!rst_n) key_rst_r <= 2'b11;
      else key_rst_r <= key_rst;
      //当寄存器key_rst由1变为0时,key_an的值变为高,维持一个时钟周期 
      wire[2:0] key_an = key_rst_r & (~key_rst);
      /*
      key_rst 1 1 1 0 0 1
      ~key_rst 0 0 0 1 1 0
      key_rst_r 1 1 1 0 0 1
      key_an 0 0 1 0 0
      */
      //---------------------------------------------------------------------------
      reg[19:0]  cnt;	//计数寄存器
      always @ (posedge clk  or negedge rst_n)
      if (!rst_n) cnt <= 20'd0;	//异步复位
     	else if(key_an) cnt <=20'd0;
      else cnt <= cnt + 1'b1;
      reg[1:0] low_sw;
      always @(posedge clk  or negedge rst_n)
      if (!rst_n) low_sw <= 2'b11;
      else if (cnt == 20'hfffff) 	//满20ms,将按键值锁存到寄存器low_sw中 cnt == 20'hfffff
       low_sw <= {sw2_n,sw1_n};
      //---------------------------------------------------------------------------
      reg  [1:0] low_sw_r; //每个时钟周期的上升沿将low_sw信号锁存到low_sw_r中
      always @ ( posedge clk  or negedge rst_n )
      if (!rst_n) low_sw_r <= 2'b11;
      else low_sw_r <= low_sw;
      /*
      low_sw 11 11 11 10 10 10
      ~low_sw 00 00 00 01 01 01
      low_sw_r 11 11 11 10 10 10
      led_ctrl 00 00 00 01 00 00
       */
      //当寄存器low_sw由1变为0时,led_ctrl的值变为高,维持一个时钟周期 
      wire[1:0] led_ctrl = low_sw_r[1:0] & ( ~low_sw[1:0]);
      reg dir;
      always @ (posedge clk or negedge rst_n)
      if (!rst_n) begin
       dir <= 1'b0; //复位信号有效时,led灯方向控制寄存器置0,也就是默认为向左流动
       end
     	else begin
     		if(led_ctrl[0] == 1'b1) dir <= 1'b1; //控制led灯向右流动
     		if(led_ctrl[1] == 1'b1) dir <= 1'b0;  //控制led灯向左流动
      	 end
      reg [23:0] delay; //led灯延迟计数器
      always @(posedge clk or negedge rst_n)
      begin
     	if(!rst_n)
      		delay <= 24'b0;
     	else
      		delay <= delay + 24'b1;
      end
      always @(posedge clk or negedge rst_n)
      begin
     	if(!rst_n)
      		led <= 8'b0111_1111; //复位信号有效时,led灯处于静止状态,且只有一个灯led7亮
     	else if(delay == 24'hffffff) //否则,延迟到达24'hffffff,进行如下操作
      	begin
     		if(switch == 1'b1)  //如果拨码开关处于off状态时,则led灯处于静止状态,且只有一个等led7亮
      			led <= 8'b0111_1111;
     		else //否则,也就是拨码开关处于on状态时,则led做出如下动作:
      		begin
     			case(dir) //dir是控制方向的状态,如果dir <= 1'b1,则从左向右流动,如果dir <= 'b0,则从右向左流动
     			1'b1: led <= {led[0],led[7:1]};
     			1'b0: led <= {led[6:0],led[7]};
     			default: ;
      			endcase
      		end
      	end
      end
      endmodule
  
 

我注释也写的很清楚,我就不多解释了,如果你真的想了解,那就认真研读代码,肯定能懂;不过前提是度过了按键消抖的那篇博文。

实验结果十分完美,和我设想的一样。

如何用ISE进行整个流程,我以前也用一个简单的实例说过:全过程实现一个最简单的FPGA项目之PWM蜂鸣器控制

那纯理论上也说过:XIlinx FPGA开发基本流程(一)(总介绍)

 

 

文章来源: reborn.blog.csdn.net,作者:李锐博恩,版权归原作者所有,如需转载,请联系作者。

原文链接:reborn.blog.csdn.net/article/details/81748879

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。