前几天在手持的wince设备上进行调试串口通信,着实让人挠头啊,串口能打开也能关闭,但就是收发数据不行,搞了好长时间,才发现,是硬件连接有问题。
我用的是vs2008+C#,系统跑的是wince6.0,用C#开发串口通信其实最简单的就是直接拖控件,很方便,但欠缺灵活性,这里就不说了,我用代码实现的串口程序如下:
已经跑通,可以直接用的。
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace SmartDeviceProject1
{
class wincecom
{
#region 变量、函数声明定义部分
//设备控制块结构体类型
[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 control
*//*RTS_CONTROL_DISABLE时,RTS置为OFF
RTS_CONTROL_ENABLE时, RTS置为ON
RTS_CONTROL_HANDSHAKE时,
当接收缓冲区小于半满时RTS为ON
当接收缓冲区超过四分之三满时RTS为OFF
RTS_CONTROL_TOGGLE时,
当接收缓冲区仍有剩余字节时RTS为ON ,否则缺省为OFF*/
//public int fAbortOnError; // TRUE时,有错误发生时中止读和写操作 abort on error
//public int fDummy2; // 未使用 reserved
public 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 byte XonChar; // 指定用于发送和接收字符XON的值 Tx and Rx XON character
public byte XoffChar; // 指定用于发送和接收字符XOFF值 Tx and Rx XOFF character
public byte ErrorChar; // 本字符用来代替接收到的奇偶校验发生错误时的值 error replacement character
public byte EofChar; // 当没有使用二进制模式时,本字符可用来指示数据的结束 end of input character
public byte EvtChar; // 当接收到此字符时,会产生一个事件 received event character
public ushort wReserved1; // 未使用 reserved; do not use
}
//串口超时时间结构体类型 ,以毫秒为单位
[StructLayout(LayoutKind.Sequential)]
public struct COMMTIMEOUTS
{
public int ReadIntervalTimeout; //读间隔超时
public int ReadTotalTimeoutMultiplier; //读时间系数
public int ReadTotalTimeoutConstant; //读时间常量
public int WriteTotalTimeoutMultiplier; //写时间系数
public int WriteTotalTimeoutConstant; //写时间常量
}
//溢出缓冲区结构体类型
[StructLayout(LayoutKind.Sequential)]
public struct OVERLAPPED
{
public int Internal;
public int InternalHigh;
public int Offset;
public int OffsetHigh;
public int hEvent;
}
[DllImport("coredll.dll")]
public 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("coredll.dll")]
public 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
//int r
);
[DllImport("coredll.dll")]
public 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
//int s
);
[DllImport("coredll.dll")]
public static extern bool CloseHandle(
int hObject // handle to object
);
[DllImport("coredll.dll")]
public static extern bool GetCommState(
int hFile, //通信设备句柄
ref DCB lpDCB // 设备控制块DCB
);
[DllImport("coredll.dll")]
public static extern bool SetCommState(
int hFile, // 通信设备句柄
ref DCB lpDCB // 设备控制块
);
[DllImport("coredll.dll")]
public static extern bool GetCommTimeouts(
int hFile, // 通信设备句柄 handle to comm device
ref COMMTIMEOUTS lpCommTimeouts // 超时时间 time-out values
);
[DllImport("coredll.dll")]
public static extern bool SetCommTimeouts(
int hFile, // 通信设备句柄 handle to comm device
ref COMMTIMEOUTS lpCommTimeouts // 超时时间 time-out values
);
//清空读写缓冲区
[DllImport("coredll.dll")]
public static extern bool PurgeComm(
int hFile,
uint dwFlags
);
//设置读写缓冲区
[DllImport("coredll.dll")]
public static extern bool SetupComm(
int hFile, // 通信设备句柄 handle to file
int dwInQueue, //输入缓冲区的大小
int dwOutQueue //输出缓冲区的大小
);
//得到串口最后一次返回的错误
[DllImport("coredll.dll")]
private static extern uint GetLastError();
//设置DCB标志位
internal void SetDcbFlag(int whichFlag, int setting, DCB dcb)
{
uint num;
setting = setting << whichFlag;
if ((whichFlag == 4) || (whichFlag == 12))
{
num = 3;
}
else if (whichFlag == 15)
{
num = 0x1ffff;
}
else
{
num = 1;
}
dcb.flags &= ~(num << whichFlag);
dcb.flags |= (uint)setting;
}
//comm port win32 file handle
static int hComm = -1;
//win32 api constants
const uint GENERIC_READ = 0x80000000;// WINAPI常量,写标志
const uint GENERIC_WRITE = 0x40000000;// WINAPI常量,读标志
const int OPEN_EXISTING = 3; // WINAPI常量,打开已存在
//清空读写缓冲区
const int PURGE_REABORT = 0x2;
const int PURGE_REACLEAR = 0x8;
const int PURGE_TXABORT = 0x1;
const int PURGE_TXACLEAR = 0x4;
int ReadTimeout = 1000; //超时长
string comPort = "COM4:";//端口名称(COM1,COM2...COM4...)
//string PortNum="4";//端口号
//string comPort = string.Format("COM{0}:", PortNum);//将端口号格式化
DCB dcbCommPort = new DCB();
COMMTIMEOUTS ctoCommPort = new COMMTIMEOUTS();
//OVERLAPPED ovlCommPort = new OVERLAPPED();//溢出缓冲区
#endregion
// 打开串口 OPEN THE COMM PORT.
public int OpenCom()
{
hComm = CreateFile(comPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
if (!SetupComm(hComm, 1024, 1024))//输入输出缓冲区大小都是1024个字节
return -1;
// 设置通信超时时间 SET THE COMM TIMEOUTS.
if (!GetCommTimeouts(hComm, ref ctoCommPort))
return -2;
ctoCommPort.ReadTotalTimeoutConstant = ReadTimeout;
ctoCommPort.ReadTotalTimeoutMultiplier = 0;
ctoCommPort.WriteTotalTimeoutMultiplier = 0;
ctoCommPort.WriteTotalTimeoutConstant = 0;
if (!SetCommTimeouts(hComm, ref ctoCommPort))
return -3;
// 设置串口 SET BAUD RATE, PARITY, WORD SIZE, AND STOP BITS.
if (!GetCommState(hComm, ref dcbCommPort))
return -4;
dcbCommPort.DCBlength = Marshal.SizeOf(dcbCommPort);
dcbCommPort.BaudRate = 115200;
dcbCommPort.flags = 0;
dcbCommPort.ByteSize = (byte)8;
dcbCommPort.Parity = (byte)0;
dcbCommPort.StopBits = 0;
//if (dcbCommPort.Parity > 0)
//{
// dcbCommPort.fParity = 1;
//dcbCommPort.flags |= 2;
//}
//dcbCommPort.flags |= 1;
//dcbCommPort.wReserved = 0;
//------------------------------
/* SetDcbFlag(0, 1, dcbCommPort); //二进制方式
SetDcbFlag(1, (dcbCommPort.Parity == 0) ? 0 : 1, dcbCommPort);
SetDcbFlag(2, 0, dcbCommPort); //不用CTS检测发送流控制
SetDcbFlag(3, 0, dcbCommPort); //不用DSR检测发送流控制
SetDcbFlag(4, 0, dcbCommPort); //禁止DTR流量控制
SetDcbFlag(6, 0, dcbCommPort); //对DTR信号线不敏感
SetDcbFlag(9, 1, dcbCommPort); //检测接收缓冲区
SetDcbFlag(8, 0, dcbCommPort); //不做发送字符控制
SetDcbFlag(10, 0, dcbCommPort); //是否用指定字符替换校验错的字符
SetDcbFlag(11, 0, dcbCommPort); //保留NULL字符
SetDcbFlag(12, 0, dcbCommPort); //允许RTS流量控制
SetDcbFlag(14, 0, dcbCommPort); //发送错误后,继续进行下面的读写操作
//------------------------------
dcbCommPort.wReserved = 0; //没有使用,必须为0
dcbCommPort.XonLim = 0; //指定在XOFF字符发送之前接收到缓冲区中可允许的最小字节数
dcbCommPort.XoffLim = 0; //指定在XOFF字符发送之前缓冲区中可允许的最小可用字节数
dcbCommPort.XonChar = 0; //发送和接收的XON字符
dcbCommPort.XoffChar = 0; //发送和接收的XOFF字符
dcbCommPort.ErrorChar = 0; //代替接收到奇偶校验错误的字符
dcbCommPort.EofChar = 0; //用来表示数据的结束
dcbCommPort.EvtChar = 0; //事件字符,接收到此字符时,会产生一个事件
dcbCommPort.wReserved1 = 0; //没有使用
*/
if(!SetCommState(hComm, ref dcbCommPort))
return -5;
return hComm;
}
//串口发送函数
public int SendCom(byte[] BufWrite, int SendNum)
{
if (hComm != -1)
{
int intRealWrite = 0;
OVERLAPPED ovlCommPort = new OVERLAPPED();
//PurgeComm(hComm, PURGE_REABORT | PURGE_REACLEAR | PURGE_TXABORT | PURGE_TXACLEAR );
//向串口发送数据
bool a = WriteFile(hComm, BufWrite, SendNum, ref intRealWrite, ref ovlCommPort);
return intRealWrite;
}
return -6;
}
// 清除接收缓冲区
public void ClearReceiveBuf()
{
if (hComm != -1)
{
PurgeComm(hComm, PURGE_REABORT | PURGE_REACLEAR);
}
}
// 清除发送缓冲区
public void ClearSendBuf()
{
if (hComm != -1)
{
PurgeComm(hComm, PURGE_TXABORT | PURGE_TXACLEAR);
}
}
//从串口读取数据
public int ReadCom(ref byte[] BufRead, int NumBytes)
{
if (hComm != -1)
{
//byte[] BufRead = new byte[NumBytes];//接收数据的缓冲区
int intBytesRead = 0;//实际接收的多少字节
OVERLAPPED ovlCommPort = new OVERLAPPED();
//PurgeComm(hComm, PURGE_REABORT | PURGE_REACLEAR | PURGE_TXABORT | PURGE_TXACLEAR | PURGE_TXACLEAR);
//接收从串口返回来的数据
bool b = ReadFile(hComm, BufRead, NumBytes, ref intBytesRead, ref ovlCommPort);
return intBytesRead;
}
return -1;
}
//关闭串口
public bool CloseCom()
{
bool c = CloseHandle(hComm);
return c;
}
// 发送命令
public int SendCommand(byte[] SendData, ref byte[] ReceiveData, int Overtime)
{
if (hComm != -1)
{
COMMTIMEOUTS ctoCommPort = new COMMTIMEOUTS();
// 设置通信超时时间
GetCommTimeouts(hComm, ref ctoCommPort);
ctoCommPort.ReadTotalTimeoutConstant = Overtime;
ctoCommPort.ReadTotalTimeoutMultiplier = 0;
ctoCommPort.WriteTotalTimeoutMultiplier = 0;
ctoCommPort.WriteTotalTimeoutConstant = 200;
SetCommTimeouts(hComm, ref ctoCommPort);
ClearSendBuf();
ClearReceiveBuf();
int a = SendCom(SendData, SendData.Length);
//return a;
return ReadCom(ref ReceiveData, ReceiveData.Length);
}
return -1;
}
}
}