Преглед изворни кода

【软件版本】
V
【模块名称】
串口模块调整,以及超时值的用途描述加强理解。
【问题原因】

【修改描述】

【测试结果】

sat23 пре 3 година
родитељ
комит
8fc7cb139e
2 измењених фајлова са 58 додато и 1 уклоњено
  1. 45 0
      TCLCommand/TCLCommand/ReadMe.txt
  2. 13 1
      TCLCommand/TCLCommand/Serial.cpp

+ 45 - 0
TCLCommand/TCLCommand/ReadMe.txt

@@ -81,6 +81,51 @@ WriteTotalTimeoutConstant表示写数据总超时常量
 将 ReadIntervalTimeout、ReadTotalTimeoutMultiplier、ReadTotalTimeoutConstant都设置为0
 5:WriteFile没有超时设置:将WriteTotalTimeoutMultiplier和WriteTotalTimeoutConstant设置为0
 
+/////////////////////////////////////////////////////////////////////////////
+COMMTIMEOUTS 结构体被用在SetCommTimeouts和GetCommTimeouts 函数中,以便设置和查询通讯设备的超时参数。这个参数决定ReadFile, WriteFile, ReadFileEx, 和WriteFileEx 操作设备的行为。
+
+typedef struct _COMMTIMEOUTS {
+  DWORD ReadIntervalTimeout;
+  DWORD ReadTotalTimeoutMultiplier;
+  DWORD ReadTotalTimeoutConstant;
+  DWORD WriteTotalTimeoutMultiplier;
+  DWORD WriteTotalTimeoutConstant;} COMMTIMEOUTS, *LPCOMMTIMEOUTS;
+成员
+ReadIntervalTimeout
+在通讯过程中接收两个字符之间的最长超时时间,按毫秒计算。在ReadFile操作,当接收到第一个字符时,开始一个计时周期。如果接收任意两个字符之间的时隔超过本限制,ReadFile操作将完成并返回任何已缓冲的数据。0代表本参数未设置。
+如果设置为MAXDWORD, 并且ReadTotalTimeoutConstant和ReadTotalTimeoutMultiplier成员为0,代表读取操作立即返回那些已接收的数据,即使没有收到任何字符。(两个字符之间的接收间隔)
+
+ReadTotalTimeoutMultiplier
+乘数用于计算读取操作的总超时时间,按毫秒计算。对于每个读取操作,这个值将乘以要读取的字节数。(读取单个字符的最大超时)
+ReadTotalTimeoutConstant
+一个用于计算对于读取操作的总超时周期的常数,按毫秒计算。对每次读取操作,实际总超时时间为ReadTotalTimeoutMultiplier 成员与请求的字节数年的乘积加此值。
+ReadTotalTimeoutMultiplier和ReadTotalTimeoutConstant成员为0代表总读取总超时时间无效(读取所有字节的时间为ReadTotalTimeoutMultiplier*BytesToRead+ReadTotalTimeoutConstant)。
+
+WriteTotalTimeoutMultiplier
+乘数用来计算写操作的总超时周期,按毫秒计算。对每个写操作,这个值将乘以要写入的字节数。(写单个字符的最大超时)
+WriteTotalTimeoutConstant
+一个用于计算写入操作的总超时周期的常数,按毫秒计算。对于每一次写入操作,实际总超时时间为WriteTotalTimeoutMultiplier 成员与要写入字节的乘积再加此值.
+WriteTotalTimeoutMultiplier和WriteTotalTimeoutConstant成员为0代表总写入时间无效(写入所有字节的时间为WriteTotalTimeoutMultiplier*BytesToWrite+WriteTotalTimeoutConstant)。
+
+备注
+如果一个应用程序设置ReadIntervalTimeout和ReadTotalTimeoutMultiplier为 MAXDWORD并且设置ReadTotalTimeoutConstant 为一个大于零且小于MAXDWORD的值, 在调用ReadFile时将会发生如下现象:
+
+如果在输入缓冲区中有任何字符,ReadFile 立即返回缓冲区中的内容。
+如果在缓冲区中没有任何字符,ReadFile 将等待接收到一个字符并立即返回.
+如果在ReadTotalTimeoutConstant指定的时间值内无任何字节返回,ReadFile超时.
+
+
+/////////////////////////////////////////////////////////////////////////////
+串口读取事件分为两个阶段(我以Win32 API函数ReadFile读取串口过程来说明一下)
+第一个阶段是:串口执行到ReadFile()函数时,串口还没有开始传输数据,所以串口缓冲区的第一个字节是没有装数据的,这时候总超时起作用,如果在总超时时间内没有进行串口数据的传输,ReadFile()函数就返回,当然 没有读取到任何数据。而且,间隔超时并没有起作用。
+第二阶段:假设总超时为20秒,程序运行到ReadFile(),总超时开始从0 计时,如果在计时到达10秒时,串口开始了数据的传输,那么从接收的第一个字节开始,间隔超时就开始计时,假如间隔超时为1ms,那么在读取完第一个字节后,串口开始等待1ms,如果1ms之内接收到了第二个字节,就读取第二个字节,间隔超时重置为0并计时,等待第三个字节的到来,如果第三个字节到来的时间超过了1ms,那么ReadFile()函数立即返回,这时候总超时计时是没到20秒的。如果在20秒总计时时间结束之前,所有的数据都遵守数据间隔为1ms的约定并陆陆续续的到达串口缓冲区,那么就成功进行了一次串口传输和读取;如果20秒总计时时间到,串口还陆陆续续的有数据到达,即使遵守字节间隔为1ms的约定,ReadFile()函数也会立即返回,这时候总超时就起作用了。
+总结起来,总超时在两种情况下起作用
+第一:串口没进行数据传输,等待总超时时间那么长ReadFile()才返回。非正常数据传输
+第二:数据太长,总超时设置太短,数据还没读取完就返回了。读取的数据是不全的
+间隔超时触发是有条件的
+第一:在总超时时间内。
+第二:串口进行了数据的传输。
+成功的进行一次串口数据的传输和读取,只有总超时和间隔超时相互参与配合才能完成
 
 /////////////////////////////////////////////////////////////////////////////
 Command.data文件格式说明,键值对形式存在[key=value]:

+ 13 - 1
TCLCommand/TCLCommand/Serial.cpp

@@ -217,7 +217,7 @@ DWORD CBaseSerial::ReadSync(LPVOID Buffer, DWORD dwBufferLength)
     
     COMSTAT Stat;
     DWORD dwError;
-
+#if 0
     DWORD dwLastLen = 0;
     ULONGLONG ulTick = GetTickCount();    
     // 直到有数据为止,超时3秒;
@@ -255,7 +255,19 @@ DWORD CBaseSerial::ReadSync(LPVOID Buffer, DWORD dwBufferLength)
         DWORD dwError = GetLastError();
         utils::_dprintf("读出错:%ld", dwError);
     }
+#else
+    if ( ::ClearCommError(_hCommHandle, &dwError, &Stat) && dwError > 0 ) {
+        ::PurgeComm(_hCommHandle, PURGE_RXABORT | PURGE_RXCLEAR);    // 清空输入缓冲区(PURGE_RXCLEAR)
+        utils::_dprintf("读出错: ClearCommError出错");
+    }
 
+    DWORD uReadLength = 0;
+    if ( !::ReadFile(_hCommHandle, Buffer, dwBufferLength, &uReadLength, NULL) )
+    {
+        DWORD dwError = GetLastError();
+        utils::_dprintf("读出错:%ld", dwError);
+    }
+#endif
     return uReadLength;
 }