ArduinoとWindows間で、USB経由でシリアル通信をする機会が多くあったので、昔を思い出しつつまとめていきたいと思っています。今回は、Windows側から送信したコマンドをArduinoで受信し、Arduino上のLEDをON/OFFするという、シリアル通信版「Lチカ」です。
1.Arduino側のプログラム
Arduino IDEで書き込むプログラムです。PCから文字を受け取り、それに応じて内蔵LED(13番ピン)をON/OFFします。
C++
// Arduino側:受信プログラム
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(9600); // 通信速度を9600bpsに設定
}
void loop() {
if (Serial.available() > 0) {
char data = Serial.read(); // データを1文字読み込む
if (data == '1') {
digitalWrite(LED_BUILTIN, HIGH); // LED点灯
Serial.println("LED ON");
}
else if (data == '0') {
digitalWrite(LED_BUILTIN, LOW); // LED消灯
Serial.println("LED OFF");
}
}
}2.Windows側のコード [C#](コンソール版)
C#のSystem.IO.Ports.SerialPort1クラスを使用して、Arduinoが接続されているCOMポート2へデータを送信します。
- System.IO.Portsは、元々標準で使用可能でしたが、現在は外付けのパッケージになっています。NugetからSystem.IO.Portsをインストールしてください。 ↩︎
- コードの中でCOM3としていますが、お手元の環境によって番号変わって来ますので、Arduinoを接続したうえで、デバイスマネージャで確認して必要に応じて変更してください。 ↩︎
C#
using System;
using System.IO.Ports;
class Program
{
static void Main()
{
// ポート名(COM3などは環境に合わせて変更)と通信速度を指定
SerialPort serialPort = new SerialPort("COM3", 9600);
try
{
serialPort.Open(); // ポートを開く
Console.WriteLine("通信開始:1で点灯、0で消灯、Qで終了");
while (true)
{
string input = Console.ReadLine();
if (input.ToLower() == "q") break;
serialPort.Write(input); // Arduinoへデータを送信
}
}
catch (Exception ex)
{
Console.WriteLine("エラー: " + ex.Message);
}
finally
{
if (serialPort.IsOpen) serialPort.Close(); // ポートを閉じる
}
}
}3.Windows側のプログラム [C#] Form版
Form版のコードです。Form版もSystem.IO.Ports.SerialPortをNuGetでインストールしておく必要があります。COMポートCOMポートの確認も忘れずに。
3.1 画面構成
Form画面の構成を以下のように設定してください。
| コントロール | 名前(Name) | 用途 |
|---|---|---|
| ComboBox | cmbPortName | 接続するCOMポートを選択 |
| Button | btnConnect | ポートの「接続/切断」を送信 |
| Button | btnLedOn | LED点灯コマンド(‘1’)を送信 |
| Button | btnLedOff | LED消灯コマンド(‘2’)を送信 |
3.2 ソースコード
Arduino側のコードは前回(コンソール版)と同じもので動作します。
C#
using System;
using System.IO.Ports;
using System.Windows.Forms;
namespace ArduinoGuiApp
{
public partial class Form1 : Form
{
private SerialPort serialPort;
public Form1()
{
InitializeComponent();
InitializeSerialPort();
}
private void InitializeSerialPort()
{
serialPort = new SerialPort();
serialPort.BaudRate = 9600;
// 利用可能なCOMポートを列挙してコンボボックスに追加
string[] ports = SerialPort.GetPortNames();
cmbPortName.Items.AddRange(ports);
if (ports.Length > 0) cmbPortName.SelectedIndex = 0;
}
// 接続・切断ボタンの処理
private void btnConnect_Click(object sender, EventArgs e)
{
if (!serialPort.IsOpen)
{
try
{
serialPort.PortName = cmbPortName.Text;
serialPort.Open();
btnConnect.Text = "切断";
ToggleControls(true);
}
catch (Exception ex)
{
MessageBox.Show("接続に失敗しました: " + ex.Message);
}
}
else
{
serialPort.Close();
btnConnect.Text = "接続";
ToggleControls(false);
}
}
// 送信処理:LED ON
private void btnLedOn_Click(object sender, EventArgs e)
{
SendData("1");
}
// 送信処理:LED OFF
private void btnLedOff_Click(object sender, EventArgs e)
{
SendData("0");
}
private void SendData(string data)
{
if (serialPort.IsOpen)
{
serialPort.Write(data);
}
}
private void ToggleControls(bool connected)
{
btnLedOn.Enabled = connected;
btnLedOff.Enabled = connected;
cmbPortName.Enabled = !connected;
}
// フォームを閉じる際にポートを確実に閉じる
protected override void OnFormClosing(FormClosingEventArgs e)
{
if (serialPort.IsOpen) serialPort.Close();
base.OnFormClosing(e);
}
}
}3.2 ソースの解説
- ポートの自動取得:
SerialPort.GetPortNames()を使うことで、ポート番号を選択するようにしました。 - 状態管理: ポートが閉じているときに送信ボタンを押すとエラーになるため、接続状態に応じて
Enabledプロパティを切り替える(ボタンをグレーアウトさせる)処理をしています。 - リソース管理: フォームを閉じる際(
OnFormClosing)にポートを閉じる処理をしえています。
4.まとめ
今回は、Arduino側が受信専用、Windows側が送信専用になっている一方通行の通信の例でしたが、無事LEDのON/OFFはできたでしょうか。
Arduinoからセンサーのデータを取得したり、時間のかかる処理をしてその完了を取得する場合は、双方向の通信が必要になり、より複雑な処理が必要になりますので、次の機会に説明したいと思っています。

最近のコメント