本文主要是讲述如何通过C#实现串口通信:
自己用API写串口通信,可以方便实现自己想要的各种功能,用现成的已经封装好的类库,常见两个串口操作类是JustinIO和SerialStreamReader。介绍JustinIO的使用方法:
1、打开串口:
函数原型:public void Open()
说明:打开事先设置好的端口
using JustinIO; static JustinIO.CommPort ss_port = new JustinIO.CommPort(); ss_port.PortNum = COM1; //端口号 ss_port.BaudRate = 19200; //串口通信波特率 ss_port.ByteSize = 8; //数据位 ss_port.Parity = 0; //奇偶校验 ss_port.StopBits = 1;//停止位 ss_port.ReadTimeout = 1000; //读超时 try { if (ss_port.Opened) { ss_port.Close(); ss_port.Open(); //打开串口 } else { ss_port.Open();//打开串口 } return true; } catch(Exception e) { MessageBox.Show("错误:" + e.Message); return false; }
2、写串口:
函数原型:public void Write(byte[] WriteBytes)
WriteBytes 就是你的写入的字节,注意,字符串要转换成字节数组才能进行通信
3、读串口:
函数原型:public byte[] Read(int NumBytes)
NumBytes 读入缓存数,注意读取来的是字节数组,要实际应用中要进行字符转换
4、关闭串口:
函数原型:ss_port.Close()
5、整合代码
using System; using System.Runtime.InteropServices; namespace JustinIO { class CommPort { public int PortNum; public int BaudRate; public byte ByteSize; public byte Parity; // 0-4=no,odd,even,mark,space public byte StopBits; // 0,1,2 = 1, 1.5, 2 public int ReadTimeout; //comm port win32 file handle private int hComm = -1; public bool Opened = false; //win32 api constants private const uint GENERIC_READ = 0x80000000; private const uint GENERIC_WRITE = 0x40000000; private const int OPEN_EXISTING = 3; private const int INVALID_HANDLE_VALUE = -1; [StructLayout(LayoutKind.Sequential)] public struct DCB { //taken from c struct in platform sdk public int DCBlength; // sizeof(DCB) public int BaudRate; // current baud rate /* these are the c struct bit fields, bit twiddle flag to set public int fBinary; // binary mode, no EOF check public int fParity; // enable parity checking public int fOutxCtsFlow; // CTS output flow control public int fOutxDsrFlow; // DSR output flow control public int fDtrControl; // DTR flow control type public int fDsrSensitivity; // DSR sensitivity public int fTXContinueOnXoff; // XOFF continues Tx public int fOutX; // XON/XOFF out flow control public int fInX; // XON/XOFF in flow control public int fErrorChar; // enable error replacement public int fNull; // enable null stripping public int fRtsControl; // RTS flow control public int fAbortOnError; // abort on error public int fDummy2; // reserved */ public uint flags; public ushort wReserved; // not currently used public ushort XonLim; // transmit XON threshold public ushort XoffLim; // transmit XOFF threshold public byte ByteSize; // number of bits/byte, 4-8 public byte Parity; // 0-4=no,odd,even,mark,space public byte StopBits; // 0,1,2 = 1, 1.5, 2 public char XonChar; // Tx and Rx XON character public char XoffChar; // Tx and Rx XOFF character public char ErrorChar; // error replacement character public char EofChar; // end of input character public char EvtChar; // received event character public ushort wReserved1; // reserved; do not use } [StructLayout(LayoutKind.Sequential)] private struct COMMTIMEOUTS { public int ReadIntervalTimeout; public int ReadTotalTimeoutMultiplier; public int ReadTotalTimeoutConstant; public int WriteTotalTimeoutMultiplier; public int WriteTotalTimeoutConstant; } [StructLayout(LayoutKind.Sequential)] private struct OVERLAPPED { public int Internal; public int InternalHigh; public int Offset; public int OffsetHigh; public int hEvent; } [DllImport("kernel32.dll")] private static extern int CreateFile( string lpFileName, // file name uint dwDesiredAccess, // access mode int dwShareMode, // share mode int lpSecurityAttributes, // SD int dwCreationDisposition, // how to create int dwFlagsAndAttributes, // file attributes int hTemplateFile // handle to template file ); [DllImport("kernel32.dll")] private static extern bool GetCommState( int hFile, // handle to communications device ref DCB lpDCB // device-control block ); [DllImport("kernel32.dll")] private static extern bool BuildCommDCB( string lpDef, // device-control string ref DCB lpDCB // device-control block ); [DllImport("kernel32.dll")] private static extern bool SetCommState( int hFile, // handle to communications device ref DCB lpDCB // device-control block ); [DllImport("kernel32.dll")] private static extern bool GetCommTimeouts( int hFile, // handle to comm device ref COMMTIMEOUTS lpCommTimeouts // time-out values ); [DllImport("kernel32.dll")] private static extern bool SetCommTimeouts( int hFile, // handle to comm device ref COMMTIMEOUTS lpCommTimeouts // time-out values ); [DllImport("kernel32.dll")] private static extern bool ReadFile( int hFile, // handle to file byte[] lpBuffer, // data buffer int nNumberOfBytesToRead, // number of bytes to read ref int lpNumberOfBytesRead, // number of bytes read ref OVERLAPPED lpOverlapped // overlapped buffer ); [DllImport("kernel32.dll")] private static extern bool WriteFile( int hFile, // handle to file byte[] lpBuffer, // data buffer int nNumberOfBytesToWrite, // number of bytes to write ref int lpNumberOfBytesWritten, // number of bytes written ref OVERLAPPED lpOverlapped // overlapped buffer ); [DllImport("kernel32.dll")] private static extern bool CloseHandle( int hObject // handle to object ); [DllImport("kernel32.dll")] private static extern uint GetLastError(); public void Open() { DCB dcbCommPort = new DCB(); COMMTIMEOUTS ctoCommPort = new COMMTIMEOUTS(); // OPEN THE COMM PORT. hComm = CreateFile("COM" + PortNum ,GENERIC_READ | GENERIC_WRITE,0, 0,OPEN_EXISTING,0,0); // IF THE PORT CANNOT BE OPENED, BAIL OUT. if(hComm == INVALID_HANDLE_VALUE) { throw(new ApplicationException("Comm Port Can Not Be Opened")); } // SET THE COMM TIMEOUTS. GetCommTimeouts(hComm,ref ctoCommPort); ctoCommPort.ReadTotalTimeoutConstant = ReadTimeout; ctoCommPort.ReadTotalTimeoutMultiplier = 0; ctoCommPort.WriteTotalTimeoutMultiplier = 0; ctoCommPort.WriteTotalTimeoutConstant = 0; SetCommTimeouts(hComm,ref ctoCommPort); // SET BAUD RATE, PARITY, WORD SIZE, AND STOP BITS. GetCommState(hComm, ref dcbCommPort); dcbCommPort.BaudRate=BaudRate; dcbCommPort.flags=0; //dcb.fBinary=1; dcbCommPort.flags|=1; if (Parity>0) { //dcb.fParity=1 dcbCommPort.flags|=2; } dcbCommPort.Parity=Parity; dcbCommPort.ByteSize=ByteSize; dcbCommPort.StopBits=StopBits; if (!SetCommState(hComm, ref dcbCommPort)) { //uint ErrorNum=GetLastError(); throw(new ApplicationException("Comm Port Can Not Be Opened")); } //unremark to see if setting took correctly //DCB dcbCommPort2 = new DCB(); //GetCommState(hComm, ref dcbCommPort2); Opened = true; } public void Close() { if (hComm!=INVALID_HANDLE_VALUE) { CloseHandle(hComm); } } public byte[] Read(int NumBytes) { byte[] BufBytes; byte[] OutBytes; BufBytes = new byte[NumBytes]; if (hComm!=INVALID_HANDLE_VALUE) { OVERLAPPED ovlCommPort = new OVERLAPPED(); int BytesRead=0; ReadFile(hComm,BufBytes,NumBytes,ref BytesRead,ref ovlCommPort); OutBytes = new byte[BytesRead]; Array.Copy(BufBytes,OutBytes,BytesRead); } else { throw(new ApplicationException("Comm Port Not Open")); } return OutBytes; } public void Write(byte[] WriteBytes) { if (hComm!=INVALID_HANDLE_VALUE) { OVERLAPPED ovlCommPort = new OVERLAPPED(); int BytesWritten = 0; WriteFile(hComm,WriteBytes,WriteBytes.Length,ref BytesWritten,ref ovlCommPort); } else { throw(new ApplicationException("Comm Port Not Open")); } } } } }
使用SerialPort类的方法:
方法一:
首先要添加
using System.IO;
using System.IO.Ports;
1...在类的内部定义SerialPort com;
2...打开串口
com = new SerialPort();
com.BaudRate = 115200;
com.PortName = "COM1";
com.DataBits = 8;
com.Open();//打开串口
3...发送数据
Byte[] TxData ={1,2,3,4,5,6,7,8 };
com.Write(TxData, 0, 8);
4...接收数据
4.1使用事件接收
this.com.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(this.OnDataReceived);
private void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
4.2使用线程接收
接收数据启动一个线程,使其接收。
在类的内部定义
Thread _readThread;
bool _keepReading;
打开串口后启动线程
_keepReading = true;
_readThread = new Thread(ReadPort);
_readThread.Start();
线程函数:
private void ReadPort() { while (_keepReading) { if (com.IsOpen) { byte[] readBuffer = new byte[com.ReadBufferSize + 1]; try { // If there are bytes available on the serial port, // Read returns up to "count" bytes, but will not block (wait) // for the remaining bytes. If there are no bytes available // on the serial port, Read will block until at least one byte // is available on the port, up until the ReadTimeout milliseconds // have elapsed, at which time a TimeoutException will be thrown. int count = com.Read(readBuffer, 0, com.ReadBufferSize); String SerialIn = System.Text.Encoding.ASCII.GetString(readBuffer, 0, count); if (count != 0) //byteToHexStr(readBuffer); ThreadFunction(byteToHexStr(readBuffer,count)); } catch (TimeoutException) { } } else { TimeSpan waitTime = new TimeSpan(0, 0, 0, 0, 50); Thread.Sleep(waitTime); } } }
方法二:使用C#自带的SerialPor控件。
1...在“工具箱”的“组件”中选择SerialPor控件添加。
2...设置串口并打开
serialPort1.PortName = "COM1";
serialPort1.BaudRate = 9600;
serialPort1.Open();
3...写入数据可以使用Write或者下面的函数
serialPort1.WriteLine(str);
4...添加数据接收的事件
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
使用中的一些常见问题
C#中SerialPort类中DataReceived事件GUI实时处理方法(来自wanglei_wan@yahoo.com.cn 的看法)
MSDN:从 SerialPort 对象接收数据时,将在辅助线程上引发 DataReceived 事件。由于此事件在辅助线程而非主线程上引发,因此尝试修改主线程中的一些元素(如 UI 元素)时会引发线程异常。如果有必要修改主 Form 或 Control 中的元素,必须使用 Invoke 回发更改请求,这将在正确的线程上执行.进而要想将辅助线程中所读到的数据显示到主线程的Form控件上时,只有通过Invoke方法来实现
下面是代码实例:
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) { int SDateTemp = this.serialPort1.ReadByte(); //读取串口中一个字节的数据 this.tB_ReceiveDate.Invoke( //在拥有此控件的基础窗口句柄的线程上执行委托Invoke(Delegate) //即在textBox_ReceiveDate控件的父窗口form中执行委托. new MethodInvoker( /*表示一个委托,该委托可执行托管代码中声明为 void 且不接受任何参数的任何方法。 在对控件的 Invoke 方法进行调用时或需要一个简单委托又不想自己定义时可以使用该委托。*/ delegate{ /*匿名方法,C#2.0的新功能,这是一种允许程序员将一段完整代码区块当成参数传递的程序代码编写技术,通过此种方法可 以直接使用委托来设计事件响应程序以下就是你要在主线程上实现的功能但是有一点要注意,这里不适宜处理过多的方法,因为C#消息机制是消息流水线响应机制,如果这里在主线程上处理语句的时间过长会导致主UI线程阻塞,停止响应或响应不顺畅,这时你的主form界面会延迟或卡死 */ this.tB_ReceiveDate.AppendText(SDateTemp.ToString());//输出到主窗口文本控件 this.tB_ReceiveDate.Text += " ";} ) ); }
如何知道当前电脑有哪个串口
在窗体上添加一个comboBox控件。
然后使用comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames()); 或者
string[] portList = System.IO.Ports.SerialPort.GetPortNames();
for (int i = 0; i < portList.Length; ++i)
{
string name = portList[i];
comboBox1.Items.Add(name);
}
博客参考:http://blog.csdn.net/byxdaz/article/details/6748234
相关推荐
### C#串口通信详解与数据丢失问题的解决方法 #### 概述 串口通信是一种常见的设备间数据传输方式,在工业控制、自动化测试等领域应用广泛。然而,在使用C#进行串口通信开发时,很多开发者都遇到过数据丢失的问题...
本项目"济南电柜"中的"C#串口通信+CRC校验"是针对初学者的一个实践案例,适用于VS2010开发环境,确保了通信的正确性。 串口通信(Serial Port Communication)是指通过计算机的串行端口进行数据传输。在C#中,我们...
C#作为一种强大的编程语言,提供了丰富的API来支持串口通信。本篇将深入探讨C#中实现串口通信的相关知识点,并结合提供的"串口客户端"和"串口服务端"源码进行讲解。 首先,我们要了解C#中的`System.IO.Ports`命名...
在C#编程环境下,我们可以利用.NET Framework提供的System.IO.Ports命名空间来实现串口通信功能。本文将深入探讨如何在C#中连接串口并发送字符,以便于开发相关应用。 首先,我们要了解串口通信的基本概念。串行...
在.NET框架下,C#语言提供了丰富的库来支持各种类型的通信方式,其中之一就是串口通信。串口通信在工业控制、设备调试、数据传输等领域有着广泛的应用。本资源"**C# 串口通信类库和例子**"是基于.NET 2.0版本的,它...
在IT领域,尤其是在软件开发中,串口通讯和Socket通讯是两种常见的通信方式...通过学习和分析这些代码,开发者可以更好地掌握如何在C#环境中实现设备间的串口通信和网络间的Socket通信,为开发相关项目打下坚实的基础。
这个类是上位机串口编程的框架类,用单例模式多线程...类里面是我开发使用的命令,使用者可以参考这个类实现自己的串口通讯框架类,包括数据的发送和接收,事件的触发,错误的处理,单例模式的实现等,希望对您有帮助.
c#串口通讯,c#编写的串口通讯,功能很齐全
综上所述,这个例程涵盖了C#编程、Windows Forms界面设计、串口通信等多个方面,是学习和实践C#串口通讯的一个良好起点。通过深入理解和实践这些知识点,开发者可以创建自己的串口通信应用,满足各种硬件设备的交互...
7. **示例代码**:DEMO中的`CSharpPort`可能是包含了一个简单的C#串口通信示例。示例通常会包含创建`SerialPort`对象、设置串口参数、打开串口、注册事件处理函数、发送与接收数据以及关闭串口的步骤。通过分析这个...
在C#编程中,串口通信(Serial Communication)是一种...通过以上步骤,我们可以构建一个基本的C#串口通信程序,解决中文乱码和回车换行问题。在实际应用中,还可以根据需求添加更多的功能,如数据校验、心跳检测等。
8. **学习建议**:在深入学习C#串口通信时,除了理解代码示例,还应了解串口通信的基本概念和协议,如RS-232标准、串口通信协议等。此外,可以尝试连接实际的硬件设备,如串口打印机、传感器等,进行实践操作,以...
3. **C#串口通信API**:除了使用MSComm控件,C#自身也提供了`System.IO.Ports.SerialPort`类,这是一个强大且易于使用的API,可以完成打开、关闭串口,设置串口参数,以及读写数据等功能。相比于MSComm控件,`...
本文将深入探讨C#中实现串口通信的两种方法:使用Windows API和SerialPort类。 首先,我们来理解串口通信的基本概念。串口通信,也称为串行通信,是指数据以位(bit)为单位,逐位进行传输的方式。在C#中,串口通信...
c#编写串口通讯代码多线程实现,逻辑与界面分离。发送与接收都为单独线程
在IT领域,串口通信是一种常见且重要的通信方式,...以上就是关于"C#串口通信源代码,实现字符串和16进制的发送以及接受"这个主题的详细说明。理解并掌握这些知识点,将有助于你在实际项目中实现有效的串口通信功能。
C#串口通信结合CRC16: 在C#中,串口通信时发送数据前需要计算并附加CRC16校验码,接收数据后则需校验CRC以确认数据完整性和正确性。以下是一段简化的代码示例: ```csharp using System.IO.Ports; // 创建...
具体实现中,以下是一段基本的C#串口通信代码示例: ```csharp using System.IO.Ports; public class SerialPortManager { private SerialPort _serialPort; public SerialPortManager() { // 初始化串口 _...
根据提供的文件信息,我们可以总结出以下关于C#串口通信程序的关键知识点: ### C#串口通信概述 在计算机通信领域,串行通信是一种常见的数据传输方式,它通过一条信号线将数据一位接一位地传输。对于需要与硬件...