异步串行通信,如何得知数据真正发送完毕? ( 积分: 200 )

  • 主题发起人 主题发起人 叮叮当当
  • 开始时间 开始时间

叮叮当当

Unregistered / Unconfirmed
GUEST, unregistred user!
我是搞工控的,写串口通信程序几年了,但是一直没能解决这个问题。<br><br>搞过工控的朋友应该知道,在422多机通讯时(一台计算机与多台单片机通讯),需要使用串行口的RTS来控制数据的发送。网络中的某台机器需要发送数据时,先把RTS打开,数据发送完毕后,关闭RTS,同一时刻只能有一台机器打开RTS发送数据,否则就会造成发送冲突。<br><br>因此需要在发送前打开RTS,这是很简单的,因为程序知道何时开始发送数据,但是在发送完后要及时关闭RTS,这却很难做到,因为Windows下的串行通信,好像都是把要发送的数据塞到Windows的串口缓冲区里面,Windows的驱动程序会自动完成缓冲区内数据的发送,具体什么时候完全发完,就不得而知了。<br><br>我用过很多串行通信控件,它们一般都有个发送缓冲区空的事件(比如TMS Async32控件是OnTxEmpty()),但是当这些事件触发时,只不过是发送缓冲区空了,可能串行口还在把最后的数据一位一位地移出呢,数据并没有真正的发送完毕,如果这时关闭RTS,就会造成最后一些数据无法正确发出,目标机器就会遗漏这些数据。我采取的做法是在发送函数返回后,或者发送缓冲区空事件中,人为延迟一段时间,再关闭RTS。这样虽然可以勉强过关,但发送的数据长度和波特率不同,就会造成所需的延迟时间不同,这很难准确计算。更糟糕的是,Windows的运行速度、程序的优先级似乎都会对一批数据的发送时间造成影响,靠估算最后数据的发出时间,实在很渺茫。因此我需要一个也许是底层的方法,来得到数据真正发送完毕的通知。<br><br>其实串口内部有一个移位寄存器,通过端口操作对这个寄存器的状态进行判断,就能知道数据有没有发送完毕。以前在DOS下用汇编语言进行串口编程的时候,发送和接收缓存由应用程序自己实现,每次只发送和接收1个字节,就是通过判断这个移位寄存器的状态来保证当1个字节完整发送完毕之后才再发送剩余的字节。现在Windows完全接管了对硬件的直接控制权,自行实现串口硬件的发送和接收操作,和访问这个移位寄存器都成了不可能的事。。
 
我是搞工控的,写串口通信程序几年了,但是一直没能解决这个问题。<br><br>搞过工控的朋友应该知道,在422多机通讯时(一台计算机与多台单片机通讯),需要使用串行口的RTS来控制数据的发送。网络中的某台机器需要发送数据时,先把RTS打开,数据发送完毕后,关闭RTS,同一时刻只能有一台机器打开RTS发送数据,否则就会造成发送冲突。<br><br>因此需要在发送前打开RTS,这是很简单的,因为程序知道何时开始发送数据,但是在发送完后要及时关闭RTS,这却很难做到,因为Windows下的串行通信,好像都是把要发送的数据塞到Windows的串口缓冲区里面,Windows的驱动程序会自动完成缓冲区内数据的发送,具体什么时候完全发完,就不得而知了。<br><br>我用过很多串行通信控件,它们一般都有个发送缓冲区空的事件(比如TMS Async32控件是OnTxEmpty()),但是当这些事件触发时,只不过是发送缓冲区空了,可能串行口还在把最后的数据一位一位地移出呢,数据并没有真正的发送完毕,如果这时关闭RTS,就会造成最后一些数据无法正确发出,目标机器就会遗漏这些数据。我采取的做法是在发送函数返回后,或者发送缓冲区空事件中,人为延迟一段时间,再关闭RTS。这样虽然可以勉强过关,但发送的数据长度和波特率不同,就会造成所需的延迟时间不同,这很难准确计算。更糟糕的是,Windows的运行速度、程序的优先级似乎都会对一批数据的发送时间造成影响,靠估算最后数据的发出时间,实在很渺茫。因此我需要一个也许是底层的方法,来得到数据真正发送完毕的通知。<br><br>其实串口内部有一个移位寄存器,通过端口操作对这个寄存器的状态进行判断,就能知道数据有没有发送完毕。以前在DOS下用汇编语言进行串口编程的时候,发送和接收缓存由应用程序自己实现,每次只发送和接收1个字节,就是通过判断这个移位寄存器的状态来保证当1个字节完整发送完毕之后才再发送剩余的字节。现在Windows完全接管了对硬件的直接控制权,自行实现串口硬件的发送和接收操作,和访问这个移位寄存器都成了不可能的事。。
 
为何不直接采用 CTS/RTS 握手协议呢?<br>如果你希望当数据真正发送完就关闭RTS,那么这个过程可让机器内部自动完成的。
 
想楼上2为大哥学习,我刚开始学习搞工控,希望以后多多指教
 
TO: SupermanTm<br><br>真的可以吗?是不是在初始化串口的时候进行设置?能否给个例子?<br>谢谢!!
 
不要用CTS/RTS直接用235,
 
是在初始化串行口就设置的,通常的串行口控件(SPCOMM,TCOMPORT)等都有HandShake属性的,设置为 CTS/RTS 就可以了。<br>此外,如果硬件是你自己设计的,也可以考虑 41426277兄的建议,不用硬件握手,自己订立软件协议,这样的程序容易维护而且可以移植到使用USB-UART的串行口。
 
看看完成端口,说不定可以
 
会在结束的时候通知
 
TO:41426277<br>235是什么?<br><br>TO:SupermanTm<br>你说的用CTS/RTS协议我去试一下,请问使用USB-UART的串行口(USB转串口线?)就不支持CTS/RTS握手协议吗?<br><br>TO:zealothasu<br>你说的完成端口是以太网的概念,这里是讨论串行通信,不相干吧。
 
完成端口适用于操作file之类的异步操作,好处是调用直接返回,操作系统在操作完成的时候通知你,具体会不会像你说的在塞到缓冲区就返回我就不知道了,<br>[red]记住:完成端口不是仅仅使用在以太网,而是使用在异步操作上[/red]
 
SPCOMM 有一个 OnSendDataEmpty 事件,<br>还有一个 SendDataEmpty 属性表明缓冲区数据是否发完。<br><br>这两个对你的应用没有作用吗?
 
我在实际的应用中 2 3 5 总线方式,<br>下接设备40多个时,用SPCOMM通讯,用到了 SendDataEmpty 属性<br>应用还算成功。
 
TO: darnis<br>SPCOMM以及它的那个 OnSendDataEmpty()事件和属性我都用过,并不是真正的数据发送结束。你用的是普通232通讯吧,没有RTS的问题的。
 
呵,我用的是232转422(还是485?我搞不清),我计算机上的应用确实是只关心232通讯<br>硬一点东西我搞不清楚。<br>不过你所说的问题,应该可以用协议来解决,我感觉,<br><br>因为我做的那个应用当时也出现过很多问题,<br>后来把协议修改一下,比如,当时我的应用里面,下位机接受的有命令报文,有数据报文,<br>每一种报文都要求收到回应才认为我的数据已经正确地传送到了下位机,<br>最初是这样,也出问题,是因为数据报比较大时有一定机率会与命令报匹配上,导致非预想的错误。<br>为了解决这个问题,又改了协议,把所谓的多机通讯功能用上,也就是把数据帧的第9位用上了(不知道算不算多机通讯功能位)。后来才总算通讯稳定了。
 
TO:SupermanTm<br>你说的使用RTS/CTS流控制确实有在发送时自动开关RTS的作用!<br>我用TMS Async32 TVaComm控件做了测试,发现在初始化的时候,将FlowControl.ControlRts设为rtsToggle可以有这样的效果,以后再也不用手动控制RTS了,哈哈!谢谢你,非常感谢!!<br><br>也谢谢大家的关注和帮忙提帖!
 
后退
顶部