在读取串口数据时,老是返回上一次发送的数据?

C_yjun 2014-01-13 05:01:47
运用的是SerialPort类来进行串口的读写。该类我们老大做了修改。由于不是MFC类不能使用BEGIN_MESSAGE_MAP() END_MESSAGE_MAP() 来发送消息。我利用串口监听软件可以看到,数据是同步的,但是读取上来时,却是上一次发送的数据。而且在打开串口时会读到一个字符

串口通信刚接触不久,可能表述的不是太好,有些东西理解的也不是太好,求大神帮助,有哪里有问题也请点出来,在这先谢了。第一次发帖有点紧张.....通信基本代码如下:

读取数据

BOOL CSerialPort::ReadData(unsigned char* cDest,unsigned int iDataCount)
{
if(iDataCount>m_iRecCounter)
{
m_iRecCounter=0;
m_iReadPointer=0;
return FALSE;
}

unsigned int i,j;
j=0;
for(i=0;i<iDataCount;i++)
{
cDest[i]=m_szRecBuffer[m_iReadPointer++];
if(m_iReadPointer>=REC_BUFSIZE)
m_iReadPointer=0;
}
m_iRecCounter-=iDataCount;

return TRUE;
}


打开串口


void CExMessage::Open()
{
// 串口初始化
m_SerialPort.InitPort(this,(UINT)5,38400,'N',8,1,EV_RXFLAG | EV_RXCHAR,512);
// 启动串口监视线程
m_SerialPort.StartMonitoring();

}


发送数据

void CExMessage::Send()
{
char send[11] = {0x4D,0x45,0x41,0x53,0x3A,0x56,0x4F,0x4C,0x54,0x3F,0x0A};
// 发送数据
m_SerialPort.WriteToPort(send,11);
::SendMessage(this->m_hWnd, WM_COMM_CTS_DETECTED, 0, (LPARAM)OnComm());
}

OnCom事件

LRESULT CExMessage::OnComm()
{
CString Receive = _T("");
unsigned char str[100];
memset(str,'\0',100);
//m_SerialPort.GetRec()获取接收缓冲区内的字节数
if(!m_SerialPort.ReadData(str,m_SerialPort.GetRec()))
{
// 复位串口
m_SerialPort.ResetComport();
AfxMessageBox(L"错误:实际读取字节个数大于缓冲区字节个数!");
return 0;
}

Receive =str ;

m_fVoltage = CStringToFloat(Receive);
return 0;
}
...全文
2146 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
C_yjun 2014-01-15
  • 打赏
  • 举报
回复
结贴了,谢谢大家的帮助,虽然问题没有很好的解决,但是换一种方式却解决了。可能是基础原因吧,你们讲解的不能完全掌握。 利用下面的消息。

BEGIN_MESSAGE_MAP()
END_MESSAGE_MAP() 
线程和缓冲区有时间,应该去好好看看。再次谢谢大家!
C_yjun 2014-01-14
  • 打赏
  • 举报
回复
引用 17 楼 baichi4141 的回复:
如果你是被SerialPort类限制了,那就抛弃它 说白了读写串口不过就是ReadFile和WriteFile而已,开个线程建个循环完事
你说的很有道理,但是不太怎么会实现。算了,我还是用MFC类来实现,用BEGIN_MESSAGE_MAP() END_MESSAGE_MAP() 来发送消息。还要去想想如果控制读取的数据的字节个数。
baichi4141 2014-01-14
  • 打赏
  • 举报
回复
如果你是被SerialPort类限制了,那就抛弃它 说白了读写串口不过就是ReadFile和WriteFile而已,开个线程建个循环完事
baichi4141 2014-01-14
  • 打赏
  • 举报
回复
引用 14 楼 u011534805 的回复:
你说的有道理,我刚接触串口通信不太久,太深的东西自己也不太了解。但是我试了下按照你的方法,设置300ms但是还是一样的。其实用BEGIN_MESSAGE_MAP() END_MESSAGE_MAP() 来发送消息就能很好的解决这个问题,但是我这边接收的数据不统一,不好设置触发的字节数,我用的是SCPI协议,来测电压,但电压为1~9V时读取7位,10~99V时读取8位,以此类推。所以我用了SendMessage发送消息,也去掉了触发OnCom事件的消息,想问下当所读取的字节个数不统一时怎么解决。不能设置接收一个字节来接收,这样在ReadData中也会只接收一个字节。虽然在串口监听中可以看到数据已经上来了。但是ReadData做了处理,几个字节触发就只接收几个字节。如果接收的字节大于触发的字节,则获取不到数据
缓冲区是操作系统管理的,你不能控制接收几个字节,只能控制你读取几个字节,缓冲区的数据是在你没有去读取的时候操作系统一点一点攒起来的,对于不确定字节数的接收情形,你就该不依赖操作系统在缓冲区自动攒数据,而是不停去读缓冲区在你自己的内存里攒起来,并不停尝试当前攒的这些数据是否已经符合某种返回格式
baichi4141 2014-01-14
  • 打赏
  • 举报
回复
引用 14 楼 u011534805 的回复:
你说的有道理,我刚接触串口通信不太久,太深的东西自己也不太了解。但是我试了下按照你的方法,设置300ms但是还是一样的。其实用BEGIN_MESSAGE_MAP() END_MESSAGE_MAP() 来发送消息就能很好的解决这个问题,但是我这边接收的数据不统一,不好设置触发的字节数,我用的是SCPI协议,来测电压,但电压为1~9V时读取7位,10~99V时读取8位,以此类推。所以我用了SendMessage发送消息,也去掉了触发OnCom事件的消息,想问下当所读取的字节个数不统一时怎么解决。不能设置接收一个字节来接收,这样在ReadData中也会只接收一个字节。虽然在串口监听中可以看到数据已经上来了。但是ReadData做了处理,几个字节触发就只接收几个字节。如果接收的字节大于触发的字节,则获取不到数据
循环读取,每次读一个字节,自己保存处理 你这种设定字节数的用法只适用于最简单的情形,别的不说,假如对方设备有错误处理,如果执行成功返回5个字节(内含数据)执行失败返回3个字节(内含错误码),你这种方法就死定了
C_yjun 2014-01-14
  • 打赏
  • 举报
回复
引用 13 楼 baichi4141 的回复:
[quote=引用 8 楼 u011534805 的回复:] [quote=引用 7 楼 baichi4141 的回复:] 简单地说,你每次发送数据之后,要等待一段时间才有返回数据 串口通讯都是低速设备,别以为你两条语句那点时间足以让串口完成发送处理返回这么一大堆任务 因为你每次发送之后立刻处理数据,自然第一次没有数据,第二次处理的是第一次慢悠悠返回的数据,以此类推
不好意思!现在在看到。 是不是在发送和读取之间需要有点延迟... 我发现在接收缓冲区,好像没及时更新,接收的数据还是长次的[/quote] 嗯,需要有点延迟,发送后等个两三百毫秒就行了 说到底,楼主还是不明白串口到底是个什么东西 楼主是不是以为自己WriteToPort(send,11)之后,数据就发出去了?错!你的函数本质上只是告诉操作系统“我要发这些数据”,什么时候发怎么发是操作系统决定的,你只能通知它却无权控制它!接收数据也是,楼主你询问的是操作系统的缓冲区,操作系统接不接受数据何时接收数据接收多少数据你管不着! 假定WriteToPort(send,11);这条语句用了3毫秒执行完成(当然不可能这么慢,举例子而已),然后呢?操作系统也许要等个5毫秒才会处理你交给它的数据,发送花个20毫秒,那边的设备要收到数据后等待10ms的空窗期才能判断收到了全部数据,花个10毫秒处理,再返回20毫秒,操作系统接收后再保存到缓冲区,等着你不知道什么时候突然心血来潮读取一下子…… 现在你明白写串口后立刻读取是多么荒谬的想法了吗?现在你明白为什么你第二次读读到的是第一次返回的数据了吗?因为你第一次读数据的时候,很可能操作系统甚至还没把你刚交给它的数据发送出去!等到你第一次读完了干别的去了,操作系统这边才慢慢的发数据收数据直到把第一次返回的数据接收完全,然后你又来写了第二次数据,没等操作系统发出去呢又要读数据,你说操作系统能交给你什么数据?除了第一次返回的数据外它还有什么可交给你的? 串口是低速设备,如果是单方向的发送那效率还算过得去,一来一回的交互,每秒钟最多几十条,和程序的执行速度完全不是一个数量级。 原理就这么简单。[/quote] 你说的有道理,我刚接触串口通信不太久,太深的东西自己也不太了解。但是我试了下按照你的方法,设置300ms但是还是一样的。其实用BEGIN_MESSAGE_MAP() END_MESSAGE_MAP() 来发送消息就能很好的解决这个问题,但是我这边接收的数据不统一,不好设置触发的字节数,我用的是SCPI协议,来测电压,但电压为1~9V时读取7位,10~99V时读取8位,以此类推。所以我用了SendMessage发送消息,也去掉了触发OnCom事件的消息,想问下当所读取的字节个数不统一时怎么解决。不能设置接收一个字节来接收,这样在ReadData中也会只接收一个字节。虽然在串口监听中可以看到数据已经上来了。但是ReadData做了处理,几个字节触发就只接收几个字节。如果接收的字节大于触发的字节,则获取不到数据
baichi4141 2014-01-13
  • 打赏
  • 举报
回复
引用 8 楼 u011534805 的回复:
[quote=引用 7 楼 baichi4141 的回复:] 简单地说,你每次发送数据之后,要等待一段时间才有返回数据 串口通讯都是低速设备,别以为你两条语句那点时间足以让串口完成发送处理返回这么一大堆任务 因为你每次发送之后立刻处理数据,自然第一次没有数据,第二次处理的是第一次慢悠悠返回的数据,以此类推
不好意思!现在在看到。 是不是在发送和读取之间需要有点延迟... 我发现在接收缓冲区,好像没及时更新,接收的数据还是长次的[/quote] 嗯,需要有点延迟,发送后等个两三百毫秒就行了 说到底,楼主还是不明白串口到底是个什么东西 楼主是不是以为自己WriteToPort(send,11)之后,数据就发出去了?错!你的函数本质上只是告诉操作系统“我要发这些数据”,什么时候发怎么发是操作系统决定的,你只能通知它却无权控制它!接收数据也是,楼主你询问的是操作系统的缓冲区,操作系统接不接受数据何时接收数据接收多少数据你管不着! 假定WriteToPort(send,11);这条语句用了3毫秒执行完成(当然不可能这么慢,举例子而已),然后呢?操作系统也许要等个5毫秒才会处理你交给它的数据,发送花个20毫秒,那边的设备要收到数据后等待10ms的空窗期才能判断收到了全部数据,花个10毫秒处理,再返回20毫秒,操作系统接收后再保存到缓冲区,等着你不知道什么时候突然心血来潮读取一下子…… 现在你明白写串口后立刻读取是多么荒谬的想法了吗?现在你明白为什么你第二次读读到的是第一次返回的数据了吗?因为你第一次读数据的时候,很可能操作系统甚至还没把你刚交给它的数据发送出去!等到你第一次读完了干别的去了,操作系统这边才慢慢的发数据收数据直到把第一次返回的数据接收完全,然后你又来写了第二次数据,没等操作系统发出去呢又要读数据,你说操作系统能交给你什么数据?除了第一次返回的数据外它还有什么可交给你的? 串口是低速设备,如果是单方向的发送那效率还算过得去,一来一回的交互,每秒钟最多几十条,和程序的执行速度完全不是一个数量级。 原理就这么简单。
C_yjun 2014-01-13
  • 打赏
  • 举报
回复
引用 11 楼 AfterSeptember 的回复:
我之前做串口通信的时候好像也碰到过这个问题,忘记怎么解决的了。= =
未注销 2014-01-13
  • 打赏
  • 举报
回复
我之前做串口通信的时候好像也碰到过这个问题,忘记怎么解决的了。= =
C_yjun 2014-01-13
  • 打赏
  • 举报
回复
引用 9 楼 hdg3707 的回复:
你接收完数据并处理(比如显示)后就清除接收缓冲,看看是不是你接收太快导致接收超时退出才继续显示上一次的数据

不是接收太快,而是没上来。我在下面设置断点

发送两次以后再触发断点,结果触发的这次根本没有数据上来
hdg3707 2014-01-13
  • 打赏
  • 举报
回复
你接收完数据并处理(比如显示)后就清除接收缓冲,看看是不是你接收太快导致接收超时退出才继续显示上一次的数据
C_yjun 2014-01-13
  • 打赏
  • 举报
回复
引用 7 楼 baichi4141 的回复:
简单地说,你每次发送数据之后,要等待一段时间才有返回数据 串口通讯都是低速设备,别以为你两条语句那点时间足以让串口完成发送处理返回这么一大堆任务 因为你每次发送之后立刻处理数据,自然第一次没有数据,第二次处理的是第一次慢悠悠返回的数据,以此类推
不好意思!现在在看到。 是不是在发送和读取之间需要有点延迟... 我发现在接收缓冲区,好像没及时更新,接收的数据还是长次的
baichi4141 2014-01-13
  • 打赏
  • 举报
回复
简单地说,你每次发送数据之后,要等待一段时间才有返回数据 串口通讯都是低速设备,别以为你两条语句那点时间足以让串口完成发送处理返回这么一大堆任务 因为你每次发送之后立刻处理数据,自然第一次没有数据,第二次处理的是第一次慢悠悠返回的数据,以此类推
C_yjun 2014-01-13
  • 打赏
  • 举报
回复
引用 5 楼 shen_wei 的回复:
Send() 之后,立即 ReadData()
可以这样说把,应为执行下面这句就会直接调用OnCom函数。 ::SendMessage(this->m_hWnd, WM_COMM_CTS_DETECTED, 0, (LPARAM)OnComm());
shen_wei 2014-01-13
  • 打赏
  • 举报
回复
Send() 之后,立即 ReadData()
C_yjun 2014-01-13
  • 打赏
  • 举报
回复
引用 3 楼 shen_wei 的回复:
cDest[i] 看这个里面的值是否每次都改变 、 、
每次都会有数据上来,但是上来的数据不是本次的,而是上次发送返回的数据。 如: 第一次发送程序中没数据上来,但是监听软件中有数据。 第二次发送后,却读取的第一次发送时返回的数据。 数据不同步?找不到原因。
shen_wei 2014-01-13
  • 打赏
  • 举报
回复
cDest[i] 看这个里面的值是否每次都改变 、 、
C_yjun 2014-01-13
  • 打赏
  • 举报
回复
引用 1 楼 zhuyf87 的回复:
在ReadData中设置一个段点,单步调试一下。
单步有数据上来。单步只能看到有没有数据返回,却不能判断是哪次发送的数据.
zhuyf87 2014-01-13
  • 打赏
  • 举报
回复
在ReadData中设置一个段点,单步调试一下。

16,470

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧