热度 19
2013-7-31 14:28
1241 次阅读|
2 个评论
昨天把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 key ,//3位按键,0位控制是否流动,1位控制从低向高,2位控制从高向低 output wire o_led //8位led ); /*---------------------------Internal registers and wires--------------------------------*/ /* Register Output Signals */ reg led; //led输出寄存器 /* internal logic use signals */ reg cnt_key; //按键消抖计时 reg key_r; //上一时钟周期按键状态寄存 reg key_p; //按键消抖时20ms前按键状态寄存 reg flag_key_p; //按键下降沿标志 reg flag_key; //流水灯流动状态 reg 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 == 1'b0 ) //0位,控制是否流动,若按下该状态进行反转 flag_key = ~flag_key ; else if ( ~key || ~key ) //1位,控制从低向高,2位控制从高向低 flag_key = ~key ; //这两位若按下这对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 == 1'b1 ) //0位,为真,开始流动 begin if ( flag_key == 1'b1 ) //1位,为真,从低向高 led = {led ,led }; else if ( flag_key == 1'b1) //2位,为真,从高向低 led = {led ,led }; 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的值进行相应流动,这个就太简单了。 虽然程序很简单,但前几天试过一次,不知道是不是那次脑子比较乱,愣是没整理好思路。这次,为了保险起见,我先写了流水灯的部分,然后先写了控制一个按键的代码试试,最后才将多个按键一起控制的代码完善了。至于仿真,这次没做,虽然不符合规范,但这次我也深深深深体会到按功能模块进行代码设计是多么重要,第一次我就是整个过程一起考虑,才成了一锅粥,也肯定有刚开始学,脑子根本转不过来的原因,但我相信,代码看多,写多,自然就好了。