#c #visual-studio #serial-port
#c #visual-studio #последовательный порт
Вопрос:
//#include "StdAfx.h"
#include <stdio.h>
#include <windows.h>
#include <winbase.h>
#include <iostream>
#include <tchar.h>
using namespace std;
int main()
{
int com = 'COM2';
string data = "n 010400 n";
char output[32];
//unsigned int length = 0;
DCB config = {0};
bool abContinue = true;
DWORD dwBytesWritten;
DWORD dwBytesRead;
int isRead = false;
HANDLE m_hCommPort = ::CreateFile(L"COM2",
GENERIC_READ|GENERIC_WRITE,//access ( read and write)
0, //(share) 0:cannot share the COM port
0, //security (None)
OPEN_EXISTING,// creation : open_existing
0, // we dont want overlapped operation
0// no templates file for COM port...
);
config.DCBlength = sizeof(config);
if((GetCommState(m_hCommPort, amp;config) == 0))
{
printf("Get configuration port has a problem.");
return FALSE;
}
config.BaudRate = 9600;
config.StopBits = ONESTOPBIT;
config.Parity = PARITY_NONE;
config.ByteSize = DATABITS_8;
config.fDtrControl = 0;
config.fRtsControl = 0;
if (!SetCommState(m_hCommPort, amp;config))
{
printf( "Failed to Set Comm State Reason: %dn",GetLastError());
//return E_FAIL;
}
printf("Current Settingsn Baud Rate %dn Parity %dn Byte Size %dn Stop Bits %d", config.BaudRate,
config.Parity, config.ByteSize, config.StopBits);
int isWritten = WriteFile(m_hCommPort, amp;data,(DWORD) sizeof(data), amp;dwBytesWritten, NULL);
//memset(output, 0, sizeof(output));
while (abContinue)
{
isRead = ReadFile(m_hCommPort, output, sizeof(output), amp;dwBytesRead, NULL);
if(!isRead)
{
abContinue = false;
break;
}
}
cin.get();
}
У меня возникли проблемы с чтением с com-порта. Если я выполняю код пошагово, он переходит в «isRead = ReadFile(m_hCommPort, output, sizeof(output), amp;dwBytesRead, NULL);» и не возвращается…. Это моя первая попытка, но безуспешно.
Комментарии:
1. Моя проблема с точностью до наоборот.
ReadFile
ничего не ожидает, просто возвращает 0 прочитанных байт и возвращаемое значениеTRUE
-.-
Ответ №1:
Вы могли бы попробовать какой-нибудь код, подобный этому, после того, как вы открыли файл, но прежде чем пытаться его использовать:
COMMTIMEOUTS timeouts;
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 1;
timeouts.ReadTotalTimeoutConstant = 1;
timeouts.WriteTotalTimeoutMultiplier = 1;
timeouts.WriteTotalTimeoutConstant = 1;
if (!SetCommTimeouts(m_hCommPort, amp;timeouts))
// setting timeouts failed.
Редактировать: возможно, проще начать с некоторого кода, который работает, и заставить его делать то, что вы хотите, вместо того, чтобы пытаться заставить ваш код работать. Вот простая терминальная программа. Это в высшей степени минималистично, но работает (по крайней мере, достаточно хорошо, чтобы я мог видеть выходные данные моего GPS, например). Это далеко от того, что кто-либо (меньше всего я) назвал бы сложным, но должно дать хотя бы некоторое представление о том, как начать.
#include <stdio.h>
#include <conio.h>
#include <string.h>
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
void system_error(char *name) {
// Retrieve, format, and print out a message from the last error. The
// `name' that's passed should be in the form of a present tense noun
// (phrase) such as "opening file".
//
char *ptr = NULL;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
0,
GetLastError(),
0,
(char *)amp;ptr,
1024,
NULL);
fprintf(stderr, "nError %s: %sn", name, ptr);
LocalFree(ptr);
}
int main(int argc, char **argv) {
int ch;
char buffer[1];
HANDLE file;
COMMTIMEOUTS timeouts;
DWORD read, written;
DCB port;
HANDLE keyboard = GetStdHandle(STD_INPUT_HANDLE);
HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode;
char port_name[128] = "\\.\COM3";
char init[] = ""; // e.g., "ATZ" to completely reset a modem.
if ( argc > 2 )
sprintf(port_name, "\\.\COM%c", argv[1][0]);
// open the comm port.
file = CreateFile(port_name,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if ( INVALID_HANDLE_VALUE == file) {
system_error("opening file");
return 1;
}
// get the current DCB, and adjust a few bits to our liking.
memset(amp;port, 0, sizeof(port));
port.DCBlength = sizeof(port);
if ( !GetCommState(file, amp;port))
system_error("getting comm state");
if (!BuildCommDCB("baud=19200 parity=n data=8 stop=1", amp;port))
system_error("building comm DCB");
if (!SetCommState(file, amp;port))
system_error("adjusting port settings");
// set short timeouts on the comm port.
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 1;
timeouts.ReadTotalTimeoutConstant = 1;
timeouts.WriteTotalTimeoutMultiplier = 1;
timeouts.WriteTotalTimeoutConstant = 1;
if (!SetCommTimeouts(file, amp;timeouts))
system_error("setting port time-outs.");
// set keyboard to raw reading.
if (!GetConsoleMode(keyboard, amp;mode))
system_error("getting keyboard mode");
mode amp;= ~ ENABLE_PROCESSED_INPUT;
if (!SetConsoleMode(keyboard, mode))
system_error("setting keyboard mode");
if (!EscapeCommFunction(file, CLRDTR))
system_error("clearing DTR");
Sleep(200);
if (!EscapeCommFunction(file, SETDTR))
system_error("setting DTR");
if ( !WriteFile(file, init, sizeof(init), amp;written, NULL))
system_error("writing data to port");
if (written != sizeof(init))
system_error("not all data written to port");
// basic terminal loop:
do {
// check for data on port and display it on screen.
ReadFile(file, buffer, sizeof(buffer), amp;read, NULL);
if ( read )
WriteFile(screen, buffer, read, amp;written, NULL);
// check for keypress, and write any out the port.
if ( kbhit() ) {
ch = getch();
WriteFile(file, amp;ch, 1, amp;written, NULL);
}
// until user hits ctrl-backspace.
} while ( ch != 127);
// close up and go home.
CloseHandle(keyboard);
CloseHandle(file);
return 0;
}
Комментарии:
1. хорошо, кажется, это устраняет проблему с потоком, но, похоже, я не могу заставить ReadFile () заполнить мой выходной массив.
2. Я должен уточнить, я пытаюсь взаимодействовать со встроенной системой через serial, а ее протокол запроса / ответа основан на строках. У меня это работает на HyperTerminal, но я пытаюсь создать свой собственный код, который делает по существу то же самое.
3. Хорошо, я более тщательно просмотрел ваш код. Это действительно помогает, спасибо!
Ответ №2:
Если вы явно не устанавливаете тайм-ауты, то ReadFile будет блокироваться на неопределенный срок, пока данные не станут доступны.
Ответ №3:
Функция ReadFile может блокировать ваш поток, если это так, она будет оставаться заблокированной до тех пор, пока некоторые данные не будут прочитаны с последовательного порта. Вот ссылка, посмотрите, поможет ли это. Удачи.
Ответ №4:
У меня возникла эта проблема при чтении файла с установленными тайм-аутами. Это сводило меня с ума, поэтому в итоге я получил из Интернета некоторый код, который действительно работал, а затем менял построчно, чтобы увидеть, где была ошибка.
Оказывается, он прочитал файл нормально. Моей проблемой было WaitCommEvent, которое зависало, когда порт был отключен, поскольку ни одно com-событие так и не было получено…