どうも!リョクちゃです。
今回は前回の記事の応用例といった形になります。
ArduinoProMini互換機とCdsと呼ばれる明るさセンサを用いて、
室内の明るさを計測し、Cdsからの値をArduinoProMini互換機を経由し
シリアル通信で受信します。
受信した値をリアルタイムでチャートコントロールに表示するといった内容の
実験をしてみましたので紹介していきます。
ちなみに前回はこちら
目次
準備編
VisualStudio2019を使って、Windowsフォームアプリケーションを作成していきます。
最初の手順については、下記記事をご参照ください。
Cdsとは
硫化カドミウムセルと呼ばれ、硫黄(元素記号:S)とカドミウム(cd)の化合物になります。
下図の表面の受光部分に光を受けると明るさによって、抵抗値を低くする特性があります。
Cdsセンサ
特徴としては、
- 受光した際の反応が遅い
- 応答性を必要とする用途には不得手
といった特徴が挙げられます。
特性を利用して、暗いときに自動的に光っていく自動照明灯などに用いられたりしています。
CdsとArduinoProMini互換機の接続
ArduinoProMini互換機とCdsは以下のように接続しました。
Cdsは光を効率よく受け取れるよう黒い筒を被せています。
互換機のA01端子にCdsを接続します。
A01端子はアナログピンと呼ばれ、Cdsで受け取った値をアナログ値で取得します。
互換機はA0~A7までの8ピンが搭載されています。
フォームの作成
今回は以下のようなフォームを作成します。
各1~8までのコントロールの名称やテキストは以下のように設定しています。
No | コントロール | 名前 | テキスト |
---|---|---|---|
1 | Label | Label1 | COM Port |
2 | Label | Label2 | INPUT |
3 | ComboBox | cbComPort | |
4 | RichTextBox | rtxSerial | |
5 | Chart | chPhoto | |
6 | Label | lblTimer | Timer:off |
7 | Button | btConnect | Connect |
8 | Button | btClear | CLEAR |
実行環境
筆者の実行環境は、
- VisualStudio2019
- Windows 10 64bit
- .Net Framework 4.5.1
になります。
※ Windows7 8 8.1でも動作はできますが、
画面デザインの表示が変わるかもしれません。
アプリケーションの目的
ArudinoProMini互換機に接続されたCdsの計測値をシリアル通信を介し、
受信することでrtxSerialとchPhotoにそれぞれ表示できることを目的とします。
rtxSerialでは受け取った値を表示、chPhotoでは値を折れ線グラフ化することとします。
プログラム編
ArduioProMini互換機のスケッチ
AruduinoIDEを使用して、スケッチを作成していきます。
スケッチは前回作成したスケッチを使用していきます。
定数・変数の宣言
Cdsがつながっているピン情報を定数、Cdsからの値を記憶するのを変数として
それぞれ宣言します。
1 2 |
const int Cds = 1; // Cdsがつながっているピン int val = 0; // Cdsからの値を記憶する変数 |
setup()ブロックでの処理
シリアルポートの設定を行います。
1 2 3 4 |
void setup() { Serial.begin(9600); //シリアルポートを9600bpsで開く } |
loop()ブロックでの処理
Cdsからの値を変数で受け取ります。
Cdsの値を受け取るには、
と記述することで受け取ることができます。
ArduinoProMiniでは、0~1023の範囲でアナログ値(整数値)を受け取ることができます。
これはアナログピンが10ビットのAD(アナログ・デジタル)コンバータを搭載しているからです。
受け取った値はSerial.printlnに引数として渡します。
これを1秒間隔で実行するようにします。
以下がloop()ブロック内のコードになります。
1 2 3 4 5 6 |
void loop() { val = analogRead(Cds); // Cdsの値を受け取る Serial.println(val); delay(1000); //1秒停止 } |
以上が、今回のスケッチとなります。
VB.Netのコード
定数・変数宣言
定数には、履歴の上限を50件としたいのであらかじめ宣言しておきます。
変数には、Comポートの選択値を代入する変数と
受け取った情報を記憶する変数そして受け取ったデータを
格納しておくコレクション(キュー)をそれぞれ変数として宣言します。
1 2 3 4 5 6 7 8 9 10 11 |
#Region "定数宣言" Private Const MAX_HISTORY As Integer = 50 #End Region #Region "変数宣言" Private _comPort As String Private mrecvData As String = "" 'センサ値データの履歴 Private countHistory As Queue(Of Integer) = New Queue(Of Integer) #End Region |
フォームロード時の処理
以下の処理を行います。
- タイマーの非アクティブ
- COMポートの取得をし、コンボボックスへ反映
- チャートの表示を初期化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#Region "画面ロード" Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load Timer1.Enabled = False 'COMポートを取得 _comPort = "" For Each sp As String In My.Computer.Ports.SerialPortNames Me.cbComPort.Items.Add(sp) Next sp 'チャートの表示を初期化 Call InitializeChart() End Sub #End Region |
チャートの表示を初期化する部分は関数として新たに作成しています。
初期化の関数
今回はチャートを計測機器に表示されているかのようなモニタデザインにしていきます。
こんなイメージにしていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
#Region "グラフ表示の初期化" Private Sub InitializeChart() With chPhoto 'チャート全体の背景色を設定 .BackColor = Color.Black .ChartAreas(0).BackColor = Color.Transparent 'チャート表示エリア周囲の余白をカットする .ChartAreas(0).InnerPlotPosition.Auto = False .ChartAreas(0).InnerPlotPosition.Width = 100 ' 100% .ChartAreas(0).InnerPlotPosition.Height = 90 ' 90 %(横軸のメモリラベル印字分の余白) .ChartAreas(0).InnerPlotPosition.X = 8 .ChartAreas(0).InnerPlotPosition.Y = 0 'X,Y軸情報のセット関数を定義 Dim setAxis As Action(Of DataVisualization.Charting.Axis) = Sub(axisInfo) '軸の目盛ラベルのフォントサイズ上限値を制限 axisInfo.LabelAutoFitMaxFontSize = 8 '軸のメモリラベルの文字色をセット axisInfo.LabelStyle.ForeColor = Color.White '軸タイトルの文字色をセット axisInfo.TitleForeColor = Color.White '軸の色をセット axisInfo.MajorGrid.Enabled = True axisInfo.MajorGrid.LineColor = ColorTranslator.FromHtml("#008242") axisInfo.MinorGrid.Enabled = False axisInfo.MinorGrid.LineColor = ColorTranslator.FromHtml("#008242") End Sub 'X,Y軸の表示方法を定義 setAxis(.ChartAreas(0).AxisY) setAxis(.ChartAreas(0).AxisX) .ChartAreas(0).AxisY.MinorGrid.Enabled = True .ChartAreas(0).AxisY.Maximum = 1023 '縦軸の最大値を1023にする .AntiAliasing = DataVisualization.Charting.AntiAliasingStyles.None '折れ線グラフとして表示 .Series(0).ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line '線の色を指定 .Series(0).Color = ColorTranslator.FromHtml("#00FF00") '凡例を非表示、各値に数値を表示しない .Series(0).IsVisibleInLegend = False .Series(0).IsValueShownAsLabel = False End With End Sub #End Region |
シリアル通信に関連する処理
ハードウェアとの接続に関しては以下の処理を行います。
- Connectボタン押下
- シリアル通信の準備
- シリアル通信の開始
既に接続されている場合は、通信を閉じる処理を実行します。 - 接続確立後ボタンのテキストをDis-connectに変更
- タイマーの設定(1秒周期でチャートの再描画を行います。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
#Region "コネクトボタンクリック" Private Sub btConnect_Click(sender As Object, e As EventArgs) Handles btConnect.Click If (btConnect.Text = "Connect") Then If (_comPort <> "") Then Me.SerialPort1.Close() Me.SerialPort1.PortName = _comPort With Me.SerialPort1 .BaudRate = 9600 .DataBits = 8 .Parity = Parity.None .StopBits = StopBits.One .Handshake = Handshake.None .Encoding = System.Text.Encoding.Default .ReadTimeout = 10000 End With Me.SerialPort1.Open() btConnect.Text = "Dis-connect" '1秒周期でチャートを再描画 Timer1.Enabled = True Timer1.Interval = 50 lblTimer.Text = "Timer: ON" Else MsgBox("Select a COM port first") End If Else Me.SerialPort1.Close() Me.btConnect.Text = "Connect" Me.Timer1.Enabled = False Me.lblTimer.Text = "Timer: OFF" End If End Sub #End Region |
データの受信に関する処理の流れは以下のようにします。
- データを受信
受け取った値が0ならnothing & vbcrlf(改行コード)を戻り値として返します。
0でなければ、受け取った値を整数型に変換し、戻り値として返します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#Region "シリアルデータ受信処理" Private Function ReceiveSerialData(ByRef value As Integer) As String Dim Incoming As String Incoming = SerialPort1.ReadLine() If Incoming Is Nothing Then value = 0 Return "nothing" & vbCrLf Else value = CInt(Incoming) Return Incoming End If End Function #End Region |
チャートコントロールの処理
1秒間隔で再描画を行うので、タイマーイベントの処理は以下のようにしました。
- コレクション変数に受け取った値を格納
- rtxSerialに受け取った値を表示
- コレクション変数が格納許容数を超えていたら格納した値を取り除く
- グラフの再描画
これらの処理を行います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#Region "タイマー処理" Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick Dim value As Integer mrecvData = ReceiveSerialData(value) rtxSerial.Text &= mrecvData countHistory.Enqueue(value) '履歴の最大数を超えていたら、古いものを削除する While countHistory.Count > MAX_HISTORY countHistory.Dequeue() End While 'グラフを再描画する Call showChart() End Sub #End Region |
履歴の最大数を超えていたら、コレクション変数に最初に格納された値から取り除きます。
以降、同様の処理を1秒ごとに繰り返します。
グラフへの描画処理は以下の関数を作成し行います。
1 2 3 4 5 6 7 8 9 |
#Region "グラフの描画" Private Sub showChart() 'チャートに値をセット chPhoto.Series(0).Points.Clear() For Each value As Integer In countHistory chPhoto.Series(0).Points.Add(New DataPoint(0, value)) Next value End Sub #End Region |
実行編
実際にArduinoProMini互換機と接続して、プログラムを実行していきます。
プログラム起動時
COMポートの選択
接続後の明るさ受信
接続後の明るさ受信(数分経過後)
Cdsにライトを照らしたり、指でCdsを覆ったりして明るさを変化させてみました。
うーん、データの受信にインターバルを設定しているせいか、
スムーズな受信ができていない気がします。
これは改善の余地がありです。
※ もしコードを試される方がいましたらお気を付けください。
まとめ
ArduinoProMini互換機とCdsを使って計測値を受信し、チャートコントロールで
リアルタイムに可視化することができました。
PCとArduinoProMini互換機の通信が同期していないせいか、タイミングによっては
受信できなくなったり、チャートコントロールでの表示が遅れたりとしてしまいました。
まだまだ勉強と改善が必要です……。
読者の方の何らかの参考になれば嬉しいです。
最後までご覧いただきありがとうございます。
・こちらの書籍を参考にVB.Net勉強しています。