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

问题叙述:

当拨码开关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开发基本流程(一)(总介绍)

猜你喜欢

转载自blog.csdn.net/Reborn_Lee/article/details/81748879