关于Win32串口
阅读原文时间:2023年07月15日阅读:2

因为近段时间接触Hid相对来说多一些,由此忽略了串口中获取cbInQue这个重要的东西,下面是错误代码

// Win32SerialPortLib.cpp : 定义 DLL 应用程序的导出函数。
//

#include "stdafx.h"
#include "Win32SerialPortLib.h"
#include

HANDLE hcomm;
EXTERN_C WIN32SERIALPORTLIB_API bool Open(char *com, int baud)
{
char szDCB[];
sprintf_s(szDCB, "baud=%d parity=%c data=%d stop=%d", baud, 'N', , );
hcomm = CreateFileA(com,
GENERIC_READ | GENERIC_WRITE,
,
NULL,
OPEN_EXISTING,
,
);
if (hcomm == INVALID_HANDLE_VALUE) return false;
return true;
}

EXTERN_C WIN32SERIALPORTLIB_API int Read(unsigned char *data, DWORD len)
{
DWORD readed;
BOOL rt = ReadFile(hcomm, data, len, &readed, NULL);
if (!rt)
{
PurgeComm(hcomm, PURGE_RXCLEAR | PURGE_RXABORT);
return ;
}

 return readed;  

}

EXTERN_C WIN32SERIALPORTLIB_API void Write(unsigned char *data, DWORD len)
{
if (hcomm == INVALID_HANDLE_VALUE) return;
DWORD writed;
BOOL rt = WriteFile(hcomm, data, len, &writed, NULL);
if (!rt)
{
PurgeComm(hcomm, PURGE_TXCLEAR | PURGE_TXABORT);
return;
}
}

EXTERN_C WIN32SERIALPORTLIB_API void Close()
{
if (hcomm != INVALID_HANDLE_VALUE)
{
CloseHandle(hcomm);
hcomm = INVALID_HANDLE_VALUE;
}
}

经过测试


// Win32SerialPortTest.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include
#include
#include "Win32SerialPort.h"
using namespace std;

bool _stoprequired = false;

void read_callback();
void printhex(unsigned char *data, int len);

int _tmain(int argc, _TCHAR* argv[])
{
Open("COM5", );
thread read_t(read_callback);
read_t.detach();

 cout << endl;  
 cout << "continue in main thread." << endl;  
 //ab 69 42 01 fe c0 00 00 c0  
 unsigned char data\[\] = { 0xab, 0x69, 0x42, 0x01, 0xfe, 0xc0, 0x00, 0x00, 0xc0 };  
 Write(data, sizeof(data) / sizeof(unsigned char));

 // 获取标准输入输出设备句柄  
 HANDLE hOut = GetStdHandle(STD\_OUTPUT\_HANDLE);  
 HANDLE hIn = GetStdHandle(STD\_INPUT\_HANDLE);

 DWORD           dwRes, dwState = ;  
 INPUT\_RECORD    keyRec;  
 COORD           crHome = { ,  }, crPos;  
 char            ch;  
 CONSOLE\_SCREEN\_BUFFER\_INFO bInfo;  
 while (true)  
 {  
     ReadConsoleInput(hIn, &keyRec, , &dwRes);  
     if (keyRec.EventType == KEY\_EVENT)  
     {  
         // Press key down  
         if (keyRec.Event.KeyEvent.bKeyDown)  
         {  
             // 基础功能键  
             switch (keyRec.Event.KeyEvent.wVirtualKeyCode)  
             {  
                 // 回车  
             case VK\_RETURN:  
                 printf("\\n");  
                 break;

                 // 空格  
             case VK\_SPACE:  
                 Write(data, sizeof(data) / sizeof(unsigned char));  
                 break;

             case VK\_BACK:           // 按删除时删掉一个字符(只能当前行操作)  
                 GetConsoleScreenBufferInfo(hOut, &bInfo);  
                 crPos = bInfo.dwCursorPosition;  
                 if (crPos.X != )  
                 {  
                     crPos.X -= ;  
                 }  
                 SetConsoleCursorPosition(hOut, crPos);  
                 printf(" ");  
                 SetConsoleCursorPosition(hOut, crPos);  
                 break;

             case VK\_ESCAPE:         // 按ESC键时退出  
                 \_stoprequired = true;  
                 Close();  
                 Sleep();  
                 CloseHandle(hOut);  // 关闭标准输出设备句柄  
                 CloseHandle(hIn);   // 关闭标准输入设备句柄  
                 return ;

             default:  
                 break;  
             }

             // 打印字符  
             ch = keyRec.Event.KeyEvent.uChar.AsciiChar;  
             // 输出可以打印的字符(详参ASCII表)  
             if (ch > 0x20 && ch < 0x7e)  
             {  
                 putchar(ch);  
             }  
         }  
     }  
 }

 return ;  

}

void read_callback()
{
unsigned char buff[];
while (!_stoprequired)
{
int n = Read(buff, );
if (n > )
{
printhex(buff, n);
}
//cout << "detach test." << endl;
//this_thread::sleep_for(chrono::seconds(1));
}
}

void printhex(unsigned char *data, int len)
{
for (int i = ; i < len; i++)
{
printf("%2x ", data[i]);
}
printf("\n");
}

表现现象是Read函数不单单是阻塞,还会让Write函数也阻塞,这种情况是是没有留意到的地方,此处作一个记录.


异步IO版本,异步代码上方的注释为同步IO版本


// Win32SerialPortLib.cpp : 定义 DLL 应用程序的导出函数。
//

#include "stdafx.h"
#include "Win32SerialPortLib.h"
#include

HANDLE hcomm;
OVERLAPPED ovw;
OVERLAPPED ovr;
EXTERN_C WIN32SERIALPORTLIB_API HANDLE Open(char *com, int baud)
{
char szDCB[];
sprintf_s(szDCB, "baud=%d parity=%c data=%d stop=%d", baud, 'N', , );
//hcomm = CreateFileA(com,
// GENERIC_READ | GENERIC_WRITE,
// 0,
// NULL,
// OPEN_EXISTING,
// 0,
// 0);
hcomm = CreateFileA(com,
GENERIC_READ | GENERIC_WRITE,
,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
);
if (hcomm == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE;
// 设置缓冲大小
BOOL rt = SetupComm(hcomm, , );
if (!rt) return INVALID_HANDLE_VALUE;
// 设置超时
COMMTIMEOUTS commtimeouts;
commtimeouts.ReadIntervalTimeout = ;
commtimeouts.ReadTotalTimeoutConstant = ;
commtimeouts.ReadTotalTimeoutMultiplier = ;
commtimeouts.WriteTotalTimeoutConstant = ;
commtimeouts.WriteTotalTimeoutMultiplier = ;
rt = SetCommTimeouts(hcomm, &commtimeouts);
if (!rt) return INVALID_HANDLE_VALUE;
// 设置DCB
DCB dcb;
#ifdef UNICODE
DWORD num = MultiByteToWideChar(CP_ACP, , szDCB, -, NULL, );
wchar_t *pwStr = new wchar_t[num];
MultiByteToWideChar(CP_ACP, , szDCB, -, pwStr, num);
#else
DWORD num = strlen(szDCB) + ;
char *pwStr = new char[num];
strcpy(pwStr, szDCB);
#endif
rt = GetCommState(hcomm, &dcb);
if (!rt) return INVALID_HANDLE_VALUE;
rt = BuildCommDCB(pwStr, &dcb);
if (!rt) return INVALID_HANDLE_VALUE;
delete[] pwStr;
rt = SetCommState(hcomm, &dcb);
if (!rt) return INVALID_HANDLE_VALUE;
// 清空串口缓冲区
rt = PurgeComm(hcomm, PURGE_RXCLEAR | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_TXABORT);
if (!rt) return INVALID_HANDLE_VALUE;

 return hcomm;  

}

EXTERN_C WIN32SERIALPORTLIB_API int Read(unsigned char *data, DWORD len)
{
DWORD read_size = ;
if (hcomm == INVALID_HANDLE_VALUE) return ;
COMSTAT comstat;
DWORD error;
ClearCommError(hcomm, &error, &comstat);
// 串口有错误
if (error > )
{
PurgeComm(hcomm, PURGE_RXCLEAR | PURGE_RXABORT);
return read_size;
}
if (comstat.cbInQue > )
{
//BOOL rt = ReadFile(hcomm, data, comstat.cbInQue, &read_size, NULL);
//if (!rt) return 0;
BOOL rt = ReadFile(hcomm, data, comstat.cbInQue, &read_size, &ovr);
if (!rt)
{
rt = GetLastError();
if (rt == ERROR_IO_PENDING)
{
// 此时是否需要对IO状态作处理看需求,处理与否不会影响IO
//rt = WaitForSingleObject(hcomm, 50);
//switch (rt)
//{
//case WAIT_OBJECT_0:
// cout << "指定的对象处于有信号状态" << endl;
// if (GetOverlappedResult(hcomm, &ovr, &read_size, FALSE))
// cout << "read " << read_size << " bytes" << endl;
// break;
//case WAIT_TIMEOUT:
// cout << "等待超时" << endl;
// break;
//case WAIT_FAILED:
// cout << "出现错误,CODE [" << GetLastError() << "]" << endl;
// break;
//case WAIT_ABANDONED:
// cout << "当Handle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象会引发此返回值" << endl;
// break;
//}
}
else
{
CancelIo(hcomm);
return ;
}
}
}

 return read\_size;  

}

EXTERN_C WIN32SERIALPORTLIB_API void Write(unsigned char *data, DWORD len)
{
DWORD write_size;
if (hcomm == INVALID_HANDLE_VALUE) return;
COMSTAT comstat;
DWORD error;
BOOL rt = ClearCommError(hcomm, &error, &comstat);
if (!rt) return;
// 串口有错误
if (error > )
{
PurgeComm(hcomm, PURGE_TXCLEAR | PURGE_TXABORT);
return;
}

 WriteFile(hcomm, data, len, &write\_size, NULL);  
 rt = WriteFile(hcomm, data, len, &write\_size, &ovw);  
 if (!rt)  
 {  
     rt = GetLastError();  
     if (rt == ERROR\_IO\_PENDING)  
     {  
         // 此时是否需要对IO状态作处理看需求,处理与否不会影响IO  
         //rt = WaitForSingleObject(hcomm, 50);  
         //switch (rt)  
         //{  
         //case WAIT\_OBJECT\_0:  
         //    cout << "指定的对象处于有信号状态" << endl;  
         //    if (GetOverlappedResult(hcomm, &ovr, &write\_size, FALSE))  
         //        cout << "write " << write\_size << " bytes" << endl;  
         //    break;  
         //case WAIT\_TIMEOUT:  
         //    cout << "等待超时" << endl;  
         //    break;  
         //case WAIT\_FAILED:  
         //    cout << "出现错误,CODE \[" << GetLastError() << "\]" << endl;  
         //    break;  
         //case WAIT\_ABANDONED:  
         //    cout << "当Handle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象会引发此返回值" << endl;  
         //    break;  
         //}  
     }  
     else  
     {  
         CancelIo(hcomm);  
         return;  
     }  
 }  

}

EXTERN_C WIN32SERIALPORTLIB_API void Close()
{
if (hcomm != INVALID_HANDLE_VALUE)
{
CancelIo(hcomm);
CloseHandle(hcomm);
hcomm = INVALID_HANDLE_VALUE;
}
}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章