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

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



[第102回]


●プッシュスイッチカウントプログラム

サンプルプログラムですから簡単なプログラムを…。
というつもりだったのですが、結構長いプログラムになってしまいました。
7セグメントLEDはダイナミックドライブで表示を行なっています。
ダイナミックドライブは出力端子が少なくて済むというメリットがあるのですが、その分プログラムが複雑になってしまいます。
下がプッシュスイッチカウントプログラムのソースプログラムリストです。

--cpld training swin-counter
--19/5/31 8/22
--
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library ARITHMETIC;
use ARITHMETIC.std_logic_arith.all;

entity trngswcntr1c is
PORT (
                SEGOUT:out std_logic_vector(7 downto 0);
                LEDOUT:out std_logic_vector(3 downto 0);
                CK1:in std_logic;
                SWA:in std_logic;
                SWB:in std_logic;
                SWC:in std_logic
                        );

end trngswcntr1c;

architecture rtl of trngswcntr1c 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 swcntrb0:std_logic_vector(3 downto 0);
        signal swcntrb1:std_logic_vector(3 downto 0);
        signal swcntrc0:std_logic_vector(3 downto 0);
        signal swcntrc1:std_logic_vector(3 downto 0);
        signal swbon:std_logic;
        signal swcon:std_logic;
        --
begin
-- 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;
--
--1/1000
process(cntr1(11))
begin
        if cntr1(11)'event and cntr1(11)='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;
--
-- ******* sw in counter ******
--sw on check
process(cntrss0(3))--10ms
begin
        if cntrss0(3)'event and cntrss0(3)='1' then
                swbon<=SWB;
                swcon<=SWC;
        end if;
end process;
--cntrb
--
process(SWA,swbon)
begin
        if swbon'event and swbon='0' then
                        swcntrb0<=swcntrb0+"0001";
        end if;
        if swcntrb0="1010" or SWA='0' then
                swcntrb0<="0000";
        end if;
end process;
--
process(swcntrb0(3))
begin
        if swcntrb0(3)'event and swcntrb0(3)='0' then
                swcntrb1<=swcntrb1+"0001";
        end if;
        if swcntrb1="1010" or SWA='0' then
                swcntrb1<="0000";
        end if;
end process;
--cntrc
--
process(SWA,swcon)
begin
        if swcon'event and swcon='0' then
                        swcntrc0<=swcntrc0+"0001";
        end if;
        if swcntrc0="1010" or SWA='0' then
                swcntrc0<="0000";
        end if;
end process;
--
process(swcntrc0(3))
begin
        if swcntrc0(3)'event and swcntrc0(3)='0' then
                swcntrc1<=swcntrc1+"0001";
        end if;
        if swcntrc1="1010" or SWA='0' then
                swcntrc1<="0000";
        end if;
end process;
--
--7seg disp
--
leddatabf3<=swcntrc0;
leddatabf2<=swcntrc1;
leddatabf1<=swcntrb0;
leddatabf0<=swcntrb1;
--
end rtl;

プッシュスイッチBを押すたびにカウントアップし、結果を7セグメントLEDの上位2桁(左側の2桁)に表示します。
これだけでは面白くないので、もうひとつカウンタを作りました。
プッシュスイッチCを押すたびにカウントアップし、結果を7セグメントLEDの下位2桁(右側の2桁)に表示します。
そしてプッシュスイッチAを押すと2つのカウンタをともに0クリアします。

プログラムの説明です。
4.096MHz(4096KHz)を12ビットのバイナリカウンタでカウントします。

begin
-- 7seg drive clock 1KHz from 4096KHz
process(CK1)
begin
        if CK1'event and CK1='1' then
                cntr1<=cntr1+"000000000001";
        end if;
end process;


7セグメントLEDをダイナミックドライブするためのクロックとして1KHzを得るためです。
プログラムの次のところでその1KHzを利用して7セグメントLEDのダイナミックドライブのためのカウンタの処理を行なっています。

-- 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;


12ビットのカウンタcntr1の最上位ビットcntr1(11)が1から0に変わるとき、ということはcntr1がオーバフローしたとき、という意味になります。
111111111111が000000000000になったときということです。
これは1KHzのタイミングです。
つまり1KHzのクロックで、ledcntrをカウントアップします。
ledcntrは”100”になると”000”にクリアされます。
4桁の7セグメントLEDをドライブするための0、1、2、3のクロックを得ています。
同時に実際に7セグメントLEDをドライブする4ビットのデータを”0001”→”0010”→”0100”→”1000”の順に左シフトしています。
このデータはトランジスタをONにする信号として出力されます。
’1’になった出力の先にあるトランジスタがONになることで、その桁の7セグメントLEDのカソードがLアクティブになります。
カソードがアクティブになる期間はわずか1/1000秒です。
シフトデータによって順に4桁をドライブしますから各桁は1/1000秒間点灯し、次の3/1000秒は消灯するということを繰り返します。
1秒間に250回それが繰り返されることになります。
非常にわずかな時間ごとの点灯ですが、最近のLEDは高速高輝度なので、これでもそれなりに光ります(前回の写真参照)。

プログラムの次のところでは、今度は7セグメントLEDに出力する各桁のデータを処理しています。

                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;


LEDOUT<=ledoutbf;
は上で説明したシフトデータをトランジスタドライブのための出力端子に出力するところですが、その下の
SEGOUT<=segdata;
のsegdataはまだ出てきていません。
VHDLプログラムは原則としてどこにどの順番に書いてもよいので、ここに書いてしまいましたが、この行はもっと下の方で書いたほうがわかりやすかったかもしれません。
segdataは各桁に表示する数字をセグメントデータに変換したもので、それをセグメント表示用出力端子に出力しています。
その次のprocess文のところは、4桁分の表示データ(実際の数値)を格納しているデータバッファleddatabf0〜leddatabf3の値をセグメントデータに変換するため、0、1、2、3の表示タイミングごとに一旦leddatawkに入れています。

その次のところでは、leddatawkに入れた数値(0〜9)をセグメント表示データに変換しています。

--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;


変換後の値はsegdataに入れられます。
このsegdataは上で説明した
SEGOUT<=segdata;
のところで7セグメントLEDの出力データとして出力されます。

説明の途中ですが、ちょっと長くなってしまいましたので、本日はここまでにいたします。
次回に続きます。

CPLD入門![第102回]
2019.8.25upload

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