コンテック社のデジタル入出力ボードを使う(初級編)

コンテック社のデジタル入出力ボード PIO-16/16L(LPCI)H を使って、コンピュータと外部機器のデジタル入出力を実現する方法を紹介します。

PIO-16/16L(LPCI)H は PCI バスに挿入する拡張ボードですが、マザーボードに PCI-Express バスしかない場合は、ピン配置互換で電気的にも互換である DIO-1616L-LPE という拡張ボードを使います。本記事内に外部電源、スイッチ、LEDの接続方法を示していますが、まったく同じ接続でかまいません。

Fig. 1 製作するWPFアプリケーション

デジタル入出力ボードをパソコンに挿す

まず最初に、パソコンの筐体をあけて、PCIバス、または、PCI-Express バスに拡張ボードを挿入してください。冬の乾燥している時期は静電気などのショックを与えないようにしてください。パソコンの筐体をプラスドライバなどで開けるときに体にたまった静電気の電荷が金属筐体へ放出されるので過度に注意する必要はありません。

PCIバスにボードを挿すときは、グッと力を入れなければ入りません。その時に勢いが余って拡張ボードやマザーボードの配線パターンなどをひっかけて傷つけないように注意してください。静電気よりもこちらで壊すことのほうが多いように思います。

デジタル入出力ボードのドライバやSDKをインストールする

コンテック社のインストール手順書にしたがって、デジタル入出力ボードのソフトウェアドライバ、サンプルソース、オンラインヘルプなどをインストールしてください。

正しくインストールできたかどうかはデバイスマネージャで確認します。

スタートメニューを右クリックすると Fig. 2 のような画面になるので、そこで「デバイスマネージャー」を選びます。そうすれば Fig. 3 のダイアログが表示されます。これがデバイスマネージャで、システムに認識されているハードウェア類が列挙されています。

ここに "CONTEC Devices" という項目が見つかりますので、そこの末尾の "DIO000" という文字列のメモをとってください。必ず "DIO000" であるとは限りません。まれに "DIO001" になったりするときもありますのでご注意ください。

Fig. 2 スタートメニューを右クリックしたとき
Fig. 3 デバイスマネージャ

外部回路を接続する

デバイスマネージャでデジタル入出力ボードが正しくインストールされていることが確認できたら、つぎは電気配線です。

Fig. 4 に示すように、スイッチ、LEDと直列に抵抗 4.7kΩ、外部直流電源を、ボードの端子台に接続します。

INP 06..01、INP 14..09 は接続が省略されていますがスイッチを接続してください。
OUTP 06..01、OUTP 14..09 は接続が省略されていますが LED と直列に 4.7kΩ の抵抗を接続してください。

LEDと直列に4.7kΩの抵抗をつなぐのが面倒でしたら、抵抗内蔵型のLEDや電流制限型のLEDを使ってください。

26番、27番、1番、2番のピンは共通です、どれかひとつだけ +24V に接続するだけでかまいません。
39番、40番、14番、15番のピンは共通です、どれかひとつだけ +24V に接続するだけでかまいません。
49番、50番、24番、25番のピンは共通です、どれかひとつだけ GND に接続するだけでかまいません。

26番ピンに供給された +24V が、27番ピンを経て39番ピンに供給されます。39番ピンに供給された +24V が、共通として40番ピンと15番ピンにも供給されます。そこからLEDに対して電力を供給します。

Fig. 4 実体配線図

コンテック社の純正アプリケーションで外部回路接続が正しいか確認する

電気配線ができたら外部回路が正しく接続されているか、コンテック社の純正アプリケーションでテストします。

純正のアプリケーションの名前は cdiodiag.exe です。ドライバやSDKが正しくインストールされていれば、 c:/Windows/System32/ というディレクトリに cdiodiag.exe が配置されているはずです。

前述の場所になければ cdiodiag.exe を検索して探し出してください。

Fig. 5 コンテック社が作成した動作確認アプリ cdiodiag.exe

cdiodiag.exe を起動します。ソフトウェアの外観を Fig. 5 に示します。Fig.4 の実態配線図のスイッチ(SW)を押せば入力ポートのスイッチに対応したビットが赤く変化するはずです。

出力ポートはユーザがマウスでクリックしてトグルオンオフします。そうすればそのビットに接続された LED が点灯/消灯するはずです。ボタンを押して赤くしたときはLED点灯です。トグルして緑の時はLED消灯です。

コンテック社が作成した動作確認アプリケーションで自分の意図どおりに正しく動作するまでは自作プログラム作成を控えてください。うまく動いていない場合、外部回路の接続が正しいかどうか、電線が抜けていないか、電源が入っているか、そういったことを再チェックしてください。

正しく動いていても、パソコンがコゲ臭くないか、外部回路がコゲ臭くないか、妙な熱をもっていないか、電気火花が散っていないか、そういったことも同時に確認してください。

自分のプログラムの作成を開始する

ここまでくれば、ようやくプログラム作成を開始できるようになりました。

プロジェクトの新規作成でWPFアプリケーションのプロジェクトを作成してください。

構成マネージャでは x64 形式の実行ファイルを作成するように設定します。x64形式の実行ファイルを作成する方法は下記の記事をご確認ください。

x64形式の実行ファイルを作成する

VisualStudio の「新規プロジェクト」では、生成される実行ファイルの形式が AnyCPU です。デジタル入出力ボードや画像入力ボードではこれを x64 にしなければならない場…

Ctrl + Alt + L のショートカットキーで、ソリューションエクスプローラを表示させてください。プロジェクトを右クリックして、「追加」...「既存の項目」を実行してください。

Fig. 6 ソリューションエクスプローラで既存の項目の追加

プログラムを作成するにはコンテック社が提供した CdioCs.cs というファイルがないとビルドができません。多くの場合は下記のディレクトリに配置されています。

c:/Program Files(x86)/CONTEC/API-PAC(W32)/DIOWDM/Samples/Dio/Vcs/SimpleIO/CdioCs.cs

もし、上記の場所になければファイル検索を実施して CdioCs.cs を見つけてプロジェクトに追加してください。

Fig. 7 CdioCs.cs ファイルをプロジェクトに追加するダイアログ

CdioCs.cs ファイルが正しくプロジェクトに追加されたことを確認します。Fig. 8 のようになります。

Fig. 8 プロジェクトに CdioCs.cs ファイルが追加されたことが確認できた

ソースコードの解説

XAML でウインドウにボタンを16個配置します。該当のデジタル入出力ボードは出力を16点もっていますので16個です。ウインドウ下部のステータスバーには入力の16点の状態を示すようにします。

出力とは、パソコン→外部回路の信号の流れです。昔からこのことを outp (アウトピィ)と称します。
入力とは、外部回路→パソコンの信号の流れです。昔からこのことを inp (インピィ)と称します。

<Window x:Class="aaa.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:aaa"
        mc:Ignorable="d"
        Title="MainWindow" Height="240" Width="720">

    <DockPanel>

        <Menu DockPanel.Dock="Top">

            <MenuItem x:Name="menuApplication" Header="Application">
                <MenuItem x:Name="menuApplicationQuit" Header="Quit" Click="menuApplicationQuit_Click"/>
            </MenuItem>

            <MenuItem x:Name="menuDio" Header="DIO">
                <MenuItem x:Name="menuDioInit" Header="Init" Click="menuDioInit_Click" />
                <MenuItem x:Name="menuDioExit" Header="Exit" Click="menuDioExit_Click" />
            </MenuItem>

            <MenuItem x:Name="menuOutp" Header="Outp">
                <MenuItem x:Name="menuOutpAllOn"  Header="All ON"  Click="menuOutpAllOn_Click" />
                <MenuItem x:Name="menuOutpAllOff" Header="All OFF" Click="menuOutpAllOff_Click" />
            </MenuItem>

        </Menu>

        <ToolBarTray DockPanel.Dock="Top">
            <ToolBar>

                <Border BorderBrush="DarkViolet" BorderThickness="1" >
                    <Button x:Name="tbnApplicationQuit" Content="Quit" Width ="48" Height="48" Click="menuApplicationQuit_Click"></Button>
                </Border>

                <Separator />

                <Button x:Name="tbnDioInit" Content="DIO.Init" Width ="48" Height="48" Click="menuDioInit_Click"></Button>
                <Button x:Name="tbnDioExit" Content="DIO.Exit" Width ="48" Height="48" Click="menuDioExit_Click"></Button>

                <Separator />

                <Button x:Name="tbnOutpAllOn"  Content="Outp.All ON"  Width ="96" Height="48" Click="menuOutpAllOn_Click"></Button>
                <Button x:Name="tbnOutpAllOff" Content="Outp.All OFF" Width ="96" Height="48" Click="menuOutpAllOff_Click"></Button>

            </ToolBar>
        </ToolBarTray>

        <StatusBar x:Name="the_stb" DockPanel.Dock="Bottom" Height="30" RenderTransformOrigin="0.484,7.414">
            <Label x:Name="stbLabel000"/>
            <Separator/>
            <Label x:Name="stbLabel001"/>
            <Separator/>
            <Label x:Name="stbLabel002" Background="Black" Foreground="Lime"/>
            <Separator/>
            <Label x:Name="stbLabel003" Background="Black" Foreground="Lime"/>
        </StatusBar>

        <Grid>
            <Button x:Name="btn07" Content="outp07" HorizontalAlignment="Left" Margin="20,19,0,0" VerticalAlignment="Top" Width="75" Click="btnNn_Click"/>
            <Button x:Name="btn06" Content="outp06" HorizontalAlignment="Left" Margin="100,19,0,0" VerticalAlignment="Top" Width="75" Click="btnNn_Click"/>
            <Button x:Name="btn05" Content="outp05" HorizontalAlignment="Left" Margin="180,19,0,0" VerticalAlignment="Top" Width="76" Click="btnNn_Click"/>
            <Button x:Name="btn04" Content="outp04" HorizontalAlignment="Left" Margin="261,19,0,0" VerticalAlignment="Top" Width="75" Click="btnNn_Click"/>
            <Button x:Name="btn03" Content="outp03" HorizontalAlignment="Left" Margin="367,19,0,0" VerticalAlignment="Top" Width="75" Click="btnNn_Click"/>
            <Button x:Name="btn02" Content="outp02" HorizontalAlignment="Left" Margin="447,19,0,0" VerticalAlignment="Top" Width="75" Click="btnNn_Click"/>
            <Button x:Name="btn01" Content="outp01" HorizontalAlignment="Left" Margin="527,19,0,0" VerticalAlignment="Top" Width="76" Click="btnNn_Click"/>
            <Button x:Name="btn00" Content="outp00" HorizontalAlignment="Left" Margin="608,19,0,0" VerticalAlignment="Top" Width="75" Click="btnNn_Click"/>

            <Button x:Name="btn15" Content="outp15" HorizontalAlignment="Left" Margin="20,66,0,0" VerticalAlignment="Top" Width="75" Click="btnNn_Click"/>
            <Button x:Name="btn14" Content="outp14" HorizontalAlignment="Left" Margin="100,66,0,0" VerticalAlignment="Top" Width="75" Click="btnNn_Click"/>
            <Button x:Name="btn13" Content="outp13" HorizontalAlignment="Left" Margin="180,66,0,0" VerticalAlignment="Top" Width="76" Click="btnNn_Click"/>
            <Button x:Name="btn12" Content="outp12" HorizontalAlignment="Left" Margin="261,66,0,0" VerticalAlignment="Top" Width="75" Click="btnNn_Click"/>
            <Button x:Name="btn11" Content="outp11" HorizontalAlignment="Left" Margin="367,66,0,0" VerticalAlignment="Top" Width="75" Click="btnNn_Click"/>
            <Button x:Name="btn10" Content="outp10" HorizontalAlignment="Left" Margin="447,66,0,0" VerticalAlignment="Top" Width="75" Click="btnNn_Click"/>
            <Button x:Name="btn09" Content="outp09" HorizontalAlignment="Left" Margin="527,66,0,0" VerticalAlignment="Top" Width="76" Click="btnNn_Click"/>
            <Button x:Name="btn08" Content="outp08" HorizontalAlignment="Left" Margin="608,66,0,0" VerticalAlignment="Top" Width="75" Click="btnNn_Click"/>

        </Grid>

    </DockPanel>



</Window>

以降 MainWindow.xaml.cs のソースコードを解説します。

下記の名前空間の追加をお忘れなく.
using CdioCs; (コンテック社のデジタル入出力を使うため)
using System.Windows.Threding; (ディスパッチタイマを使うため)

70行目、デバイスの名称を宣言します。const でなくてもかまいません。この文字列は外部ファイルなどから読み込んでもかまいません。デバイス名称は「デバイスマネージャ」でメモした文字列を一言一句違わず指定してください。

72行目、コンテック社が用意してくれたデジタル入出力デバイスのクラスを自分で使うための宣言です。

197行目、ソフトが起動してウインドウが作成される寸前にデジタル入出力デバイスのクラスを生成します。

200行目、タイマを使って常にデジタル入力の状態を監視します。タイマで実施する内容は128~187行目の独自メソッド my_timer_method() に書いてあります。

136行目の InpByte() メソッドで入力ビット0~7の状態を監視しています。
140行目の InpByte() メソッドで入力ビット8~15の状態を監視しています。

169行目、入力ビット0~7、8~15の状態をステータスバーに示すために文字列に変換する独自メソッド get_value_string() をコールしています。

入力ビットを文字列に変換するメソッドは86~126行目です。

250行目、デジタル入出力デバイスを使うための初期化 Init() します。これをやらないと、Cdioクラスに定義してあるメソッド InpByte(), OutByte(), EchoBackByte() などが使えません。

294行目、デジタル入出力デバイスを使わなくなったら破棄 Exit() します。

ハードウェアデバイスを使う場合は、だいたいこの流れです。
デバイスのクラスを生成して...メソッドを使う前に初期化して...ソフトの終了時に破棄する、のような流れです。

初期化には Init とか Initialize とか Open などのメソッド名を割り当てられる場合が多いです。
破棄には Exit とか Close とか Free などのメソッド名を割り当てられる場合が多いです。

339、348行目、EchoBackByte() メソッドで現在のデジタル出力がどうなっているかを調べます。その状態をもとに次にどのような値を OutByte() で出力をするかプログラミングします。主にビット演算を使います。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

// この using を忘れないように. Don't forget to add this sentence.
using CdioCs;
using System.Windows.Threading;

namespace aaa
{

	public partial class MainWindow : Window
	{

		const short PORT_LOWER = 0;
		const short PORT_UPPER = 1;

		// LOWER, OUTP.
		const byte BIT_OUTP_07 = 0x80;
		const byte BIT_OUTP_06 = 0x40;
		const byte BIT_OUTP_05 = 0x20;
		const byte BIT_OUTP_04 = 0x10;
		const byte BIT_OUTP_03 = 0x08;
		const byte BIT_OUTP_02 = 0x04;
		const byte BIT_OUTP_01 = 0x02;
		const byte BIT_OUTP_00 = 0x01;

		// LOWER, INP.
		const byte BIT_INP_07 = 0x80;
		const byte BIT_INP_06 = 0x40;
		const byte BIT_INP_05 = 0x20;
		const byte BIT_INP_04 = 0x10;
		const byte BIT_INP_03 = 0x08;
		const byte BIT_INP_02 = 0x04;
		const byte BIT_INP_01 = 0x02;
		const byte BIT_INP_00 = 0x01;

		// UPPER, OUTP.
		const byte BIT_OUTP_15 = 0x80;
		const byte BIT_OUTP_14 = 0x40;
		const byte BIT_OUTP_13 = 0x20;
		const byte BIT_OUTP_12 = 0x10;
		const byte BIT_OUTP_11 = 0x08;
		const byte BIT_OUTP_10 = 0x04;
		const byte BIT_OUTP_09 = 0x02;
		const byte BIT_OUTP_08 = 0x01;

		// UPPER, INP.
		const byte BIT_INP_15 = 0x80;
		const byte BIT_INP_14 = 0x40;
		const byte BIT_INP_13 = 0x20;
		const byte BIT_INP_12 = 0x10;
		const byte BIT_INP_11 = 0x08;
		const byte BIT_INP_10 = 0x04;
		const byte BIT_INP_09 = 0x02;
		const byte BIT_INP_08 = 0x01;

		// デバイスマネージャでデジタル入出力ボードのデバイス名称を調べること.
		const String DEV_NAME_DIO = "DIO000";

		Cdio MyDio;
		short MyId;
		bool FlagCanUseDio = false;

		const long TIMER_INTERVAL_MSEC = 200;
		DispatcherTimer MyTimer;

		const String STR_INVALID_INP = "XXXX - XXXX";

		String StrInpUpper = STR_INVALID_INP;
		String StrInpLower = STR_INVALID_INP;

		//////////////////////////////////////////////////////////////////

		private bool get_value_string( ref String want_lower, ref String want_upper, byte value_lower, byte value_upper )
		{

			want_lower = "INP LOWER ";
			want_upper = "INP UPPER ";

			byte mask;

			// -------------------------------------

			mask = BIT_INP_07; if (( value_lower & mask ) == mask ) { want_lower += "●"; } else { want_lower += "〇"; }
			mask = BIT_INP_06; if (( value_lower & mask ) == mask ) { want_lower += "●"; } else { want_lower += "〇"; }
			mask = BIT_INP_05; if (( value_lower & mask ) == mask ) { want_lower += "●"; } else { want_lower += "〇"; }
			mask = BIT_INP_04; if (( value_lower & mask ) == mask ) { want_lower += "●"; } else { want_lower += "〇"; }

			want_lower += " - ";

			mask = BIT_INP_03; if (( value_lower & mask ) == mask ) { want_lower += "●"; } else { want_lower += "〇"; }
			mask = BIT_INP_02; if (( value_lower & mask ) == mask ) { want_lower += "●"; } else { want_lower += "〇"; }
			mask = BIT_INP_01; if (( value_lower & mask ) == mask ) { want_lower += "●"; } else { want_lower += "〇"; }
			mask = BIT_INP_00; if (( value_lower & mask ) == mask ) { want_lower += "●"; } else { want_lower += "〇"; }

			// -------------------------------------

			mask = BIT_INP_15; if (( value_upper & mask ) == mask ) { want_upper += "●"; } else { want_upper += "〇"; }
			mask = BIT_INP_14; if (( value_upper & mask ) == mask ) { want_upper += "●"; } else { want_upper += "〇"; }
			mask = BIT_INP_13; if (( value_upper & mask ) == mask ) { want_upper += "●"; } else { want_upper += "〇"; }
			mask = BIT_INP_12; if (( value_upper & mask ) == mask ) { want_upper += "●"; } else { want_upper += "〇"; }

			want_upper += " - ";

			mask = BIT_INP_11; if (( value_upper & mask ) == mask ) { want_upper += "●"; } else { want_upper += "〇"; }
			mask = BIT_INP_10; if (( value_upper & mask ) == mask ) { want_upper += "●"; } else { want_upper += "〇"; }
			mask = BIT_INP_09; if (( value_upper & mask ) == mask ) { want_upper += "●"; } else { want_upper += "〇"; }
			mask = BIT_INP_08; if (( value_upper & mask ) == mask ) { want_upper += "●"; } else { want_upper += "〇"; }

			// -------------------------------------

			return true;

		}
	
		private void my_timer_method(object sender, EventArgs e)
		{

			if ( FlagCanUseDio )
			{

				// bit07 ~ bit00 の入力状態を監視する.
				byte v_lower = 0x00;
				int iret_lower = MyDio.InpByte( MyId, PORT_LOWER, out v_lower );

				// bit15 ~ bit08 の入力状態を監視する.
				byte v_upper = 0x00;
				int iret_upper = MyDio.InpByte( MyId, PORT_UPPER, out v_upper );

				bool bret_low = false;
				bool bret_upp = false; 

				// 戻り値が int では以降使いにくいので bool にする.
				if ( iret_lower == (int)( CdioConst.DIO_ERR_SUCCESS ))
				{
					bret_low = true;
				}
				else
				{
					bret_low = false;
				}

				// 戻り値が int では以降使いにくいので bool にする.
				if ( iret_upper == (int)( CdioConst.DIO_ERR_SUCCESS ))
				{
					bret_upp = true;
				}
				else
				{
					bret_upp = false;
				}

				// bit07 ~ bit00, bit15 ~ bit08 の入力状態監視はどちらも成功したか?
				if ( bret_low && bret_upp )
				{
					// ステータスバーに表示する入力状態を示す文字列を取得する.
					get_value_string( ref StrInpLower, ref StrInpUpper, v_lower, v_upper );
				}
				else
				{
					StrInpLower = STR_INVALID_INP;
					StrInpUpper = STR_INVALID_INP;
				}

			}
			else
			{
				StrInpLower = STR_INVALID_INP;
				StrInpUpper = STR_INVALID_INP;
			}

			// 再描画を要請する(OnRender実行).
			this.InvalidateVisual();

		}

		//////////////////////////////////////////////////////////////////

		public MainWindow()
		{

			InitializeComponent();

			// コンテック社が定義したデジタル入出力クラスを使う.
			MyDio = new Cdio();

			// タイマを作成する.
			MyTimer = new DispatcherTimer();

			// タイマ間隔を設定する.
			long ticks_usec = TIMER_INTERVAL_MSEC * 1000;
			long ticks_nsec100 = ticks_usec * 10;
			MyTimer.Interval = new TimeSpan( ticks_nsec100 );

			// 実行するメソッドを登録する.
			MyTimer.Tick += new EventHandler( my_timer_method );

			// タイマ実行を開始する.
			MyTimer.Start();

			this.Title = "GazoYaro";

		}

		protected override void OnRender( DrawingContext dc )
		{

			// デバイス名称を表示する.
			stbLabel000.Content = DEV_NAME_DIO;

			if ( FlagCanUseDio )
			{
				// デバイスが使える状態ならばステータスバーラベルを水色にする.
				stbLabel001.Content = "can use.";
				stbLabel001.Background = Brushes.Aqua;
			}
			else
			{
				// デバイスが使えない状態ならばステータスバーラベルをデフォルトのグレー色にする.
				stbLabel001.Content = "cannot use.";
				stbLabel001.Background = Brushes.Transparent;
			}

			// ステータスバーラベルに現在のデジタル入力状態を表示する.
			stbLabel002.Content = StrInpUpper;
			stbLabel003.Content = StrInpLower;

		}

		private void menuDioInit_Click( object sender, RoutedEventArgs e )
		{

			// DIOが使用可能状態になっているかどうか.
			if (!( FlagCanUseDio ))
			{

				// DIOデバイスを初期化する.
				int ret = MyDio.Init( DEV_NAME_DIO, out MyId );

				if ( ret == (int)( CdioConst.DIO_ERR_SUCCESS ))
				{
					FlagCanUseDio = true;
				}
				else
				{
					FlagCanUseDio = false;
					MessageBox.Show( "Error: MyDio.Init();" );
				}

			}

			// 再描画を要請する.
			this.InvalidateVisual();

		}

		private void menuDioExit_Click( object sender, RoutedEventArgs e )
		{

			if ( FlagCanUseDio )
			{

				int ret;

				// 出力ビットは全部オフにする, 00 to 07.
				ret = MyDio.OutByte( MyId, PORT_LOWER, 0x00 );
				if ( ret != (int)( CdioConst.DIO_ERR_SUCCESS ))
				{
					MessageBox.Show( "Error: MyDio.OutByte( MyId, PORT_LOWER, 0x00 );" );
					return;
				}

				// 出力ビットは全部オフにする, 08 to 15.
				ret = MyDio.OutByte( MyId, PORT_UPPER, 0x00 );
				if ( ret != (int)( CdioConst.DIO_ERR_SUCCESS ))
				{
					MessageBox.Show( "Error: MyDio.OutByte( MyId, PORT_UPPER, 0x00 );" );
					return;
				}

				// DIO デバイスを終了する.
				ret = MyDio.Exit( MyId );

				if ( ret != (int)( CdioConst.DIO_ERR_SUCCESS ))
				{
					MessageBox.Show( "Error: MyDio.Exit();" );
				}

				FlagCanUseDio = false;

			}

			// 再描画を要請する.
			this.InvalidateVisual();

		}

		private void menuApplicationQuit_Click( object sender, RoutedEventArgs e )
		{

			if ( FlagCanUseDio )
			{
				// Exit() するようにユーザにしらせて終了は中断する.
				MessageBox.Show( "Please exec DIO.Exit" );
				return; // warning.
			}

			// タイマーをとめる.
			MyTimer.Stop();

			// このウインドウを閉じてアプリケーションを終了する.
			this.Close();

		}

		private void btnNn_Click( object sender, RoutedEventArgs e )
		{

			if (!( FlagCanUseDio ))
			{
				MessageBox.Show( "Please exec DIO.Init" );
				return; // warning.
			}

			// bit07 ~ bit00 の出力状態を取得する.
			byte value_lower;
			int iret_lower = MyDio.EchoBackByte( MyId, PORT_LOWER, out value_lower );
			if ( iret_lower != (int)( CdioConst.DIO_ERR_SUCCESS ))
			{
				MessageBox.Show( "Error: MyDio.EchoBackByte( PORT_LOWER );" );
				return; // warning.
			}

			// bit15 ~ bit08 の出力状態を取得する.
			byte value_upper;
			int iret_upper = MyDio.EchoBackByte( MyId, PORT_UPPER, out value_upper );
			if ( iret_upper != (int)( CdioConst.DIO_ERR_SUCCESS ))
			{
				MessageBox.Show( "Error: MyDio.EchoBackByte( PORT_UPPER );" );
				return; // warning.
			}

			bool flag_lower;

			// ビットの状態を反転させる.
			if      ( sender.Equals( btn07 )){ flag_lower = true;  value_lower ^= BIT_OUTP_07; } // 07.
			else if ( sender.Equals( btn06 )){ flag_lower = true;  value_lower ^= BIT_OUTP_06; }
			else if ( sender.Equals( btn05 )){ flag_lower = true;  value_lower ^= BIT_OUTP_05; }
			else if ( sender.Equals( btn04 )){ flag_lower = true;  value_lower ^= BIT_OUTP_04; }
			else if ( sender.Equals( btn03 )){ flag_lower = true;  value_lower ^= BIT_OUTP_03; }
			else if ( sender.Equals( btn02 )){ flag_lower = true;  value_lower ^= BIT_OUTP_02; }
			else if ( sender.Equals( btn01 )){ flag_lower = true;  value_lower ^= BIT_OUTP_01; }
			else if ( sender.Equals( btn00 )){ flag_lower = true;  value_lower ^= BIT_OUTP_00; } // 00.
			else if ( sender.Equals( btn15 )){ flag_lower = false; value_upper ^= BIT_OUTP_15; } // 15.
			else if ( sender.Equals( btn14 )){ flag_lower = false; value_upper ^= BIT_OUTP_14; }
			else if ( sender.Equals( btn13 )){ flag_lower = false; value_upper ^= BIT_OUTP_13; }
			else if ( sender.Equals( btn12 )){ flag_lower = false; value_upper ^= BIT_OUTP_12; }
			else if ( sender.Equals( btn11 )){ flag_lower = false; value_upper ^= BIT_OUTP_11; }
			else if ( sender.Equals( btn10 )){ flag_lower = false; value_upper ^= BIT_OUTP_10; }
			else if ( sender.Equals( btn09 )){ flag_lower = false; value_upper ^= BIT_OUTP_09; }
			else if ( sender.Equals( btn08 )){ flag_lower = false; value_upper ^= BIT_OUTP_08; } // 08.
			else                             { return; } // warning.

			// 下位か上位か?
			if ( flag_lower )
			{
				// bit07 ~ bit00 に値を出力する.
				iret_lower = MyDio.OutByte( MyId, PORT_LOWER, value_lower );
				if ( iret_lower != (int)( CdioConst.DIO_ERR_SUCCESS ))
				{
					MessageBox.Show( "Error: MyDio.OutByte( PORT_LOWER );" );
					return; // warning.
				}
			}
			else
			{
				// bit15 ~ bit08 に値を出力する.
				iret_upper = MyDio.OutByte( MyId, PORT_UPPER, value_upper );
				if ( iret_upper != (int)( CdioConst.DIO_ERR_SUCCESS ))
				{
					MessageBox.Show( "Error: MyDio.OutByte( PORT_UPPER );" );
					return; // warning.
				}
			}

			// 再描画を要請する.
			this.InvalidateVisual();

		}

		private void menuOutpAllOn_Click( object sender, RoutedEventArgs e )
		{

			if ( FlagCanUseDio )
			{

				byte value_lower = 0;
				value_lower |= BIT_OUTP_07;
				value_lower |= BIT_OUTP_06;
				value_lower |= BIT_OUTP_05;
				value_lower |= BIT_OUTP_04;
				value_lower |= BIT_OUTP_03;
				value_lower |= BIT_OUTP_02;
				value_lower |= BIT_OUTP_01;
				value_lower |= BIT_OUTP_00;
				int iret_lower = MyDio.OutByte( MyId, PORT_LOWER, value_lower );
				if ( iret_lower != (int)( CdioConst.DIO_ERR_SUCCESS ))
				{
					MessageBox.Show( "Error: MyDio.OutByte( PORT_LOWER );" );
					return; // warning.
				}

				byte value_upper = 0;
				value_upper |= BIT_OUTP_15;
				value_upper |= BIT_OUTP_14;
				value_upper |= BIT_OUTP_13;
				value_upper |= BIT_OUTP_12;
				value_upper |= BIT_OUTP_11;
				value_upper |= BIT_OUTP_10;
				value_upper |= BIT_OUTP_09;
				value_upper |= BIT_OUTP_08;
				int iret_upper = MyDio.OutByte( MyId, PORT_UPPER, value_upper );
				if ( iret_upper != (int)( CdioConst.DIO_ERR_SUCCESS ))
				{
					MessageBox.Show( "Error: MyDio.OutByte( PORT_UPPER );" );
					return; // warning.
				}

			}
			else
			{
				MessageBox.Show( "Please exec DIO.Init" );
			}

		}

		private void menuOutpAllOff_Click( object sender, RoutedEventArgs e )
		{

			if ( FlagCanUseDio )
			{

				byte value_lower = 0;
				int iret_lower = MyDio.OutByte( MyId, PORT_LOWER, value_lower );
				if ( iret_lower != (int)( CdioConst.DIO_ERR_SUCCESS ))
				{
					MessageBox.Show( "Error: MyDio.OutByte( PORT_LOWER );" );
					return; // warning.
				}

				byte value_upper = 0;
				int iret_upper = MyDio.OutByte( MyId, PORT_UPPER, value_upper );
				if ( iret_upper != (int)( CdioConst.DIO_ERR_SUCCESS ))
				{
					MessageBox.Show( "Error: MyDio.OutByte( PORT_UPPER );" );
					return; // warning.
				}

			}
			else
			{
				MessageBox.Show( "Please exec DIO.Init" );
			}

		}

	}

}

かなり長いコードになってしまったので、コピーペーストでビルドするのは不可能だと思います。プロジェクトをZIPアーカイブして用意しました。よろしければ下記からダウンロードして試してみてください。