kivantium活動日記

プログラムを使っていろいろやります

FPGAでデジタル時計を作った話

学校の課題でFPGAを使ってデジタル時計を作りました。成績が出たので記事にします。

機能と動作している様子は以下の動画を見てください
www.youtube.com

以下ソースコードです。
回路図もコメントも無くて大変不親切なのですが、回路図を起こすのが面倒という身勝手な理由でソースコードだけ貼って終わりにします。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Clock is
  Port ( A : out  STD_LOGIC_VECTOR (15 downto 0);
         B : out  STD_LOGIC_VECTOR (15 downto 0);
         C : inout  STD_LOGIC_VECTOR (15 downto 0);
         clk : in STD_LOGIC);
end Clock;

architecture Behavioral of Clock is
  signal counter : STD_LOGIC_VECTOR(24 downto 0) := (others => '0');
  signal counter2 : STD_LOGIC_VECTOR(14 downto 0) := (others => '0');
  signal dot : STD_LOGIC := '0';
  signal clk_blink : STD_LOGIC := '0';
  signal isSetmode : STD_LOGIC := '0';
  signal set_sw : STD_LOGIC := '0';
  signal set_sw_before : STD_LOGIC := '0';
  signal up_sw : STD_LOGIC := '0';
  signal up_sw_before : STD_LOGIC := '0';
  signal down_sw : STD_LOGIC := '0';
  signal down_sw_before : STD_LOGIC := '0';
  signal sec : STD_LOGIC_VECTOR(5 downto 0) := "000000";
  signal digit : STD_LOGIC_VECTOR(1 downto 0) := "00";
  signal config_digit : STD_LOGIC_VECTOR(1 downto 0) := "00";
  signal number : STD_LOGIC_VECTOR(3 downto 0) := "0000";
  signal min01 : STD_LOGIC_VECTOR(3 downto 0) := "0000";
  signal min10 : STD_LOGIC_VECTOR(3 downto 0) := "0000";
  signal hour01 : STD_LOGIC_VECTOR(3 downto 0) := "0000";
  signal hour10 : STD_LOGIC_VECTOR(3 downto 0) := "0000";
  
begin
  A <= "0000000000000000";
  B <= "0000000000000000";
  C(1) <= '1';
  set_sw <= (not C(0)) and set_sw_before;
  up_sw <= (not C(14)) and up_sw_before;
  down_sw <= (not C(15)) and down_sw_before;
  process(clk) begin
    if rising_edge(clk) then      
      if counter /= "1111010000100100000000000" then
        counter <= counter+1;
      else
        counter <= "0000000000000000000000000";
        dot <= not dot;
        if isSetmode='0' then
          if sec /= "111011" then
            sec <= sec + 1;
          else
            sec <= "000000";
            if min01 /= "1001" then
              min01 <= min01 + 1;
            else
              min01 <= "0000";
              if min10 /= "0101" then
                min10 <= min10 + 1;
              else
                min10 <= "0000";
                if hour10="0010" and hour01="0011" then
                  hour01 <= "0000";
                  hour10 <= "0000";
                else
                  if hour01 /= "0101" then
                    hour01 <= hour01 + 1;
                  else
                    hour01 <= "0000";
                    hour10 <= hour10 + 1;
                  end if;
                end if;
              end if;
            end if;
          end if;
        end if;
      end if;
      if counter(23 downto 0) = "111010000100100000000000" then
        clk_blink <= not clk_blink;
      end if;
      counter2 <= counter2 + 1;
      if counter2 = "111110100000000" then
        counter2 <= "000000000000000";
        set_sw_before <= C(0);
        if set_sw = '1' then
          if isSetmode = '0' then
            isSetmode <= '1';
            config_digit <= "00";
          else
            case config_digit is
              when "00" => 
                config_digit <= "10";
                if hour10 = "0010" and hour01 >= "0100" then
                  hour01 <= "0000";
                end if;
              when "10" =>
                config_digit <= "11";
              when "11" =>
                config_digit <= "01";
              when "01" =>
                isSetmode <= '0';
                sec <= "000000";
                counter <= "0000000000000000000000000";
              when others =>
                null;
            end case;
          end if;
        end if;
        up_sw_before <= C(14);
        if up_sw = '1' and isSetmode='1' then
          case config_digit is
            when "01" =>
              if min01 = "1001" then
                min01 <= "0000";
              else
                min01 <= min01 + 1;
              end if;
            when "11" =>
              if min10 = "0101" then
                min10 <= "0000";
              else
                min10 <= min10 + 1;
              end if;
            when "10" =>
              if hour10 = "0010" then
                if hour01 = "0011" then
                  hour01 <= "0000";
                else
                  hour01 <= hour01 + 1;
                end if;
              else
                if hour01 = "1001" then
                  hour01 <= "0000";
                else
                  hour01 <= hour01 + 1;
                end if;
              end if;
            when "00" =>
              if hour10 = "0010" then
                hour10 <= "0000";
              else
                hour10 <= hour10 + 1;
              end if;
            when others =>
              null;
          end case;
        end if;
        down_sw_before <= C(15);
        if down_sw = '1' and isSetmode = '1' then
          case config_digit is
            when "01" =>
              if min01 = "0000" then
                min01 <= "1001";
              else
                min01 <= min01 - 1;
              end if;
            when "11" =>
              if min10 = "0000" then
                min10 <= "0101";
              else
                min10 <= min10 - 1;
              end if;
            when "10" =>
              if hour10 = "0010" then
                if hour01 = "0000" then
                  hour01 <= "0011";
                else
                  hour01 <= hour01 - 1;
                end if;
              else
                if hour01 = "0000" then
                  hour01 <= "1001";
                else
                  hour01 <= hour01 - 1;
                end if;
              end if;
            when "00" =>
              if hour10 = "0000" then
                hour10 <= "0010";
              else
                hour10 <= hour10 - 1;
              end if;
            when others =>
              null;
          end case;
        end if;
        case digit is
          when "00" =>
            number <= hour10;
            digit <= "10";
            if (isSetmode='0' and hour10="0000") or (isSetmode='1' and clk_blink='0' and config_digit="00") then
              C(2)<='0';
            else
              C(2)<='1';
            end if;
            C(11)<='0'; C(12)<='0'; C(10)<='0';
            C(7) <= '1';
          when "10" =>
            number <= hour01;
            digit <= "11";
            if isSetmode='1' and clk_blink='0' and config_digit="10" then
              C(11) <= '0';
            else
              C(11) <= '1';
            end if;
            C(2)<='0'; C(12)<='0'; C(10)<='0';
            C(7) <= '1';
          when "11" =>
            number <= min10;
            digit <= "01";
            if (isSetmode='0' and min10="0000") or (isSetmode='1' and clk_blink='0' and config_digit="11") then
              C(12)<='0';
            else
              C(12)<='1';
            end if;
            C(2)<='0'; C(11)<='0'; C(10)<='0';
            C(7) <= '1';
          when "01" =>
            number <= min01;
            digit <= "00";
            if isSetmode='1' and clk_blink='0' and config_digit="01" then
              C(10) <= '0';
            else
              C(10) <= '1';
            end if;
            C(2)<='0'; C(11)<='0'; C(12)<='0';
            C(7) <= dot;
          when others =>
            null;
        end case;
      end if;
      case number is
        when "0000"  =>
          C(3)<='0'; C(13)<= '0'; C(8)<='0'; C(6)<='0';
          C(5)<='0'; C(4)<='0'; C(9)<='1';
        when "0001"  =>
          C(3)<='1'; C(13)<= '0'; C(8)<='0'; C(6)<='1';
          C(5)<='1'; C(4)<='1'; C(9)<='1';
        when "0010"  =>
          C(3)<='0'; C(13)<= '0'; C(8)<='1'; C(6)<='0';
          C(5)<='0'; C(4)<='1'; C(9)<='0';
        when "0011"  =>
          C(3)<='0'; C(13)<= '0'; C(8)<='0'; C(6)<='0';
          C(5)<='1'; C(4)<='1'; C(9)<='0';
        when "0100"  =>
          C(3)<='1'; C(13)<= '0'; C(8)<='0'; C(6)<='1';
          C(5)<='1'; C(4)<='0'; C(9)<='0';
        when "0101"  =>
          C(3)<='0'; C(13)<= '1'; C(8)<='0'; C(6)<='0';
          C(5)<='1'; C(4)<='0'; C(9)<='0';
        when "0110"  =>
          C(3)<='0'; C(13)<= '1'; C(8)<='0'; C(6)<='0';
          C(5)<='0'; C(4)<='0'; C(9)<='0';
        when "0111"  =>
          C(3)<='0'; C(13)<= '0'; C(8)<='0'; C(6)<='1';
          C(5)<='1'; C(4)<='0'; C(9)<='1';
        when "1000"  =>
          C(3)<='0'; C(13)<= '0'; C(8)<='0'; C(6)<='0';
          C(5)<='0'; C(4)<='0'; C(9)<='0';
        when "1001"  =>
          C(3)<='0'; C(13)<= '0'; C(8)<='0'; C(6)<='0';
          C(5)<='1'; C(4)<='0'; C(9)<='0';
        when others =>
          C(3)<='1'; C(13)<= '1'; C(8)<='1'; C(6)<='1';
          C(5)<='1'; C(4)<='1'; C(9)<='1';
      end case;
    end if;
  end process;
end Behavioral;