Какой тип переменной следует использовать для lpBuffer C ++ ReadFile
а также WriteFile
функции для связи между ПК на базе Windows XP и системой на основе микроконтроллера? ПК имеет приложение WinForm в VS2010 C ++ / CLI. Прошивка микроконтроллера — ANSI C.
Предполагается, что мой компьютер передает символы команд (например, «S», «C» и т. Д.), За которыми следует символ завершения команды 0xd
(шестнадцатеричное для десятичной 13). Система на основе микроконтроллера будет отвечать 5-10 байтами, которые будут представлять собой смесь символов ASCII и шестнадцатеричных чисел, например, «V» с последующим 0x41
0x72
и т.п.
ПК передает и микроконтроллер получает:
TxMessage
, PP1
а также pTx
объявлен как char
и сохраняя nNumberOfBytesToWrite
как 2, заставляет микроконтроллер получать 0x53
за ‘S’, а затем 0xC3
вместо 0xd
,
TxMessage
, PP1
а также pTx
объявлен как wchar_t
и сохраняя nNumberOfBytesToWrite
как 2, заставляет микроконтроллер получать 0x53
только для «S».
TxMessage
, PP1
а также pTx
объявлен как wchar_t
и сохраняя nNumberOfBytesToWrite
как 4, заставляет микроконтроллер получать 0x53
за ‘S’, а затем 0xd
правильно.
Третья схема передачи и получения выше соответствует моему ожидаемому поведению решения. Но путаница здесь: хотя ПК может передавать 4 байта (для двух wchar
типы), микроконтроллер получает 2 байта 0x53
для ‘S’, правильно следует 0xD
,
Микроконтроллер передает и ПК получает:
При условии, что wchar_t
это правильный выбор для lpBuffer
, что должно быть моим nNumberOfBytesToRead
для получения 10 байтов от микроконтроллера? ReadFile будет ожидать 20 байтов в силу wchar_t
тогда как микроконтроллер будет передавать только 10 байтов.
Удивительно, независимо от объявления (RxMessage
, PP2
а также pRx
) как wchar_t
, char
или же unsigned char
ReadFile получает 10 байтов от микроконтроллера (соответствует моему ожидаемому поведению решения). Но проблема в том, что 10 раз передавая «A» с микроконтроллера, ReadFile на конце ПК получает нежелательную информацию, такую как «S», 0x0
, 0xd
, 0x54
, 0x29
,
/// Required designer variable.
HANDLE hCommPort;
BOOL fSuccess;
array<wchar_t> ^ TxMessage;
array<unsigned char> ^ RxMessage;
TxMessage = gcnew array<wchar_t> (12);
RxMessage = gcnew array<unsigned char> (12);{
TxMessage[0]='S';//target cmd
TxMessage[1]=0xd;//cmd termination character
DWORD dwhandled;
if (hCommPort != INVALID_HANDLE_VALUE)
{
pin_ptr<wchar_t> pp1 = &TxMessage[0];
wchar_t *pTx = pp1;
fSuccess = WriteFile(hCommPort, pTx, 4, &dwhandled, NULL);PurgeComm(hCommPort, PURGE_RXABORT|PURGE_TXABORT|PURGE_RXCLEAR|PURGE_TXCLEAR);
pin_ptr<unsigned char> pp2 = &RxMessage[0];
unsigned char *pRx = pp2;
fSuccess = ReadFile(hCommPort, pRx, 10, &dwhandled, NULL);
}//if IsOpen
else{
this->toolStripStatusLabel4->Text="Port Not Opened";}
}
ReadFile/WriteFile
не заботятся о типах C ++, они работают с точки зрения чтения / записи байтов. ReadFile
читает указанное количество байтов (или меньше, если для чтения меньше байтов) из файла / устройства и помещает их в память, указанную lpBuffer
, WriteFile
записывает указанное количество байтов в файл / устройство из памяти, на которую указывает lpcBuffer
, Буфер памяти для этих функций — это просто область выделенной памяти, которая имеет размер, по крайней мере, столько же байтов, сколько вы указываете этим функциям в третьем параметре.
wchat_t
многобайтовый тип Его размер может быть больше одного байта. Следовательно, ваш TxMessage[0]='S'; TxMessage[1]=0xd;
фактически может заполнять не два байта в памяти, а, скажем, 4 байта. Например, это может быть x0053
, x000D
в wchar_t
представление. С точки зрения WriteFile
это не волнует, как и что вы положили в эту память. Он будет читать сырую память и будет записывать на устройство. Итак, если ваше устройство ожидает x530D
, это может быть не получится, но x0053
,
В общем, подумайте о байтах. Если вам нужно написать 4 байта x0A0B0C0D
для вашего устройства не имеет значения, КАК вы выделили буфер для этого значения. Это может быть 4 байта unsigned int = x0A0B0C0D
, может быть char[ 4 ] = {x0A, x0B, x0C, x0D}
, может быть int short [ 2 ]= {x0A0B, x0C0D}
, это может быть ЛЮБОЙ тип C ++, включая пользовательский класс. Но первые 4 байта памяти, указанные указателем памяти, передаются WriteFile
должно быть x0A0B0C0D
,
Так же, ReadFile
будет читать количество байтов, которые вы укажете. Если ваше устройство отправляет вам, скажем, 2 байта, ReadFile
запишет 2 байта, которые попадет в память, указанную указателем, который вы передаете ему (и вы несете ответственность за то, чтобы у него было достаточно выделенных байтов). Опять же, не имеет значения, как вы распределили его, если выделено 2 байта. После этого, опять же, вы можете посмотреть на эти два байта как хотите — это может быть char[ 2 ]
, может быть int short
и т.п.
Использование байтов — естественное совпадение, последовательные порты — это устройства, ориентированные на байты. Вы могли бы сделать свой передающий код похожим на это:
bool SendCommand(HANDLE hCommPort) {
auto TxMessage = gcnew array<Byte> { 'S', '\r' };
pin_ptr<Byte> pbytes = &TxMessage[0];
DWORD bytesSent = 0;
BOOL fSuccess = WriteFile(hCommPort, pbytes, TxMessage->Length,
&bytesSent, NULL);
return fSuccess && bytesSent == TxMessage->Length);
}
Ваш принимающий код должен выполнять больше работы, количество байтов, возвращаемых вами из ReadFile (), непредсказуемо. Протокол необходим, чтобы указать, когда вы должны прекратить чтение. Фиксированная длина ответа является распространенным явлением. Или специальный последний символ очень распространен. Это может выглядеть так:
bool ReceiveResponse(HANDLE hCommPort, array<Byte>^ RxMessage, int% RxCount) {
for (; RxCount < RxMessage->Length; ) {
DWORD bytesReceived = 0;
pin_ptr<Byte> pbytes = &RxMessage[0];
BOOL fSuccess = ReadFile(hCommPort, pbytes, RxMessage->Length - RxCount,
&bytesReceived, NULL);
if (!fSuccess) return false;
int rxStart = RxCount;
RxCount += bytesReceived;
for (int ix = rxStart; ix < RxCount; ++ix) {
if (RxMessage[ix] == '\r') return true;
}
}
return true;
}
Не забывайте о классе .NET System :: IO :: Ports :: SerialPort. Он имеет встроенную поддержку кодирования, которая облегчает работу с символами против байтов. Ваш метод ReceiveResponse () может привести к простому вызову ReadLine () с правильно установленным свойством NewLine.
Извиняюсь за неспособность ответить раньше, чем это. Фактически проблема была идентифицирована и исправлена после публикации моего последнего комментария. Это связано с 9-битным протоколом, навязанным микроконтроллером. Оригинальная микропрограмма — это 9-битный протокол для работы с одним из множества подчиненных. Для тестирования разработки у меня была временная модификация 8-битного протокола. К сожалению, модификации пропустили регистр режима UART, который остался как 9-битный режим. С коробкой / предвзятым умом я продолжал отлаживать