WinUSBデバイスとシリアル通信するには

WinUSB

WindowsRuntimeでは、サードパーティー製のドライバで接続されたデバイスとのシリアル通信が禁止されています。

基本的にWindowsストアアプリなどからUSBデバイスとシリアル通信を行うには、USBデバイスが「WinUSB.sys」というドライバで認識されていなければいけません。

たとえばエレコムのUC-SGTなどは、RS232C→USBの変換ケーブルですが、公式でWinUSBをインストールするドライバパッケージ(中身はinfファイル)が提供されているのでドライバを入れれば、UC-SGTで接続されたデバイスはWindowsストアアプリからシリアル通信が可能となります。

とにかく、WindowsRuntimeでシリアル通信を行うには、デバイスをWinUSBというドライバで認識できなければ使うことができません。

 

デバイスをWinUSBとして認識させる2つの方法

デバイスをWinUSBとして認識させるには2つの方法があります。

  1. カスタムinfファイルを作成する方法 (条件 端末に物理キーボードが付いている場合)
  2. レジストリにGUIDを登録する方法 (条件 レジストリをいじっても問題無い場合)

 

1番目のカスタムinfファイルを作成する方法は、端末に物理キーボードが付いていることが条件になります。

なぜなら、オリジナルなinfファイルをつくり、インストールするためデジタル証明の無いドライバーをインストールする許可を端末に与えなければいけません。

Windows8.1でデジタル証明のないドライバをインストールする許可を与えるには、PCの設定→保守と管理→回復→PCの起動をカスタマイズする→トラブルシューティング→詳細オプション→その他の修復オプションを表示→スタートアップ設定に行き、

「7キー」を押してドライバー署名の強制を無効にするを押さなければいけません。

20140923_072229394_iOS

 

 

しかし端末に物理キーボードなどがついていない場合、7キーを押すことができません。USBキーボードを接続しても認識しない場合が多いので、ラップトップなど、PCに物理キーボードが標準で付いている場合はこちらのカスタムinfファイルを作成する方法をとれますが、端末に物理キーボードがついていない場合、レジストリをいじる必要があります。

 

2番目のレジストリにGUIDを登録する方法は、端末に物理キーボードがついていない場合使用します。

そもそもすべてのデバイスはデバイスマネージャからWinUSBドライバをドライバとして選択すればドライバを適用できます。

しかし、認識するときにシステムが登録されているGUIDにデバイスと一致するものがあるかどうか見に行くのですがその時にデバイスのGUIDがなくて認識できません。

そこで、レジストリにデバイスのGUIDを登録することでデバイスを認識することができます。

GUIDとはGlobally Unique Identifierの略でなにかを一意に決定する識別子(ID)です。

このような形をしています。{d53fa365-5ag4-4436-938b-9db4734c6ca3}

 

Arduinoを接続してみる

Arduinoマイコンとは様々IOが標準で搭載されたAVRマイコンで非常に使い勝手がよく、シリアル通信をすることもできます。

今回はArduino UNOを接続してみたいと思います。

20140923_114511201_iOS

 

カスタムinfファイルを作成する方法

こちらの方法でデバイスが認識できればGUIDを追加する方法はしなくてもよいです。

infファイルとは、Windowsのソフトウエアをインストール用の設定が記述されたファイルのことです。

事前にOSにinfファイルをインストールしておくと、デバイスが接続されたときそのinfファイルを仲介してWinUSBドライバを読み込んでくれます。

40

カスタムinfファイルとは、そのinfファイルを自分で記述して事前にインストールしておくことを指します。

 

ではカスタムinfファイルを作成してみましょう。

以下のテキストデータをテキストエディタで書き込みます。

;
;
; Installs WinUsb
;

[Version]
Signature = "$Windows NT$"
Class     = USBDevice
ClassGUID = {88BAE032-5A81-49f0-BC3D-A4FF138216D6}
Provider  = %ManufacturerName%
CatalogFile = WinUSBInstallation.cat
DriverVer=09/04/2012,13.54.20.543

; ========== Manufacturer/Models sections ===========

[Manufacturer]
%ManufacturerName% = Standard,NTamd64

[Standard.NTamd64]
%DeviceName% =USB_Install, USB\VID_2341&PID_0043


; ========== Class definition ===========

[ClassInstall32]
AddReg = ClassInstall_AddReg

[ClassInstall_AddReg]
HKR,,,,%ClassName%
HKR,,NoInstallClass,,1
HKR,,IconPath,%REG_MULTI_SZ%,"%systemroot%\system32\setupapi.dll,-20"
HKR,,LowerLogoVersion,,5.2

; =================== Installation ===================

[USB_Install]
Include = winusb.inf
Needs   = WINUSB.NT

[USB_Install.Services]
Include =winusb.inf
Needs   = WINUSB.NT.Services

[USB_Install.HW]
AddReg=Dev_AddReg

[Dev_AddReg]
HKR,,DeviceInterfaceGUIDs,0x10000,"{2702F300-4B94-4E4D-B0BD-238A6404E9F9}"

; [DestinationDirs]
; If your INF needs to copy files, you must not use the DefaultDestDir directive here.  
; You must explicitly reference all file-list-section names in this section.

; =================== Strings ===================

[Strings]
ManufacturerName="garicchi"
ClassName="Universal Serial Bus devices"
DeviceName="Arduino WinUSB"
REG_MULTI_SZ = 0x00010000

編集すべきところは

%DeviceName% = と [Dev_AddReg] と ManufacturerName= と DeviceName= の4つです。

 

%DeviceName% =

ここではVendorIDとProductIDを指定します。

ArduinoのVendorIDとProductIDの取得方法は、通常の方法でArduinoのドライバーをインストールしてデバイスマネージャからプロパティを表示します。

41

 

ハードウエアIDの項目を見るとVID_****とPID_****が書かれています。

 

42

 

コレをさきほどの%DeviceName% =USB_Install, USB\以降に書きます。

おそらく同じArduinoUNOを使っているとVIDとPIDは同じ値になるはずです。

[Dev_AddReg]

ここではオリジナルのGUIDを作成して書き込みます。

GUIDの作成は、VisualStudioのGUID作成ツールで行います。

VisualStudioのメニューバーの[ツール]→[GUIDの作成]を押します。

43

 

GUID形式はレジストリ形式を選択し、[新規GUIDの作成]をしてコピーします。

44

 

GUIDをコピーしたら

[Dev_AddReg]
HKR,,DeviceInterfaceGUIDs,0x10000,”*************”

の「*」の部分に貼り付けます。

 

ManufacturerName=

個々にはデバイスドライバの製造者名を書き込みます。なんでも大丈夫です

DeviceName=

個々には表示されるデバイス名を書き込みます。

ここに書いた値がデバイスマネージャに表示されます。

 

ここまでできたら拡張子を.infとしてファイルを保存しておきましょう。

45

 

デジタル署名の無いinfファイルのインストールを許可する

設定チャーム→PCの設定→保守と管理→回復→PCの起動をカスタマイズするで[今すぐ再起動をする]を押します。

そして青い画面で、トラブルシューティング→詳細オプション→その他の修復オプションを表示→スタートアップ設定に行き、

「7キー」を押します。

これでデジタル署名の無いinfファイルのインストールが許可されます。

 カスタムinfファイルをインストールする

では先ほど作成したinfファイルを右クリックして[インストール]を押しましょう。

49

 

[このドライバーソフトウエアをインストールします]をクリックします。

53

 

このダイアログが出れば成功です。

54

 

Arduinoの標準ドライバをアンインストールする。

カスタムinfファイルをインストールできたら現在インストールしている標準のArduinoドライバをアンインストールしましょう。

デバイスマネージャからArduinoUNOを削除します。

46

 

このデバイス・ドライバーソフトウエアを削除するにチェックをいれ、OKを押します。

47

 

できたら一度、Arduinoを抜き差ししましょう。

デバイスマネージャのユニバーサル・シリアル・バスデバイスの項目に自分がinfファイルに設定した名前と同じ名前でArduinoが認識できていれば成功です。

55

もし認識できていない場合は、不明なデバイスのどれかがArduinoなので、プロパティからVendorIDとProductIDで特定しましょう。

特定できたら、ドライバーソフトウエアの更新を押します。

57

 

コンピュータを参照してドライバーソフトウエアを検索します。を押します。

58

 

コンピュータ上のデバイス・ドライバーの一覧から選択します。を押します。

 

59

 

ユニバーサルシリアルバスデバイスを選択し、次へを押します。

 

60

 

正しくinfファイルがインストールされていればこの中の項目に自分の作成したinfファイルと同一名のものがあるのでそれを選択し、次へを押します。

62

 

 

ドライバーのインストールが完了すれば成功です。

64

カスタムinfファイルを作成する方法は以上で終わりです。

あとはWinUSBのAPIを利用することでシリアル通信が可能となります。

WinUSBのインストール

 

レジストリにGUIDを追加する方法

こちらの方法でデバイスが認識できればカスタムinfの方法はしなくても大丈夫です。

こちらの方法はレジストリを編集するので注意して編集してください。

もしレジストリを編集してお使いのPCの動作が不安定になっても私は責任を負いません。

 

レジストリにGUIDを追加する方法は、一度ArduinoをWinUSBドライバで読み込ませます。

現在インストールしているArduinoのドライバを一度削除します。

46

 

このデバイスのドライバーソフトウエアを削除するにチェックを入れ、[OK]を押します。

 

47

 

できたら一度、ハードウエアの変更のスキャンを押しましょう。

 

48

 

続いて[ほかのデバイス]の中から不明なデバイスのどれか1つがArduinoなのでプロパティを見てVendorIDとProductIDで特定しましょう。

特定できたらドライバーソフトウエアの更新を押します。

57

 

コンピュータを参照してドライバーソフトウエアを検索します。を押します。

58

コンピュータ上のデバイス・ドライバーの一覧から選択します。を押します。

59

ユニバーサルシリアルバスデバイスを選択し、次へを押します。

60

Microsoftの中に、WinUSBデバイスがあるのでそれを選択します。

61

ドライバーのインストールが完了すれば成功です。

63

 

GUIDを生成する

VisualStudioのGUID生成ツールを使ってGUIDを作りましょう。

VisualStudioのメニューバーの[ツール]→[GUIDの作成]を押します。

43

 

GUID形式はレジストリ形式を選択し、[新規GUIDの作成]をしてコピーします。

44

 

ではレジストリを編集します。

ファイル名を指定して実行で「regedit」と入力し、レジストリエディタを立ち上げます。

65

 

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\<VID_****&PID_*****>の下の更に下の改装にDevice Parametersがあるので、その中に新規で文字列を追加しましょう。

↑(****はArduinoのVendorIDとProductIDに対応)

 

名前は[DeviceInterfaceGUIDs]で値に先ほど作成したGUIDを設定します。

68

 

以上でGUIDを追加する方法は完了です。

あとはWinUSBのAPIから呼び出すとシリアル通信をすることができます。

 

USBシリアル通信の準備

では実際にUSBで接続されたデバイスとシリアル通信を行ってみましょう。

 

まずはPackage.manifestファイルを編集します。

Package.manifestファイルを右クリック→[コードの表示]を押しましょう。

37

Packageタグにwc属性を追加しましょう。

<Package xmlns="http://schemas.microsoft.com/appx/2010/manifest"
         xmlns:m2="http://schemas.microsoft.com/appx/2013/manifest"
         xmlns:wb="http://schemas.microsoft.com/appx/2013/manifest"
         >

Capabilityタグの要素に以下を追加します。

wc:DeviceタグのId属性はVendorIDとProductIDを接続したいデバイスに置き換えてください。

m2:FunctionタグのType属性に関してはCDCコントロールは02 * *で共通です。

詳しくはWindowsデベロッパーセンターに載っています。

<wb:DeviceCapability Name="usb">
  <wb:Device Id="vidpid:2341 0043">
    <m2:Function Type="classId:02 * *"/>
  </wb:Device>
</wb:DeviceCapability>

 

続いて以下のUsbSerialPortクラスをコピペして新しいクラスとして追加しましょう。

Usbシリアル通信はUsbDeviceクラスからUsbInterfaceクラスでインターフェースを指定してDataWriterとDataReaderで通信を行いますが、結構めんどくさいので以下のクラスを使ってシリアル通信をします。

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Windows.Devices.Usb;
using Windows.Storage.Streams;

namespace UsbSerial
{
    public class UsbSerialPort:IDisposable
    {
        private UsbDevice device;

        public UsbDevice Device
        {
            get { return device; }
        }

        private bool isOpen;

        public bool IsOpen
        {
            get { return isOpen; }
        }

        private bool isListened;

        public bool IsListened
        {
            get { return isListened; }
        }
        
        public event EventHandler<DataReceivedEventArgs> ListenDataReceived;
        
        private uint baudRate;
        private Parity parity;
        private int dataBits;
        private StopBits stopBits;

        private bool dtrEnable;
        private bool rtsEnable;

        // USB interfaces
        private UsbInterface interfaceCdcControl;
        private UsbInterface interfaceCdcData;

        private DataWriter writer;
        private DataReader reader;


        public UsbSerialPort(UsbDevice device)
        {
            this.device = device;
            this.dtrEnable = false;
            this.rtsEnable = false;
            this.isOpen = false;
            isListened = false;
            ListenDataReceived += (s, e) => { };
        }

        public async Task<bool> OpenAsync(uint baudRate)
        {
            return await OpenAsync(baudRate, Parity.None, 8, StopBits.One);
        }

        //ポートオープン
        public async Task<bool> OpenAsync(uint baudRate, Parity parity, int dataBits, StopBits stopBits)
        {

            this.baudRate = baudRate;
            this.parity = parity;
            this.dataBits = dataBits;
            this.stopBits = stopBits;

            //デバイスのインターフェース一覧から選択する
            foreach (UsbInterface usbInterface in device.Configuration.UsbInterfaces)
            {
                if (usbInterface == null)
                {
                    continue;
                }

                foreach (UsbInterfaceSetting interfaceSetting in usbInterface.InterfaceSettings)
                {
                    byte index = interfaceSetting.InterfaceDescriptor.InterfaceNumber;
                    byte interfaceClass = interfaceSetting.InterfaceDescriptor.ClassCode;

                    if (interfaceClass == InterfaceClass.CdcControl)
                    {
                        interfaceCdcControl = usbInterface;
                    }
                    else if (interfaceClass == InterfaceClass.CdcData)
                    {
                        interfaceCdcData = usbInterface;
                    }
                    else if (interfaceClass == InterfaceClass.VendorSpecific)
                    {
                        if (interfaceCdcControl == null)
                        {
                            // Test SetLineCoding/GetLineCoding
                            uint written = 0;
                            IBuffer gotBuffer = null;
                            try
                            {
                                written = await this.SetLineCoding(index,9600, 0, 0, 8);
                            }
                            catch (Exception)
                            {
                                // This interface is not compatible with CDC ACM. Try the next interface.
                                continue;
                            }

                            try
                            {
                                gotBuffer = await this.GetLineCoding(index);

                            }
                            catch (Exception)
                            {
                                // This interface is not compatible with CDC ACM. Try the next interface.
                                continue;
                            }

                            if (gotBuffer != null && gotBuffer.Length == 7)
                            {
                                var lineCodingReader = DataReader.FromBuffer(gotBuffer);
                                lineCodingReader.ByteOrder = ByteOrder.LittleEndian;
                                var bps = lineCodingReader.ReadUInt32();
                                if (bps == 9600)
                                {
                                    // This could be a interfaceCdcControl.
                                    interfaceCdcControl = usbInterface;
                                }
                            }
                        }

                        if (interfaceCdcData == null)
                        {
                            if (usbInterface.BulkInPipes.Count > 0 &&
                                usbInterface.BulkOutPipes.Count > 0)
                            {
                                // This could be a CdcData.
                                interfaceCdcData = usbInterface;
                            }
                        }
                    }

                }
            }

            if (this.interfaceCdcControl != null && this.interfaceCdcData != null)
            {
                // Flush the pipes.
                for (int IN = 0; IN < this.interfaceCdcData.BulkInPipes.Count; IN++)
                {
                    this.interfaceCdcData.BulkInPipes[IN].FlushBuffer();
                }

                var len = await SetLineCoding(this.interfaceCdcControl.InterfaceNumber, this.baudRate, (byte)this.stopBits, (byte)this.parity, (byte)this.dataBits);

                // Do SetControlLineState
                len = await SetControlLineState(this.interfaceCdcControl.InterfaceNumber);

                var outputStream = this.interfaceCdcData.BulkOutPipes[0].OutputStream;
                
                writer = new DataWriter(outputStream);

                var inputStream = this.interfaceCdcData.BulkInPipes[0].InputStream;
                interfaceCdcData.BulkInPipes[0].FlushBuffer();
                reader = new DataReader(inputStream);

                isOpen = true;
                return true;
            }
            else
            {
                return false;
            }


        }

        //指定したバイト数データ読み込み
        public async Task<IBuffer> ReadBufferAsync(uint count)
        {
            if (isOpen == false)
            {
                throw new Exception("ポートがオープンされてません");
            }
            var i = await reader.LoadAsync(count);
            IBuffer buff = reader.ReadBuffer(i);
            if (i > 0)
            {
                return buff;
            }
            else
            {
                return await ReadBufferAsync(count);
            }
        }

        public async Task<byte[]> ReadBytesAsync(uint count)
        {
            IBuffer buff = await ReadBufferAsync(count);
            using (DataReader reader = DataReader.FromBuffer(buff))
            {
                byte[] bytes = new byte[buff.Length];
                reader.ReadBytes(bytes);
                return bytes;
            }
        }

        public void StartDataListen(uint count)
        {
            Task.Run(async() =>
            {
                
                isListened = true;
                while (isListened)
                {
                    var bytes= await ReadBytesAsync(count);
                    ListenDataReceived(this,new DataReceivedEventArgs(bytes));
                }
            });
        }

        public void StopDataListen()
        {
            isListened = false;
        }


        //データ書き込み
        public async Task WriteBufferAsync(IBuffer buffer)
        {
            if (isOpen == false)
            {
                throw new Exception("ポートがオープンされてません");
            }
            uint offset = 0;
            uint count = buffer.Length;

            writer.WriteBuffer(buffer, offset, count);

            var written = await writer.StoreAsync();
        }

        public async Task WriteBytesAsync(byte[] bytes)
        {
            using (DataWriter writer = new DataWriter())
            {
                writer.WriteBytes(bytes);
                var buffer = writer.DetachBuffer();

                await WriteBufferAsync(buffer);
            }
        }

        //ポートを閉じる
        public void Dispose()
        {
            if (writer != null)
            {
                writer.Dispose();
                writer = null;
            }
            if (reader != null)
            {
                reader.Dispose();
                reader = null;
            }
            isOpen = false;
        }

        private async Task<IBuffer> GetLineCoding(uint index)
        {

            var buffer = new Windows.Storage.Streams.Buffer(7);
            buffer.Length = 7;

            var requestType = new UsbControlRequestType();
            requestType.AsByte = RequestType.Get;

            var packet = new UsbSetupPacket();
            packet.RequestType = requestType;
            packet.Request = RequestCode.GetLineCoding;
            packet.Value = 0;
            packet.Length = buffer.Length;
            packet.Index = index;

            return await this.device.SendControlInTransferAsync(packet, buffer);

        }


        private async Task<uint> SetLineCoding(uint index, uint dteRate, byte charFormat, byte parityType, byte dataBits)
        {
            IBuffer detachBuffer = null;
            // SetLineCoding
            using (var writer = new DataWriter())
            {
                writer.ByteOrder = Windows.Storage.Streams.ByteOrder.LittleEndian;
                writer.WriteUInt32(dteRate);
                writer.WriteByte(charFormat);
                writer.WriteByte(parityType);
                writer.WriteByte(dataBits);
                detachBuffer = writer.DetachBuffer();
            }
            var requestType = new UsbControlRequestType();
            requestType.AsByte = RequestType.Set;

            return await UsbControlRequestForSet(index, requestType, RequestCode.SetLineCoding, 0, detachBuffer);
        }

        private async Task<uint> SetControlRequest(byte request, ushort value, IBuffer buffer)
        {
            var requestType = new UsbControlRequestType();
            requestType.AsByte = RequestType.Set;
            return await UsbControlRequestForSet(this.interfaceCdcControl.InterfaceNumber, requestType, request, value, buffer);

        }
        private async Task<uint> UsbControlRequestForSet(uint index, UsbControlRequestType requestType, byte request, ushort value, IBuffer buffer)
        {
            var packet = new UsbSetupPacket();
            packet.RequestType = requestType;
            packet.Request = request;
            packet.Value = value;
            packet.Length = buffer != null ? buffer.Length : 0;
            packet.Index = index;

            return await this.device.SendControlOutTransferAsync(packet, buffer);
        }

        private async Task<uint> SetControlLineState(uint index)
        {
            // SetControlLineState

            var requestType = new UsbControlRequestType();
            requestType.AsByte = RequestType.Set;

            var value = (this.rtsEnable ? 1 : 0) << 1 | (this.dtrEnable ? 1 : 0);

            return await UsbControlRequestForSet(index, requestType, RequestCode.SetControlLineState, (ushort)value, null);
        }


        public async Task SetDtrEnableAsync(bool value)
        {
            this.dtrEnable = value;
            var count = await SetControlLineState(this.interfaceCdcControl.InterfaceNumber);
        }

        public async Task SetRtsEnableAsync(bool value)
        {

            this.rtsEnable = value;
            var count = await SetControlLineState(this.interfaceCdcControl.InterfaceNumber);

        }



    }


    public class InterfaceClass
    {
        public const byte CdcControl = 2;
        public const byte CdcData = 10;
        public const byte VendorSpecific = 255;
    }

    public class RequestType
    {
        public const byte Set = 0x21;
        public const byte Get = 0xA1;
    }

    public class RequestCode
    {
        public const byte SetLineCoding = 0x20;
        public const byte GetLineCoding = 0x21;
        public const byte SetControlLineState = 0x22;
        public const byte SendBreak = 0x23;
    }

    public enum Parity
    {
        None = 0,
        Odd,
        Even,
        Mark,
        Space
    };

    public enum StopBits
    {
        None = -1,
        One = 0,
        OnePointFive = 1,
        Two = 2
    };

    public class DataReceivedEventArgs : EventArgs
    {
        public byte[] Data { get; set; }
        public DataReceivedEventArgs(byte[] data)
        {
            this.Data = data;
        }
    }
}

 

USBSerialPortクラスを使う

では先ほどのUsbSerialPortクラスを使ってみましょう。

UsbDeviceクラスのGetDeviceSelectorメソッドにVendorIdとProductIdを指定してselectorを取得します。

その後、DeviceInformationのFindAllAsyncメソッドを使ってデバイスを取得します。

取得したDeviceのIdを使って、UsbDeviceを取得します。

そしてUsbDeviceを使ってUsbSerialPortクラスを初期化します。

UsbDevice device;
UsbSerialPort port;
string selector=UsbDevice.GetDeviceSelector(0x2341,0x0043);
var deviceInfoList=await DeviceInformation.FindAllAsync(selector);
if (deviceInfoList.Count > 0)
{
    DeviceInformation deviceInfo=deviceInfoList.First();
    this.device=await UsbDevice.FromIdAsync(deviceInfo.Id);
    this.port = new UsbSerialPort(device);
   
}

 

UsbSerialPortを初期化したらOpenAsyncでポートをオープンします。

通信速度は9600とします。

bool isOk=await port.OpenAsync(9600);

 

データを受信した時のイベントをハンドルしておきます。

port.ListenDataReceived += async (s, arg) =>
{
   byte[] bytes = arg.Data;

   await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
   {
       char c = (char)bytes[0];
       Debug.WriteLine(c.ToString());
   });
};

データのリッスンを開始します。

引数で指定したバイト数だけ読み込みます。

もしデータが流れてきた場合ListenDataReceivedイベントが発動します。

port.StartDataListen(1);

 

データを書き込みます。

今回は2という数字をバイトデータとして送ります。

byte value=2;
byte[] bytes = { (byte)value };

await port.WriteBytesAsync(bytes);

 

Arduino側のプログラム

Arduinoはドライバを変更してしまったので別のPCでArduinoIDEを使ってプログラムを書き込む必要があります。

Arduino側のプログラムはシリアルポートにデータが流れてきたらそのままデータを返して13番のLEDを100ミリ秒点灯させます。

int ledPin=13;

void setup(){
  pinMode(ledPin,OUTPUT);
  Serial.begin(9600);
}

void loop(){
  int data=Serial.read();
  if(data!=-1){
    Serial.print(data);
    digitalWrite(ledPin,HIGH);
    delay(100);
    digitalWrite(ledPin,LOW);
  }
}

20140923_164841269_iOS

これでArduinoとタブレットをつないでプログラムを実行するとシリアル通信できます。

 

2件のコメント

  • 菊池恭平 より:

    USBSerialPortクラスを使うときメインはどんな感じで書きました?

    • garicchi より:

      コメントありがとうございます
      「USBSerialPortクラスを使う」セクションに書いてあるところがMainメソッドに書く内容となっています
      コードは分割していますが
      上から順番にコピペしていけばうごくはずです

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください