期待其他的解决方式

时间:2022-06-07 05:12:39

此刻大大都硬件设备均给与串口技术与计算机相连,因此串口的应用措施开发越来越遍及。例如,在计算机没有安置网卡的情况下,将本机上的一些信息数据 传输到另一台计算机上,那么操作串口通信就可以实现。运行本措施,,在“发送数据”文本框中输入要传送的数据,单击【发送】按钮,将传送的数据发送到所选择 的端标语中;单击【接收】按钮,通报的数据被接收到“接收数据”文本框中。如图13.1所示。 
  技术要点
  在.NET Framework 2.0*给了SerialPort类,该类主要实现串口数据通信等。下面主要介绍该类的主要属性(表13.1)和要领(表13.2)。
  表13.1 SerialPort类的常用属性
  名称
  说明
  BaseStream
  获取 SerialPort 东西的根本 Stream 东西
  BaudRate
  获取或设置串行波特率
  BreakState
  获取或设置中断信号状态
  BytesToRead
  获取接收缓冲区中数据的字节数
  BytesToWrite
  获取发送缓冲区中数据的字节数
  CDHolding
  获取端口的载波检测行的状态
  CtsHolding
  获取“可以发送”行的状态
  DataBits
  获取或设置每个字节的标准数据位长度
  DiscardNull
  获取或设置一个值,该值指示 Null 字节在端口和接收缓冲区之间传输时是否被忽略
  DsrHolding
  获取数据设置就绪 (DSR) 信号的状态
  DtrEnable
  获取或设置一个值,该值在串行通信过程中启用数据终端就绪 (DTR) 信号
  Encoding
  获取或设置传输前后文本转换的字节编码
  Handshake
  获取或设置串行端口数据传输的握手协议
  IsOpen
  获取一个值,该值指示 SerialPort 东西的打开或*状态
  NewLine
  获取或设置用于解释 ReadLine( )和WriteLine( )要领挪用结束的值
  Parity
  获取或设置奇偶校验查抄协议
  
  续表
  名称
  说明
  ParityWordStr
  获取或设置一个字节,该字节在产生奇偶校验错误时替换数据流中的无效字节
  PortName
  获取或设置通信端口,包孕但不限于所有可用的 COM 端口
  ReadBufferSize
  获取或设置 SerialPort 输入缓冲区的巨细
  ReadTimeout
  获取或设置读取操纵未完成时产生超时之前的毫秒数
  ReceivedBytesThreshold
  获取或设置 DataReceived 事件产生前内部输入缓冲区中的字节数
  RtsEnable
  获取或设置一个值,该值指示在串行通信中是否启用请求发送 (RTS) 信号
  StopBits
  获取或设置每个字节的标准遏制位数
  WriteBufferSize
  获取或设置串行端口输出缓冲区的巨细
  WriteTimeout
  获取或设置写入操纵未完成时产生超时之前的毫秒数
  
  表13.2 SerialPort类的常用要领
  方 法 名 称
  说明
  Close
  *端口连接,将 IsOpen 属性设置为False,并释放内部 Stream 东西
  Open
  打开一个新的串行端口连接
  Read
  从 SerialPort 输入缓冲区中读取
  ReadByte
  从 SerialPort 输入缓冲区中同步读取一个字节
  ReadChar
  从 SerialPort 输入缓冲区中同步读取一个字符
  ReadLine
  一直读取到输入缓冲区中的 NewLine 值
  ReadTo
  一直读取到输入缓冲区中指定 value 的字符串
  Write
  已重载。将数据写入串行端口输出缓冲区
  WriteLine
  将指定的字符串和 NewLine 值写入输出缓冲区
  
  注意:用跳线使串口的第2、3针连接,可以在本地计算机上实现串口通信,所以,通过串口的第2、3针的连接可以对措施进行检测。串口截面图如图13.2所示。
  图13.2 串口截面图
  实现过程
  (1)新建一个项目,定名为Ex13_01,默认窗体为Form1。
  (2)在Form1窗体中,主要添加两个Button控件,分袂用于执行发送数据和接受数据,添加两个TextBox控件,用于输入发送数据和显示接收数据。
  (3)主要措施代码。
   private void button1_Click(object sender, EventArgs e)
   {
   serialPort1.PortName = "COM1";
   serialPort1.BaudRate = 9600;
   serialPort1.Open();
   byte[] data = Encoding.Unicode.GetBytes(textBox1.Text);
   string str = Convert.ToBase64String(data);
   serialPort1.WriteLine(str);
   MessageBox.Show("数据发送告成!","系统提示");
   }
   private void button2_Click(object sender, EventArgs e)
   {
   byte[] data = Convert.FromBase64String(serialPort1.ReadLine());
   textBox2.Text = Encoding.Unicode.GetString(data);
   serialPort1.Close();
   MessageBox.Show("数据接收告成!","系统提示");
   }
  触类旁通
  按照本实例,读者可以实现以下成果。
  长途监控对方计算机屏幕。
   下位机控制措施。
  实例419通过串口*对方计算机
  实例说明
  在网络应用措施中,主要通过网卡实现数据的传输,因此可以操作套接字技术实现长途*计算机。如果计算机中没有安置网卡,该如何实现长途*计算机呢?本例实现了操作串口*对方计算机,措施运行功效如图13.3所示。
  技术要点
  本实例使用SerialPort类的属性和要领,请参见实例“通过串口发送数据”。下面主要介绍SerialPort类的DataReceived 事件,DataReceived 事件为本实例的主要使用技术。DataReceived事件暗示将措置惩罚惩罚 SerialPort 东西的数据接收事件的要领。串行接收事件可以由 SerialData 枚举中的任何项引起,是否引发此事件由操纵系统决定,所以不必然会呈报所有奇偶校验错误。
  注意:本实例从开发到测试,都是由本地计算机完成的,用户只需要使用跳线将串口的第2、3针连接,可以在本地计算机上实现串口通信。跳线连接请参见图13.2。
  实现过程
  (1)新建一个项目,定名为Ex13_02,默认窗体为Form1。
  (2)在Form1窗体中,主要添加两个Button控件,分袂用于打开通信串口和*对方计算机。
  (3)主要措施代码。
   private void button1_Click(object sender, EventArgs e)
   {
   //打开串口
   serialPort1.PortName = "COM1";
   serialPort1.Open();
   button1.Enabled = false;
   button2.Enabled = true;
   } //数据接收事件,期待接收关机命令
   private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
   {
   byte[] data = Convert.FromBase64String(serialPort1.ReadLine());
   string str = Encoding.Unicode.GetString(data);
   serialPort1.Close();
   if (str == "关机")
   {
   Process p = new Process();
   p.StartInfo.FileName = "cmd.exe";
   p.StartInfo.UseShellExecute = false;
   p.StartInfo.RedirectStandardInput = true;
   p.StartInfo.RedirectStandardOutput = true;
   p.StartInfo.RedirectStandardError = true;
   p.StartInfo.CreateNoWindow = true;
   p.Start();
   p.StandardInput.WriteLine("shutdown /s");
   p.StandardInput.WriteLine("exit");
   }
   } //发送关机命令
   private void button2_Click(object sender, EventArgs e)
   {
   if (button2.Text == "*计算机")
   {
   //发送关机命令数据
   byte[] data = Encoding.Unicode.GetBytes("关机");
   string str = Convert.ToBase64String(data);
   serialPort1.WriteLine(str);
   button2.Text = "打消关机";
   }
   else
   {
   button2.Text = "*计算机";
   button1.Enabled = true;
   button2.Enabled = false;
   //打消关机
   Process p = new Process();
   p.StartInfo.FileName = "cmd.exe";
   p.StartInfo.UseShellExecute = false;
   p.StartInfo.RedirectStandardInput = true;
   p.StartInfo.RedirectStandardOutput = true;
   p.StartInfo.RedirectStandardError = true;
   p.StartInfo.CreateNoWindow = true;
   p.Start();
   p.StandardInput.WriteLine("shutdown /a");
   p.StandardInput.WriteLine("exit");
   }
   }
  在我的测试软件中发明一个问题,就是当发送数据小于或即是8位时,一切正常,如果大于8为字节,则在datareceived事件中接收到的数据会分成两段,第一段为8位,第二段为剩下的字节,很奇怪,在msdn中讲到不能保证每次发送的数据都能正确接收到,需要参照BytesToRead属性来确定要读取的数据量,所以我想出来的解决步伐为:
  int DataLength=serialPort.BytesToRead;
  int i=0;
  StringBuilder sb=new StringBuilder();
  while(i<DataLength)
  {
   byte[] ds=new byte[1024];
   int len=serialPort.Read(ds,0,1024);
   sb.Append(Encoding.Ascii.GetString(ds,0,len));
   i+=len;
  }
  Console.Write(sb,ToString());
  这种奇怪的要领可以解决问题,后来想想应该是串口的事情方法决定的也有可能,等候其他的解决方法。

微软代码:取出本机的COM端口字符串

public static string[] GetPortNames()

{

RegistryKey localMachine = null;

RegistryKey key2 = null;

string[] textArray = null;

//这里有个断言,判断该注册表项是否存在

new RegistryPermission(RegistryPermissionAccess.Read, @"HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM").Assert();

try

{

localMachine = Registry.LocalMachine;

key2 = localMachine.OpenSubKey(@"HARDWARE\DEVICEMAP\SERIALCOMM", false);

if (key2 != null)

{

string[] valueNames = key2.GetValueNames();

textArray = new string[valueNames.Length];

for (int i = 0; i < valueNames.Length; i++)

{

textArray[i] = (string) key2.GetValue(valueNames[i]);

}

}

}

finally

{

if (localMachine != null)

{

localMachine.Close();

}

if (key2 != null)

{

key2.Close();

}

CodeAccessPermission.RevertAssert();

}

if (textArray == null)

{

textArray = new string[0];

}

return textArray;

}

VS.NET2005中SerialPort控件操纵详解(C#)

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.IO.Ports;

namespace SerialPorts

{

public partial class frm_Main : Form

{

#region Public Enumerations

public enum DataMode { Text, Hex }

public enum LogMsgType { Incoming, Outgoing, Normal, Warning, Error };

#endregion

private Color[] LogMsgTypeColor = { Color.Orange, Color.Green, Color.Black, Color.Blue, Color.Red };

//禁用和启用措施中各控件的状态

private void EnableControls()

{

// 基于串口的打开与否,设置控件状态

gbPortSettings.Enabled = !ComPort.IsOpen;

btns.Enabled = btnstop.Enabled = txtSendData.Enabled = btnSend.Enabled = ComPort.IsOpen;

if (ComPort.IsOpen) btnOpenPort.Text = "*串口";

else btnOpenPort.Text = "打开串口";

}

//初始化组件的数据,为串口供给相关参数

private void InitializeControlValues()

{

cmbParity.Items.Clear(); cmbParity.Items.AddRange(Enum.GetNames(typeof(Parity)));

cmbStopBits.Items.Clear(); cmbStopBits.Items.AddRange(Enum.GetNames(typeof(StopBits)));

cmbPortName.Items.Clear();

foreach (string s in SerialPort.GetPortNames())

cmbPortName.Items.Add(s);

cmbPortName.Text = cmbPortName.Items[0].ToString();

cmbParity.Text = cmbParity.Items[0].ToString();

cmbStopBits.Text = cmbStopBits.Items[0].ToString();

cmbDataBits.Text = cmbDataBits.Items[0].ToString();

cmbParity.Text = cmbParity.Items[0].ToString();

cmbBaudRate.Text = cmbBaudRate.Items[0].ToString();

EnableControls();

}

//十六进制转换字节数组

private byte[] HexStringToByteArray(string s)

{

s = s.WordStr(" ", "");

byte[] buffer = new byte[s.Length / 2];

for (int i = 0; i < s.Length; i += 2)

buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);

return buffer;

}

//字节数组转换十六进制

private string ByteArrayToHexString(byte[] data)

{

StringBuilder sb = new StringBuilder(data.Length * 3);

foreach (byte b in data)

sb.Append(Convert.ToString(b, 16).PadLeft(2, ‘0‘).PadRight(3, ‘ ‘));

return sb.ToString().ToUpper();

}

//显示数据日志

private void Log(LogMsgType msgtype, string msg)

{

rtfTerminal.Invoke(new EventHandler(delegate

{

rtfTerminal.SelectedText = string.Empty;

rtfTerminal.SelectionFont = new Font(rtfTerminal.SelectionFont, FontStyle.Bold);

rtfTerminal.SelectionColor = LogMsgTypeColor[(int)msgtype];

rtfTerminal.AppendText(msg);

rtfTerminal.ScrollToCaret();

}));

}

//串口发送方法

#region Local Properties

private DataMode CurrentDataMode

{

get

{

if (rbHex.Checked) return DataMode.Hex;

else return DataMode.Text;

}

set

{

if (value == DataMode.Text) rbText.Checked = true;

else rbHex.Checked = true;

}

}

#endregion

//发送数据

private void SendData()

{

if (CurrentDataMode == DataMode.Text)

{

// 发送用户的文本到串口

ComPort.Write(txtSendData.Text);

// 将用户的文本显示到数据窗口

Log(LogMsgType.Outgoing, txtSendData.Text + "\n");

}

else

{

try

{

// 转换用户十六进制数据到字节数组

byte[] data = HexStringToByteArray(txtSendData.Text);

// 发送数据到串口

ComPort.Write(data, 0, data.Length);

// 将用户十六进制数据到数据窗口

Log(LogMsgType.Outgoing, ByteArrayToHexString(data) + "\n");

}

catch (FormatException)

{

// 转换错误

Log(LogMsgType.Error, "十六进制数据有误: " + txtSendData.Text + "\n");

}

}

txtSendData.SelectAll();

}

/// <summary>

/// -------------------------------------------------------------

/// </summary>

public frm_Main()

{

InitializeComponent();

}

private void Form1_Load(object sender, EventArgs e)

{

InitializeControlValues();

ComPort.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);

}

//打开串口

private void btnOpenPort_Click(object sender, EventArgs e)

{

if (ComPort.IsOpen) ComPort.Close();

else

{

//设置串口参数

ComPort.BaudRate = int.Parse(cmbBaudRate.Text);

ComPort.DataBits = int.Parse(cmbDataBits.Text);

ComPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), cmbStopBits.Text);

ComPort.Parity = (Parity)Enum.Parse(typeof(Parity), cmbParity.Text);

ComPort.PortName = cmbPortName.Text;

// 打开串口

ComPort.Open();

}

// 转变组件状态

EnableControls();

// 如果串口打开,将焦点放入txtSendData

if (ComPort.IsOpen) txtSendData.Focus();

}

private void rbHex_CheckedChanged(object sender, EventArgs e)

{

if (rbHex.Checked) CurrentDataMode = DataMode.Hex;

}

private void rbText_CheckedChanged(object sender, EventArgs e)

{

if (rbText.Checked) CurrentDataMode = DataMode.Text;

}

//接收数据

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)

{

// 判断用户用的是字节模式还是字符模式

if (CurrentDataMode == DataMode.Text)

{

// 读取缓冲区的数据

string data = ComPort.ReadExisting();

// 显示读取的数据到数据窗口

Log(LogMsgType.Incoming, data + "\n");

}

else

{

// 获取字节长度

int bytes = ComPort.BytesToRead;

// 创建字节数组

byte[] buffer = new byte[bytes];

// 读取缓冲区的数据到数组

ComPort.Read(buffer, 0, bytes);

// 显示读取的数据到数据窗口

Log(LogMsgType.Incoming, ByteArrayToHexString(buffer) + "\n");

}

}

//发送数据按键

private void btnSend_Click(object sender, EventArgs e)

{

SendData();

}

private void lnkAbout_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)

{

(new frmAbout()).ShowDialog(this);

}

//时间组件控制发送数据

private void timer1_Tick(object sender, EventArgs e)

{

SendData();

}

//持续发送数据

private void button1_Click(object sender, EventArgs e)

{

delay.Enabled = true;

btns.Enabled = !delay.Enabled;

btnstop.Enabled = delay.Enabled;

}

//遏制持续发送数据

private void button2_Click(object sender, EventArgs e)

{

delay.Enabled = false;

btns.Enabled = !delay.Enabled;

btnstop.Enabled = delay.Enabled;