您的位置:首页 > 其它

WIN32控制台下的串口通信程序

2015-11-17 22:36 453 查看
Winodws平台下,文件、通信设备、命名管道、邮件槽、磁盘、控制台等都是以文件的形式存在,它们的创建于打开操作都是利用CreateFile()函数。在MSDN中CreateFile()的声明方式为:

HANDLE WINAPI CreateFile(
_In_     LPCTSTR               lpFileName,  //文件名“COM1”,"COM2"等
_In_     DWORD                 dwDesiredAccess,  //访问模式,读、写
_In_     DWORD                 dwShareMode,  //共享模式,常为0表示独占方式
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,   //安全属性通常为NULL
_In_     DWORD                 dwCreationDisposition,   //创建或打开方式
_In_     DWORD                 dwFlagsAndAttributes,  //文件属性或标志
_In_opt_ HANDLE                hTemplateFile  //临时文件,又或者模板,通常为NULL
);
以下Win32控制台程序演示CreateFile()函数的调用方式,

#include <iostream>
#include <cstdlib>
#include <Windows.h>

using namespace std;

bool OpenPort();  //打开串口
bool OpenPort()
{
HANDLE hComm;
hComm = CreateFile(L"COM3",   //串口编号
GENERIC_READ | GENERIC_WRITE,  //允许读写
0,   //通讯设备必须以独占方式打开
NULL,
OPEN_EXISTING,   //通讯设备已存在
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,   //重叠方式
NULL);   //通讯设备不能用模板打开
if (hComm == INVALID_HANDLE_VALUE)
{
CloseHandle(hComm);
return FALSE;
}
else
return TRUE;

}
int main()
{
bool open;
open = OpenPort();
if (open)
cout << "Open serial port successfully!" << endl;
else
cout << "Open serial port unsuccessfully!" << endl;
return EXIT_SUCCESS;
}
我的主机只有一个串口COM1,使用虚拟串口软件额外创建了两个窗口COM2和COM3,修改COM口均能测试成功,如下所示:



在Windows串口通信中还会用到设备控制、超时控制、通信错误、通信状态、通信事件等操作,以下演示了对设备控制DCB和超时控制COMMTIMEOUTS的设置

#include <iostream>
#include <cstdlib>
#include <Windows.h>

bool OpenPort();  //打开串口
bool SetupDCB(int rate_arg); //设置DCB设备控制块
bool SetupTimeout(DWORD ReadInterval, DWORD ReadTotalMultiplier,
DWORD ReadTotalConstant, DWORD WriteTotalMultiplier, DWORD WriteTotalConstant);  //超时设置
HANDLE hComm;
bool OpenPort()
{
//HANDLE hComm;
hComm = CreateFile(L"COM1",  //指定串口
GENERIC_READ | GENERIC_WRITE,  //允许读写
0,  //以独占方式打开
0,  //无安全属性
OPEN_EXISTING,  //通讯设备已存在
0,  //同步I/O
0);   //不指定模式
if (hComm == INVALID_HANDLE_VALUE)
{
CloseHandle(hComm);
return FALSE;
}
else
return TRUE;
}

bool SetupDCB(int rate_arg)
{
DCB dcb;
memset(&dcb, 0,sizeof(dcb));
if (!GetCommState(hComm, &dcb))  //获取当前DCB配置
return FALSE;
/* ---------- 串口设置 ------- */
dcb.DCBlength = sizeof(dcb);  //DCB块大小
dcb.BaudRate = rate_arg;  //波特率
dcb.Parity = NOPARITY;    //奇偶校验0-4:分别表示不校验、奇校验,偶校验、标号、空格
dcb.fParity = 0;   //不允许奇偶校验
dcb.StopBits = ONESTOPBIT;   //停止位
dcb.ByteSize = 8;   //数据位,以字节表示4-8
dcb.fOutxCtsFlow = 0;   //CTS输出流控制
dcb.fOutxDsrFlow = 0;   //DSR输出流控制
dcb.fDtrControl = DTR_CONTROL_DISABLE;  //DTR流控制类型
dcb.fDsrSensitivity = 0;   //对DSR信号线不敏感
dcb.fRtsControl = RTS_CONTROL_DISABLE;  //RTS流控制
dcb.fOutX = 0;   //XON/XOFF输出流控制
dcb.fInX = 0;   //XON/XOFF输入流控制
/* ---------- 容错机制 ------- */
dcb.fErrorChar = 0;   //允许错误替换
dcb.fBinary = 1;   //二进制模式,不检测EOF
dcb.fNull = 0;   //允许剥离,去掉NULL字符
dcb.fAbortOnError = 0;   //有错误时终止读写操作
dcb.wReserved = 0;   //
dcb.XonLim = 2;   //XON发送字符之前缓冲区中允许接收的最小字节数
dcb.XoffLim = 4;   //XON发送字符之前缓冲区中允许的最小可用字节数
dcb.XonChar = 0x13;   //发送和接受XON字符
dcb.XoffChar = 0x19;   //发送和接受XOFF字符
dcb.EvtChar = 0;   //接收到的事件字符
if (!SetCommState(hComm, &dcb))
return FALSE;
else
return TRUE;
}

bool SetupTimeout(DWORD ReadInterval, DWORD ReadTotalMultiplier,
DWORD ReadTotalConstant, DWORD WriteTotalMultiplier, DWORD WriteTotalConstant)
{
COMMTIMEOUTS time;
time.ReadIntervalTimeout = ReadInterval;   //读时间超时
time.ReadTotalTimeoutConstant = ReadTotalConstant;  //读时间常量
time.ReadTotalTimeoutMultiplier = ReadTotalMultiplier;  //读时间系数
time.WriteTotalTimeoutConstant = WriteTotalConstant;  //写时间常量
time.WriteTotalTimeoutMultiplier = WriteTotalMultiplier;  //写时间系数
if (!SetCommTimeouts(hComm, &time))
return FALSE;
else
return TRUE;
}
int main()
{
if (OpenPort())
std::cout << "Open port success" << std::endl;
if (SetupDCB(9600))
std::cout << "Set DCB success" << std::endl;
if (SetupTimeout(0, 0, 0, 0, 0))
std::cout << "Set timeout success" << std::endl;
SetCommMask(hComm, EV_RXCHAR);  //当有字符在inbuf中时产生这个事件
PurgeComm(hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);

return EXIT_SUCCESS;
}


在COM1口的测试结果如下,



串口的读写操作:

本例实现串口的读写,采用虚拟串口虚拟一对串口COM2和COM3,COM2用于接收,COM3用于发送。完整代码如下:

#include <iostream>
#include <cstdlib>
#include <windows.h>

HANDLE hComm;
OVERLAPPED OverLapped;
COMSTAT Comstat;
DWORD dwCommEvents;

bool OpenPort();  //打开串口
bool SetupDCB(int rate_arg);  //设置DCB
bool SetupTimeout(DWORD ReadInterval, DWORD ReadTotalMultiplier, DWORD
ReadTotalConstant, DWORD WriteTotalMultiplier, DWORD WriteTotalConstant);   //设置超时
void ReciveChar();   //接收字符
bool WriteChar(char* szWriteBuffer, DWORD dwSend);  //发送字符

bool OpenPort()
{
hComm = CreateFile(L"COM2",
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
0);
if (hComm == INVALID_HANDLE_VALUE)
return FALSE;
else
return true;
}

bool SetupDCB(int rate_arg)
{
DCB dcb;
memset(&dcb, 0, sizeof(dcb));
if (!GetCommState(hComm, &dcb))//获取当前DCB配置
{
return FALSE;
}
dcb.DCBlength = sizeof(dcb);
/* ---------- Serial Port Config ------- */
dcb.BaudRate = rate_arg;
dcb.Parity = NOPARITY;
dcb.fParity = 0;
dcb.StopBits = ONESTOPBIT;
dcb.ByteSize = 8;
dcb.fOutxCtsFlow = 0;
dcb.fOutxDsrFlow = 0;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fDsrSensitivity = 0;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.fOutX = 0;
dcb.fInX = 0;
dcb.fErrorChar = 0;
dcb.fBinary = 1;
dcb.fNull = 0;
dcb.fAbortOnError = 0;
dcb.wReserved = 0;
dcb.XonLim = 2;
dcb.XoffLim = 4;
dcb.XonChar = 0x13;
dcb.XoffChar = 0x19;
dcb.EvtChar = 0;
if (!SetCommState(hComm, &dcb))
{
return false;
}
else
return true;
}

bool SetupTimeout(DWORD ReadInterval, DWORD ReadTotalMultiplier, DWORD
ReadTotalConstant, DWORD WriteTotalMultiplier, DWORD WriteTotalConstant)
{
COMMTIMEOUTS timeouts;
timeouts.ReadIntervalTimeout = ReadInterval;
timeouts.ReadTotalTimeoutConstant = ReadTotalConstant;
timeouts.ReadTotalTimeoutMultiplier = ReadTotalMultiplier;
timeouts.WriteTotalTimeoutConstant = WriteTotalConstant;
timeouts.WriteTotalTimeoutMultiplier = WriteTotalMultiplier;
if (!SetCommTimeouts(hComm, &timeouts))
{
return false;
}
else
return true;
}

void ReciveChar()
{
bool bRead = TRUE;
bool bResult = TRUE;
DWORD dwError = 0;
DWORD BytesRead = 0;
char RXBuff;
for (;;)
{
bResult = ClearCommError(hComm, &dwError, &Comstat);
if (Comstat.cbInQue == 0)
continue;
if (bRead)
{
bResult = ReadFile(hComm,  //通信设备(此处为串口)句柄,由CreateFile()返回值得到
&RXBuff,  //指向接收缓冲区
1,  //指明要从串口中读取的字节数
&BytesRead,   //
&OverLapped);  //OVERLAPPED结构
std::cout << RXBuff << std::endl;
if (!bResult)
{
switch (dwError == GetLastError())
{
case ERROR_IO_PENDING:
bRead = FALSE;
break;
default:
break;
}
}
}
else
{
bRead = TRUE;
}
}
if (!bRead)
{
bRead = TRUE;
bResult = GetOverlappedResult(hComm,
&OverLapped,
&BytesRead,
TRUE);
}
}

bool WriteChar(char* szWriteBuffer, DWORD dwSend)
{
bool bWrite = TRUE;
bool bResult = TRUE;
DWORD BytesSent = 0;
HANDLE hWriteEvent=NULL;
ResetEvent(hWriteEvent);
if (bWrite)
{
OverLapped.Offset = 0;
OverLapped.OffsetHigh = 0;
bResult = WriteFile(hComm,  //通信设备句柄,CreateFile()返回值得到
szWriteBuffer,  //指向写入数据缓冲区
dwSend,  //设置要写的字节数
&BytesSent,  //
&OverLapped);  //指向异步I/O数据
if (!bResult)
{
DWORD dwError = GetLastError();
switch (dwError)
{
case ERROR_IO_PENDING:
BytesSent = 0;
bWrite = FALSE;
break;
default:
break;
}
}
}
if (!bWrite)
{
bWrite = TRUE;
bResult = GetOverlappedResult(hComm,
&OverLapped,
&BytesSent,
TRUE);
if (!bResult)
{
std::cout << "GetOverlappedResults() in WriteFile()" << std::endl;
}
}
if (BytesSent != dwSend)
{
std::cout << "WARNING: WriteFile() error.. Bytes Sent:" << BytesSent << "; Message Length: " << strlen((char*)szWriteBuffer) << std::endl;
}
return TRUE;
}
int main()
{
if (OpenPort())
std::cout << "Open port success" << std::endl;
if (SetupDCB(9600))
std::cout << "Set DCB success" << std::endl;
if (SetupTimeout(0, 0, 0, 0, 0))
std::cout << "Set timeout success" << std::endl;
PurgeComm(hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
WriteChar("Please send data:", 20);
std::cout << "Received data:";
ReciveChar();
return EXIT_SUCCESS;
}
首先编译运行如下结果:



此时打开串口调试助手,设置串口号为COM3,波特率9600,数据位8,停止位1,以ASCII码形式发送,然后在发送栏写入要发送的字符如“Hello world!”,点击发送,COM2口就可以成功接收发送来的数据,并且COM3口成功接收到了COM2发来的数据请求。图如所示,



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: