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

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



[第105回]


●デジタル時計プログラム(2)

前回からの続きです。
プログラムの説明に入る前に、時刻の初期設定の操作について説明をしておきます。
スイッチCを押すと、押している間、1秒ごとに分の下位1桁をカウントするカウンタがカウントアップしていきます。
しかしカウントアップするのは分の下位1桁だけで、カウントが9→0になっても、上位桁はカウントアップしないでもとのままの値を維持します。
スイッチBを押すと、押している間、1秒ごとに分の上位1桁をカウントするカウンタがカウントアップしていきます。
しかしカウントアップするのは分の上位1桁だけで、カウントが5→0になっても、時の桁はカウントアップしないでもとのままの値を維持します。
スイッチAを押すと、押している間、1秒ごとに時をカウントするカウンタがカウントアップしていきます。
時のカウントアップは2桁で行なわれます。
0→23までカウントアップ→0を繰り返します。
このほかの機能もあるのですが、それについてはそのプログラム部分の説明のところで書くことにします。

下はスイッチCを押したとき、分の下位1桁のカウントアップを行なうプログラム部分です。
スイッチCを押したときと押していないとき(つまり通常の時計の動作)も一緒にプログラムしています。
そのためちょっとわかりにくいプログラムになっています。

--swcon set(every 1 second)
--select counterm0 clock
process(SWC,cntrs1(2),cntrss1(3))
begin
        if SWC='0' then
                cntrm0ck<=cntrss1(3);-- if SWC on,then count up every 1 sec
        else
                cntrm0ck<=cntrs1(2);
        end if;
end process;
process(cntrm0ck)
begin
        if cntrm0ck'event and cntrm0ck='0' then
                cntrm0<=cntrm0+"0001";
        end if;
        if cntrm0="1010" then
                cntrm0<="0000";
        end if;
end process;


このプログラムは少し説明が必要です。
SWC=’0’というのは、スイッチCが押されたときです。
そのときはcntrm0ckにはcntrss1(3)の値が入ります。
cntrss1は1/10秒のカウンタです。
その最上位ビットの値がcntrm0ckに入ります。
スイッチCが押されていないときは、cntrs1(2)がcntrm0ckに入ります。
cntrs1(2)は10秒の位のカウンタの最上位ビットです。
その次のprocessではcntrm0(分の下位1桁のカウンタ)の処理を行なっています。
cntrm0ckの値が1から0になる瞬間にcntrm0がカウントアップします。
cntrm0ckはスイッチCの状態によってcntrss1(3)かcntrs1(2)のどちらかの値になっていますから、その値が1から0になる(ということは上位桁への桁上げが発生する)ときに、cntrm0がカウントアップします。
つまり、スイッチCが押されているときには分の下位桁(cntrm0)が1秒ごとにカウントアップし、スイッチCが押されていないときは、分の下位桁は秒の上位桁からの繰り上がりでカウントアップします(これは通常の時計の動作です)。
要約すると、スイッチCが押されているときは、分の位のカウンタが1秒ごとにカウントアップし、押されていないときは通常の時計の動作をします。

次は分の上位桁の動作です。

--minuteH
--swbon set(every 1 second)
--select counterm1 clock
process(SWB,cntrm0(3),cntrss1(3))
begin
        if SWB='0' then
                cntrm1ck<=cntrss1(3);-- if SWB on,then count up every 1 sec
        else
                cntrm1ck<=cntrm0(3);
        end if;
end process;
--
process(cntrm1ck,SWC)
begin
        if cntrm1ck'event and cntrm1ck='0' and SWC='1' then
                cntrm1<=cntrm1+"001";
        end if;
        if cntrm1="110" then
                cntrm1<="000";
        end if;
end process;


上で説明した分の位の動作とほとんど同じです。
上ではスイッチCでしたが今度はスイッチBを使います。
分の上位桁は、スイッチBが押されていると1秒ごとにカウントアップします。
押されていないときは通常の時計の動作(分の下位桁からの繰り上がりでカウントアップする)になります。
分の上位桁のカウントアップのところは、上で説明した分の下位桁の動作と異なるところがあります。
if cntrm1ck’event and cntrm1ck=’0’ のうしろに and SWC=’1’ が追加されています。
これはどういうことでしょうか。
この部分がないと、分の下位桁の設定のためにスイッチCを押していると、1秒ごとにカウントアップしていくのですが、9から0に変わるときに上位桁への桁上がりが発生してしまい、上位桁がカウントアップされてしまいます。
細かい話ですが、たとえば現在の値が○○時47分のときに、それを49分に設定するつもりでスイッチCを押したところ、うっかり押し過ぎて9から0に変わってしまったとします。
そのときに上位桁への桁上がりが発生すると、50分になってしまいます。
そうすると下位桁だけではなくて上位桁まで再設定しなければなりません。
スイッチCを押しているときは分の下位桁だけがカウントアップするけれど、上位桁は変化しない、というようにしておきたいのは、上記のことを避けるためです。
その動作を普通に考えれば、分の下位桁のところで、スイッチCが押されているときには上位桁へ桁上がりしない、というようなプログラムにしようと考えそうですが、その考えは多分うまくいきませんでしょう。
意外に思われるかもしれませんが、ここは下位桁ではなくて上位桁のカウントアップのところに and SWC=’1’ を追加するだけで、期待した通りの動作になります。
SWC=’1’はスイッチCが押されていないとき、という意味になります。

次は時の位の動作です。

--hour
--swaon set(every 1 second)
--select counterh clock
process(SWA,cntrm1(2),cntrss1(3))
begin
        if SWA='0' then
                cntrhck<=cntrss1(3);-- if SWA on,then count up every 1 sec
        else
                cntrhck<=cntrm1(2);
        end if;
end process;
--
process(cntrhck,SWB)
begin
        if cntrhck'event and cntrhck='0' and SWB='1' then
                cntrh<=cntrh+"000001";
        end if;
        if cntrh(3 downto 0)="1010" then
                cntrh(3 downto 0)<="0000";
                cntrh(5 downto 4)<=cntrh(5 downto 4)+"01";
        elsif cntrh="100100" then
                cntrh<="000000";
        end if;
end process;


時の位はスイッチAが押されていると1秒ごとにカウントアップします。
押されていないときは通常の時計の動作(分の上位桁からの繰り上がりでカウントアップする)になります。
時の位のカウントアップも、上で説明した分の上位桁の動作と同じです。
スイッチBが押されているときには分の上位桁からの桁上がりでカウントアップしないように、
if cntrhck’event and cntrhck=’0’ のうしろに and SWB=’1’ が追加されています。
それともうひとつ、時の位は0時から23時(59分59秒)までですが、初期設定については分の場合のように上位桁と下位桁を分けずに0〜23までカウントアップします。
10進2桁のカウンタなのでcntrhは6ビットカウンタになっています。
もっとも10進カウンタなので、どうせ下位桁が1010のときに0クリアして上位桁に桁上がりするようにしなければなりませんから、上位2桁と下位4桁の2つのカウンタに分けて記述してもそれほど違いのあるプログラムにはなりません。

さて。
デジタル時計なので、どうせならば秒の桁まで表示させてみたいものです。
しかしこのトレーニングボードの7セグメントLEDは4桁しかありません。
表示は4桁しかできませんが、カウンタとしては1/1000秒の単位までカウントしています。
82C55プログラムでCポートを入力にしたときに利用できるように、8ビットのジャンパピン用ヘッダーがボード上にあります。
[第101回]に写真があります。
基板右側のSP1がジャンパピン(ショートピン)用のヘッダーです。
ジャンパピンをセットすると、そのビットの入力が’0’になります。
オープンのビットには’1’が入力されます。
これを利用して時分と分秒の切換表示ができるように考えました。
それが下の部分です。

--7seg disp select
--HHMM or MMSS
process(PCL,cntrss0,cntrss1,cntrs0,cntrs1,cntrm0,cntrm1)
begin
        if PCL(0)='0' then
                leddatabf3<=cntrss0;
                leddatabf2<=cntrss1;
                leddatabf1<=cntrs0;
                leddatabf0<='0' & cntrs1;
        elsif PCL(1)='0' then
                leddatabf3<=cntrs0;
                leddatabf2<='0' & cntrs1;
                leddatabf1<=cntrm0;
                leddatabf0<='0' & cntrm1;
        else
                leddatabf3<=cntrm0;
                leddatabf2<='0' & cntrm1;
                leddatabf1<=cntrh(3 downto 0);
                leddatabf0<="00" & cntrh(5 downto 4);
        end if;
end process;
--
end rtl;


ジャンパピンの入力はPCHとPCLの各4ビットですが、ここでは右端の2ビットを使います。
PCL(0)とPCL(1)です。
時分と分秒の切換だけならPCL(0)だけでできるのですが、8ビットもありますから、さらに秒と1/100秒の表示も選択できるようにしました。
右端のビット0をショートすると秒と1/100秒の表示になります。
右から2番目のビット1をショートすると分と秒の表示になります。
ビット0にもビット1にもジャンパピンをセットしないときは時分の表示になります。

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

trngwatch1c.txt

[第91回]の通りに作業してください。
今回新規作成するフォルダはtrngwatch1cです。
作業が済んだら[第92回]以後のところを参考にして、コンパイル、端子名ファイルのコピー作業を行なってください。

CPLD入門![第105回]
2019.9.4upload

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