記事一覧

24進カウンタをつくる

2013年06月14日(金)14時53分

24進カウンタをつくってみます。

厄介なのは1桁目の動作ですね。

すなわち、
2桁目が0,1の場合、9までカウントアップして繰り上がり
2桁目が2の場合、3までカウントアップして繰り上がり
です。

この見方を逆にして、
1桁目は、
1桁目の繰り上がりがある場合、0になり、
1桁目の繰り上がりがない場合、カウントアップする

1桁目の繰り上がりは、
1桁目が9の場合と、
2桁目の繰り上がりがある場合
です。

つまり、繰り上がりをうまく利用すれば、簡単になりそうです。

こんなことができるのは、同時処理*1だからです。

Aの定義の中にBがあり、
Bの定義の中にAがある。

こんな禅問答のような処理ができるのです。

-- 24 Counter with CARRYOUT, Async RESET, and Enable
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity COUNTER24 is
    port(
        CLK      : in  std_logic;    -- 33MHz
        RESET    : in  std_logic;
        ENABLE   : in  std_logic;
        LED_7SEG1: out std_logic_vector(7 downto 0);
        LED_7SEG2: out std_logic_vector(7 downto 0);
        CARRYOUT : out std_logic
    );
end COUNTER24;

architecture RTL of COUNTER24 is
signal DIV_COUNTER : std_logic_vector(24 downto 0);
signal DIV_CLK     : std_logic;
signal COUNT1 : std_logic_vector(3 downto 0);
signal COUNT2 : std_logic_vector(3 downto 0);
signal CARRY1 : std_logic;
signal CARRY2 : std_logic;

begin
    -- CLK
    process(CLK,RESET)
   begin
        if (RESET = '0') then
            DIV_COUNTER <= (others => '0');
        elsif (CLK'event and CLK = '0') then
            DIV_COUNTER <= DIV_COUNTER + 1;
        end if;
    end process;
    
   DIV_CLK <= not DIV_COUNTER(23);    -- 2Hz:(23)
                                      -- 1Hz:(24) 4Hz:(22) 8Hz:(21)...

    -- 24Counter
    -- Count 1digit : COUNT1
    process(DIV_CLK,RESET)
    begin
        if (RESET = '0') then
            COUNT1 <= (others => '0');
        elsif (DIV_CLK'event and DIV_CLK = '0') then
            if (ENABLE = '1') then
                if (CARRY1 = '1') then
                    COUNT1 <= (others => '0');
                else
                    COUNT1 <= COUNT1 + 1;
                end if;
            end if;
        end if;
    end process;

    -- Count 2digit : COUNT2
    process(DIV_CLK,RESET)
    begin
        if (RESET = '0') then
            COUNT2 <= (others => '0');
        elsif (DIV_CLK'event and DIV_CLK = '0') then
            if (ENABLE = '1') then    
                if (CARRY1 = '1') then
                    if (COUNT2 = "0010") then
                        COUNT2 <= (others => '0');
                    else
                        COUNT2 <= COUNT2 + 1;
                    end if;
                end if;
            end if;
        end if;
    end process;

    -- Carry from 1digit : CARRY1
    process(COUNT1,CARRY2)
    begin
        if (COUNT1 = "1001" or CARRY2 = '1') then
            CARRY1 <= '1';
        else
            CARRY1 <= '0';
        end if;
    end process;

    -- Carry from 2digit : CARRY2
    process(COUNT1, COUNT2)
    begin
        if (COUNT1 = "0011" and COUNT2 = "0010") then
            CARRY2 <= '1';
        else
            CARRY2 <= '0';
        end if;
    end process;
    
    CARRYOUT <= CARRY2;
    
    -- End 24Counter

    -- 7seg LED Decoder
   process(COUNT1)
   begin
      case COUNT1 is
         when "0000" => LED_7SEG1 <= "00000011"; -- 0
         when "0001" => LED_7SEG1 <= "10011111"; -- 1
         when "0010" => LED_7SEG1 <= "00100101"; -- 2
         when "0011" => LED_7SEG1 <= "00001101"; -- 3
         when "0100" => LED_7SEG1 <= "10011001"; -- 4
         when "0101" => LED_7SEG1 <= "01001001"; -- 5
         when "0110" => LED_7SEG1 <= "01000001"; -- 6
         when "0111" => LED_7SEG1 <= "00011111"; -- 7
         when "1000" => LED_7SEG1 <= "00000001"; -- 8
         when "1001" => LED_7SEG1 <= "00001001"; -- 9
         when others => LED_7SEG1 <= "01100001"; -- E
      end case;
   end process;

   process(COUNT2)
   begin
      case COUNT2 is
         when "0000" => LED_7SEG2 <= "00000011"; -- 0
         when "0001" => LED_7SEG2 <= "10011111"; -- 1
         when "0010" => LED_7SEG2 <= "00100101"; -- 2
         when "0011" => LED_7SEG2 <= "00001101"; -- 3
         when "0100" => LED_7SEG2 <= "10011001"; -- 4
         when "0101" => LED_7SEG2 <= "01001001"; -- 5
         when "0110" => LED_7SEG2 <= "01000001"; -- 6
         when "0111" => LED_7SEG2 <= "00011111"; -- 7
         when "1000" => LED_7SEG2 <= "00000001"; -- 8
         when "1001" => LED_7SEG2 <= "00001001"; -- 9
         when others => LED_7SEG2 <= "01100001"; -- E
      end case;
   end process;
    -- End 7seg LED Decoder

end RTL;

*1:今まで何気にコードを書いてましたが、説明してないですね。(^_^;)そのうち、書きます。書こうかな。たぶん。いつか。そのうち

60進カウンタをつくる

2013年06月14日(金)11時59分

60進カウンタをつくってみます。

少し工夫が必要なのは、10の桁が 0 1 2 3 4 5 0 1 2... となることと、そのタイミングです。

単純に

if (DIV_CLK'event and DIV_CLK = '0') then
    if (COUNT2 = "0101") then
        COUNT2 <= (others => '0');
    else
        COUNT2 <= COUNT2 + 1;
    end if;
end if;

ではダメで、
1.1桁目が9の時、つまり繰り上がりが発生したときにカウントアップし、
2.5の次を0にする
必要があります。

Enable信号(入力)を入れました。Enable信号が入っているときのみ、カウントします。
つまり、カウントしたり、止めたりできます。

また、拡張性の為、60カウントした時の繰り上がりも入れています。

似たようなコードを何回も書くのも、いい加減疲れて来ました。
そろそろ、階層設計*1で書いた方がいいですね。

-- 60 Counter with Sync RESET
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity COUNTER60 is
    port(
        CLK      : in  std_logic;
        RESET    : in  std_logic;
        ENABLE   : in  std_logic;
        LED_7SEG1: out std_logic_vector(7 downto 0);
        LED_7SEG2: out std_logic_vector(7 downto 0);
        CARRYOUT : out std_logic
    );
end COUNTER60;

architecture RTL of COUNTER60 is
signal DIV_COUNTER : std_logic_vector(24 downto 0);
signal DIV_CLK     : std_logic;
signal COUNT1 : std_logic_vector(3 downto 0);
signal COUNT2 : std_logic_vector(3 downto 0);
signal CARRY  : std_logic;

begin

    -- CLK
    process(CLK,RESET)
    begin
        if (RESET = '0') then
            DIV_COUNTER <= (others => '0');
        elsif (CLK'event and CLK = '0') then
            DIV_COUNTER <= DIV_COUNTER + 1;
        end if;
    end process;
    
    DIV_CLK <= not DIV_COUNTER(23);    -- 2Hz:(23)
                                      -- 1Hz:(24) 4Hz:(22) 8Hz:(21)...
    
    -- 10Counter with AsyncReset
    process(DIV_CLK,RESET)
    begin
        if (RESET = '0') then
            COUNT1 <= (others => '0');
        elsif (DIV_CLK'event and DIV_CLK='0') then
            if (ENABLE = '1') then
                if (COUNT1 = "1001") then
                    COUNT1 <= (others => '0');
                else
                    COUNT1 <= COUNT1 + 1;
                end if;
            end if;
        end if;
    end process;

    -- Carry from 1digit
    process(COUNT1)
    begin
        if (COUNT1 = "1001" and ENABLE = '1') then
            CARRY <= '1';
        else
            CARRY <= '0';
        end if;
    end process;
    
    -- 6Counter with AsyncReset
    process(DIV_CLK,RESET)
    begin
        if (RESET = '0') then
            COUNT2 <= (others => '0');
        elsif (DIV_CLK'event and DIV_CLK = '0') then
            if (CARRY = '1' and ENABLE = '1') then
                if (COUNT2 = "0101") then
                    COUNT2 <= (others => '0');
                else
                    COUNT2 <= COUNT2 + 1;
                end if;
            end if;
        end if;
    end process;
    
    -- Carry from 2digit
    process(COUNT1,COUNT2)
    begin
        if (COUNT1 = "1001" and COUNT2 = "0101" and ENABLE = '1') then
            CARRYOUT <= '1';
        else
            CARRYOUT <= '0';
        end if;
    end process;
    
    -- 7seg LED Decoder
    process(COUNT1)
    begin
        case COUNT1 is
            when "0000" => LED_7SEG1 <= "00000011"; -- 0
            when "0001" => LED_7SEG1 <= "10011111"; -- 1
            when "0010" => LED_7SEG1 <= "00100101"; -- 2
            when "0011" => LED_7SEG1 <= "00001101"; -- 3
            when "0100" => LED_7SEG1 <= "10011001"; -- 4
            when "0101" => LED_7SEG1 <= "01001001"; -- 5
            when "0110" => LED_7SEG1 <= "01000001"; -- 6
            when "0111" => LED_7SEG1 <= "00011111"; -- 7
            when "1000" => LED_7SEG1 <= "00000001"; -- 8
            when "1001" => LED_7SEG1 <= "00001001"; -- 9
            when others => LED_7SEG1 <= "01100001"; -- E
        end case;
    end process;

    process(COUNT2)
    begin
        case COUNT2 is
            when "0000" => LED_7SEG2 <= "00000011"; -- 0
            when "0001" => LED_7SEG2 <= "10011111"; -- 1
            when "0010" => LED_7SEG2 <= "00100101"; -- 2
            when "0011" => LED_7SEG2 <= "00001101"; -- 3
            when "0100" => LED_7SEG2 <= "10011001"; -- 4
            when "0101" => LED_7SEG2 <= "01001001"; -- 5
            when "0110" => LED_7SEG2 <= "01000001"; -- 6
            when "0111" => LED_7SEG2 <= "00011111"; -- 7
            when "1000" => LED_7SEG2 <= "00000001"; -- 8
            when "1001" => LED_7SEG2 <= "00001001"; -- 9
            when others => LED_7SEG2 <= "01100001"; -- E
        end case;
    end process;

end RTL;

*1:なんの前触れもなく、階層設計で書くかもしれません(^_^;)