目次
前
次
I/O設計
定義したインタプリタは、接続部品に無関係に
スキャン処理でメモリ内容を更新していきます。
接続部品とメモリ内容を関係づけないと、シーケンス動作
ができません。入力メモリと出力メモリという概念を導入
します。
入力メモリと出力メモリの実現は、非常に簡単です。
スキャン処理を開始する前に、入力の状態を読取り
入力メモリに転送します。
1スキャンが終了したなら、出力メモリの内容を
接続部品に転送します。
スキャン動作は、次のように関数を組み合わせて
記述できます。
/* get INPUT state */
get_input_information();
/* scanning */
perform_scanning();
/* put OUTPUT state */
update_output();
関数get_input_informationが、入力の状態を入力メモリ
に反映させます。
関数update_outputが、出力メモリの内容を出力に反映
させます。
2つの関数とマイコン周辺の回路を設計します。
入力回路と関数
入力の状態を入力メモリに反映させるには、入力ピン
からデータを取得して、格納するだけで充分です。
入力に接続できるスイッチ、センサーをいくつにするか
決めれば、関数を作成できます。
16ビット分を入力することにします。
ノイズ防止と過大入力から、マイコンを保護するために
次の回路を接続します。
フォトカプラ(TLP521-4)を利用し、ノイズ防止、過大
入力保護の双方を実現します。
フォトカプラの出力をラッチ(74HC574)に入力します。
ラッチは、マイコンからのトリガーで入力状態を確定します。
ラッチで、入力状態記憶後、マイコンは8ビットずつデータ
を取り込みます。
関数get_input_informationの動作シーケンスです。
- ラッチトリガー出力
- nOEAをイネーブルにし、8ビットデータ入力
- nOEAをディセーブル
- 入力8ビットデータを、配列に転送
- nOEBをイネーブルにし、8ビットデータ入力
- 入力8ビットデータを、配列に転送
- nOEBをディセーブル
16ビットデータを、8ビットずつ2回に分けて
配列memoryに転送します。
インタプリタが扱うメモリには、ビット番号を振って
あるので、ビット番号0〜15に相当するエリアに転送
します。
マイコンのピンに、機能を割当てます。
- 入力ポート ポートA
- ラッチトリガー ポートBの0ビット目
- nOEA ポートBの1ビット目
- nOEB ポートBの2ビット目
仕様ができたので、コードを作成します。
#define ITRG 0
#define OEA 1
#define OEB 1
void get_input_information(void)
{
/* send latch trigger */
PORTB |= (1 << ITRG) ;
PORTB &= ~(1 << ITRG) ;
/* enable nOEA */
PORTB &= ~(1 << OEA) ;
/* get data */
*(memory+0) = PINA ;
/* disable OEA */
PORTB |= (1 << OEA) ;
/* enable nOEB */
PORTB &= ~(1 << OEB) ;
/* get data */
*(memory+1) = PINA ;
/* disable OEA */
PORTB |= (1 << OEB) ;
}
出力回路と関数
出力メモリの内容を出力に反映させるには、出力ピン
へデータを出力するだけです。
出力に接続できるアクチュエータをいくつにするか
決めれば、関数を作成できます。
16ビット分を出力することにします。
ノイズ防止と出力側から、マイコンを保護するために
次の回路を接続します。
ラッチ(74HC574)を使い、出力メモリの16ビット分を
外部に引き出します。さらに、ラッチ(74HC574)出力
を、フォトカプラに接続します。
フォトカプラ(TLP521-4)を利用し、ノイズ防止、外部
からの回込み過大入力から保護します。
関数update_outputの動作シーケンスです。
- 配列から出力メモリの内容を取得し出力
- OTRGAにラッチパルス出力
- 配列から出力メモリの内容を取得し出力
- OTRGBにラッチパルス出力
16ビットデータを、8ビットずつ2回に分けて
配列memoryから転送します。
インタプリタが扱うメモリには、ビット番号を振って
あるので、ビット番号16〜31に相当するエリアから
転送します。
マイコンのピンに、機能を割当てます。
- 出力ポート ポートC
- 出力イネーブル ポートBの3ビット目
- ラッチパルスA ポートBの4ビット目
- ラッチパルスB ポートBの5ビット目
仕様ができたので、コードを作成します。
#define OTRGA 4
#define OTRGB 5
void update_output(void)
{
/* set data */
PORTC = *(memory+2) ;
/* send latch pulse */
PORTB |= (1 << OTRGA) ;
PORTB &= ~(1 << OTRGA) ;
/* set data */
PORTC = *(memory+3) ;
/* send latch pulse */
PORTB |= (1 << OTRGB) ;
PORTB &= ~(1 << OTRGB) ;
}
出力イネーブル信号は、出力メモリの初期状態を決めて
から、ラッチの出力をフォトカプラに伝達する目的
で利用します。
出力にはアクチュエータが接続されているので、不用意な
動作は重大事故を起こす原因になります。
出力イネーブルを用意すると、緊急停止と初期状態を
確定するまで、出力アクチュエータを停止させること
ができます。
PLCを実現するマイコンの起動時に、出力メモリの状態を
確定後、出力イネーブル信号をイネーブルにします。
最近は、74HCの500番シリーズは入手しにくいので
CPLDの中に、I/O用レジスタを入れることが多くなり
ました。
XC95108を使う場合のVHDLコードは、以下です。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity mpreg is
port(
-- system
nRESET : in std_logic;
CLOCK : in std_logic;
-- sequencer inputs
SelInp : in std_logic ;
Din : out std_logic_vector(7 downto 0);
-- sequencer outputs
TRGW : in std_logic ;
SelOut : in std_logic ;
Dout : in std_logic_vector(7 downto 0);
-- I/O input
IOinp : in std_logic_vector(15 downto 0) ;
IOout : out std_logic_vector(15 downto 0) --;
);
end mpreg;
architecture behavioral of mpreg is
-- trigger
signal iTRGW : std_logic ;
signal iTRGW_SFT : std_logic_vector(2 downto 0) ;
-- inputs register
signal iIOregIn : std_logic_vector(15 downto 0);
-- outputs register
signal iIOregOut : std_logic_vector(15 downto 0);
begin
-- trigger
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iTRGW_SFT <= "000" ;
elsif rising_edge( CLOCK ) then
iTRGW_SFT <= iTRGW_SFT(1 downto 0) & TRGW ;
end if ;
end process ;
iTRGW <= '1' when ( iTRGW_SFT = "011" or iTRGW_SFT = "001" ) else '0' ;
-- inputs
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iIOregIn <= (others => '0') ;
elsif rising_edge( CLOCK ) then
iIOregIn <= IOinp ;
end if ;
end process ;
Din <= iIOregIn(15 downto 8) when ( SelInp = '1' ) else iIOregIn(7 downto 0);
-- outputs
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iIOregOut <= (others => '0') ;
elsif rising_edge( CLOCK ) then
if ( iTRGW = '1' ) then
if ( SelOut = '1' ) then
iIOregOut(15 downto 8) <= Dout ;
else
iIOregOut( 7 downto 0) <= Dout ;
end if ;
end if ;
end if ;
end process ;
IOout <= iIOregOut ;
end behavioral;
ピンアサインは、以下としました。
# system
NET "CLOCK" LOC = "P9" ;
NET "nRESET" LOC = "P74" ;
# I/O inputs
NET "SelInp" LOC = "P11" ;
NET "Din<7>" LOC = "P10" ;
NET "Din<6>" LOC = "P7" ;
NET "Din<5>" LOC = "P6" ;
NET "Din<4>" LOC = "P5" ;
NET "Din<3>" LOC = "P4" ;
NET "Din<2>" LOC = "P3" ;
NET "Din<1>" LOC = "P2" ;
NET "Din<0>" LOC = "P1" ;
# I/O outputs
NET "TRGW" LOC = "P23" ;
NET "SelOut" LOC = "P21" ;
NET "Dou<7>" LOC = "P20" ;
NET "Dou<6>" LOC = "P19" ;
NET "Dou<5>" LOC = "P18" ;
NET "Dou<4>" LOC = "P17" ;
NET "Dou<3>" LOC = "P15" ;
NET "Dou<2>" LOC = "P14" ;
NET "Dou<1>" LOC = "P13" ;
NET "Dou<0>" LOC = "P12" ;
# inputs
NET "IOinp<15>" LOC = "P65" ;
NET "IOinp<14>" LOC = "P63" ;
NET "IOinp<13>" LOC = "P62" ;
NET "IOinp<12>" LOC = "P61" ;
NET "IOinp<11>" LOC = "P58" ;
NET "IOinp<10>" LOC = "P57" ;
NET "IOinp<9>" LOC = "P56" ;
NET "IOinp<8>" LOC = "P55" ;
NET "IOinp<7>" LOC = "P54" ;
NET "IOinp<6>" LOC = "P53" ;
NET "IOinp<5>" LOC = "P52" ;
NET "IOinp<4>" LOC = "P51" ;
NET "IOinp<3>" LOC = "P50" ;
NET "IOinp<2>" LOC = "P48" ;
NET "IOinp<1>" LOC = "P47" ;
NET "IOinp<0>" LOC = "P46" ;
# outputs
NET "IOout<15>" LOC = "P84" ;
NET "IOout<14>" LOC = "P83" ;
NET "IOout<13>" LOC = "P82" ;
NET "IOout<12>" LOC = "P81" ;
NET "IOout<11>" LOC = "P80" ;
NET "IOout<10>" LOC = "P79" ;
NET "IOout<9>" LOC = "P77" ;
NET "IOout<8>" LOC = "P76" ;
NET "IOout<7>" LOC = "P75" ;
NET "IOout<6>" LOC = "P72" ;
NET "IOout<5>" LOC = "P71" ;
NET "IOout<4>" LOC = "P70" ;
NET "IOout<3>" LOC = "P69" ;
NET "IOout<2>" LOC = "P68" ;
NET "IOout<1>" LOC = "P67" ;
NET "IOout<0>" LOC = "P66" ;
目次
前
次