转载地址:
学了C#,因为本人搞嵌入式方面的研究,难免和串口多有打交道,故用c#做了个串口发送应用程序。因为.net2003还没有做串口控件进去,所以这个程序化了我1个星期,包括类的处理以及很多次的调试,现在已经可以实现串口的打开并发送数据(关闭和接收没做好,时间问题:)),还是等下.net2005再弄了(据说2005把串口控件做进去了,方便了呀!)
using System;
using System.Drawing;using System.Collections;using System.ComponentModel;using System.Windows.Forms;using System.Data;using System.Runtime.InteropServices;namespace SerialPort_628
{ /// <summary> /// Form1 的摘要说明。 /// </summary> public class Form1 : System.Windows.Forms.Form { private System.Windows.Forms.TextBox textBox2; private System.Windows.Forms.TextBox textBox4; private System.Windows.Forms.ComboBox comboBox1; private System.Windows.Forms.PictureBox pictureBox1; private System.Windows.Forms.TextBox SendData; private System.Windows.Forms.TextBox ReceiveData; private System.Windows.Forms.Button button1; private System.Windows.Forms.Button button2; private System.Windows.Forms.Timer timer1; private System.Windows.Forms.PictureBox pictureBox2; private System.Windows.Forms.Button button3; private System.Windows.Forms.ComboBox comboBox2; private System.ComponentModel.IContainer components;public Form1()
{ // // Windows 窗体设计器支持所必需的 // InitializeComponent();//
// TODO: 在 InitializeComponent 调用后添加任何构造函数代码 // }/// <summary>
/// 清理所有正在使用的资源。 /// </summary> protected override void Dispose( bool disposing ) { if( disposing ) { if (components != null) { components.Dispose(); } } base.Dispose( disposing ); }#region Windows 窗体设计器生成的代码
/// <summary> /// 设计器支持所需的方法 - 不要使用代码编辑器修改 /// 此方法的内容。 /// </summary> private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this.SendData = new System.Windows.Forms.TextBox(); this.ReceiveData = new System.Windows.Forms.TextBox(); this.button1 = new System.Windows.Forms.Button(); this.textBox2 = new System.Windows.Forms.TextBox(); this.textBox4 = new System.Windows.Forms.TextBox(); this.comboBox1 = new System.Windows.Forms.ComboBox(); this.button2 = new System.Windows.Forms.Button(); this.pictureBox1 = new System.Windows.Forms.PictureBox(); this.timer1 = new System.Windows.Forms.Timer(this.components); this.pictureBox2 = new System.Windows.Forms.PictureBox(); this.button3 = new System.Windows.Forms.Button(); this.comboBox2 = new System.Windows.Forms.ComboBox(); this.SuspendLayout(); // // SendData // this.SendData.Location = new System.Drawing.Point(24, 96); this.SendData.Multiline = true; this.SendData.Name = "SendData"; this.SendData.Size = new System.Drawing.Size(176, 184); this.SendData.TabIndex = 0; this.SendData.Text = ""; // // ReceiveData // this.ReceiveData.Location = new System.Drawing.Point(488, 96); this.ReceiveData.Multiline = true; this.ReceiveData.Name = "ReceiveData"; this.ReceiveData.Size = new System.Drawing.Size(176, 184); this.ReceiveData.TabIndex = 2; this.ReceiveData.Text = ""; // // button1 // this.button1.Location = new System.Drawing.Point(296, 176); this.button1.Name = "button1"; this.button1.TabIndex = 3; this.button1.Text = "发送"; this.button1.Click += new System.EventHandler(this.button1_Click); // // textBox2 // this.textBox2.Location = new System.Drawing.Point(24, 72); this.textBox2.Name = "textBox2"; this.textBox2.ReadOnly = true; this.textBox2.TabIndex = 4; this.textBox2.Text = "发送数据区"; // // textBox4 // this.textBox4.Location = new System.Drawing.Point(488, 72); this.textBox4.Name = "textBox4"; this.textBox4.ReadOnly = true; this.textBox4.TabIndex = 5; this.textBox4.Text = "接收数据区"; // // comboBox1 // this.comboBox1.Items.AddRange(new object[] { "COM1 ", "COM2"}); this.comboBox1.Location = new System.Drawing.Point(24, 32); this.comboBox1.Name = "comboBox1"; this.comboBox1.Size = new System.Drawing.Size(64, 20); this.comboBox1.TabIndex = 6; this.comboBox1.Text = "COM1 "; this.comboBox1.TextChanged += new System.EventHandler(this.comboBox1_TextChanged); // // button2 // this.button2.Location = new System.Drawing.Point(128, 32); this.button2.Name = "button2"; this.button2.TabIndex = 7; this.button2.Text = "打开"; this.button2.Click += new System.EventHandler(this.button2_Click); // // pictureBox1 // this.pictureBox1.BackColor = System.Drawing.SystemColors.Control; this.pictureBox1.Location = new System.Drawing.Point(104, 32); this.pictureBox1.Name = "pictureBox1"; this.pictureBox1.Size = new System.Drawing.Size(8, 16); this.pictureBox1.TabIndex = 8; this.pictureBox1.TabStop = false; // // timer1 // this.timer1.Interval = 1000; this.timer1.Tick += new System.EventHandler(this.timer1_Tick); // // pictureBox2 // this.pictureBox2.BackColor = System.Drawing.SystemColors.Control; this.pictureBox2.Location = new System.Drawing.Point(568, 40); this.pictureBox2.Name = "pictureBox2"; this.pictureBox2.Size = new System.Drawing.Size(8, 16); this.pictureBox2.TabIndex = 11; this.pictureBox2.TabStop = false; // // button3 // this.button3.Location = new System.Drawing.Point(592, 40); this.button3.Name = "button3"; this.button3.TabIndex = 10; this.button3.Text = "打开"; this.button3.Click += new System.EventHandler(this.button3_Click); // // comboBox2 // this.comboBox2.Items.AddRange(new object[] { "COM1 ", "COM2"}); this.comboBox2.Location = new System.Drawing.Point(488, 40); this.comboBox2.Name = "comboBox2"; this.comboBox2.Size = new System.Drawing.Size(64, 20); this.comboBox2.TabIndex = 9; this.comboBox2.Text = "COM2"; // // Form1 // this.AutoScaleBaseSize = new System.Drawing.Size(6, 14); this.ClientSize = new System.Drawing.Size(696, 346); this.Controls.Add(this.pictureBox2); this.Controls.Add(this.button3); this.Controls.Add(this.comboBox2); this.Controls.Add(this.pictureBox1); this.Controls.Add(this.button2); this.Controls.Add(this.comboBox1); this.Controls.Add(this.textBox4); this.Controls.Add(this.textBox2); this.Controls.Add(this.button1); this.Controls.Add(this.ReceiveData); this.Controls.Add(this.SendData); this.Name = "Form1"; this.Text = "Form1"; this.ResumeLayout(false);}
#endregion/// <summary>
/// 应用程序的主入口点。 /// </summary> [STAThread] static void Main() { Application.Run(new Form1()); } CommPort Sport = new CommPort(); CommPort Rport = new CommPort(); private void button1_Click(object sender, System.EventArgs e) { Sport.Write(System.Text.Encoding.Default.GetBytes(SendData.Text.ToString())); //MessageBox.Show("数据已经发送!","",MessageBoxButtons.OK,MessageBoxIcon.Asterisk); }private void button2_Click(object sender, System.EventArgs e)
{ Sport.PortNum = comboBox1.Text.ToString(); //端口号 Sport.Parity = 0; //奇偶校验 Sport.BaudRate = 9600;//串口通信波特率 Sport.ByteSize = 8; //数据位 Sport.StopBits = 1;//停止位 Sport.ReadTimeout = 1000; //读超时 if (Sport.Opened) { Sport.Close(); Sport.Open(); //打开串口 } else { Sport.Open();//打开串口 } pictureBox1.BackColor = System.Drawing.Color.Red; }private void comboBox1_TextChanged(object sender, System.EventArgs e)
{ pictureBox1.BackColor = System.Drawing.Color.WhiteSmoke; }private void timer1_Tick(object sender, System.EventArgs e)
{ if(Rport.Opened) { byte[] bs = Sport.Read(1); ReceiveData.Text=System.Text.Encoding.ASCII.GetString(bs); } }private void button3_Click(object sender, System.EventArgs e)
{ Rport.PortNum = comboBox2.Text.ToString(); //端口号 Rport.BaudRate = 9600;//串口通信波特率 Rport.Parity = 0;//奇偶校验 Rport.StopBits = 1;//停止位 Rport.ByteSize = 8;//数据位 Rport.ReadTimeout = 1000;//读超时 if (Rport.Opened) { Rport.Close(); Rport.Open(); //打开串口 } else { Rport.Open();//打开串口 } pictureBox2.BackColor = System.Drawing.Color.Red; } }class CommPort
{public string 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;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;//comm port win32 file handle
private int hComm = INVALID_HANDLE_VALUE;[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; // 指定是否允许二进制模式,在windows95中必须主TRUE binary mode, no EOF check public int fParity; // 指定是否允许奇偶校验 enable parity checking public int fOutxCtsFlow; // 指定CTS是否用于检测发送控制,当为TRUE是CTS为OFF,发送将被挂起。 CTS output flow control public int fOutxDsrFlow; // 指定CTS是否用于检测发送控制 DSR output flow control public int fDtrControl; // DTR_CONTROL_DISABLE值将DTR置为OFF, DTR_CONTROL_ENABLE值将DTR置为ON, DTR_CONTROL_HANDSHAKE允许DTR"握手" DTR flow control type public int fDsrSensitivity; // 当该值为TRUE时DSR为OFF时接收的字节被忽略 DSR sensitivity public int fTXContinueOnXoff; // 指定当接收缓冲区已满,并且驱动程序已经发送出XoffChar字符时发送是否停止。TRUE时,在接收缓冲区接收到缓冲区已满的字节XoffLim且驱动程序已经发送出XoffChar字符中止接收字节之后,发送继续进行。 FALSE时,在接收缓冲区接收到代表缓冲区已空的字节XonChar且驱动程序已经发送出恢复发送的XonChar之后,发送继续进行。XOFF continues Tx public int fOutX; // TRUE时,接收到XoffChar之后便停止发送接收到XonChar之后将重新开始 XON/XOFF out flow control public int fInX; // TRUE时,接收缓冲区接收到代表缓冲区满的XoffLim之后,XoffChar发送出去接收缓冲区接收到代表缓冲区空的XonLim之后,XonChar发送出去 XON/XOFF in flow control public int fErrorChar; // 该值为TRUE且fParity为TRUE时,用ErrorChar 成员指定的字符代替奇偶校验错误的接收字符 enable error replacement public int fNull; // eTRUE时,接收时去掉空(0值)字节 enable null stripping public int fRtsControl; // RTS flow controlpublic int fAbortOnError; // TRUE时,有错误发生时中止读和写操作 abort on error
public int fDummy2; // 未使用 reservedpublic uint flags;
public ushort wReserved; // 未使用,必须为0 not currently used public ushort XonLim; // 指定在XON字符发送这前接收缓冲区中可允许的最小字节数 transmit XON threshold public ushort XoffLim; // 指定在XOFF字符发送这前接收缓冲区中可允许的最小字节数 transmit XOFF threshold public byte ByteSize; // 指定端口当前使用的数据位 number of bits/byte, 4-8 public byte Parity; // 指定端口当前使用的奇偶校验方法,可能为:EVENPARITY,MARKPARITY,NOPARITY,ODDPARITY 0-4=no,odd,even,mark,space public byte StopBits; // 指定端口当前使用的停止位数,可能为:ONESTOPBIT,ONE5STOPBITS,TWOSTOPBITS 0,1,2 = 1, 1.5, 2 public char XonChar; // 指定用于发送和接收字符XON的值 Tx and Rx XON character public char XoffChar; // 指定用于发送和接收字符XOFF值 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, // 要打开的串口名称 uint dwDesiredAccess, // 指定串口的访问方式,一般设置为可读可写方式 int dwShareMode, // 指定串口的共享模式,串口不能共享,所以设置为0 int lpSecurityAttributes, // 设置串口的安全属性,WIN9X下不支持,应设为NULL int dwCreationDisposition, // 对于串口通信,创建方式只能为OPEN_EXISTING int dwFlagsAndAttributes, // 指定串口属性与标志,设置为FILE_FLAG_OVERLAPPED(重叠I/O操作),指定串口以异步方式通信 int hTemplateFile // 对于串口通信必须设置为NULL ); [DllImport("kernel32.dll")] private static extern bool GetCommState( int hFile, //通信设备句柄 ref DCB lpDCB // 设备控制块DCB ); [DllImport("kernel32.dll")] private static extern bool BuildCommDCB( string lpDef, // 设备控制字符串 ref DCB lpDCB // 设备控制块 ); [DllImport("kernel32.dll")] private static extern bool SetCommState( int hFile, // 通信设备句柄 ref DCB lpDCB // 设备控制块 ); [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(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("串口被占用,不能打开串口!")); }// 设置通信超时时间 SET THE COMM TIMEOUTS.
GetCommTimeouts(hComm,ref ctoCommPort); ctoCommPort.ReadIntervalTimeout = Int32.MaxValue; ctoCommPort.ReadTotalTimeoutConstant = 0; ctoCommPort.ReadTotalTimeoutMultiplier = 0; ctoCommPort.WriteTotalTimeoutMultiplier = 10; ctoCommPort.WriteTotalTimeoutConstant = 1000; SetCommTimeouts(hComm,ref ctoCommPort);// 设置串口 SET BAUD RATE, PARITY, WORD SIZE, AND STOP BITS.
dcbCommPort.DCBlength = Marshal.SizeOf(dcbCommPort); GetCommState(hComm, ref dcbCommPort); dcbCommPort.BaudRate=BaudRate; dcbCommPort.Parity=Parity; dcbCommPort.ByteSize=ByteSize; dcbCommPort.StopBits=StopBits; SetCommState(hComm, ref dcbCommPort); Opened = true; }public void Close()
{ if (hComm!=INVALID_HANDLE_VALUE) { CloseHandle(hComm); hComm = INVALID_HANDLE_VALUE; Opened = false; PortNum = null; } }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("串口未打开!")); } 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("串口未打开!")); } } }}