CnComm勘误及Faq(将会持续更新)

勘误

1、2009-5-14 据shunruo网友发现了一个重要的BUG,在此感谢shunruo网友,还有张冬冬网友

CnComm1.5第1180行 函数:DWORD Write(LPCVOID lpBuf, DWORD dwSize)

原有代码:

 

DWORD Write(LPCVOID lpBuf, DWORD dwSize)
{
    DWORD dwTemp 
= dwSize, dwFree = FreeSize();
    
    
if (dwFree)//! 首先查找末尾空闲,并写入数据
    {
        DWORD dwCopy 
= dwFree > dwSize ? dwSize : dwFree;
        memcpy(L_
->P_ + L_->E_, lpBuf, dwCopy);
        dwTemp 
-= dwCopy, L_->E_ += dwCopy;
    }

    
if (dwTemp)//! 剩余的数据分配新的空间并写入
    {
        memcpy(NewBlock(dwSize)
->P_, lpBuf, dwTemp);//重要的BUG
        L_
->E_ += dwTemp;
    }

    S_ 
+= dwSize;
    
return dwSize;
}

 

请将该函数内容修正如下:

 

DWORD Write(LPCVOID lpBuf, DWORD dwSize)
{
    DWORD dwTemp = dwSize, dwFree = FreeSize(), dwCopy = 0;

    if (dwFree)//! 首先查找末尾空闲,并写入数据
    {
        dwCopy = dwFree > dwSize ? dwSize : dwFree;
        memcpy(L_->P_ + L_->E_, lpBuf, dwCopy);
        dwTemp -= dwCopy, L_->E_ += dwCopy;
    }

    if (dwTemp)//! 剩余的数据分配新的空间并写入
    {
        memcpy(NewBlock(dwSize)->P_, ((LPBYTE)lpBuf )+ dwCopy, dwTemp);//该处原代码未作偏移值修正,由于缓冲区一般较大,这一块在测试中忽略了
        L_->E_ += dwTemp;
    }

    S_ += dwSize;
    return dwSize;
}


2、2009-4-29 根据网友柠檬的提醒,发现一个CnComm在WinCE下使用一个潜在的缺陷
CnComm1.5第1700行 函数: virtual bool SetupPort()
原有代码:

    virtual bool SetupPort()
    {
        
if(!CN_ASSERT(IsOpen()))
            
return false;

        
if(!CN_ASSERT(::SetupComm(hComm_, 4096, 4096)))//! 配置端口发送接收队列大小, 读4096字节, 写4096字节, 阻塞I/O模式发送队列无意义
            return false
; //此处有些硬件不支持
        
        
if(!CN_ASSERT(::GetCommTimeouts(hComm_, &CO_)))
            
return false;

        CO_.ReadIntervalTimeout            
= 100;//! 配置超时结构 字符最小间隔100ms
        CO_.ReadTotalTimeoutMultiplier    = 0;
        CO_.ReadTotalTimeoutConstant    
= IsOverlappedMode() ? 500 : 250;//! 读超时 重叠I/O模式下500毫秒 阻塞I/O模式下250毫秒
        CO_.WriteTotalTimeoutMultiplier = IsOverlappedMode() ? 1 : 0;
        CO_.WriteTotalTimeoutConstant    
= IsOverlappedMode() ? 10000 : 250;//! 写超时 重叠I/O模式下(10000+1×字节数)毫秒 阻塞I/O模式下250毫秒

        
if(!CN_ASSERT(::SetCommTimeouts(hComm_, &CO_)))
            
return false
        
        
if(!CN_ASSERT(::PurgeComm(hComm_, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR )))//! 清除端口
            return false
        
        
return true;
    } 

将该函数修正如下:
    virtual bool SetupPort()
    {
        
if(!CN_ASSERT(IsOpen()))
            
return false;

    
#if defined(CN_COMM_FOR_CE)
        ::SetupComm(hComm_, 4096, 4096);
    #else
        if(!CN_ASSERT(::SetupComm(hComm_, 4096, 4096)))//! 配置端口发送接收队列大小, 读4096字节, 写4096字节, 阻塞I/O模式发送队列无意义
        return false; 
    #endif

        
        
if(!CN_ASSERT(::GetCommTimeouts(hComm_, &CO_)))
            
return false;

        CO_.ReadIntervalTimeout            
= 100;//! 配置超时结构 字符最小间隔100ms
        CO_.ReadTotalTimeoutMultiplier    = 0;
        CO_.ReadTotalTimeoutConstant    
= IsOverlappedMode() ? 500 : 250;//! 读超时 重叠I/O模式下500毫秒 阻塞I/O模式下250毫秒
        CO_.WriteTotalTimeoutMultiplier = IsOverlappedMode() ? 1 : 0;
        CO_.WriteTotalTimeoutConstant    
= IsOverlappedMode() ? 10000 : 250;//! 写超时 重叠I/O模式下(10000+1×字节数)毫秒 阻塞I/O模式下250毫秒

        
if(!CN_ASSERT(::SetCommTimeouts(hComm_, &CO_)))
            
return false
        
        
if(!CN_ASSERT(::PurgeComm(hComm_, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR )))//! 清除端口
            return false
        
        
return true;
    } 

 3 、2009-5-18 根据网友腾空的提示,发现一个关于内置缓冲区的BUG
CnComm1.5第1726行 函数: DWORD PortToBuffer(DWORD dwPortByteNum)
原有代码:

//! 将端口数据读入缓冲区的
    DWORD PortToBuffer(DWORD dwPortByteNum)
    {
        
return dwPortByteNum ? I_.Release(ReadPort(I_.GetFreePtr(dwPortByteNum), dwPortByteNum)) : 0;
    }

将该函数修正如下:

    //! 将端口数据读入缓冲区的
    DWORD PortToBuffer(DWORD dwPortByteNum)
    {
        BlockBuffer::InnerLock locker(&I_);
        return dwPortByteNum ? I_.Release(ReadPort(I_.GetFreePtr(dwPortByteNum), dwPortByteNum)) : 0;
    }

 4、2009-6-11 根据网友deke_chen的提示,修改两个BUG
CnComm1.5 第487行 wchar_t * ReadString(wchar_t *szBuffer, DWORD dwLength, DWORD dwWaitTime = INFINITE)
原有代码:

    //! 读取串口 dwLength - 1 个UNICODE字符到 szBuffer 返回 C 模式字符串指针 适合一般字符通讯
    wchar_t * ReadString(wchar_t *szBuffer, DWORD dwLength, DWORD dwWaitTime = INFINITE)
    {
        CN_ASSERT(szBuffer);
        szBuffer[Read(szBuffer, dwLength - 1, dwWaitTime)] = L'\0';
        return szBuffer;
    }

将该函数修正如下:

    //! 读取串口 dwLength - 1 个UNICODE字符到 szBuffer 返回 C 模式字符串指针 适合一般字符通讯
    wchar_t * ReadString(wchar_t *szBuffer, DWORD dwLength, DWORD dwWaitTime = INFINITE)
    {
        CN_ASSERT(szBuffer);
        szBuffer[(Read(szBuffer, (dwLength - 1)*sizeof(wchar_t), dwWaitTime) +1)/ sizeof(wchar_t)] = L'\0';
        return szBuffer;
    }

注:不推荐使用UNICODE字符串通讯,因为串口是字符通讯,不能保障2个字节的UNICODE字符一次性被接收到

CnComm1.5 第1307行 wchar_t* ReadString(wchar_t* lpBuf, DWORD dMaxSize)
原有代码:

        //! 读入UNICODE字符串缓冲区
        wchar_t* ReadString(wchar_t* lpBuf, DWORD dMaxSize)
        {
            lpBuf[Read(lpBuf, dMaxSize)] = L'\0';
            return lpBuf;
        }

 将该函数修正如下:

        //! 读入UNICODE字符串缓冲区
        wchar_t* ReadString(wchar_t* lpBuf, DWORD dMaxSize)
        {
            lpBuf[(Read(lpBuf, dMaxSize*sizeof(wchar_t))+1) / sizeof(wchar_t)] = L'\0';
            return lpBuf;
        }

CnComm1.5 第1331行 void Clear(bool bDeleteAll = false)
原有代码:

        //! 清除 \param bDeleteAll 为true时释放所有内存, 否则保留一个内存块以提高效率
        void Clear(bool bDeleteAll = false)
        {
            if (F_ && (F_==L_) && F_->S_>(M_<<2))
                memset(F_, 0, sizeof(Block));
            else
            {
                for (Block* t = F_;  t; delete  F_)
                    F_ = t, t = t->N_;

                F_ = L_ = NULL, S_ = 0;
            }
        }

 将该函数修正如下:

        //! 清除 \param bDeleteAll 为true时释放所有内存, 否则保留一个内存块以提高效率
        void Clear(bool bDeleteAll = false)
        {
            if (F_ && (F_==L_) && F_->S_>(M_<<2))
            {
                DWORD S = F_->S_;
                memset(F_, 0, sizeof(Block)), F_->S_ = S;
            }
            else
            {
                for (Block* t = F_;  t; delete  F_)
                    F_ = t, t = t->N_;

                F_ = L_ = NULL, S_ = 0;
            }
        }


 

Faq

1、用CnComm写的程序发送不正常,但用其他程序打开端口后,再用CnComm写的程序就好了?
分析:
具体原因是配置参数失败。并且该网友没有检查Open()或者SetState()的返回值, 所以没有发现配置参数失败造成的。

比如设置波特率"9600,O,7,1",不小心把配置字符串写成了"9600,7,O,1"。
使用CnComm配置后失败,并没有检查返回值,发送数据就会是乱码,或者不能正确接收。
这时很自然的,你会用其他工具程序打开端口,由于有可视界面,打开参数正确,又能正常发送。
然后你又想用CnComm再打开试试,结果发现又行了。
实际上配置串口失败,会采用上一次正确配置,所以看上去正常了,实际上单独运行就不行了。

这和我的笔误,即有一回把"9600,N,8,1"误写成了"9600,8,N,1",客观上造成去多网友照搬出错,对于这一部分网友,真诚表示歉意。
不过我还有看到更夸张的写法,但部分网友不检查返回值,是一个很不好的现象。
if (!Com.Open(19600)) 
    assert(
0);

if (!Com.Open(1"9600,N,8,1")) 
    assert(
0);
最起码也要像上面这样写,当然这只是举例,实际应用应该更严谨才对。
另外在CnComm1.5版本以后打开和配置出错,调试版中都会产生错误提示,即便是你不检查返回值。

CnComm配置字符串的标准写法:

"BBBB,P,D,S" BBBB 为波特率,P 为奇偶校验,D 为数据位数,S 为停止位数。
 
合法的奇偶校验值:
E  偶数 (Even)
M  标记 (Mark)
N  缺省 (Default)
None   
O 奇数 (Odd)
S 空格 (Space) 
合法的数据位:
4
5
6
7
8 (缺省)
合法的停止位值:
1  (缺省)
1.5   
2  

2、发送10个字节数据,每次都分成两部分,比如"0123456789", 被分成"01234"和"56789", 能不能一次读取10个字节?
分析:这是个通讯的基本问题。
由于是10个字节,你才会问这个问题,如果是1百万个字节,你就不会这样问我了。
你肯定不敢开口要求一次性接受1百万个字节。
通讯归根结底是看似连续,实则断续。
在CnComm1.5已经针对这个问题作了修改,对于百千个字节可以做到连续一次性接受
CnComm1.3可以采用Read(buf, 1000, false);
最好升级到CnComm1.5。这里参见我在CSDN博客中接收处理两种用法
最规范的做法,是利用缓冲区缓存数据,然后再做处理。

3、调用发送语句后,马上关闭串口,常常数据发不出。
分析:如果你采用重叠IO方式即CnComm默认方式打开串口,发送数据并不是在Write语句调用后马上发生,而是系统在后台帮你发送。
而你立即调用关闭,关闭里有清空队列的代码,就没有系统运行的机会。
解决办法:同步IO,不存在这个问题。

使用重叠IO,在CnComm1.5 ,可以按如下做法
   
    CnComm com;
    com.Open(
1);
    com.Write(
"test");
    com.Flush();
    com.Close();


 

 

posted on 2009-05-15 09:56 llbird 阅读(10319) 评论(45)  编辑 收藏 引用

评论

# 错误 2009-05-15 22:39 张冬冬

修正的第一个错误:“
memcpy(NewBlock(dwSize)->P_, lpBuf + dwCopy, dwTemp);//该处原代码未作偏移值修正,由于缓冲区一般较大,这一块在测试中忽略了”

这块在调试中出现错误:
错误 7 error C2036: 'LPCVOID' :

还有Comm_.Write(buffer); 怎么不返回写入的数字呢?
我是新手 请指教。

还有写的很好,以后要好好研究
  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2009-05-15 22:52 llbird

memcpy(NewBlock(dwSize)->P_, ((LPBYTE)lpBuf) + dwCopy, dwTemp);//

这里忘记把const属性去掉  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2009-05-15 22:57 llbird

Comm_.Write(buffer);
不返回发送数量是因为重叠IO的作用。
系统将在后台帮你把数据发送出去,由于串口是低速设备,如果你要等待返回发送数量将浪费系统资源,所以函数直接返回,以便你继续操作,这样并行操作,提高系统利用率  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2009-05-16 08:05 张冬冬

奥 看来我对串口的工作机制及C++语言规范还不是太懂,
谢谢回复,会努力的。  回复  更多评论   

# evc关于模拟器的环境搭建咨询 2009-05-30 08:27 hanliang

目前我手上搭建了wince 5.0模拟器的环境,但是无法测试通过.想确定一下你手上是如何搭建的模拟器环境.谢谢.我的邮箱是:hanliang516@126.com  回复  更多评论   

# 接受速度稍微有点慢,不知道是我用法不对还是怎么? 2009-05-30 12:23 张天浩

您好,看到这个串口类感觉很强大,多些作者开源,但是有个问题是我在应用中感觉速度稍微慢,不知道是不是我应用方式不对?请指教.
我的应用介绍:开发一个读卡器的dll类库。实现发送命令。
我的做法是这样:
------1、定义两个全局变量,一个是长度一个是接收到的Buff如下
//-----------全局变量
char buffReceived[255];
int intReceived;

------2、继承类:
class ClientComm : public CnComm
{
public:
//! 配置CnComm 监视线程 重叠IO 双缓冲区
ClientComm() //: CnComm(EN_THREAD | EN_TX_BUFFER | EN_RX_BUFFER | EN_OVERLAPPED)
{
hEvent_ = CreateEvent(NULL, TRUE, FALSE, NULL);
}
//!
virtual ~ClientComm()
{
CloseHandle(hEvent_);
}
//! 接收命令响应信息 \sa CnComm::OnReceive()
void OnReceive()
{
char buffer[1024];
int len;
len = Read(buffer, 1024);
for (int i = 0; i<len ; i++)
{
buffReceived[intReceived] = buffer[i];
intReceived++;
}

}
//! 等待命令响应


protected:
HANDLE hEvent_; //!< 等待输入事件

};

------3、 处理事件

bool SendCmdIn()
{
char pSendBuf[10];
Comm_.Write(pSendBuf,5);//发送数据
//处理监控得到的数据

while(1)
{
Sleep(1); //暂停1毫秒
if(intReceived==1 && (BYTE)buffReceived[0]== 0x01)
{
return true;
}
}

}  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新)[未登录] 2009-05-30 13:16 llbird

C++写的类,当然性能是正常的。俺这么多年从来就没有听说性能问题。
什么叫慢?你的代码片段不足以让人了解你要做什么,如何测试,DLL和主模块如何搭配,业务的东西你要自己做的,我不对业务做咨询。
你如果能够准确明了的描述问题和想法,我有时间还是会做解答,但不承诺。
只对CnComm本身问题做咨询。

注意超时控制,如果你想要接收到数据再返回,
要用精确控制。
比如14个字节的应答包

void OnReceive()
{
for (1..14)
Read(&c, 1);//一个字节一个字节读

或者Read(&c, 14);//直接控制恰当的字节数,而不是一味的用1024
或则Read函数会一直等到1024个字节,但实际上它等不到,因为根本不可能应答1024字节,它就会等个几百毫秒超时了在返回,可能这就是你说的慢,不知道我的理解真不正确?

另外你的模式有问题,
while(1)
{
Sleep(1); //暂停1毫秒
if(intReceived==1 && (BYTE)buffReceived[0]== 0x01)
{
return true;
}
}
不应该这样用你可以用通知方式会更理想,循环很浪费CPU,直接WaitEvent更好一些
}


  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2009-05-30 17:36 张天浩

谢谢回复,我测试了一下确实是Read(&c, 1024);的问题,,不过还是把全部代码发出来供llbird 及大家查看,可能这个问题初学者都能遇到吧,希望大家有时间给指点一下。
//======实现功能:向串口发送pSendBuf1,期望返回长度为1,当返回为0x01时,继续发送pSendBuf2,否则退出,发送pSendBuf2 ,期望返回长度为2,返回char[0] = 0x01 并且char[1] =0x02 时成功否则失败。
//========实现代码

//-----------全局变量定义接受字符串和长度
char buffReceived[255];
int intReceived;

//! 执行结果: 协议 ASCII(0~N)+0x3
class ClientComm : public CnComm
{
public:
//! 配置CnComm 监视线程 重叠IO 双缓冲区
ClientComm() //: CnComm(EN_THREAD | EN_TX_BUFFER | EN_RX_BUFFER | EN_OVERLAPPED)
{
hEvent_ = CreateEvent(NULL, TRUE, FALSE, NULL);
}
//!
virtual ~ClientComm()
{
CloseHandle(hEvent_);
}
//! 接收命令响应信息 \sa CnComm::OnReceive()
void OnReceive()
{
char buffer[1];
int len;
len = Read(buffer, 1);
for (int i = 0; i<len ; i++)
{
buffReceived[intReceived] = buffer[i];
intReceived++;
}

}

//! 等待命令响应
bool WaitReturn(DWORD dwWaitTime = 100)
{
return WaitForSingleObject(hEvent_, dwWaitTime) == WAIT_OBJECT_0;
}



protected:
HANDLE hEvent_; //!< 等待输入事件

};

ClientComm Comm_;
ClientComm::BlockBuffer Rx_;



bool SendCmdIn() //
{
char pSendBuf1[5];
pSendBuf1[0]=80;
pSendBuf1[1]=01;
pSendBuf1[2]=00;//
pSendBuf1[3]=00;
pSendBuf1[4]=00;
intReceived =0;//初始化计数器
dwBytesWritten=Comm_.Write(pSendBuf1,5);//发送 pSendBuf1 期望返回长度为1 数据位 0x01
while(1)
{
Sleep(1); //暂停1毫秒
//应答成功
if(intReceived==1 && (BYTE)buffReceived[0]== 0x01 )
{
break;//成功 退出
}
////应答失败
else if (intReceived>1)//
{
return false;//返回
}
}

char pSendBuf2[5];
pSendBuf2[0]=80;
pSendBuf2[1]=01;
pSendBuf2[2]=02;//
pSendBuf2[3]=00;
pSendBuf2[4]=00;
intReceived =0;//初始化计数器
dwBytesWritten=Comm_.Write(pSendBuf2,5);//发送 pSendBuf2 期望返回长度为2 数据位 0x01 0x02

while(1)
{
Sleep(1); //暂停1毫秒
//应答成功
if(intReceived==2 && buffReceived[0]== 0x01&&buffReceived[1]== 0x02 )
{
break;//成功 退出
}
////应答失败
else if (intReceived>1)//
{
return false;//返回
}
}
return true;

}

  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2009-07-20 20:01 scaler

刚下了v1.5的,用了下发现当接收连续的字符时,当中间包含有0x00 的数据时,会丢掉后面的数据  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新)[未登录] 2009-07-20 20:46 llbird

当中间包含有0x00 的数据时不可以使用ReadString
应使用Read  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2009-10-19 17:10 tianyu2467

你好!我用你你给的vc6的例子用2008编译后,当接收数据时出现蓝屏(2005的例子收不到数据).
然后我自己根据你网上的帖子写,用ReadString()读数据仍然蓝屏.这是怎么回事?  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2009-10-19 17:11 tianyu2467

补充一点1.3的类没有问题,可发可收.  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新)[未登录] 2009-10-21 22:59 llbird

例子是有BUG的,必须用1.51的版本,或者按照本文的进行修正。  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2010-02-23 11:55 liqs99

请问一下,什么是读反冲啊。
我的程序过一段时间总是在423行这里出问题
while (!CN_ASSERT(::GetOverlappedResult(hComm_, &RO_, &dwReadResult, TRUE)))
;  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2010-03-24 14:36 xihuwuyu

我拿来主义了!非常感谢!  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2010-03-26 14:30 xihuwuyu

bird老大,我可以直接#include CnComm.h吗?为什么引用后会编译通不过?f:\design\gms09\cncomm.h(1053) : error C2629: unexpected 'struct CnComm::BlockBuffer::Iterator ('
f:\design\gms09\cncomm.h(1053) : error C2334: unexpected token(s) preceding ':'; skipping apparent function body
可以指教下吗?俺太菜了!  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新)[未登录] 2010-04-21 15:16 John

你好,之前用LsComm写了几天,都处理不好,后来找到您这个CnComm类,中文注释相当亲切,代码也友好。就准备写一个接收程序,可是一接收就蓝屏啊。(我用的是SerialNull虚拟串口生成一对串口COM3和COM4在本机上调试),CNCOMM单独发送没有问题,我用WINDOWS自带的终端开两个串口相互收发也没有问题,就是CNCOMM一接收马上蓝屏:报 stop:0x000000d1。
我调了一下,蓝屏的代码大概在:
ReadPort这个函数的
if (!::ReadFile(hComm_,pBuffer,dwLength,&dwReadResult,&R0_))
这里。实在是没招了啊,请大大指点。  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新)[未登录] 2011-01-18 10:03 tom

采用16进制传输的时候,解包成ascii A0变成20???B0变成30?  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新)[未登录] 2011-01-26 11:09 bird

llbird,OverlappedModel的逻辑不是很清晰,不像Remon Spekreijse的CSerialPort那么容易理解,你觉得呢?比如dwMask = 0以及dwMask = EV_RXCHAR的处理就不是很好。  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新)[未登录] 2011-02-26 14:36 llbird

抱歉,那段代码是支持WINCE,他的代码是只支持WINDOWS的@bird
  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2011-03-11 21:46 sg

健哥,你还有关注这个类啊!真可惜你转行了@llbird
  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2011-07-27 14:25 1111

@llbird 使用READ依然不能接收0x00。。接收后后面数据丢失
  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新)[未登录] 2011-07-28 21:00 llbird

多检查一下程序吧,这个类用了很久了,酒精考验了,类似Read、Write之类的就不用问了,肯定没问题的。  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2011-08-31 16:43 zjs

我想请教一个问题,我在OnReceive()中接收数据后在在哪个函数里处理这些数据?
void OnReceive()

接收函数...
处理数据...

我在OnReceive()里处理数据时为什么处理数据的函数执行不了  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2011-09-23 16:51 CnComm学习

发送十六进制 80 00
收到的是00 00
调试跟踪,发现进了
//! 响应EV_BREAK事件
virtual void OnBreak()
{
ClearCommBreak(hComm_);
Notify(ON_COM_BREAK);
}
我如果注释掉ClearCommBreak这句,则可以收到80 00了。
用作者的VC6的那个串口通讯工具测试,发送十六进制的80 00 后,弹出一个窗口“COM4 be placed in a break state.”。

我想知道进入OnBreak,这是一个什么情况?这个处理是做什么的?
像我要正常收到80 00,是不是需要进行其它配置?
我是在C++Builder2010下使用的,现在就调用了:
g_Comm->Open(4);
BYTE data[]={0x80,0x00};
g_Comm->Write(data,sizeof(data)/sizeof(data[0]));
然后就是添加LRESULT __fastcall TForm1::OnReceive(TMessage &msg)。
  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2011-12-17 15:17 Daywei

请教一个问题 如果 我每次发固定的字节数 比如8字节,有两种情况 第一种 我每隔一段时间发一次,共发五次,第二种 我在瞬间 比如 0.1毫秒内发了 五次,他们的接收过程是否相同,我个人测试发现 read可能一下读了 16个字节,而剩下的就按照发一次多少字节就接收多少字节,也就是说两者接收到的数据相同但接收的过程却不一致,尤其第二种不稳定,请教这是什么原因  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2011-12-26 23:21 Doug

今天拿来测了下...因为只需要接收下位机传上来的数据...所以只使用了类里的onRecieve函数...我的波特率是156250的...所以才会找上llbird你的这个类哈...
接收有些许问题...有丢字节的情况出现...自己调用的程序有这种情况...用回你原来1.5版本的测试程序也有同样的情况...尝试更改传输的字节数...同样出现丢字节的情况...
尽量帮你再多测几次看看是为什么吧...
有情况再上来跟你反映...嘿嘿...  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2012-01-13 14:33 Doug

總算把事情搞完了,寫總結時還提到這個問題,現在過來澄清一下,其實從Debug中的數據來看,在內存傳送中,由於LZ的示例程序中Ascii2Hex這個函數裡,在接收到0x00這個字節時(由於我是把低層的地址傳上來,所以會存在這個字節),程序會把其認為是該字符串的結束符'\0',於是便會丟失數據.
再者,當把m_Rx接收到的字符串用StaticEdit來顯示時,會出現有多餘的兩個字節(是無意義的),後來在調試時,發現內部傳輸是沒問題的,只是在顯示出來時卻多了兩個字節,但是在接下來更新的字符串上來時又會把這多餘的兩個字節都覆蓋掉,原以為是String在接收顯示完畢後沒有及時被清空,後來發現清空後還是出現同樣的情況,卻又一直沒法找到,礙於時間,便不再追求.若有其它人尋找到原因及解決方法,方便的話請順便郵件於我.huangxiaodon@sohu.com謝謝.  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2012-02-01 10:43 dwwzl

if (msg.WParam == Comm_.GetPort())
行总是出现警告:
W8012 Comparing signed and unsigned values
如何修正呢?  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2012-03-16 16:46 文俊

在调试的时候向设备发送命令没有一点反应,不知道我这种调用是不是有问题,请指点,谢谢!

CnComm Com;
CnComm::BlockBuffer bb;

if (!Com.Open(1, "9600,N,8,1"))
{
assert(0);
}
char buf[1024] = {0};
Com.WritePort("*CLS",25);
Com.WritePort("*RST",25);
Com.WritePort("SYST:LOC",25);
Com.WritePort("SYST:REM",25);
Com.WritePort("MEAS:RES? DEF,DEF",25);
Com.ReadString(buf,25,500);
//上面的这些命令没有一点反应 ,但在MSCOMM测试的时候是正常的,只是不知道为什么使用MSCOMM的时候,不能在我需要的时候得到返回值。还请大师指点。谢谢!
bb.Write("MEAS:RES? DEF,DEF",20);//写入20个字节
bb.Read(buf, 20);//读出20个字节 并返回实际读出数

bb.Clear();//清空
我的邮箱:jonesvale@live.cn,请指点,谢谢!  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新)[未登录] 2012-04-01 13:53 kkk

cn_assert(isopen()failed;cncomm(909)  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2012-05-02 10:18 syrchina

连续两个Com.Write()
只接收到第一个的数据,
第二个没收到,
Why?
请指点  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2012-09-21 08:44 huaqping

谢谢 llbird,有这个更新 CnComm就好用了。  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2012-09-25 09:09 huaqping

llbird,这几天用CnComm在VC下写了个测试工具,发现一个问题用Comm_.Read(szComSendBuf, 1);时若缓冲区有两个数据,有时只能接受到的是第二个数据,第一个就丢掉了。请问有没有取接受缓冲区数据量的函数?  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2013-01-15 18:14 恨铁不成钢

曾经疯狂而执着的健哥终于甩手了哦……
中国编程界一大损失  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2013-03-14 13:26 ajia

这个类最高支持多少的通讯速率 为什么超过115200就不行了  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2013-03-26 18:35 Karsion

说接收速度慢的朋友,检查一下有没有预定义WIN32,没有的话会用WINCE模式打开,默认阻塞IO,win32的可以在打开前调用 this->SetOption(EN_THREAD | EN_OVERLAPPED);
设置重叠IO(OVERLAPPED这个)  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2013-06-06 23:21 mzcc

前辈好,您写的CnComm实在是非常的好用。
我想问一下,CnComm的接收缓冲区会溢出么?
我在xp下运用CnComm快速的接收数据,估计10ms接收一次13byte,用的是625000波特率。在连续10分钟左右,则会出现电脑死机的情况,您看这会是缓冲区溢出的原因么?  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2013-10-10 09:45 12345

1234  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2013-10-10 09:47 12345

@Doug
这个是库函数strlen的问题,它会将0x00作为字串的终止符, 只能自己写一个strlen,
这个也不会太困难, 至于多出的2个字符, 还是在asciitohex函数中, 最后一句,
有加入"\0"  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2013-10-11 12:02 12345

请教博主:
如何最大限度提升cncomm的发送速度?

我遇到的问题是: 假设用通用com工具做发送, cncomm做接收, 假定速率为10kbytes/s, 这时用cncomm发送, cncomm接收(对传), 速率只有5kbytes/s  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2013-12-12 20:07 卖钢材不如卖矿泉水

空前绝后,后无来者啊。
除了llbird还真没有继承人了了  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2014-02-26 14:05 听枫2005

cnComm类中没有提供清空发送缓存区和接收缓存区的接口.如果上一次返回的数据在接收缓存区内由于某些原因没有被处理,则下一次接收数据时会将上一次的数据也一起读取出来,在某些特定环境下,这可能会导致致命错误.所以应该提供两个接口让用户自主选择.  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2014-03-24 16:39 梦游鲨鱼

void Clear(bool bDeleteAll = false)
{
if (F_ && (F_==L_) && F_->S_>(M_<<2))
{
DWORD S = F_->S_;
memset(F_, 0, sizeof(Block)), F_->S_ = S;
}
else
{
for (Block* t = F_; t; delete F_)
F_ = t, t = t->N_;

F_ = L_ = NULL, S_ = 0;
}
}


这个代码有错,bDeleteAll 根本就没有被使用,并且就是在if分句中也没有S_ = 0;  回复  更多评论   

# re: CnComm勘误及Faq(将会持续更新) 2014-03-24 16:51 梦游鲨鱼

在BlockBuffer析构时,buffer的内存没有被释放  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理


<2024年12月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

导航

统计

常用链接

留言簿(8)

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜