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

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



[第106回]


●周波数カウンタ

今まで説明してきたプログラムは実用というよりはVHDLプログラムのサンプルという意味合いが強いものでした。
しかし今回紹介する周波数カウンタプログラムは、このままで十分実用になります。
周波数カウンタプログラムのうち7セグメントLED表示部分はデジタル時計プログラムと同じです。
デジタル時計プログラムでは4.096MHz水晶を発振して得た4.096MHzのクロックを分周して1KHzのクロックを作り、それからさらに1秒のクロックを作成してそれをカウントすることで時計の時分秒にしています。
今回の周波数カウンタは同じようにして作成した1秒をゲートにして、その1秒間に、別に入力する周波数をカウントします。
カウントする対象のパルス信号はボード上の8pinソケットの6番ピンから入力します。
5番ピンがGNDです。



プログラムの説明に入る前に実際の動作を写真で見ていただきます。
手頃な入力パルスとして、クロック発生回路の出力をつないでみました。
クロック発生回路はいくつかの異なる周波数のパルスを出力することができます。
今回は4MHzのパルスをつなぎました。



4MHzは4000KHzですから、4000000Hzです。
8桁の表示ならば04000000と表示されるはずですが、CPLDトレーニングボードの7セグメント表示は4桁ですから、そのうちの上位4桁が表示されています。
CPLDトレーニングボードもクロック発生回路もクロックは水晶発振によって得ていますから、それなりにかなり良い精度が得られます。
CPLDトレーニングボードは4.096MHz水晶を発振させています。
クロック発生回路は4MHzです。
水晶発振によって得られる周波数はかなり良い精度なのですが、それでも誤差がゼロということではありません。
当然CPLDトレーニングボードの側の、つまり測定する側の周波数にも、測定される側のクロック発生回路の周波数にも誤差が含まれます。
0400の表示を期待したいところですが、今回の測定テストでは写真の通り0399と表示されました。
さてそういうことになりますと、下位の値が気になるところです。
CPLDトレーニングボードには7セグメントLEDは4桁しかありませんが、そのほかに8ビット×3組のビット表示LEDがあります。
せっかくあるものなら利用すべきです。
ということで、実は3組の8ビット表示LEDのうち、AポートとBポートの出力を使って下位4桁を表示させています。
写真を見ていただくと9953と表示されていることがわかります。
左から、1001 1001 0101 0011です。
そういうことなのですが、やはりそれではちょっと読みにくいので、できれば下位桁も7セグメントLEDに表示させたいものです。
そこでプッシュスイッチを使って上位4桁と下位4桁の切換え表示が行なえるように考えました。
下の写真では下位桁が表示されています。



プログラムをシンプルにすることと限られたマクロセルの範囲内で機能を実現するために、カウントした周波数の値を保持するバッファはありません。
1秒カウントしたら次の1秒は表示のためにカウントを停止させています。
写真はそのようにして1秒カウントして1秒表示する、という繰り返しのなかで撮影しました。
さきほどの上位桁が表示されている写真と今回の下位桁が表示されている写真は時間的に異なっているため、末尾の1桁が1カウントずれています。
でも1/4000000のズレですから、これはどちらの水晶発振回路もしっかり安定している、ということになりますでしょう。
カウントされた値は上位と下位をつなげると3999952Hzになります。
−48/4000000の誤差です。
−12/1000000ですから−12ppmです。
これだけの精度が出れば上等でありましょう。

ところで上の説明で、プッシュスイッチを使って上位桁と下位桁の表示を切り換える、と書きました。
スイッチAを押したときに下位桁を表示するようにプログラムしました。
でも写真ではスイッチは押していません。
実はここのところもちょっと悩んだところです。
上位桁はスイッチを押していないときに表示されますから、表示が静止している1秒の間に写真を撮ることができます。
しかし下位桁の写真は?
片手でスイッチを押しながら、片手でカメラのシャッターボタンを押す?
いやいや、若いときならともかく、この歳になってそんな芸当はとてもできそうにありません。
で。
本来は必要の無い機能なのですが、写真撮影をするために、スイッチAを押す代わりにPCL(0)にジャンパピンをセットしたときも下位桁を表示するようにプログラムを変更しました。

ジャンパピンのところを拡大しました。



ちょっと見にくいですがSP1の右端のところにジャンパピンをセットしています。
プログラムをちょっと工夫するだけでこういうことができてしまう、というところがソフトウェアのソフトたる所以でありましょう。

ということで、下がソースプログラムリストです。

--cpld training fcounter
--19/5/29 5/30 6/20 6/21 9/5
--
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library ARITHMETIC;
use ARITHMETIC.std_logic_arith.all;

entity trngfcntr1b is
PORT (
                SEGOUT:out std_logic_vector(7 downto 0);
                LEDOUT:out std_logic_vector(3 downto 0);
                CK1:in std_logic;
                CK2:in std_logic;
                SWA:in std_logic;
                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)
                        );
end trngfcntr1b;

architecture rtl of trngfcntr1b is
        signal cntr0:std_logic_vector(13 downto 0);--4096khz/4096/4=250hz
        signal cntr1:std_logic_vector(7 downto 0);--1/250
        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 fcntr0:std_logic_vector(3 downto 0);
        signal fcntr1:std_logic_vector(3 downto 0);
        signal fcntr2:std_logic_vector(3 downto 0);
        signal fcntr3:std_logic_vector(3 downto 0);
        signal fcntr4:std_logic_vector(3 downto 0);
        signal fcntr5:std_logic_vector(3 downto 0);
        signal fcntr6:std_logic_vector(3 downto 0);
        signal fcntr7:std_logic_vector(3 downto 0);
        signal gateon:std_logic;
        signal ck2in:std_logic;
        signal fcclr:std_logic;
        signal ck13:std_logic;
        signal ck1khz:std_logic;
        signal ck1sec:std_logic;
        --
begin
PA(7 downto 4)<=fcntr3;
PA(3 downto 0)<=fcntr2;
PB(7 downto 4)<=fcntr1;
PB(3 downto 0)<=fcntr0;
--
-- 7seg drive clock 1kHz
process(CK1)
begin
        if CK1'event and CK1='1' then
                cntr0<=cntr0+"00000000000001";
        end if;
end process;
--
-- ******* fcounter ******
ck13<=cntr0(13);--250hz
--
--1sec and fcclr
process(ck13)
begin
        if cntr1(7 downto 3)="11111" and gateon='0' then
                fcclr<='1';
        else
                fcclr<='0';
        end if;
        if cntr1="11111010" then
                cntr1<="00000000";
        elsif ck13'event and ck13='0' then
                cntr1<=cntr1+"00000001";
        end if;
end process;
ck1sec<=cntr1(7);
--
process(ck1sec)
begin
        if ck1sec'event and ck1sec='0' then
                gateon<=gateon+'1';
        end if;
end process;
--
ck2in<=CK2 and gateon;
--
process(ck2in)
begin
        if fcntr0="1010" or fcclr='1' then
                fcntr0<="0000";
        elsif ck2in'event and ck2in='1' then
                        fcntr0<=fcntr0+"0001";
        end if;
end process;
--
process(fcntr0(3))
begin
        if fcntr1="1010" or fcclr='1' then
                fcntr1<="0000";
        elsif fcntr0(3)'event and fcntr0(3)='0' then
                fcntr1<=fcntr1+"0001";
        end if;
end process;
--
process(fcntr1(3))
begin
        if fcntr2="1010" or fcclr='1' then
                fcntr2<="0000";
        elsif fcntr1(3)'event and fcntr1(3)='0' then
                fcntr2<=fcntr2+"0001";
        end if;
end process;
--
process(fcntr2(3))
begin
        if fcntr3="1010" or fcclr='1' then
                fcntr3<="0000";
        elsif fcntr2(3)'event and fcntr2(3)='0' then
                fcntr3<=fcntr3+"0001";
        end if;
        end process;
--
process(fcntr3(3))
begin
        if fcntr4="1010" or fcclr='1' then
                fcntr4<="0000";
        elsif fcntr3(3)'event and fcntr3(3)='0' then
                fcntr4<=fcntr4+"0001";
        end if;
end process;
--
process(fcntr4(3))
begin
        if fcntr5="1010" or fcclr='1' then
                fcntr5<="0000";
        elsif fcntr4(3)'event and fcntr4(3)='0' then
                fcntr5<=fcntr5+"0001";
        end if;
end process;
--
process(fcntr5(3))
begin
        if fcntr6="1010" or fcclr='1' then
                fcntr6<="0000";
        elsif fcntr5(3)'event and fcntr5(3)='0' then
                fcntr6<=fcntr6+"0001";
        end if;
        end process;
--
process(fcntr6(3))
begin
        if fcntr7="1010" or fcclr='1' then
                fcntr7<="0000";
        elsif fcntr6(3)'event and fcntr6(3)='0' then
                fcntr7<=fcntr7+"0001";
        end if;
        end process;
--
--7seg disp select
--H4 or L4
process(ledcntr,SWA,PCL(0))
begin
        if SWA='0' or PCL(0)='0' then
                leddatabf3<=fcntr0;
                leddatabf2<=fcntr1;
                leddatabf1<=fcntr2;
                leddatabf0<=fcntr3;
        else
                leddatabf3<=fcntr4;
                leddatabf2<=fcntr5;
                leddatabf1<=fcntr6;
                leddatabf0<=fcntr7;
        end if;
end process;
--
-- led drive,LEDOUT
ck1khz<=cntr0(11);
process(ck1khz)
begin
        if ledcntr(2)='1' then
                ledcntr<="000";
                ledoutbf<="0001";
        elsif ck1khz'event and ck1khz='0' then
                ledcntr<=ledcntr+"001";
                ledoutbf<=ledoutbf(2 downto 0) & '0';
        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;
--
end rtl;


今回は時間がありません。
プログラムの説明は次回にすることにいたします。

CPLD入門![第106回]
2019.9.6upload

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