先日作成した電子温度計(Stellaris LM4F120)とPCとの連携を行いたいと思い、測定データをPCに取り込み、データのグラフ表示を試しました。
以前VC++でグラフ表示を行った時 System::Drawing::Graphics等の Drawing配下のクラスを利用しましたが、今回は、Chartクラスを使ったグラフ表示を試しました。
===================================================================
1.概要
電子温度計 [UART] ==(USB)== [COMポート]
PC
測定温度
デザイン
VC++でWindowsフォームアプリケーションでプロジェクトを作成する。
Form1にChart、SerialPort オブジェクトを追加 設定する。
初期処理
Chart/Seriseに1024個のDataPointを値0で登録する。
メイン処理
シリアルポート受信イベントで電子温度計が出力する温度データを取り込む。
取り込んだ温度データを順次 Chart/Serise/DataPointオブジェクトに設定する。
===================================================================
2.VC++プロジェクト作成<<非時系列チャート>>
1)Chart設定
Form1にChartオブジェクト chart1 を作成
プロパティ設定 Seriseコレクション(ChartType:Line)
2)SerialPort設定
Form1にSerialPortオブジェクト serialPort1を作成
プロパティ設定 BaudRate と PortNameを設定
3)コーディング コンストラクタ Form1(void)
①Charting/Seriesオブジェクト series1tをローカル宣言
System::Windows::Forms::DataVisualization::Charting::Series^ series1t;
②chart1のSeries1を①で宣言したseries1tに読みだす。
series1t = this->chart1->Series["Series1"];
③Charting/DataPointオブジェクトを初期値で作成。
System::Windows:・・・:Charting::DataPoint^ tmppoint
= (gcnew System::Windows::・・・::Charting::DataPoint(i,0));
④Charting/DataPointオブジェクトを①で宣言したseries1tに登録する。
series1t->Points->Add(tmppoint);
*③④を繰り返し1024のDataPointオブジェクトをseries1t(chart1/Series1)に登録する。
⑤シリアルポートをOpenする。
this->serialPort1->Open();
4)コーディング シリアルポート受信イベント処理 (serialPort1_DataReceived)
①Charting/Series、Pointsオブジェクト series1t、tmppoint をローカル宣言
②DateTime型で現在時刻を取得する。
DateTime timesp = System::DateTime::Now;
③シリアルポート受信データを取り込み、温度データを抽出する。
strreceive = this->serialPort1->ReadLine(); [[strreceive:String]]
strvalue = strreceive->Substring(7,6); [[strvalue:String 温度データ位置:7]]
④取得した温度データでSeries1のDataPointを更新する。
(インデックス指定で、一旦Series1のDataPointを削除して、取得した温度データでDataPointオブジェクトを作成し登録し直す。)
series1t = this->chart1->Series["Series1"];
tmppoint = series1t->Points[IntPointIndex]; [[IntPointIndex:DataPointインデックス]]
series1t->Points->Remove(tmppoint);
System::Windows:・・・:Charting::DataPoint^ tmppoint1
= (gcnew System::Windows::Forms::DataVisualization::Charting::DataPoint(IntPointIndex,System::Convert::ToDouble(strvalue)));
series1t->Points->Insert(IntPointIndex,tmppoint1);
5)エラー対処
このコーディングでプログラムを実行すると、不定期のタイミングで「InvalidOperationException ”コレクションが変更されました。実行されない可能性があります。” エラー」が発生します。
①原因の予想
チャート表示処理中にチャート情報の更新が重なったため起きたエラーと思われます。
②対処
Serise1/DataPointオブジェクトの削除、挿入処理はChartを一旦非表示にして実行する。
this->chart1->Visible = false;
===================================================================
3.VC++プロジェクト作成 <<時系列チャート>>
1)Chart設定
プロパティ設定 Seriseコレクション(ChartType:Line
XValueType:Time)
2)SerialPort設定
3)コーディング コンストラクタ Form1(void)
①シリアルポートをOpenする。
4)コーディング シリアルポート受信イベント処理 (serialPort1_DataReceived)
①Charting/Seriesオブジェクト series1tをローカル宣言
②DateTime型で現在時刻を取得する。
③シリアルポート受信データを取り込み、温度データを抽出する。
④取得した温度データでDataPointを作成し Series1に登録する。
System::Windows:・・・:Charting::DataPoint^ tmppoint2
= (gcnew System:・・・:Charting::DataPoint(timesp.ToOADate(),System::Convert::ToDouble(strvalue)));
series1t->Points->Add(tmppoint2);
⑤Series1に登録されたDataPointオブジェクトが1024を超えた場合。先頭のDataPointオブジェクトを削除する。
series1t->Points->RemoveAt(0);
===================================================================
※メモ
●DataPointの設定
DateTime値をDataPointのX値に設定する場合 ToOADate()メソッドを使用する。
●チャートデータの更新処理の工夫
データDataPointコレクションの更新時 Chatオブジェクトは非表示にする。 (前述)
※気になる点
●MicroSoftのmsdnオンラインドキュメントの不備
ChartクラスのSystem名前空間からの継承階層はSystem::Windows::Forms::DataVisualization::Charting::Chartですが、オンライドキュメントでSystem名前空間から繰るとSystem::Windows::Forms名前空間 止まりでした。また、DataVisualization名前空間配下の Series等のクラスではドキュメントの繰り方で、内容の無いページが現れます。
とにかく、Chartクラスを使うのには情報が少ない。