在C ++函数WriteFile和ReadFile中用于参数LPVOID lpBuffer的变量类型

时间:2013-08-18 08:53:15

标签: c++ serial-port microcontroller

C ++ ReadFileWriteFile函数的 lpBuffer 应该使用哪种变量类型来在基于Windows XP的PC和基于微控制器的系统之间进行通信? PC在VS2010 C ++ / CLI中有WinForm应用程序。微控制器固件是ANSI C。

我的电脑应该发送命令字符(比如' S' C'等),然后是命令终止字符0xd(十进制13的十六进制)。基于微控制器的系统将响应5到10个字节,这些字节可以是ASCII字符和十六进制数字的混合,例如' V'然后是0x41 0x72等。

PC传输和微控制器接收:

  1. TxMessagePP1pTx声明为char并将nNumberOfBytesToWrite保持为2,使微控制器接收{{1}为了' S'然后是0x53而不是0xC3

  2. 0xdTxMessagePP1声明为pTx并将wchar_t保持为2,使微控制器接收{{1}为了' S'仅

  3. nNumberOfBytesToWrite0x53TxMessage声明为PP1并将pTx保持为4,使微控制器接收{{1}为了' S'正确地跟着wchar_t

  4. 上述第三种传输和接收方案符合我预期的解决方案行为。但令人困惑的是:虽然PC可能正在传输4个字节(对于两个nNumberOfBytesToWrite类型),但微控制器接收2个字节0x53用于' S'正确后跟0xd

    微控制器传输和PC接收:

    假设wchar0x53的正确选择,我的0xD 应该从微控制器接收10个字节? ReadFile可以通过wchar_t获得20个字节,而微控制器只能传输10个字节。

    令人惊讶的是,无论将lpBuffernNumberOfBytesToReadwchar_t)声明为RxMessagePP2还是pRx,ReadFile都会收到10个字节来自微控制器(符合我预期的解决方案行为)。但问题在于传播' A'来自微控制器的10次,PC端的ReadFile会收到垃圾,例如' S',wchar_tcharunsigned char,{{1 }}

    0x0

3 个答案:

答案 0 :(得分:1)

ReadFile/WriteFile不关心C ++类型,它们以读/写的字节数运行。 ReadFile从文件/设备读取指定的字节数(如果要读取的字节数更少,则读取更少),并将它们放入lpBuffer指向的内存中。 WriteFile将指定的字节数从lpcBuffer指向的内存写入文件/设备。这些函数的内存缓冲区只是一个已分配内存的区域,其大小至少与在第三个参数中告诉这些函数一样多。

wchat_t是一种多字节类型。它的大小可以大于一个字节。因此,您的TxMessage[0]='S'; TxMessage[1]=0xd;实际上可以在内存中填充不是两个字节,但是,例如,4个字节。例如,x0053表示中可以是x000Dwchar_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模式寄存器。凭借盒装/偏见的心态,我一直在调试