目次

electric keyer monitor

 XilinxのXC9572が余っていたので、エレクトリックキーヤーの
 動作をモニタするVHDLコードを作ってみた。



 エレクトリックキーヤーは、アマチュア無線でモールス符号を
 打ち出すとき、2つのスイッチで長点、短点に相当する時間分
 接点を接続します。

 単純に2つのスイッチで、接点の接続時間分を出すだけでは
 確認できないので、サイドトーンと呼ぶ1kHz程度の周波数を
 スピーカ接続し、モニタすることが多いです。

 2入力1出力のデジタル回路とみなし、エレクトリックキーヤー
 のモニタを設計する。

 最初にブロック図を作成。



 スイッチが押されたことを、シンクロナイザで判断し
 シーケンサ(ステートマシン)で1kHzの矩形波を出力
 するか否かを、時間長を含めて制御する。

 出力側から回路を定義する。

 buffer

  外部クロックを分周して、1kHzクロックが
  生成されていると仮定する。

  イネーブル信号が与えられたなら、1kHzクロックを
  外部に出力し、それ以外では'L'を出力。

  組合わせ回路と考え、次のように定義する。

  FOUT <= iCLK when ( iENABLE = '1' ) else '0' ;

 sequencer+counter

  シンクロナイザから、長点、短点のトリガーが与えられた
  なら、カウンタに値を設定。カウンタが0でないときに
  イネーブル信号を出力する。



  状態は4つあればよいので、2ビットジョンソンカウンタで
  ステートを回すシーケンサで対応する。

  状態遷移図から、シーケンサを定義。
  1. トリガーを待つ。(トリガーがきたら、カウンタを設定し、1ステートへ)
  2. カウンタが0なら2ステートに、0より大きければデクリメント。
  3. カウンタをゼロクリア後、4ステートへ。
  4. 最初に戻る
  上のステート処理を、VHDLで定義。 process (nRESET,iCLK) begin if ( nRESET = '0' ) then iSTATE <= "00" ; iSCNT <= 0 ; elsif rising_edge(iCLK) then case conv_integer(iSTATE) is -- wait trigger when 0 => if ( iSSW = '1' ) then iSTATE <= "01" ; iSCNT <= 100 ; elsif ( iLSW = '1' ) then iSTATE <= "01" ; iSCNT <= 300 ; else iSTATE <= "00" ; end if ; -- judge or decrement when 1 => if ( iSCNT = 0 ) then iSTATE <= "11" ; else iSCNT <= iSCNT - 1 ; iSTATE <= "01" ; end if ; -- clear counter when 3 => iSCNT <= 0 ; iSTATE <= "10" ; -- return first state when 2 => iSTATE <= "00" ; -- default when others => iSTATE <= "00" ; end case ; end if ; end process ; iENABLE <= iSTATE(0) ;   無線機では、CWを出力の制御信号をモノラルタイプの   プラグで与えます。   CWの出力制御信号は、iSCNTの2ビット中の1ビットを   バッファを介して出力すれば充分。   2ビットジョンソンカウンタを使うと、バイナリーカウンタ   で必須のデコーダが不要になります。   ステートマシンでは、状態値が1、3で出力制御信号を印加。  synchronizer   スイッチはチャタリングを含んでいるので、シフトレジスタを   使い、3回スイッチ状態を読込み、011で押されたと判断。   シフトレジスタは、チャタリングを除去するとともに   信号のrising_edge、falling_edgeを検出する目的で   利用する。   250Hz(周期4ms)のクロックを利用し、スイッチが   押されたことを判断するVHDLコードは以下。 process (nRESET,iCLKX) begin if ( nRESET = '0' ) then iLSW_SFT <= "000" ; iSSW_SFT <= "000" ; elsif rising_edge( iCLKX ) then iLSW_SFT <= iLSW_SFT(1 downto 0) & (not LSW) ; iSSW_SFT <= iSSW_SFT(1 downto 0) & (not SSW) ; end if ; end process ; iLSW <= '1' when ( iLSW_SFT = "011" ) else '0' ; iSSW <= '1' when ( iSSW_SFT = "011" ) else '0' ;  divider   外部クロックを、分周して1kHzと250Hzのクロックを   生成。外部クロックは4kHzとすると、カウンタを2   つ用意して、2つのクロック生成は、以下となる。 -- clock divider CLOCK = 4kHz process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iCNT <= 0 ; elsif rising_edge( CLOCK ) then if ( iCNT = 3 ) then iCNT <= 0 ; else iCNT <= iCNT + 1 ; end if ; end if ; end process ; iCLK <= '1' when ( iCNT = 0 ) else '0' ; -- 1kHz -- clock divider CLOCK = 1kHz process (nRESET,iCLK) begin if ( nRESET = '0' ) then iCNTX <= 0 ; elsif rising_edge( iCLK ) then if ( iCNT = 4 ) then iCNTX <= 0 ; else iCNTX <= iCNTX + 1 ; end if ; end if ; end process ; iCLKX <= '1' when ( iCNTX = 0 ) else '0' ; -- 250Hz  まとめると、以下。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity ekey is port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- 4kHz -- select switches LSW : in std_logic ; SSW : in std_logic ; -- CW control COUT : out std_logic ; -- side monitor FOUT : out std_logic -- ; ); end ekey ; architecture behavioral of ekey is -- divider signal iCLK : std_logic ; signal iCNT : integer range 0 to 3 ; signal iCLKX : std_logic ; signal iCNTX : integer range 0 to 4 ; -- trigger signal iLSW : std_logic ; signal iSSW : std_logic ; signal iLSW_SFT : std_logic_vector(2 downto 0) ; signal iSSW_SFT : std_logic_vector(2 downto 0) ; -- sequencer signal iSTATE : std_logic_vector(1 downto 0) ; signal iSCNT : integer range 0 to 300 ; signal iENABLE : std_logic ; begin -- outputs FOUT <= iCLK when ( iENABLE = '1' ) else '0' ; COUT <= iSTATE(0); -- clock divider CLOCK = 4kHz process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iCNT <= 0 ; elsif rising_edge( CLOCK ) then if ( iCNT = 3 ) then iCNT <= 0 ; else iCNT <= iCNT + 1 ; end if ; end if ; end process ; iCLK <= '1' when ( iCNT = 0 ) else '0' ; -- 1kHz -- clock divider CLOCK = 1kHz process (nRESET,iCLK) begin if ( nRESET = '0' ) then iCNTX <= 0 ; elsif rising_edge( iCLK ) then if ( iCNT = 4 ) then iCNTX <= 0 ; else iCNTX <= iCNTX + 1 ; end if ; end if ; end process ; iCLKX <= '1' when ( iCNTX = 0 ) else '0' ; -- 250Hz -- synchronizer process (nRESET,iCLKX) begin if ( nRESET = '0' ) then iLSW_SFT <= "000" ; iSSW_SFT <= "000" ; elsif rising_edge( iCLKX ) then iLSW_SFT <= iLSW_SFT(1 downto 0) & (not LSW) ; iSSW_SFT <= iSSW_SFT(1 downto 0) & (not SSW) ; end if ; end process ; iLSW <= '1' when ( iLSW_SFT = "011" ) else '0' ; iSSW <= '1' when ( iSSW_SFT = "011" ) else '0' ; -- sequencer+counter process (nRESET,iCLK) begin if ( nRESET = '0' ) then iSTATE <= "00" ; iSCNT <= 0 ; elsif rising_edge(iCLK) then case conv_integer(iSTATE) is -- wait trigger when 0 => if ( iSSW = '1' ) then iSTATE <= "01" ; iSCNT <= 100 ; elsif ( iLSW = '1' ) then iSTATE <= "01" ; iSCNT <= 300 ; else iSTATE <= "00" ; end if ; -- judge or decrement when 1 => if ( iSCNT = 0 ) then iSTATE <= "11" ; else iSCNT <= iSCNT - 1 ; iSTATE <= "01" ; end if ; -- clear counter when 3 => iSCNT <= 0 ; iSTATE <= "10" ; -- return first state when 2 => iSTATE <= "00" ; -- default when others => iSTATE <= "00" ; end case ; end if ; end process ; iENABLE <= iSTATE(0) ; end behavioral;  接続を指定するためのUCFファイルを記述。 # system NET "CLOCK" LOC = "P5" ; NET "nRESET" LOC = "P39" ; # control NET "LSW" LOC = "P1" ; NET "SSW" LOC = "P43" ; # CW control NET "COUT" LOC = "P2" ; # frequency NET "FOUT" LOC = "P26" ;
目次

inserted by FC2 system