经典模式流水灯实验的个人总结和思考
问题叙述:
当拨码开关SW3处于OFF时, LED停止不动,只有一个LED处于点亮,并且点亮的LED不会变化;而SW3处于ON状态时,流水灯处于流动状态。导航按键S2被按下后,LED流动方向是从上到下(D9到D2方向);导航按键S3被按下后,LED流动方向是从下到上(D2到D9)。
这里面用到了拨码开关,按键,以及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
- 点赞
- 收藏
- 关注作者
评论(0)