原创 [博客大赛]johnson流水灯实验

2013-7-31 14:28 1241 17 19 分类: FPGA/CPLD 文集: FPGA学习过程

昨天把johnson流水灯的实验做了,还是脑子清醒的时候好,一会儿就写完了并且成功运行了。
其实johnson流水灯就是普通的流水灯加上一些按键控制而已,这个过程中除了普通的流水灯以外,还有一个就是按键消抖,只有这两个点吧。
要实现的功能是:按键1,控制流水灯是否移动,按键2,控制流水灯向左移动,按键3,控制流水灯向右移动,流动频率设置为0.5s/次。
实现起来还是比较简单的,先上代码。
/*-----------------------------------------------------------------------------------------
Module Name:    test_johnson.v
File Author:    creation
Finish Time:    2013-07-26
Description:    johnson流水灯实验
-------------------------------------------------------------------------------------------
Version         Design      Coding      Simulate        Review      Rel data
V1.0
-------------------------------------------------------------------------------------------
Version         Modified History
V1.0            draft
-----------------------------------------------------------------------------------------*/
`timescale 1ns / 10ps
module test_johnson(
            input       wire            asy_rst         ,//复位
            input       wire            clk             ,//50MHZ晶振
            input       wire    [2:0]   key             ,//3位按键,0位控制是否流动,1位控制从低向高,2位控制从高向低
            output      wire    [7:0]   o_led            //8位led
);
/*---------------------------Internal registers and wires--------------------------------*/
/* Register Output Signals */
reg     [7:0]       led;                    //led输出寄存器

/* internal logic use signals */
reg     [19:0]      cnt_key;                //按键消抖计时
reg     [2:0]       key_r;                  //上一时钟周期按键状态寄存
reg     [2:0]       key_p;                  //按键消抖时20ms前按键状态寄存
reg     [2:0]       flag_key_p;             //按键下降沿标志
reg     [2:0]       flag_key;               //流水灯流动状态
reg     [24:0]      cnt_led;                //流水灯流动计时0.5s/位

/* ----------------------Logical Implementation------------------------------------------*/
/*-----------------------------------------------------------------------------------------
gen the cnt_key signal
-----------------------------------------------------------------------------------------*/
always @ ( posedge clk or negedge asy_rst )
begin
    if ( !asy_rst )
        cnt_key <= 1'b0;
    else if ( flag_key_p != 1'b0 )          //按键出现下降沿时flag_key_p不等于0,将cnt_key赋值1,开始消抖计时
        cnt_key <= 1'b1;
    else if ( cnt_key == 20'd999999 )       //按键消抖计时满20ms,计时复位等待下次,按键下降沿
        cnt_key <= 1'b0;
    else if ( cnt_key != 1'b0 )             //flag_key_p出现下降沿后cnt_key才会出现非0值
        cnt_key <= cnt_key + 1'b1;
    else
        cnt_key <= cnt_key;
end
/*-----------------------------------------------------------------------------------------
gen the key_r signal
-----------------------------------------------------------------------------------------*/
always @ ( posedge clk or negedge asy_rst )
begin
    if ( !asy_rst )
        key_r <= 3'b111;                    //按键初始状态为高电平
    else
        key_r <= key;                       //锁存上一时钟周期按键状态
end
/*-----------------------------------------------------------------------------------------
gen the flag_key_p signal
-----------------------------------------------------------------------------------------*/
always @ ( posedge clk or negedge asy_rst )
begin
    if ( !asy_rst )
        flag_key_p <= 3'b000;               //按键下降沿检测初始状态全为0,表示假
    else
        flag_key_p <= key_r & ( ~key );     //脉冲边沿检测
end
/*-----------------------------------------------------------------------------------------
gen the flag_key signal
-----------------------------------------------------------------------------------------*/
always @ ( posedge clk or negedge asy_rst )
begin
    if ( !asy_rst )
        flag_key <= 3'b010;                   //流水灯控制状态初始不流动,若按下流动则从低向高流动
    else if ( cnt_key == 20'd999999 && key == key_p )       //当按键消抖计时加满并且当前key值与20ms前键值相同,
                                                            //则开始改变流水灯控制状态
    begin
        if ( key[0] == 1'b0 )                               //0位,控制是否流动,若按下该状态进行反转
            flag_key[0] <= ~flag_key[0];
        else if ( ~key[1] || ~key[2] )                      //1位,控制从低向高,2位控制从高向低
            flag_key[2:1] <= ~key[2:1];                     //这两位若按下这对flag_key_p高两位进行赋值,此过程中需要对key反转
        else
            flag_key <= flag_key;
    end
    else
        flag_key <= flag_key;
end
/*-----------------------------------------------------------------------------------------
gen the key_p signal
-----------------------------------------------------------------------------------------*/
always @ ( posedge clk or negedge asy_rst )
begin
    if ( !asy_rst )
        key_p <= 3'b111;
    else if ( flag_key_p != 1'b0 )                          //出现按键下降沿对按键状态进行锁存,保持20ms
        key_p <= key_r;
    else
        key_p <= key_p;
end
/*-----------------------------------------------------------------------------------------
gen the cnt_led signal
-----------------------------------------------------------------------------------------*/
always @ ( posedge clk or negedge asy_rst )
begin                                                       //0.5s流水灯
    if ( !asy_rst )
        cnt_led <= 1'b0;
    else if ( cnt_led == 25'd24999999 )
        cnt_led <= 1'b0;
    else
        cnt_led <= cnt_led + 1'b1;
end
/*-----------------------------------------------------------------------------------------
gen the led signal
-----------------------------------------------------------------------------------------*/
always @ ( posedge clk or negedge asy_rst )
begin
    if ( !asy_rst )
        led <= 8'hfe;
    else if ( cnt_led == 25'd24999999 && flag_key[0] == 1'b1 )      //0位,为真,开始流动
    begin
        if ( flag_key[1] == 1'b1 )                      //1位,为真,从低向高
            led <= {led[6:0],led[7]};
        else if ( flag_key [2] == 1'b1)                 //2位,为真,从高向低
            led <= {led[0],led[7:1]};
        else
            led <= led;
    end
    else
        led <= led;
end
assign o_led = led;             //输出寄存器输出
endmodule
这段代码中主要是两个功能
1.使用脉冲边沿检测实现了按键出现下降沿时开始启动消抖计时的功能,并且将初始键值赋值给key_p,用于20ms后与key进行比较看是否20ms前后按键值相同,相同则按键有效,并对flag_key_p进行相应赋值。
2.流水灯根据flag_key的值进行相应流动,这个就太简单了。
虽然程序很简单,但前几天试过一次,不知道是不是那次脑子比较乱,愣是没整理好思路。这次,为了保险起见,我先写了流水灯的部分,然后先写了控制一个按键的代码试试,最后才将多个按键一起控制的代码完善了。至于仿真,这次没做,虽然不符合规范,但这次我也深深深深体会到按功能模块进行代码设计是多么重要,第一次我就是整个过程一起考虑,才成了一锅粥,也肯定有刚开始学,脑子根本转不过来的原因,但我相信,代码看多,写多,自然就好了。

文章评论2条评论)

登录后参与讨论

用户1718548 2013-7-27 15:40

thank you

飞言走笔 2013-7-27 14:20

Verilog? Good!
相关推荐阅读
用户1718548 2013-07-31 14:28
[博客大赛]16位乘法器实验
今天半想半参考的写完了一个16位乘法器,整个过程还算简单,代码最主要的部分就是移位计算的部分。 在写的过程中,最开始的一次移位部分的代码只有 /*-----------------------...
用户1718548 2013-07-27 22:08
VGA实验
今天又试着做了VGA显示实验,虽然回过头来看也是相当简单的,但其中有几个细节还是应该注意的(对我来说。。。。)。 首先,就是行消隐和场消隐的数据宽度,我第一次在网上随便找了一组数据试着写了写,仿...
用户1718548 2013-07-15 23:18
分频引发的折腾
总的来说今天做的相当失败,本来只是想跟着特权的视频实现个简单的分频,熟练下前两天学的,谁知道又是一堆事情。 分频本是实现相当简单,我自信绝对不会有问题,可问题出在了分频结束要让蜂鸣器响,而特权同...
我要评论
2
17
关闭 站长推荐上一条 /2 下一条