C ++ ReadFile
和WriteFile
函数的 lpBuffer 应该使用哪种变量类型来在基于Windows XP的PC和基于微控制器的系统之间进行通信? PC在VS2010 C ++ / CLI中有WinForm应用程序。微控制器固件是ANSI C。
我的电脑应该发送命令字符(比如' S' C'等),然后是命令终止字符0xd
(十进制13的十六进制)。基于微控制器的系统将响应5到10个字节,这些字节可以是ASCII字符和十六进制数字的混合,例如' V'然后是0x41
0x72
等。
PC传输和微控制器接收:
TxMessage
,PP1
和pTx
声明为char
并将nNumberOfBytesToWrite
保持为2,使微控制器接收{{1}为了' S'然后是0x53
而不是0xC3
。
0xd
,TxMessage
和PP1
声明为pTx
并将wchar_t
保持为2,使微控制器接收{{1}为了' S'仅
nNumberOfBytesToWrite
,0x53
和TxMessage
声明为PP1
并将pTx
保持为4,使微控制器接收{{1}为了' S'正确地跟着wchar_t
。
上述第三种传输和接收方案符合我预期的解决方案行为。但令人困惑的是:虽然PC可能正在传输4个字节(对于两个nNumberOfBytesToWrite
类型),但微控制器接收2个字节0x53
用于' S'正确后跟0xd
。
微控制器传输和PC接收:
假设wchar
是0x53
的正确选择,我的0xD
应该从微控制器接收10个字节? ReadFile可以通过wchar_t
获得20个字节,而微控制器只能传输10个字节。
令人惊讶的是,无论将lpBuffer
,nNumberOfBytesToRead
和wchar_t
)声明为RxMessage
,PP2
还是pRx
,ReadFile都会收到10个字节来自微控制器(符合我预期的解决方案行为)。但问题在于传播' A'来自微控制器的10次,PC端的ReadFile会收到垃圾,例如' S',wchar_t
,char
,unsigned char
,{{1 }}
0x0
答案 0 :(得分:1)
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 ++类型,包括自定义类。但传递给WriteFile
的内存指针指向的前4个字节的内存应为x0A0B0C0D
。
同样,ReadFile
将读取您指定的字节数。如果你的设备发送给你2个字节,ReadFile
会写入2个字节,它会被你传递给它的指针所指向的内存(你有责任确保它有足够的字节分配)。同样,只要分配了2个字节,它就不关心你如何分配它。之后,再次,您可以根据需要查看这两个字节 - 它可以是char[ 2 ]
,可以是int short
等。
答案 1 :(得分:1)
使用字节是自然匹配,串行端口基本上是面向字节的设备。您可以使您的传输代码如下所示:
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属性。
答案 2 :(得分:0)
抱歉不能早于此做出回应。事实上,在发布我的上一条评论后,问题得到了确认和纠正。它涉及由微控制器强制的9位协议。原始微固件是9位协议,用于解决许多从站中的一个。对于开发测试,我对8位协议进行了临时修改。不幸的是,修改错过了保持为9位模式的UART模式寄存器。凭借盒装/偏见的心态,我一直在调试