这个SerialPort的写缓冲区怎么理解?那么写出去的数据有没有延时呢?如果写的数据不比传输速率快的话例如,下位机向计算机发出数据,要求上位机根据数据作出迅速反应作出指令,现在假设下位机就发出一个字节的数据,上位机也就是计算机根据这个数据立即写出指令数据也是一个字节,那么下位机从发出数据到接收到指令需要多长时间呢?假设串口波特率本身时间不算,有没有延时呢?例如对于标准波特率,下位机从发出数据结束到接收到数据的一开始,中间会有延时么?下位从发出数据结束等待例如100ms应该能确定受到反馈数据指令吧?如果中间有延时,那么这个延时一般是怎么引起的?机理是什么?能否确定一个范围?
谢谢

解决方案 »

  1.   

    3 使用 SerialPort 设置串口属性进行串口通讯时,需要设置一些相关参数,可以通过设置SerialPort 类的属性来进行。串口属性主要包括 .PortName 串口名称,COM1, COM2等。.BaudRate 波特率,也就是串口通讯的速度,进行串口通讯的双方其波特率需要相同,如果用PC连接其他非PC系统,一般地,波特率由非PC系统决定。.Parity 奇偶校验。可以选取枚举Parity中的值.DataBits 数据位.StopBits 停止位,可以选取枚举StopBits中的值.Handshake 握手方式,也就是数据流控制方式,可以选取枚举Handshake中的值4 打开与关闭串口在创建一个SerialPort 对象,设置串口属性后,可以通过 Open()方法打开串口。数据读写完成后,可以通过Close()方法关闭串口。根据经验,对于有些系统,在打开串口后,还需要将RtsEnable设置为True,这样才能读写数据,否则不能正常读写数据。5 读写行数据    双方通讯时,一般都需要定义通讯协议,即使最简单的通过串口发送文本聊天的程序。通常是在当一方按下回车时,将其所数据的文本连同换行符发给另一方。在这个通讯事例中,协议桢是通过换行符界定的,每一桢数据都被换行符隔开,这样就很容易识别出通讯双发发送的信息。 在以上的例子中,可以用WriteLine()来发送数据,用ReadLine()来读取数据。WriteLine发送完数据后,会将换行符作为数据也发送给对方。ReadLine()读取数据时,直至遇到一个换行符,然后返回一个字符串代表一行信息。换行符可以通过SerialPort 的属性NewLine来设置。一般地,Windows将CrLn作为换行符,而在Linux下,换行符则只用一个Ln表示。    ReadLine()方法是阻塞的,直至遇到一个换行符后返回。在读取数据时,如果一直没有遇到换行符,那么在等待ReadTimeout时间后,抛出一个TimeoutException。默认情况下,ReadTimeout为InfiniteTimeout。这样,ReadLine一直处于阻塞状态,直至有新一行数据到达。    WriteLine()方法也是阻塞的,如果另一方不能及时接收数据,就会引起TimeoutException异常。    由于ReadLine()和WriteLine()方法都是阻塞式的,在程序使用SerialPort 进行串口通讯时,一般应该把读写操作交由其他线程处理,避免因为阻塞而导致程序不响应。6 读写字节或字符数据    对于字节或字符数据,用Read()方法来读数据,该方法需要一个字节或字符数组作为参数来保存读取的数据,结果返回实际读取的字节或字符数。写数据使用Write()方法,该方法可以将字节数组、字符数据或字符串发送给另一方。    如果通讯双方交换的数据位字节流数据,要构建一个使用的串口通讯程序,那么双方应该定义数据桢格式。通常数据桢由桢头和桢尾来界定。    发送数据比较简单,只需要将构造好的数据用Write()方法发送出去即可。    接收数据则比较复杂,通讯是以字节流的形式到达的,通过调用一次Read()方法并不能确保所读取的数据就是完整一桢。因此需要将每次读取的数据整合在一起,对整合后的数据进行分析,按照定义的桢格式,通过桢头和桢尾,将桢信息从字节流中抽取出来,这样才能获取有意义的信息。    除了利用Read()方法来读数据,还可以使用ReadExisting()方法来读取数据。该方法读取当前所能读到的数据,以字符串的形式返回。7 事件    SerialPort 提供了DataReceived事件。当有数据进入时,该事件被触发。该事件的触发由操作系统决定,当有数据到达时,该事件在辅助线程中被触发。辅助线程的优先级比较低,因此并不能确保每个字节的数据到达时,该事件都被触发。    在使用该事件接收数据时,最好对定义通讯协议格式,添加桢头和桢尾。在DataReceived事件中接收数据时,把数据放在数组中或字符串中缓冲起来,当接收的包含桢头和桢尾的完整数据时,在进行处理,另外,为了有效地接收数据,可以在每次读取数据后,加入System.Threading.Thread.Sleep方法进行演示。8 其他    用跳线使串口的第2、3针连接,可以在本地计算机上实现串口通信,所以,通过串口的第2、3针的连接可以对程序进行检测。.BytesToRead 该属性返回能够读到的字节数。方 法 名 称 说  明Close 关闭端口连接,将 IsOpen 属性设置为False,并释放内部 Stream 对象Open 打开一个新的串行端口连接Read 从 SerialPort 输入缓冲区中读取数据字节数ReadByte 从 SerialPort 输入缓冲区中同步读取一个字节ReadChar 从 SerialPort 输入缓冲区中同步读取一个字符ReadLine 一直读取到输入缓冲区中的 NewLine 值ReadTo 一直读取到输入缓冲区中指定 value 的字符串 Write 已重载。将数据写入串行端口输出缓冲区WriteLine 将指定的字符串和 NewLine 值写入输出缓冲区DiscardInBufferDiscardOutBuffer清空接收缓冲区数据清空输出缓冲去数据属性说明名  称说  明BaseStream获取 SerialPort 对象的基础 Stream 对象BaudRate获取或设置串行波特率BreakState获取或设置中断信号状态BytesToRead获取接收缓冲区中数据的字节数BytesToWrite获取发送缓冲区中数据的字节数CDHolding获取端口的载波检测行的状态CtsHolding获取“可以发送”行的状态DataBits获取或设置每个字节的标准数据位长度DiscardNull获取或设置一个值,该值指示 Null 字节在端口和接收缓冲区之间传输时是否被忽略DsrHolding获取数据设置就绪 (DSR) 信号的状态DtrEnable获取或设置一个值,该值在串行通信过程中启用数据终端就绪 (DTR) 信号Encoding获取或设置传输前后文本转换的字节编码Handshake获取或设置串行端口数据传输的握手协议IsOpen获取一个值,该值指示 SerialPort 对象的打开或关闭状态NewLine获取或设置用于解释 ReadLine( )和WriteLine( )方法调用结束的值Parity获取或设置奇偶校验检查协议ParityReplace获取或设置一个字节,该字节在发生奇偶校验错误时替换数据流中的无效字节PortName获取或设置通信端口,包括但不限于所有可用的 COM 端口ReadBufferSize获取或设置 SerialPort 输入缓冲区的大小 ReadTimeout获取或设置读取操作未完成时发生超时之前的毫秒数ReceivedBytesThreshold获取或设置 DataReceived 事件发生前内部输入缓冲区中的字节数RtsEnable获取或设置一个值,该值指示在串行通信中是否启用请求发送 (RTS) 信号StopBits获取或设置每个字节的标准停止位数WriteBufferSize获取或设置串行端口输出缓冲区的大小 WriteTimeout获取或设置写入操作未完成时发生超时之前的毫秒数注意:C#中SerialPort类对串口供电需要设置DtrEnable和RtsEnable两个属性在开发中有些串口设备需要串口供电,使用C#中的SerialPort类默认情况下不会出发DataReceived函数,但使用超级终端却可以接收到数据,这是因为SerialPort类的DtrEnable和RtsEnable两个属性默认是false,设为true即可接收数据了,如下:this.m_SerialPort.DtrEnable = true; //启用控制终端就续信号this.m_SerialPort.RtsEnable = true; //启用请求发送信号
      

  2.   

    哇塞,复制能力好强!
    可以看看,还有示例
    http://msdn.microsoft.com/zh-cn/library/system.io.ports.serialport_methods.aspx
      

  3.   

    延时是有的,但相对于100ms来说是微不足道的。对于来回两个字节的通信来说,100ms绰绰有余了。如果通信失败,多数是程序的问题。你应该注意:
    1.如果用其它IO类包裹BaseStream,比如StreamWriter,则写入后要调用Flush,因为StreamWriter是有缓存的。
    2.如果在DataReceived事件中接收数据,应该要把缓存的数据都读出来(长度为BytesToRead),不要在事件中做其它耗时的操作。
    3.串口通信是不保证传输正确的,所以接收错误时,应该要有重新传输纠错的机制。
      

  4.   

    谢谢楼上
    我举例100ms是为了说明问题,当然我也知道可能要求10ms也没有问题,我就是想知道到底延时会有多少,是怎么影响的,例如计算机执行其它软件比较忙的时候(但是此COM端口是专用的),其机理是什么
      

  5.   

    延迟问题不好说,事实上也没测试过,如果楼主有心要测试,可以自己在程序中添加Thread.Sleep(1000)延迟下,看看会出现什么情况。
    缓冲区其实是硬件专有的,任何硬件都自带缓冲区,例如显卡的缓存,计算机的内存,CPU的高速缓存等。这里的串口也是一样,信息先保留在缓冲区中,如果缓冲区未清除,说明对方来不及接收,理论上是会阻止继续写入的,不过还是建议测试下。
      

  6.   

    首先接收数据时,硬件缓存会引起微秒级的延时。
    UART内部有FIFO硬件缓存,比如16550兼容的UART为1/4/8/14字节(更老的8250没有FIFO,但这种串口应该已经绝迹了,除非是模拟的)启用FIFO后,接受数据时,要凑够缓存容量或超时,才会发出中断请CPU处理,超时是8个RCLKs,RCLK时钟频率是16倍波特率,也就是说在9600波特率下,最多可能延迟0.05毫秒左右,更高波特率延迟更短。可以通过禁用FIFO缓存来及时响应接收到的数据。
      

  7.   

    9年前做过串口的东西,是单片机89c52与plc通信,rs485。当时没感觉到有数据发送延迟的问题。当时需要对接受数据进行超时判断,如果2个字符之间的时间间隔为3T即超时(T很小,和波特率成反比,可能是微秒/ms级).   不知道是否lz和plc通信时发生数据传送慢的问题? 如是这样那么好好看看plc的程序设置,应当有一个缓存多少字节发送的设置。好好看说明....