さて、本題のArduinoからWindows PCへのデータ送信について説明します。ここではVisual Basic 2010 Expressを使います。2010年版をよく持ってるな!と言われそうですが、2019年版のVisual Studioでも同じことができることは確認しています。VB6はいろいろな素人プログラマーに愛されたIDEでしたが、.NETになってからはBASICのよさがなくなりました。インタープリターなので、三軸制御ソフトを実験動作中に一瞬停止してコードを書き変え、何事もなかったかのように実験を再開する、といったことができたのですが、.NETになってからBASICも中間言語に一度コンパイルされているようで、このようなことができなくなりました。もはやBASICで書く理由もあまりないのですが、惰性でVisual Basicを使っています。

 

ArduinoからのデータをPCに読み込む

 ここでは、Arduinoから1秒に一回、アナログピンA0で読んだ電圧をPCに転送し、表示するプログラムを書きます。もちろん、Arduino IDEのシリアルモニタでも同じことができますが、Visual Studioで読めば、自身の開発プログラムでこの値をいぢることができます(例えば、ファイルとして保存していくなど)。このブログはVSのチュートリアルではないので、ここでは値を表示するだけにします。

 

 Visual Basic (Visual Studio: VS)にはSerialPortというコンポーネントがあります。昔のVB6でいうMS Commに相当するものです。これをフォームに貼り付けます。VB6時代は電話機のアイコンがフォーム上に置かれましたが、最近のVSでは画面の下のほうに置かれます。

 

 

これのプロパティを以下のように設定します(Arduinoがつながれたときに、ポート番号がCOM3だのCOM8だの自動的にふられるので、Arduino IDEあるいはWindowsのデバイスマネージャでこの番号を確認して、ここに入力してください)。基本的にデフォルトのままでこうなっていると思います。名前はSerialPort1となると思うので、このままにします。

 

 

フォームに、ボタンを配置します。プロパティで、NameをbtnOpenClose、TextをOpenとします。

 

 

ダブルクリックして、以下のコードを書きます。これは、プログラム実行時にこのボタンをクリックすると実行される内容を書いていることになります。説明するまでもありませんが、シリアルポートの開閉を行うボタンです。

 

 

Private Sub btnOpenClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOpenClose.Click

 

        If btnOpenClose.Text = "Open" Then

            btnOpenClose.Text = "Close"

            SerialPort1.Open()

            System.Threading.Thread.Sleep(500) '500mSecほど待つ

        Else

            btnOpenClose.Text = "Open"

            SerialPort1.Close() '500mSecほど待つ

            System.Threading.Thread.Sleep(500)

        End If

 

End Sub

 

 

もう一つボタンを配置し、NameをbtnReadStartStop、TextをRead startとし、ダブルクリックで以下のコードを書きます。これはArduinoからの送信を読むためのルーチンを開始・停止するボタンです。

 

 

Private Sub btnReadStartStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnReadStartStop.Click

 

        If tmrRead.Enabled = True Then

            btnReadStartStop.Text = "Read start"

            tmrRead.Enabled = False

        Else

            btnReadStartStop.Text = "Read stop"

            tmrRead.Enabled = True

        End If

 

End Sub

 

 

次に、フォームにテキストボックス(NameをtxtReadに)を配置します。そして、タイマーのコンポーネント(NameをtmrReadに)を追加します。ここをダブルクリックし、以下のコードを書きます。これは、タイマーのプロパティ「Enabled」がTrueのとき、Interval(ミリ秒)の値に従って一定間隔で実行されるコードです。プロパティでIntervalの値を1000(1秒)にしておきます。EnabledはFalseのままでいいです(先につくったボタンでTrue/Falseを切り替えます)。

 

 

Private Sub tmrRead_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrRead.Tick

 

        SerialPort1.WriteLine("") 'Arduinoに改行文字を送る

        System.Threading.Thread.Sleep(100) '100mSec待つ

        txtRead.Text = Format(Val(SerialPort1.ReadLine()), "0.0")

 

End Sub

 

 

これでVSのほうは完成で、見てくれはこうなっています。

 

 

ハードウェアのほうは以下のように用意します。ここでは素直に、Arduino UNOのUSBポートとPCをつなぎます。前回説明したように、基板上の結線を通してデジタルピン0と1を使ってPCとUART通信することになります。

 

 

 

Arduinoには以下のスケッチを入れます。ここで、PCに送ったデータがVSのほうで読まれないと、PC側の受信バッファにデータが溜まったままになります。そこにまた送ると、データが重なります(読まれないうちに1023mV、1025mV、と続けて送ってしまうと、10231025となってしまいます)。VSからの「読みました」という信号が来たら新しいデータを送ることにしています。このあたりのやり方はいろいろあると思います。

 

 

 

void setup(void)

{

   Serial.begin(9600);

   while (!Serial) {

    ; // wait for serial port to connect. Needed for native USB port only

   }

}

 

void loop(void)

{

  char dummy[1];

 

  while(!Serial.available()){} //何もPCから受信がない場合は待ち続ける

  while(Serial.available()){

  dummy[0]=Serial.read();} //(改行文字の)受信があった場合、ダミーに読み込む

 

  Serial.println(5000.0*analogRead(A0)/1023); //アナログピンA0の読みを出力

}

 

 

ArduinoがPCにつながれている状態でVSのコードを走らせ(画面上のほうの横向き三角をクリック:ラジカセ世代でない若い衆にこのマークは通用するのか?と思ったが、スマホの動画再生マークもこれか)ます。ここで、フォーム上のOpenボタンをクリックすると、PCのポートが開かれ、Arduinoとシリアル通信の準備ができます。そこで(1秒程度待ってから)Read startボタンを押すとタイマーのEnabledがTrueにされるので、Arduinoとの通信が始まります。毎秒、PCにデータがArduinoから読み込まれ表示されます。

 

 

 

これを応用すれば、例えば第19回で説明したひずみアンプモジュールを用いて、ロードセルや変位計の値をPCに転送し、PC上でファイル記録・グラフ描画などいろいろできます。標準圧密試験などのように、載荷は人力で、データを読むだけ自動化したい、しかしSDカードに記録するだけでなく、Windows上で図化したい、といったときにこの方法が使えます。

 

PCからArduinoにデータを送る

 今度はPCから任意の電圧値を入力し、Arduinoを使って出力します。これにより、例えばEP(電空変換器)を使って、三軸試験のセル圧を調整するなどできます。

 

 ハードウェアは以下のようにします。第9回で説明したように、Arduino UNOにはDAC(デジタル-アナログ変換)がないので、MCP4725を使います。

 

 

 

Arduinoには以下のスケッチを入れます。第9回にならって、MCP4725のライブラリをダウンロードしておいて下さい。

 

 

#include <Adafruit_MCP4725.h>

#include <Wire.h>

 

Adafruit_MCP4725 dac;

 

void setup(void)

{

   Serial.begin(9600);

   while (!Serial) {

    ; // wait for serial port to connect. Needed for native USB port only

   }

 

   dac.begin(0x60); // 0x61 if address pin is connected to Vcc 

}

 

void loop(void)

{

  int cnt1;

  char dac_read[4]="0000";

  int dac_value=0;

 

  while(!Serial.available()){} // PCからの入力を待つ

  delay(300);

 

  cnt1=0;

  while(Serial.available())

  {

    dac_read[cnt1]=Serial.read(); //PCからの入力数字を1文字ずつ読み、dac_read配列に並べていく

    cnt1++;

  }

 

  dac_value=atoi(dac_read); //文字列を整数に

  dac.setVoltage(dac_value, false); //MCP4725に入力

  delay(100);

}

 

 

先ほどのフォームに、ボタン(NameをbtnOutput、TextをWriteに)を配置して以下のコードを書きます(SerialPort開閉のコンポーネントは先ほどつくったものを使い回します)。

 

 

Private Sub btnOutput_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOutput.Click

 

        SerialPort1.WriteLine(Int(4096 * Val(txtWrite.Text) / 5000))

 

End Sub

 

 

今度はテキストボックス(NameをtxtWriteに)を貼ります。先ほど追加したコンポーネントに加えて、このように見えます。

 

 

これで(「Open」ボタンでSerialPortが開いた状態で。また、Arduinoからの入力は止めておいてください。つまり、ボタン表示が「Read stop」になった状態です)、この新しい右下のテキストボックスに電圧値(0-5000mVの範囲:これ以外を入れるとどうなるかは知りません)を書き込み、Writeボタンをクリックすると、MCP4725のGNDとOUTの間に、指定した電圧が生じます。北海道大学の地盤物性学研究室で三軸試験装置のセル圧・ベロフラム圧制御に使っている藤倉コンポジットの電空変換器RT E/P-8-2は、十分にこのやり方で動かせます。