一:常用函数:
⑴CreateFile()和CloseHandle()函数。用于打开和关闭串口,函数原型如下:
BOOL CloseHandle(HANDLE hObjedt);
⑵GetCommState()和SetCommState()函数。用于取得和设置串口工作状态,函数原型如下:
BOOL GetCommState/SetCommState(HANDLE hFile,LPDCB lpDCB);这两个函数常用来初始化串口,其中涉及到的几个常用的DCB 结构参数是:DWORD BaudRate:串口波特率;DWORD fParity:为1 时激活奇偶校验检查;DWORD Parity:校验方式,0~4 分别对应无校验、奇校验、偶校验、校验置位、校验清零;DWORD ByteSize:数据位个数,范围是5~8;DWORD StopBits:停止位个数,0~2 分别对应1
位、1.5 位、2 位停止位。⑶GetCommTimeouts()和SetCommTimeouts()
用于取得和设置串口数据收发的超时时间,通过改变COMMTIMEOUTS 结构体的成员变量值来实现,函数原型如下:BOOL GetCommTimeouts/SetCommTimeouts
(HANDLE hFile,LPCOMMTIMEOUTS lpCommTimeouts);其中,参数COMMTIMEOUTS 是一个表达读写操作相关时间限制的结构体,其原型为:
typedef struct _COMMTIMEOUTS{ DWORD ReadIntervalTimeout;DWORD ReadTotalTimeoutMultiplier;DWORD ReadTotalTimeoutConstant;DWORD WriteTotalTimeoutMultiplier;DWORD WriteTotalTimeoutConstant;} COMMTIMEOUTS, *LPCOMMTIMEOUTS;
⑷SetupComm()和PurgeComm()函数用于设置数据缓冲区的大小和清零数据缓冲区,函数原型如下:
BOOL SetupComm(HANDLE hFile,DWORD dwInQueue, DWORD dwOutQueue);BOOL PurgeComm(HANDLE hFile,DWORD dwFlags);⑸ReadFile()和WriteFile()函数用于读写访问串口作,函数原型如下:BOOL ReadFile/WriteFile (HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToRead/Write,LPDWORD lpNumberOfBytesRead/Written,LPOVERLAPPED lpOverlapped);
参数lpBuffer 表示待读或写的数据首地址,nNumberOfBytesToRead/Write 表示待读出或写入数据的字节数长度,lpNumberOfBytesRead 收入从串口实际读出的字节个数;lpNumberOfBytesWritten 收入实际写入串口的数据个数,lpOverlapped 是指向一个可重叠型的I/O 结构的指针。
⑹ClearCommError()函数用于清除串口错误或者读取串口当前的状态,
函数原型如下:BOOL ClearCommError(HANDLE hFile,LPDWORD lpErrors, LPCOMATAT lpStat);
⑺Get/SetCommMask()和WaitCommEvent()
用于获得、设置或等待串行端口上的监视指定事件,函数原型如下:BOOL Set/GetCommMask(HANDLE hFile,DWORD dwEvtMask);BOOL WaitCommEvent(HANDLE hFile, LPDWORDlpEvtMask, LPOVERLAPPED lpOverlapped);
二:例程
1.定义变量
bool ComState = FALSE; //串口状态
HANDLE hCom = 0; //串口打开返回值
DCB dcb;
OVERLAPPED OverRead, OverWrite;
COMSTAT comstat;
OVERLAPPED os;
DWORD dwEvtMask=0;
String dat;
HANDLE m_pThread;
COMMTIMEOUTS ComTimeouts;
char ReadBuff[1024]; //读缓冲区
DWORD ReadCount; //读字节数
2.串口初始化
void __fastcall TForm1::btn1ClickSerialPortInit(TObject *Sender)
{
AnsiString comname;
if(FALSE == ComState)
{
comname = "COM" + IntToStr(3);
hCom=CreateFile( "COM3", //文件名
GENERIC_READ|GENERIC_WRITE,//访问模式允许读写
0, //此项必须是0
NULL,//无安全参数
OPEN_EXISTING,//创建方式
// FILE_FLAG_OVERLAPPED,//异步工作方式
0,
NULL);
if (hCom==INVALID_HANDLE_VALUE)
{
ShowMessage("Can not open the port !");
CloseHandle(hCom);
hCom = 0;
}
if(!GetCommState(hCom,&dcb)) //获得串口设置并用它填充dcb结构体
{
ShowMessage("GetCommState failed");
}
if (!SetupComm(hCom,1024,1024)) //设置输入输出缓冲区大小
{
ShowMessage("SetupComm failed");
}
// 设置接收超时限定
ComTimeouts.ReadIntervalTimeout = MAXDWORD;
ComTimeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
ComTimeouts.ReadTotalTimeoutConstant = 1000;
SetCommTimeouts(hCom,&ComTimeouts);
//设置dcb结构成员变量
dcb.BaudRate=9600;
dcb.fParity=0;
dcb.Parity=NOPARITY;
dcb.StopBits=ONESTOPBIT;
dcb.ByteSize=8;
dcb.fNull=FALSE;
if(!SetCommState(hCom,&dcb)) //重新配置串口
{
ShowMessage("SetCommState failed");
}
//清空串口缓冲区,退出所有相关操作
PurgeComm(hCom, PURGE_TXCLEAR | PURGE_RXCLEAR);
Form1->Caption=comname+" 通信成功!";
//-----------------------------------------------------------------------------------------
ComState = TRUE;
btn1->SetTextBuf("关闭串口");
}
else
{
CloseHandle(hCom);
ComState = FALSE;
btn1->SetTextBuf("打开串口");
}
}
//---------------------------------------------------------------------------
2.发送函数
void __fastcall TForm1::btn2ClickSendData(TObject *Sender)
{
//发送数据
BOOL WriteState;
unsigned long Written ;
DWORD dwError;
int Size = EditSndData->GetTextLen(); //Get length of string in Edit1
char *p = new char[Size]; //Creates Buffer dynamic variable
//分配内存,必须有,要不然程序会出现错误
EditSndData->GetTextBuf(p,Size);
WriteState = WriteFile(hCom,//用CreateFile 获得的文件句柄
p,//输出缓冲区首址
Size,//要求输出的字节数
&Written,//实际输出字节数
&OverWrite);//重叠操作方式数据结构地址
if (WriteState && GetLastError()== ERROR_IO_PENDING )
{
ShowMessage("Error !!!");
}
}
3.接收数据(定时查询接收)
void __fastcall TForm1::tmr1TimerReceiveData(TObject *Sender)
{
//TODO: Add your source code here
DWORD nBytesRead, dwEvent, dwError;
COMSTAT cs; // 用于存放串口状态
if(hCom==INVALID_HANDLE_VALUE) return;
ClearCommError(hCom,&dwError,&cs);
if(cs.cbInQue>sizeof(ReadBuff))
{
PurgeComm(hCom, PURGE_RXCLEAR);
return;
} // 数据多于缓冲区?是:接收数据无效,清除
ReadFile (hCom, ReadBuff, cs.cbInQue, &nBytesRead,
NULL); // 读取接收数据
ReadBuff[cs.cbInQue] = '\0';
if(cs.cbInQue > 0)
{
EditRcvData->Text = ReadBuff; // 将数据显示出来
}
}