業務ツール作成にC#を触り始めたので、学習した内容をひとまずスクラップしていきます。
シリアル通信 via COMポート
シリアル通信を行う必要があったので、COMポートの叩き方を勉強しました。
参考URL:
- https://www.codeproject.com/Articles/130109/Serial-Communication-using-WPF-RS-and-PIC-Commu
WPFだからというハマりどころはないですが、
WinFormよりは情報が少ないのかなという印象です。
使っているライブラリは、System.Windows.IOなので、コアの部分には変更はないと思います。
COMポートの開き方+叩き方
using System.IO.Ports;
namespace ComTest
{
public partial class MainWindow : Window
{
SerialPort serial = new SerialPort();
}
private void COMPort_Setup() {
try
{
serial.PortName = (String)portName;//"COM#"の形式で.
serial.BaudRate = (int)baudRate;
serial.Handshake = System.IO.Ports.Handshake.None;
serial.Parity = Parity.None;
serial.DataBits = 8;
serial.StopBits = StopBits.One;
serial.ReadTimeout = 200;
serial.WriteTimeout = 50;
serial.Open();
}
catch
{
return;//
}
serial.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(COMPort_Recieve);//受信ハンドラ
}
private void COMPort_Recieve(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string recieved_data = serial.ReadExisting();
}
private void COMPort_ASCII_TX(char[] data)
{
if (serial.IsOpen) //シリアルポートが開いている場合
{
try
{
// Send the binary data out the port
byte[] hexstring = Encoding.ASCII.GetBytes(data);
foreach (byte hexval in hexstring)
{
byte[] _hexval = new byte[] { hexval }; // need to convert byte
// to byte[] to write
serial.Write(_hexval, 0, 1);
Thread.Sleep(1);
}
}
catch
{
//送信エラー処理
}
}
}
}受信は、ハードウェア割り込みが飛んできますので、それをイベントハンダラで受け取ってやります。
送信は、今回ASCII文字列を送る前提で書いてありますが、何にしてもbyte型で送ってやればOKです。
byte型の配列を定義してやれば、センサに直接コマンドを送ったりすることができます。
using System.Windows.Threading;
private void A_Command_TX()
{
byte[] data = new byte[4]{ 0x1F, 0x43, 0x00, Convert.ToByte('\0') };
//LCDなどに文字列として放り込むことを想定し、最後に'\0'を入れてあります。
//ターゲットの仕様に合わせて組みます。
Serial_TX(data, 1, 10);
}
private void Serial_Command_TX(byte[] data, int each_wait, int final_wait)
{
try
{
foreach(byte hexval in data)
{
serial.Write(hexval, 0, 1);
Thread.Sleep(each_wait);//ターゲットデバイスの受信バッファが溢れない為のwait
}
catch
{
}
Thread.Sleep(final_wait);//ターゲットデバイスがコマンドを認識し処理が完了するまでのwait
}サンプルプログラム
お試しで、参考URLの物を少し変更して、
手持ちのVFDモジュール(Noritake Itron: GU280X16G-7xxx)に文字を表示できるようにしました。
とても汚い代物ですが参考まで。
一応受信もできるようにしてあります。
xaml
<Window x:Class="ComTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ComTest"
mc:Ignorable="d"
Title="MainWindow"
Background="Black" Height="490.263" Width="766.685" Closing="Window_Closing">
<Grid Height="454" VerticalAlignment="Top" Margin="0,0,2,0">
<StackPanel Orientation="Vertical" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="42,29,0,-21" Height="446" Width="668">
<StackPanel Orientation="Horizontal" Height="30" VerticalAlignment="Top">
<TextBlock Foreground="White" Text="Port#" TextWrapping="Wrap" FontSize="24" Width="100"/>
<ComboBox x:Name="_ComboBox_Port" Width="120"/>
<Button x:Name="_Button_Connect" Background="Orange" Content="Connect" HorizontalAlignment="Left" Height="30" VerticalAlignment="Bottom" Width="97" Click="_Button_Connect_Click"/>
<TextBlock x:Name="_TextBlock_Connected" TextWrapping="Wrap" Text="" Width="89"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Height="30" VerticalAlignment="Top">
<TextBlock Foreground="White" Text="Baud" TextWrapping="Wrap" FontSize="24" Width="100"/>
<ComboBox x:Name="_ComboBox_Baud" FontSize="18" Background="white" Height ="30" HorizontalAlignment="Left" VerticalAlignment="Top" Width="300">
<ComboBoxItem Content="4800" />
<ComboBoxItem Content="9600" />
<ComboBoxItem Content="14400" />
<ComboBoxItem Content="19200" />
<ComboBoxItem Content="38400" />
<ComboBoxItem Content="57600" />
<ComboBoxItem Content="115200" />
<ComboBoxItem Content="230400" />
<ComboBoxItem Content="460800" />
<ComboBoxItem Content="921600" />
</ComboBox>
</StackPanel>
<StackPanel Orientation="Horizontal" Height="30" VerticalAlignment="Top">
<TextBlock Foreground="White" Text="TX_MES" TextWrapping="Wrap" FontSize="24" Width="100"/>
<TextBox x:Name="_TextBox_TXMSG" TextWrapping="Wrap" Text="TXメッセージを入力" FontSize="12" Width="477"/>
<Button x:Name="_Button_Send" Background="Orange" Content="Send" HorizontalAlignment="Left" Height="30" VerticalAlignment="Top" Width="97" Click="_Button_Send_Click"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Height="310" VerticalAlignment="Top">
<TextBlock Foreground="White" Text="AP_MES" TextWrapping="Wrap" FontSize="24" Width="100"/>
<RichTextBox x:Name="_RichTextBox_APMES" HorizontalAlignment="Left" VerticalAlignment="Top" Height="281" Width="477" VerticalScrollBarVisibility="Auto"/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO.Ports;
using System.Threading;
using System.Windows.Threading;
namespace ComTest
{
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window
{
FlowDocument mcFlowDoc = new FlowDocument();
Paragraph para = new Paragraph();
SerialPort serial = new SerialPort();
private delegate void UpdateUiTextDelegate(string text);
private DispatcherTimer _Timer_main;
public MainWindow()
{
InitializeComponent();
DispatchTimer_Setup();
string[] ports = SerialPort.GetPortNames();//ポート名の取得
foreach(string port in ports)
{
_ComboBox_Port.Items.Add(port);//それぞれの名前をコンボボックスに登録
}
this._TextBlock_Connected.FontSize = 15;
}
private void DispatchTimer_Setup()
{
this._Timer_main = new DispatcherTimer
{
Interval = TimeSpan.FromMilliseconds(500)
};
this._Timer_main.Tick += (sender, e) =>
{
if (serial != null && serial.IsOpen)
{
this._TextBlock_Connected.Background = new SolidColorBrush(Colors.Green);
this._TextBlock_Connected.Text = "接続OK";
}
else
{
this._TextBlock_Connected.Background = new SolidColorBrush(Colors.Orange);
this._TextBlock_Connected.Text = "接続NG?";
}
};
this._Timer_main.Start();
}
private void COMPort_Setup() {
try
{
serial.PortName = _ComboBox_Port.SelectedItem.ToString();
serial.BaudRate = Convert.ToInt32(_ComboBox_Baud.SelectionBoxItem.ToString());
serial.Handshake = System.IO.Ports.Handshake.None;
serial.Parity = Parity.None;
serial.DataBits = 8;
serial.StopBits = StopBits.One;
serial.ReadTimeout = 200;
serial.WriteTimeout = 50;
serial.Open();
}
catch(Exception ex)
{
_RichTextBox_Write("Failed to Connect\n" + ex + "\n");
return;
}
serial.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(COMPort_Recieve);
}
private void VFD_CON()
{
byte[] data = new byte[4]{ 0x1F, 0x43, 0x00, Convert.ToByte('\0') };
VFD_TX(data, 100);
}
private void VFD_CLF()
{
byte[] data = new byte[2] { 0x0A, Convert.ToByte('\0') };//カーソルを1行下げる
VFD_TX(data, 100);
}
private void VFD_CCR()
{
byte[] data = new byte[2]{ 0x0D, Convert.ToByte('\0') }; //カーソルを同一行の一番左に移動する
VFD_TX(data, 100);
}
private void VFD_CHM()
{
byte[] data = new byte[2]{ 0x0B, Convert.ToByte('\0') }; //カーソルをホームポジションに移動する
VFD_TX(data, 100);
}
private void VFD_Clear()
{
byte[] data = new byte[2] { 0x0C, Convert.ToByte('\0') }; //画面をクリアする
VFD_TX(data, 100);
}
private void VFD_CClear()
{
byte[] data = new byte[7]{ 0x1F, 0x24, 0x00, 0x00, 0x00, 0x00, Convert.ToByte('\0') };
VFD_TX(data, 100);
}
private void VFD_TX(byte[] data, int wait)
{
try
{
serial.Write(data, 0, (data.Length - 1));
}
catch (Exception ex)
{
_RichTextBox_Write("Failed to SEND" + data + "\n" + ex + "\n");
}
Thread.Sleep(wait);
}
void VFD_half_TX(byte[] str, int wait)
{
int j = 0;
byte[] hstr = Enumerable.Repeat<byte>(Convert.ToByte('\0'), 256).ToArray();
byte[] lstr = Enumerable.Repeat<byte>(Convert.ToByte('\0'), 256).ToArray();
int length = 0;
length = str.Length;
for (int i = 0; i < (length / 2); i++)
{
hstr[j] = str[i];
j++;
}
hstr[j] = Convert.ToByte('\0');
j = 0;
for (int i = (length / 2); i < length; i++)
{
lstr[j] = str[i];
j++;
}
VFD_TX(hstr, wait);
VFD_TX(lstr, wait);
}
private void COMPort_Disconnect()
{
serial.Dispose();
}
private void _Button_Connect_Click(object sender, RoutedEventArgs e)
{
if (serial == null)
{
COMPort_Setup();
}
else
{
serial.Close();
COMPort_Setup();
}
}
private void COMPort_Recieve(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string recieved_data = serial.ReadExisting();
Dispatcher.Invoke(DispatcherPriority.Send, new UpdateUiTextDelegate(_RichTextBox_Write), recieved_data);
}
private void COMPort_ASCII_TX(char[] data)
{
if (serial.IsOpen)
{
try
{
// Send the binary data out the port
byte[] hexstring = Encoding.ASCII.GetBytes(data);
foreach (byte hexval in hexstring)
{
byte[] _hexval = new byte[] { hexval }; // need to convert byte
// to byte[] to write
serial.Write(_hexval, 0, 1);
Thread.Sleep(1);
}
}
catch (Exception ex)
{
string text = "Failed to SEND" + data + "\n" + ex + "\n";
_RichTextBox_Write(text);
}
}
}
private void _RichTextBox_Write(string text)
{
para.Inlines.Add(text);
mcFlowDoc.Blocks.Add(para);
_RichTextBox_APMES.Document = mcFlowDoc;
}
private void _TextBox_Port_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key < Key.D0 || Key.D9 < e.Key)
{
e.Handled = true;
}
}
private void _Button_Send_Click(object sender, RoutedEventArgs e)
{
VFD_Clear(); //画面クリア
VFD_CCR(); //行の先頭へカーソル移動
COMPort_ASCII_TX(_TextBox_TXMSG.Text.ToCharArray());
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
VFD_Clear(); //画面クリア
VFD_CCR(); //行の先頭へカーソル移動
COMPort_ASCII_TX("__NO_CONNECTION__".ToCharArray());
}
}
}

コメント