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