2019.9.1
前へ
次へ
ホームページトップへ戻る

[新連載]CPLD入門!
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
いつか使うことになるだろうと思ってはいたのですが。
何を今頃になって、というようなものですが。
ようやく本気で、CPLDと四つに取り組みます。
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜



[第104回]


●デジタル時計プログラム

もう9月になってしまいました。
相変わらず多忙な毎日です。
日々能力の低下を嘆いています。

さて今回はサンプルプログラムのデジタル時計プログラムです。
前回もそうでしたが今回は前回のプログラムよりももっと長くなってしまいました。
下がソースプログラムリストです。

----cpld training 19/5/25 5/26 5/27 5/28 5/29
--5/31 8/21 8/22
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library ARITHMETIC;
use ARITHMETIC.std_logic_arith.all;

entity trngwatch1c is
PORT (
--              T27:out std_logic;
--              T29:out std_logic;
                SEGOUT:out std_logic_vector(7 downto 0);
                LEDOUT:out std_logic_vector(3 downto 0);
                CK1:in std_logic;
--              CK2:in std_logic;
--              CK3:in std_logic;
                SWA:in std_logic;
                SWB:in std_logic;
                SWC:in std_logic;
--              ADRSIN:in std_logic_vector(7 downto 0);
--              DINOUT:inout std_logic_vector(7 downto 0);
                PA:out std_logic_vector(7 downto 0);
                PB:out std_logic_vector(7 downto 0);
                PCL:in std_logic_vector(3 downto 0);
                PCH:in std_logic_vector(3 downto 0)
                );
--              IOR:in std_logic;
--              IOW:in std_logic);
end trngwatch1c;

architecture rtl of trngwatch1c is
        signal cntr1:std_logic_vector(11 downto 0);--1khz 4096=2**12
        signal tm1:std_logic_vector(3 downto 0);--1/1000 sec
        signal cntrss0:std_logic_vector(3 downto 0);--1/100 sec
        signal cntrss1:std_logic_vector(3 downto 0);--1/10 sec
        signal leddatabf0:std_logic_vector(3 downto 0);
        signal leddatabf1:std_logic_vector(3 downto 0);
        signal leddatabf2:std_logic_vector(3 downto 0);
        signal leddatabf3:std_logic_vector(3 downto 0);
        signal leddatawk:std_logic_vector(3 downto 0);
        signal segdata:std_logic_vector(7 downto 0);
        signal ledoutbf:std_logic_vector(3 downto 0);
        signal ledcntr:std_logic_vector(2 downto 0);
        signal ledadrs:std_logic_vector(2 downto 0);
        signal cntrs0:std_logic_vector(3 downto 0);
        signal cntrs1:std_logic_vector(2 downto 0);
        signal cntrm0:std_logic_vector(3 downto 0);
        signal cntrm1:std_logic_vector(2 downto 0);
        signal cntrh:std_logic_vector(5 downto 0);
        --signal cntrh1:std_logic_vector(1 downto 0);
        signal tm0:std_logic;
        signal cntrm0ck:std_logic;
        signal cntrm1ck:std_logic;
        signal cntrhck:std_logic;
--
begin
PA<=cntrss1 & cntrss0;
PB<='0' & cntrs1 & cntrs0;
-- 7seg drive clock 1KHz from 4096KHz
process(CK1)
begin
        if CK1'event and CK1='1' then
                cntr1<=cntr1+"000000000001";
        end if;
end process;
-- led drive,LEDOUT
process(cntr1)
begin
        if cntr1(11)'event and cntr1(11)='0' then
                ledcntr<=ledcntr+"001";
                ledoutbf<=ledoutbf(2 downto 0) & '0';
        end if;
        if ledcntr(2)='1' then
                ledcntr<="000";
                ledoutbf<="0001";
        end if;
end process;
--
                LEDOUT<=ledoutbf;
                SEGOUT<=segdata;

-- led data out
process(ledcntr)
begin
        if ledcntr(1 downto 0)="00" then
                leddatawk<=leddatabf0;
        elsif ledcntr(1 downto 0)="01" then
                leddatawk<=leddatabf1;
        elsif ledcntr(1 downto 0)="10" then
                leddatawk<=leddatabf2;
        elsif ledcntr(1 downto 0)="11" then
                leddatawk<=leddatabf3;
        end if;
end process;
--segment change
process(leddatawk)
begin
        if leddatawk="0000" then
                segdata<="01011100";
        elsif leddatawk="0001" then
                segdata<="00000110";
        elsif leddatawk="0010" then
                segdata<="01011011";
        elsif leddatawk="0011" then
                segdata<="01001111";
        elsif leddatawk="0100" then
                segdata<="01100110";
        elsif leddatawk="0101" then
                segdata<="01101101";
        elsif leddatawk="0110" then
                segdata<="01111101";
        elsif leddatawk="0111" then
                segdata<="00000111";
        elsif leddatawk="1000" then
                segdata<="01111111";
        elsif leddatawk="1001" then
                segdata<="01101111";
        end if;
end process;
--
-- ******* watch ******
--
                tm0<=cntr1(11);
--1/1000
process(tm0)
begin
        if tm0'event and tm0='0' then
                tm1<=tm1+"0001";
        end if;
        if tm1="1010" then
                tm1<="0000";
        end if;
end process;
-- 1/100sec
process(tm1(3))
begin
        if tm1(3)'event and tm1(3)='0' then
                cntrss0<=cntrss0+"0001";
        end if;
        if cntrss0="1010" then
                cntrss0<="0000";
        end if;
end process;
--
--1/10sec
process(cntrss0(3))
begin
        if cntrss0(3)'event and cntrss0(3)='0' then
                cntrss1<=cntrss1+"001";
        end if;
        if cntrss1="1010" then
                cntrss1<="0000";
                end if;
end process;
--secondL
process(cntrss1(3),SWA,SWB,SWC)
begin
        if cntrss1(3)'event and cntrss1(3)='0' then
                cntrs0<=cntrs0+"0001";
        end if;
        if cntrs0="1010" or SWA='0' or SWB='0' or SWC='0' then
                cntrs0<="0000";
        end if;
end process;
--secondH
process(cntrs0(3),SWA,SWB,SWC)
begin
        if cntrs0(3)'event and cntrs0(3)='0' then
                cntrs1<=cntrs1+"001";
        end if;
        if cntrs1="110" or SWA='0' or SWB='0' or SWC='0' then
                cntrs1<="000";
                end if;
end process;
--swcon set(every 1 second)
--select counterm0 clock
process(SWC,cntrs1(2),cntrss1(3))
begin
        if SWC='0' then
                cntrm0ck<=cntrss1(3);-- if SWC on,then count up every 1 sec
        else
                cntrm0ck<=cntrs1(2);
        end if;
end process;
process(cntrm0ck)
begin
        if cntrm0ck'event and cntrm0ck='0' then
                cntrm0<=cntrm0+"0001";
        end if;
        if cntrm0="1010" then
                cntrm0<="0000";
        end if;
end process;
--minuteH
--swbon set(every 1 second)
--select counterm1 clock
process(SWB,cntrm0(3),cntrss1(3))
begin
        if SWB='0' then
                cntrm1ck<=cntrss1(3);-- if SWB on,then count up every 1 sec
        else
                cntrm1ck<=cntrm0(3);
        end if;
end process;
--
process(cntrm1ck,SWC)
begin
        if cntrm1ck'event and cntrm1ck='0' and SWC='1' then
                cntrm1<=cntrm1+"001";
        end if;
        if cntrm1="110" then
                cntrm1<="000";
        end if;
end process;
--hour
--swaon set(every 1 second)
--select counterh clock
process(SWA,cntrm1(2),cntrss1(3))
begin
        if SWA='0' then
                cntrhck<=cntrss1(3);-- if SWA on,then count up every 1 sec
        else
                cntrhck<=cntrm1(2);
        end if;
end process;
--
process(cntrhck,SWB)
begin
        if cntrhck'event and cntrhck='0' and SWB='1' then
                cntrh<=cntrh+"000001";
        end if;
        if cntrh(3 downto 0)="1010" then
                cntrh(3 downto 0)<="0000";
                cntrh(5 downto 4)<=cntrh(5 downto 4)+"01";
        elsif cntrh="100100" then
                cntrh<="000000";
        end if;
end process;
--7seg disp select
--HHMM or MMSS
process(PCL,cntrss0,cntrss1,cntrs0,cntrs1,cntrm0,cntrm1)
begin
        if PCL(0)='0' then
                leddatabf3<=cntrss0;
                leddatabf2<=cntrss1;
                leddatabf1<=cntrs0;
                leddatabf0<='0' & cntrs1;
        elsif PCL(1)='0' then
                leddatabf3<=cntrs0;
                leddatabf2<='0' & cntrs1;
                leddatabf1<=cntrm0;
                leddatabf0<='0' & cntrm1;
        else
                leddatabf3<=cntrm0;
                leddatabf2<='0' & cntrm1;
                leddatabf1<=cntrh(3 downto 0);
                leddatabf0<="00" & cntrh(5 downto 4);
        end if;
end process;
--
end rtl;


プログラムの説明です。
今までに説明した内容と同じか、それに近い内容のプログラム部分については説明を省きます。

最初のところでこんなことをやっています。

PA<=cntrss1 & cntrss0;
PB<='0' & cntrs1 & cntrs0;


こうすることに特別の意味はありません。
7セグメントLEDのほかに8ビットをビットごとに表示できるLEDがありますから、そこに1/100秒、1/10秒、1秒、10秒の位の表示をさせています。
簡単なモニタのつもりです。
実際には1/100秒は速いので全部点灯して見えます。
1/10秒から上ならカウントアップしている様子をモニタすることができます。

そこから
-- ******* watch ****** --
までのところは[第102回]で説明した7セグメントLED表示のところと同じですから説明は省きます。
その次からが時計の処理プログラムなのですが、最初の1/1000秒〜1/10秒のところも、すでに説明済みですからそこも説明を省きます。

その次は1秒と10秒の位のカウント処理です。
ここはちょっと余計なことをしています。

--secondL
process(cntrss1(3),SWA,SWB,SWC)
begin
        if cntrss1(3)'event and cntrss1(3)='0' then
                cntrs0<=cntrs0+"0001";
        end if;
        if cntrs0="1010" or SWA='0' or SWB='0' or SWC='0' then
                cntrs0<="0000";
        end if;
end process;
--secondH
process(cntrs0(3),SWA,SWB,SWC)
begin
        if cntrs0(3)'event and cntrs0(3)='0' then
                cntrs1<=cntrs1+"001";
        end if;
        if cntrs1="110" or SWA='0' or SWB='0' or SWC='0' then
                cntrs1<="000";
                end if;
end process;


前半部分の1秒のカウンタが10秒になるごとに0にクリアされることと、後半の10秒のカウンタが6になると0クリアされることは納得できると思います。
0クリアするところにSWA〜SWCがからんでいます。
実はプッシュスイッチA〜Cは時刻の初期設定のために使っています。
サンプルプログラムですからできるだけシンプルな動作になるように考えました。
ですから時刻の初期設定は時分のみで秒については考えないことにしました。
A〜Cのスイッチを押すことで時刻の設定を行ないますが、いずれかのスイッチが押されるたびに秒カウンタを0にクリアすることで時刻の設定を行なうときは常に秒のところは00秒に設定されることになります。

その次のところからが、時刻の初期設定のところなのですが、説明が長くなってしまいますので、今回はここまでにします。
続きは次回にいたします。

CPLD入門![第104回]
2019.9.1upload

前へ
次へ
ホームページトップへ戻る