2011年11月24日木曜日

ナイトライダー風にLEDの光が左右に流れる


by yosikawa » 2011年2月12日(土) 21:08
これまで作ったものは、ボタンなどに反応するものの、動きがない。
操作しなくても動き続けるようなものを作ってみる。

top.v :
コード: 
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    19:43:29 02/12/2011 
// Design Name: 
// Module Name:    top 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
`default_nettype none
module top(clk, led, switch, btn, rotary_a, rotary_b, rotary_press);

   input wire clk;               // グローバルクロック
   input wire [3:0] switch;      // スライドスイッチ
   input wire [3:0] btn;         // プッシュスイッチ (3:north, 2:east, 1:west, 0:south)
   input wire rotary_a;            // ロータリスイッチA接点(アクティブ・ロー)
   input wire rotary_b;            // ロータリスイッチB接点(アクティブ・ロー)
   input wire rotary_press;      // ロータリスイッチ・プッシュ
   output wire [7:0] led;         // LED

   // リセット信号を作る。
   reg [1:0] reset_count;
   always @(posedge clk) begin
      if(&reset_count == 0)
         reset_count <= reset_count + 1;
   end
   wire reset = reset_count[0];   // リセット信号。
   
   // ロータリスイッチのトリガ信号を作る。
   wire rotary_event;            // ロータリスイッチが1段階回転したとき、1パルスだけアクティブになる。
   wire rotary_right;            // rotary_event がアクティブのとき、回転方向を示す。ハイが右方向。
   S3E_Rotary S3E_Rotary(clk, reset, ‾rotary_a, ‾rotary_b, rotary_event, rotary_right);

   // 1KHz の内部クロックを作成する。
   // 分周比 50MHz / 50000 = 1KHz
   parameter integer CLK1MS_SCALE = 50000;   // 分周比
   defparam prescaler1.SCALE = CLK1MS_SCALE;
   wire clk1ms;   // 1ms 内部クロック
   Prescaler prescaler1(
      clk,         // 入力クロック
      reset,   // リセット
      clk1ms      // 分周結果。シングルパルス。
   );
   
   // 10Hz の内部クロックを作成する。
   parameter integer CLK250MS_SCALE = 100;   // 分周比
   defparam prescaler2.SCALE = CLK250MS_SCALE;
   wire clk100ms;   // 100ms 内部クロック
   Prescaler_Enabled prescaler2(clk, reset, clk1ms, clk100ms);

   // ナイトライダーみたいに、左右に動く表示を作成する。
   reg [7:0] led1;
   reg led_dir;      // 動く方向。1:右、0:左
   always @(posedge clk or negedge reset) begin
      if(!reset) begin
         led1 <= 8'd1;
         led_dir <= 0;
      end else if(clk100ms) begin
         if(led_dir) begin
            // 右に動く
            if(led1[0]) begin
               led_dir <= 0;
            end else begin
               led1 <= { 1'b0, led1[7:1] };
            end
         end else begin
            // 左に動く
            if(led1[7]) begin
               led_dir <= 1;
            end else begin
               led1 <= { led1[6:0], 1'b0 };
            end
         end
      end else if(rotary_event) begin
         if(rotary_right) begin
            led1 <= { led1[0], led1[7:1] };
         end else begin
            led1 <= { led1[6:0], led1[7] };
         end
      end
   end

   // ボタンが押された部分は反転する。
   wire [7:0] led2 = { btn, switch };
   wire [7:0] led3 = led1 ^ led2;
   assign led = rotary_press ? ‾led3 : led3;

endmodule


Prescaler.v :
コード: 
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    11:17:49 02/07/2011 
// Design Name: 
// Module Name:    Prescaler 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
`default_nettype none
module Prescaler(
   input wire clk,         // 入力クロック
   input wire reset,         // リセット
   output reg prescaled   // 分周結果。シングルパルス。
   );

   parameter integer SCALE = 2;   // 分周比。最低2。

   function integer get_width(input integer value);
      integer v2;
      begin
         v2 = value;
         for(get_width = 0; v2 > 0; get_width = get_width + 1) begin
            v2 = v2 >> 1;
         end
      end
   endfunction

   parameter count_width = get_width(SCALE - 1);
   reg [count_width - 1:0] count;
   
   always @(posedge clk or negedge reset) begin
      if(!reset) begin
         count <= 0;
         prescaled <= 0;
      end else if(count == (SCALE - 1'b1)) begin
         count <= 0;
         prescaled <= 1;
      end else begin
         count <= count + 1;
         prescaled <= 0;
      end
   end

endmodule


Prescaler_Enabled.v :
コード: 
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    17:28:51 02/08/2011 
// Design Name: 
// Module Name:    Prescaler_Enabled 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
`default_nettype none
module Prescaler_Enabled(
   input wire clk,         // 入力クロック
   input wire reset,         // リセット
   input wire enable,      // 分周元信号。1パルスだけアクティブになる信号でなければならない。
   output reg prescaled   // 分周結果。シングルパルス。
   );

   parameter integer SCALE = 2;   // 分周比。最低2。

   function integer get_width(input integer value);
      integer v2;
      begin
         v2 = value;
         for(get_width = 0; v2 > 0; get_width = get_width + 1) begin
            v2 = v2 >> 1;
         end
      end
   endfunction

   parameter count_width = get_width(SCALE - 1);
   reg [count_width - 1:0] count;
   
   always @(posedge clk or negedge reset) begin
      if(!reset) begin
         count <= 0;
         prescaled <= 0;
      end else if(enable) begin
         if(count == (SCALE - 1'b1)) begin
            count <= 0;
            prescaled <= 1;
         end else begin
            count <= count + 1;
            prescaled <= 0;
         end
      end else begin
         prescaled <= 0;
      end
   end

endmodule

0 件のコメント:

コメントを投稿