Чтение последовательного порта Win API "C"
Я написал приложение Win API. Для чтения данных последовательного порта. Это было прекрасно работать в консольном приложении без каких-либо проблем. Когда я пробую его в приложении win32 gui, его дозатор работает нормально, некоторое время он читает несколько символов, только некоторое время его читает полный буфер...
Почему это происходит...
Эти данные я отправляю из Arduino, используя "последовательный.код println("NM0");"
мой код написан для подобного ниже fromat:-
Для чтения: 4(это байты для чтения) -> NM0(это данные)
мой выход показывает как показано ниже
Читать: 4 -> NM0
Читать: 1 ->
Читать: 4 -> NM1
Читать: 1 ->
Читать: 4 -> NM1
Читать: 1 ->
Читать: 2 -> Нм
Читать: 3 -> 0
Читать: 4 -> NM0
Читать: 1 ->
Читать: 1 -> N
Читать: 4 -> M0
Читать: 1 -> N
Читать: 4 -> M1
Читать: 1 -> N
Читать: 4 -> M1
Читать: 4 -> NM0
Читать: 1 ->
Читать: 4 -> NM1
Читать: 1 ->
Что я уже пробовал:
//----------------------Чтение файла порта..----------------------------
#pragma once #include "stdafx.h" #include <istream> #include<ios> #include <Windows.h> #include <string> #include <vector> #include "myMonitor.h" #include <sstream> HANDLE hComm; // handel for the serial port bool quit = false; BOOL ConfigureSerialPort() { // Setup Com Time Outs COMMTIMEOUTS TimeOuts = { 0 }; TimeOuts.ReadIntervalTimeout = 1000; // Set Read Timeouts TimeOuts.ReadTotalTimeoutMultiplier = 500; TimeOuts.ReadTotalTimeoutConstant = 5000; TimeOuts.ReadIntervalTimeout = 1000; TimeOuts.WriteTotalTimeoutConstant = 2000; // Set Write Time Outs TimeOuts.WriteTotalTimeoutMultiplier = 500; if (!SetCommTimeouts(hComm, &TimeOuts))// Set Time Outs { myMonitor::sendTxt("\nERROR: Set Com time out faild."); }; DCB dcb; if (!GetCommState(hComm, &dcb)) { myMonitor::sendTxt("\nERROR: Get Comm state faild"); } dcb.BaudRate = 9600; // Baud Rates dcb.ByteSize = 8; // 8 bit per byte dcb.Parity = NOPARITY; // No Parity Bits dcb.StopBits = TWOSTOPBITS; //Two Stop Bits if (!SetCommState(hComm, &dcb)) { myMonitor::sendTxt("\nERROR: Set Com State faild."); return true; } else { return false; } if (!PurgeComm(hComm, PURGE_TXCLEAR | PURGE_RXCLEAR)) { myMonitor::sendTxt("\nERROR: Comm Purge Faild."); } } BOOL OpenSerialPort(int portNo, int baud) { hComm = CreateFile("\\\\.\\COM9", // COM Port GENERIC_READ | GENERIC_WRITE, // Configure for read and write 0, NULL, OPEN_EXISTING, // Open existing without creating new FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, //Synchrnous Mode. NULL); if (hComm == (HANDLE)-1) { myMonitor::sendTxt("\nPort opend"); return 0; } else { ConfigureSerialPort(); return 1; } } BOOL ReadSerialPort() { char lpBuffer[256]; DWORD dwBytesRead = 256; // read bytes COMSTAT ComStat; DWORD dwErrorFlag; OVERLAPPED m_osRead; stringstream ss; stringstream st; memset(&m_osRead, 0, sizeof(OVERLAPPED)); m_osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); ClearCommError(hComm, &dwErrorFlag, &ComStat); dwBytesRead = min(dwBytesRead, (DWORD)ComStat.cbInQue); if (!dwBytesRead)return FALSE; BOOL bReadStatus; bReadStatus = ReadFile(hComm, lpBuffer, dwBytesRead, &dwBytesRead, &m_osRead); ss <<"To read: "<< (size_t)ComStat.cbInQue<<" -> "; for (size_t i = 0; i < (size_t)ComStat.cbInQue; i++) { if (i < sizeof(lpBuffer)) { //printf("/n%c", lpBuffer[i]); ss << lpBuffer[i]; } } myMonitor::sendTxt(ss.str()); if (!bReadStatus) // if the Read File returns False { if (GetLastError() == ERROR_IO_PENDING) { WaitForSingleObject(m_osRead.hEvent, 2000); PurgeComm(hComm, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); return dwBytesRead; } return 0; } PurgeComm(hComm, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); memset(lpBuffer, 0, sizeof(lpBuffer)); return dwBytesRead; } void readPort() { while (!quit) { ReadSerialPort(); } }
///--------------------------------------------------------------------------------------
//----------------------Последовательный графический интерфейс приложения ------------------------------------------
// SerialHUB.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "SerialHUB.h" #include <Windows.h> #include "Init.h" #include "myMonitor.h" #include "Port.h" #define MAX_LOADSTRING 100 #define IDC_BUTTION_OPEN_COMM 20003 #define IDC_BUTTION_CLOSE_COMM 20004 #define IDC_BUTTION_REFRESH 20005 #define IDC_CMBOX_PORT 20006 #define IDC_TXTBOX 20007 #define IDC_LBL_STATUS 20008 #define WNDOW_WIDTH 1000 #define WNDOW_HEIGHT 600 #define BTN_GAP (WNDOW_WIDTH-500) HWND buttion_ConnectFSX; HWND buttion_DisConnectFSX; HWND buttion_OpenComm; HWND buttion_CloseComm; HWND buttion_Refresh; HWND cbBox_Com; HWND txtbox_Monitor; HWND staticLable; //Serial port Handle HANDLE RxThread; DWORD ThreadID; // Global Variables: HINSTANCE hInst; // current instance WCHAR szTitle[MAX_LOADSTRING]; // The title bar text WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name // Forward declarations of functions included in this code module: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); // TODO: Place code here. // Initialize global strings LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadStringW(hInstance, IDC_SERIALHUB, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SERIALHUB)); MSG msg; // Main message loop: while (GetMessage(&msg, nullptr, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return (int) msg.wParam; } // // FUNCTION: MyRegisterClass() // // PURPOSE: Registers the window class. // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEXW wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SERIALHUB)); wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_SERIALHUB); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassExW(&wcex); } // // FUNCTION: InitInstance(HINSTANCE, int) // // PURPOSE: Saves instance handle and creates main window // // COMMENTS: // // In this function, we save the instance handle in a global variable and // create and display the main program window. // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { hInst = hInstance; // Store instance handle in our global variable //hWnd = CreateWindowW(szWindowClass, (LPCWSTR)"CockpitX-MCP", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, //CW_USEDEFAULT, CW_USEDEFAULT, 435, 350, nullptr, nullptr, hInstance, nullptr); HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WNDOW_WIDTH, WNDOW_HEIGHT, nullptr, nullptr, hInstance, nullptr); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); myMonitor monitor(&txtbox_Monitor); return TRUE; } // // FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) // // PURPOSE: Processes messages for the main window. // // WM_COMMAND - process the application menu // WM_PAINT - Paint the main window // WM_DESTROY - post a quit message and return // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: { //Buttion buttion_OpenComm = CreateWindow("BUTTON", "Open COM", WS_CHILD | WS_VISIBLE | WS_BORDER | BS_PUSHBUTTON, BTN_GAP+283, 139, 121, 23, hWnd, (HMENU)IDC_BUTTION_OPEN_COMM, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL); buttion_CloseComm = CreateWindow("BUTTON", "Close COM", WS_CHILD | WS_VISIBLE | WS_BORDER | BS_PUSHBUTTON, BTN_GAP+283, 168, 121, 23, hWnd, (HMENU)IDC_BUTTION_CLOSE_COMM, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL); buttion_Refresh = CreateWindow("BUTTON", "Refresh", WS_CHILD | WS_VISIBLE | WS_BORDER | BS_PUSHBUTTON, BTN_GAP+283, 233, 121, 23, hWnd, (HMENU)IDC_BUTTION_REFRESH, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL); //Combo Box; cbBox_Com = CreateWindow("COMBOBOX", NULL, WS_CHILD | ES_READONLY | WS_VISIBLE | WS_BORDER | WS_TABSTOP | CBS_DROPDOWN, BTN_GAP+284, 80, 125, 225, hWnd, (HMENU)IDC_CMBOX_PORT, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL); initComboBox(&cbBox_Com); //Text Box; txtbox_Monitor = CreateWindow("EDIT", "Welcome\n", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_HSCROLL | WS_VSCROLL | ES_MULTILINE | WS_BORDER | ES_READONLY | ES_AUTOVSCROLL | ES_AUTOHSCROLL, 12, 12, BTN_GAP + 265, WNDOW_HEIGHT-100, hWnd, NULL, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL); // Set the buttion endbled condtion EnableWindow(GetDlgItem(hWnd, IDC_BUTTION_OPEN_COMM), TRUE); EnableWindow(GetDlgItem(hWnd, IDC_BUTTION_CLOSE_COMM), FALSE); EnableWindow(GetDlgItem(hWnd, IDC_CMBOX_PORT), TRUE); } break; case WM_COMMAND: { int wmId = LOWORD(wParam); // Parse the menu selections: switch (wmId) { case IDC_BUTTION_OPEN_COMM : { //Greeting to Command execution myMonitor::sendTxt("\n Init Open"); //Get the selected port from the combobox unsigned int index = 0; char strText[255] = { 0 }; //Get Selected index form the combobox. index = SendMessage(cbBox_Com, CB_GETCURSEL, 0, 0); SendMessage(cbBox_Com, CB_GETLBTEXT, index, (LPARAM)strText); string str = strText; myMonitor::sendTxt("\n Selected Port is " + str); //ConfigureSerialPort(); OpenSerialPort(9, 9600); RxThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)readPort, NULL, NULL, &ThreadID); }break; case IDC_BUTTION_CLOSE_COMM: { //Closing of the port. quit = true; WaitForSingleObject(RxThread, INFINITE); CloseHandle(RxThread); }break; case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } } break; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); // TODO: Add any drawing code that uses hdc here... EndPaint(hWnd, &ps); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // Message handler for about box. INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE; }
Gerry Schmitz
Разве вы никогда не "пишете" в последовательный порт? Откуда вы знаете, что посылается?
Member 12278335
Спасибо за повтор. Я мог бы успешно писать в последовательный порт. но попытка получить данные была проблемой.
данные принимаются . я контролирую через последовательный монитор(Eltima).
Rick York
У меня нет реального решения, но две вещи кажутся мне странными. Во-первых, ваши выходные сообщения говорят, что есть x байтов для чтения, но вы никогда не показываете столько байтов, которые были прочитаны. Что это значит на самом деле? Может быть, вам стоит сделать их колдовскую свалку или что-то в этом роде.
Во-вторых, я никогда не использовал перекрывающийся ввод-вывод. Я всегда устанавливаю порт в режим блокировки с коротким таймаутом, например 500 мс, чтобы периодически видеть, должен ли поток завершиться. В тот единственный раз, когда мы использовали перекрывающийся ввод-вывод, у нас был процесс, ожидающий нескольких событий, одним из которых был последовательный порт. Насколько я помню, было четыре возможных события : порт связи, внутреннее сообщение, клавиатура и завершение. В любом случае, вы можете подумать об этом.
KarstenK
Пожалуйста, добавьте его в качестве решения, чтобы закрыть вопрос&A.
Rick York
ОК.
[no name]
Рик Йорк определил проблему. Вы создаете перекрывающийся файл для чтения, но не обрабатываете события. Тот факт, что у вас что-то должно произойти, - это просто случайность. Документация всегда является лучшей отправной точкой, поэтому вы можете прочитать это, которое является хорошим объяснением того, как использовать потоки для обработки перекрывающихся событий. Последовательная Связь | Microsoft Docs[^]