パソコン同士や異なる周辺機器間で送受信を行う用途として古くから使用されていたシリアル通信は、現在でも使用される場面が多い通信手段の1つです。
この通信について簡単におさらいをして、C#のSerialPortクラスを使った通信プログラムを紹介します。
手軽にデータの送受信を可能にする通信手段なので、この記事を参考にしてパソコンや周辺設備を制御できるようになりましょう。
動作環境 | |
OS | Windows10 |
IDE | Visual Studio 2019 |
フレームワーク | .NET Core3.1 |
UIフレームワーク | WPFアプリ |
プログラミングを更に学びたい方必見
選抜された現役エンジニアから学べるプログラミングスクールで、現場や副業で役に立つノウハウやスキルを習得してみませんか?
オンラインに特化しているので場所に捉われず、自分のライフスタイルに合わせて受講することができます。
副業に興味がある方に人気の「はじめての副業コース」をはじめ、Web開発やシステム開発・アプリ開発などカテゴリ毎に受講ができ、初心者の方でも挫折することなく学ぶことができます。
まずはこの機会に現役のプロに無料相談をしてみましょう。
シリアル通信とは?
信号の通り道が1つしかなく、信号を順番通りに1つずつ連続的に送信する通信方式です。
通信相手から送信された信号は必ず取り込む必要があるので、送信をする信号線と受信をする信号線の2つが必要になります。

シリアル通信では通信機器同士がデータを転送する速度を合わせて、0(Low)または1(High)の2進数を連続し受け渡します。イメージはこんな感じです。

シリアル通信の通信規格はRS-232CやRS-422、RS-485があり、中でもRS-232Cは通信規格の中でも用途を問わず多く普及し、パソコンに搭載されている機種があったり、産業機器で使用される設備は標準で搭載されているものが多く存在します。
現在では周辺機器との接続・通信手段にUSBやイーサネット等が用いられるようになったこともあり、ひと昔前の通信インターフェースという位置づけになっています。
もう少し詳しくRS-232Cについてみてましょう。
RS-232Cについて
RS-232Cには9ピンまたは25ピンのD-Subコネクタで接続します。9ピンのRS232Cは「EIA574」で、25ピンのRS232は「EIA-232」という規格です。25ピンのコネクタは不要な信号も多いため一般的には9ピンのコネクタが良く使われています。

シリアル通信では、1本の通信線を用いてデータを1bitずつ送るので、正確な時間間隔で送ることが重要となります。
通信を成功させるためには、データの始まりと終わりを見分け、送信されたデータを正確に取り込む必要があります。このことを同期と言い、同期式と非同期式の2種類があります。
- 同期式:データ送信用の回線とは別にクロックと呼ぶ定周期の信号が同時に送られ、クロック信号のタイミングでデータ信号を読み取る方式を同期式といいます。
- 非同期式:クロック信号がなく、最初に届いた信号(スタートビット)の長さを測定し、その間隔で信号が送られるとして受信する方式を非同期式といいます。
一般的に非同期式が採用されていることが多いです。
シリアル通信の設定
非同期式で通信をするには必ず守らなければならない条件が1つあります。それは同期を取る為に以下の通信設定を通信相手と同じにしなければなりません。
この通信設定が同じでないと通信トラブルが発生しますので、必ず合わせましょう。
- ポート番号:シリアル通信で接続する際、窓口となる番号です。「COM1」や「COM2」という書き方をします。
- ボーレート:1秒間あたりのデータ転送速度を指定します。
- データビット:1回の送受信でどれくらいのデータを送受信するかを指定します。
- ストップビット:送信終了を合図するビット数を指定します。
- パリティ:転送するデータの誤り検出の有無を指定します。有りの場合、偶数または奇数が選択できます。
※スタートビットはデフォルトで1ビット送信されます。
ソースコード作成
それでは早速C#でシリアル通信をするためのコードを記述していきましょう。
「port.cs」という新しい項目(ファイル)を作成して、プロジェクトに追加します。
using System.IO.Ports;
接続
通信各種の設定や送受信についてはSerialPortクラスを使用します。PortOpenメソッド内で SerialPort のインスタンスを生成し、オブジェクトの初期化を行います。
private SerialPort sport = null;
public bool PortOpen(string com)
{
// シリアルポートの設定
sport ??= new SerialPort
{
PortName = com, //ポート番号
BaudRate = 9600, //ボーレート
DataBits = 8, //データビット
Parity = Parity.None, //パリティ
StopBits = StopBits.One, //ストップビット
sport.Handshake = Handshake.None; //ハンドシェイク
Encoding = Encoding.UTF8, //エンコード
WriteTimeout = 100000, //書き込みタイムアウト
ReadTimeout = 100000, //読み取りタイムアウト
NewLine = "\r\n" //改行コード指定
};
// シリアルポートに接続
if (!sport.IsOpen)
{
try
{
sport.Open(); // ポートオープン
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
return false;
}
}
return true;
}
切断
public void PortClose()
{
sport?.Close(); // ポートクローズ
sport = null;
}
送信
送信するデータは引数として渡して、WriteLineでデータを送信します。COMポートがオープンされていないとエラーが発生しますので、IsOpenで確認を入れましょう。
WriteLineを使うことで送信データの末尾に文字(”\r\n”)を自動で追加してくれます。この文字のことをデリミタ文字といい、これがないと通信相手側が送信したコマンド等のデータを認識してくれません。
public void Send(string data)
{
if (!sport.IsOpen) return; //ポートが閉じている場合は戻す
try
{
sport.WriteLine(data); //データ書き込み
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
受信
受信する時はReadLineでデータを受信します。ReadLineはデリミタ文字が通信相手から送信されるまでロックされる為、UI画面が固まってしまいます(デッドロック)。
public async Task<string> ReceiveAsync()
{
if (!sport.IsOpen) return ""; //ポートが閉じている場合は戻す
var data = await Task.Run(() => ReadData());
return data;
}
private string ReadData()
{
var data = "";
try
{
data = sport.ReadLine(); //データ書き込み
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
data = "ERROR";
}
return data;
}
COM番号の取得
public string[] GetPort()
{
return SerialPort.GetPortNames(); //ポート番号のリストを返す
}
サンプルの使用例
上記で説明したサンプルソースコードを使用して、WPFでシリアル通信を行うアプリケーションを作成してみましょう。
コンボボックスからCOM番号を選択して、接続開始ボタンをクリックすれば、通信相手にデータを送信したり受信したりすることができます。画面はマテリアルデザインを適用させてオシャレな画面に仕上げました。
マテリアルデザインの適用方法については、以下の記事で詳しく記載しています。

public partial class MainWindow : Window
{
port p = new port();
public MainWindow()
{
InitializeComponent();
btnOpen.IsEnabled = true;
btnSend.IsEnabled = false;
cmbComPort.ItemsSource = p.GetPort();
}
private void btnOpen_Click(object sender, RoutedEventArgs e)
{
if (cmbComPort.Text == "") return;
if (p.PortOpen(cmbComPort.Text))
{
btnSend.IsEnabled = true; //送信ボタン許可
}
else
{
btnSend.IsEnabled = false; //送信ボタン禁止
}
}
private async void btnSend_Click(object sender, RoutedEventArgs e)
{
if (txtSendData.Text == "") return;
p.Send(txtSendData.Text); //データを送信
txtLog.Text = await p.ReceiveAsync();
}
}
プログラミングを更に学びたい方必見
選抜された現役エンジニアから学べるプログラミングスクールで、現場や副業で役に立つノウハウやスキルを習得してみませんか?
オンラインに特化しているので場所に捉われず、自分のライフスタイルに合わせて受講することができます。
副業に興味がある方に人気の「はじめての副業コース」をはじめ、Web開発やシステム開発・アプリ開発などカテゴリ毎に受講ができ、初心者の方でも挫折することなく学ぶことができます。
まずはこの機会に現役のプロに無料相談をしてみましょう。
動作確認
手元にシリアル通信ができる設備がないので、仮想シリアルポートドライバである「com0com」を使用します。デジタル署名付きでないとWindows10のOSでは動作しない為、ver2.2.2.0をダウンロードしましょう。
com0comの設定が終わったら、デバイスマネージャーからCOM番号を確認してアプリのCOM番号を設定します。
あとはアプリからTeraTermへデータを送ったり、TeraTermからデータを送信してアプリで受信ができていることを確認してみましょう。

関連記事

以上、最後まで読んでいただきありがとうございました。

プログラミングスキルを身に付けるなら、プログラミングを効率良く学べる
「プログラミングスクール」がオススメです。
特にこんな方にオススメ!!
これからエンジニアを目指したい
プログラミングの専門性を高めたい
プログラミングを学んで副業をしたい
エンジニアに転職して年収をアップさせたい
プログラミングを触ったことがない未経験からでも、プログラミングスクールで学習すれば、エンジニアへ就職・転職することも可能です。
あなたの「行動力」と「やる気」で、あなたの人生を大きく変えるチャンスになることでしょう。
プログラミングスクールに興味がある方は是非チェックしてみてください。