一、Code
module johnson( // input input clk_50, input rst_n, input key3,key2,key1, // output output[17:0] ledr ); //parameter ledr_dir = 1'b0; //1'b1--right,1'b0--left //parameter ledr_on = 1'b1; //1'b1--on,1'b0--off reg ledr_dir; //1'b1--right,1'b0--left reg ledr_on; //1'b1--on,1'b0--off //-------------------------------------------- reg[21:0] cnt22; always@(posedge clk_50 or negedge rst_n) if(!rst_n) cnt22 <= 22'd0; else cnt22 <= cnt22 + 1'b1; //-------------------------------------------- reg[17:0] ledr_r; always@(posedge clk_50 or negedge rst_n) if(!rst_n) ledr_r <= 18'b00_0000_0000_0000_0001; else if(cnt22==22'h3fffff && ledr_on) begin if(ledr_dir) ledr_r <= {ledr_r[0],ledr_r[17:1]}; //right else ledr_r <= {ledr_r[16:0],ledr_r[17]}; //left end assign ledr = ledr_r; //-------------------------------------------- reg[2:0] key_rst; always@(posedge clk_50 or negedge rst_n) if(!rst_n) key_rst <= 3'b111; else key_rst <= {key3,key2,key1}; reg[2:0] key_rst_r; always@(posedge clk_50 or negedge rst_n) if(!rst_n) key_rst_r <= 3'b111; else key_rst_r <= key_rst; wire[2:0] key_an; //当寄存器key_rst由1变为0时,key_an的值变为高,维持一个时钟周期 assign 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_rst一个时钟周期 key_an 0 0 1 0 0 //由此可以发现当key_rst的一个周期由1变为0时,key_an由0变为1; */ reg[19:0] cnt; //20ns一周期,20ms为10的6次方,相当于2的20次方=1024x1024>1000x1000; always@(posedge clk_50 or negedge rst_n) if(!rst_n) cnt <= 20'b0; else if(key_an) cnt <= 20'b0; else cnt <= cnt+1'b1; reg[2:0] low_key; always@(posedge clk_50 or negedge rst_n) if(!rst_n) low_key <= 3'b111; else if(cnt==20'hfffff) //满20ms,将按键值锁存到寄存器low_key中 low_key <= {key3,key2,key1}; reg[2:0] low_key_r; //每个时钟的上升沿将low_key信号锁存到low_key_r中 always@(posedge clk_50 or negedge rst_n) if(!rst_n) low_key_r <= 3'b111; else low_key_r <= low_key; wire[2:0] led_ctrl; //当寄存器low_key由1变为0时,led_ctrl的值变高,维持一个时钟周期 /* low_sw 111 111 111 110 110 110 ~low_sw 000 000 000 001 001 001 low_sw_r 111 111 111 110 110 110 led_ctrl 000 000 000 001 000 000 */ assign led_ctrl = low_key_r[2:0] & (~low_key[2:0]); always@(posedge clk_50 or negedge rst_n) if(!rst_n) begin ledr_dir = 1'b0; ledr_on = 1'b0; end else begin if(led_ctrl[2]) ledr_dir <= 1'b1; //led翻转输出 if(led_ctrl[1]) ledr_dir <= 1'b0; if(led_ctrl[0]) ledr_on <= ~ledr_on; end endmodule