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

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



[第103回]


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

前回からの続きです。
その続きのところでは1/1000秒、1/100秒、1/10秒のクロックを作り出しています。


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


tm1の1クロックは1/1000秒(つまり1KHz)です。
tm1は0〜9までカウントして0に戻ります。
tm1は1桁(バイナリ4ビット)の10進カウンタです。
ここはその次の1/100秒のカウンタが必要なので、その前処理として書いています。
次の1/100秒のところも1/1000のところと同じ処理です。
cntrss0は1桁(バイナリ4ビット)の10進カウンタです。
その次の1/10秒も同じ処理です。
ここのところのクロックはプッシュスイッチのチャタリング回避のために使用しています。
当初は1/10秒のクロックを使ったのですが、それだとちょっと遅すぎてプッシュスイッチを押しても応答しないときがでてきたので、1/100秒を使うように改めました。

下がその部分です。

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


何をやっているのかわかりにくいかもしれません。
メカニカルなスイッチにはチャタリングがあります。
そのため何も対策をしないと1回押しただけなのに数回から数十回もカウントしてしまいます。
チャタリング除去のためにはスイッチと並列に0.1〜1μF程度のコンデンサを入れるのが簡便な方法です。
最初はそれも試してみたのですが、だめでした。
EPM7128SLC84の入力回路にはシュミットトリガ回路がありませんから、コンデンサのために入力信号がなまってしまうと、かえって誤動作してしまいます。
そこで上のプログラムの方法を考えました。
cntrss0(3)が1になるタイミングは0111から1000になるときですから、それは0.1秒に1回のタイミングです。
0.1秒に1回スイッチBとスイッチCの状態をそれぞれswbonとswconに入れます。

こうやって説明を書くのはなかなかに手間がかかって大変なのですが、しかしこのようにして整理しながら書くことで、はじめて考えの誤りに気が付くこともよくあります。
ここのところは私は0.01秒に1回、のつもりでプログラムを書きました。
でもこうやって整理してみると、cntrss0は1/100秒のカウンタですから、そのカウンタが10回に1回、0111から1000になるわけですから、それは0.01秒に1回ではなくて0.1秒に1回、ということなのでした。
うーん。
ちょんと押しただけではカウントアップしないときがあるかもしれません。
気持ちとしては、0.1秒以上押す、ということにすれば、問題はないはずです。
チャタリングが0.1秒もあることは考えられませんから、このくらいの値のほうが安全かもしれません。
皆様で、ここのところはcntrss0の代わりにtm1に置き換えて試してみてください(チャタリングの影響が出るかどうか)。

次のところではスイッチBのカウント処理をしています。

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


swcntrb0、swcntrb1はそれぞれ4ビットのバイナリカウンタです。
10回カウントすると(1010になると)0000にクリアします。
つまり1桁の10進カウンタです。
スイッチAを押したときも0000にクリアしますからそこのところも加えてあります。

次はスイッチCのカウント処理です。

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


ここはスイッチBの処理と全く同じです。

最後に7セグメントLEDの表示用データバッファに各カウントデータを送ります。

--7seg disp
--
leddatabf3<=swcntrc0;
leddatabf2<=swcntrc1;
leddatabf1<=swcntrb0;
leddatabf0<=swcntrb1;
--


leddatabf0〜leddatabf3は前回説明しました。
leddatabf0〜leddatabf3の値は7セグメントの表示データに変換されたあと、7セグメントLEDに出力されます。

下は前回お見せしたプログラムのソースファイルです。

trngswcntr1c.txt

[第91回]の通りに作業してください。
今回新規作成するフォルダはtrngswcntr1cです。
作業が済んだら[第92回]以後のところを参考にして、コンパイル、端子名ファイルのコピー作業を行なってください。
CPLDトレーニングキットはまだ準備作業中です。
お待たせして申し訳ありません。
手元に届きましたら、[第96回]を参考にしながら、実際にEPM7128SLC84にプログラムを書き込んでみてください。

CPLD入門![第103回]
2019.8.28upload

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