[新連載]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
前へ
次へ
ホームページトップへ戻る