業務ツール作成に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()); } } }
コメント