串口数据丢失_串口丢失数据 - CSDN
精华内容
参与话题
  • 串口通信的一般思路是:先接收数据,然后处理数据,并在数据处理之后再次等待接收新的数据。但这种方法的缺点是,在串口高速率大信息量通信时,会出现丢失数据的...因此,只是增加缓存的容量不能解决数据丢失的根本...

    串口通信的一般思路是:先接收数据,然后处理数据,并在数据处理之后再次等待接收新的数据。但这种方法的缺点是,在串口高速率大信息量通信时,会出现丢失数据的情况。
    丢失数据的原因是数据接收和数据处理再同一个线程中,如果数据处理的时间太长,则来不及接收的数据只能暂存在缓存中。因此,一旦缓存满了,新到的数据就会冲刷掉未来得及接收的数据,从而造成数据的丢失。因此,只是增加缓存的容量不能解决数据丢失的根本问题。
    解决思路:

    数据接收与数据处理分别放在两个线程中进行;

    数据接收线程:接收数据并将接收到的数据存入数据池中;

    数据处理线程:从数据池中读取数据和处理数据;

    注意:
    由于两个线程可能会同时访问数据池,因此为了使数据接收得到最快的响应,最好不选用数组结构,而是选用队列Queue作为数据池的数据结构。
    队列在顺序存储方面非常有用。数据对象在队列的一段插入,另一端移除。当两个线程同时访问队列时,一个线程负责数据存入,另一个线程只负责操作数读取,就会提高程序的运行效率。
    代码:

    数据接收线程:

    ReceiveThread()
    {
         string str = serialport.ReadExisting();   //从串口读取数据
         queue.Enqueue(str);  //将数据存入队列
    }
    

    数据处理线程:

    DealDataThread()
    {
          if(queue.Count >=1)
          {
                  string data = queue.Dequeue();  //将数据出队
                  DealWithReceiveData( data );  //处理数据
           }
    }
    
    展开全文
  • Qt以前的版本中,没有提供官方的对RS232串口的支持,编写串口程序很不方便。现在好了,在 Qt5.1 中提供了QtSerialPort模块,方便编程人员快速的开发应用串口的应用程序。 Qt5 serialPort存在的问题。

    什么是Qt5 serialPort?

    虽然现在大多数的家用PC机上已经不提供RS232接口了。但是由于RS232串口操作简单、通讯可靠,在工业领域中仍然有大量的应用。Qt以前的版本中,没有提供官方的对RS232串口的支持,编写串口程序很不方便。现在好了,在 Qt5.1 中提供了QtSerialPort模块,方便编程人员快速的开发应用串口的应用程序。

    Qt5 serialPort存在的问题。

    在项目中需要编写一个上位机串口接受数据,结果发现接受数据时,使用Qt5serialport会丢失数据。编写程序时参考文章。
    http://blog.csdn.net/u014695839/article/details/50611549
    然后换用多个版本任然存在此问题。

    解决方式。

    使用第三方库qextserialport ,使用这个比较古老的库就不会出现本文所述问题。使用这个库可以参考
    http://blog.csdn.net/u010580186/article/details/51595227
    这篇文章,这篇文章详细介绍了如何使用。包括加入.h文件,以及加入.cpp文件等。可以先参考第一部来测试是否丢失数据。

    如何判断是否丢失数据?

    我在上面提到的博文中优化了显示数据,即是可以显示看到是否有数据。数据是否丢失,使用qDebug方法
    void MainWindow::readMyCom() //读串口函数
    {
    //	qDebug() << "进入";
    	
    	if (myCom->bytesAvailable() >= 56)
    	{
    		qDebug() << "1";
    		QByteArray temp = myCom->readAll();
    		//读取串口缓冲区的所有数据给临时变量temp
    		ui->textBrowser->insertPlainText(temp);
    		qDebug() << temp;
    		//将串口的数据显示在窗口的文本浏览器中
    
    		QDataStream out(&temp, QIODevice::ReadWrite);   //将str的数据 读到out里面去
    															   //  QVector <QString> tempstr;
    		QString tempstr[112];
    		// QString buf;
    		int i = 0;
    		while (!out.atEnd())
    		{
    			qint8 outChar = 0;
    			out >> outChar;   //每次一个字节的填充到 outchar
    							  //           qDebug()<<outChar;
    							  //           QString str = QString("%1").arg(outChar&0xFF,2,16,QLatin1Char('0')).toUpper();// + QString(" ");   //2 字符宽度
    
    							  //           tempstr[i] << str;
    			tempstr[i] = QString("%1").arg(outChar & 0xFF, 2, 16, QLatin1Char('0')).toUpper();
    			//qDebug() << "******";
    			//qDebug() << tempstr[i];
    			//qDebug() << "******";
    			if (i<56)
    				i++;
    		}
    		for(int i = 0; i < 96; i++)
    			qDebug()<<tempstr[i];
    	}
    }
    

    同时还要注意串口是串口几,博文默认的是串口1,但是我的是串口3因此需要改动
    myCom = new Win_QextSerialPort("com3", myComSetting, QextSerialBase::EventDriven)



     

    展开全文
  • 刘凯 周云耀 武汉理工大学信息工程学院 武汉市...但在实际串口通信的应用中,在串口高波特率大信息量的数据通信时,会出现丢失数据的问题。此时如果只是增加串口类的缓存容量是不能根本解决问题的。本文就

    刘凯 周云耀

    武汉理工大学信息工程学院 武汉市(430070

    E-mail: lk.6@163.com

    摘要:C # 串行类( SerialPort ).NET Framework version 2.0中一个新增的类,该类将串口操作了封装,从而为串口通信提供了简便方法,而且具有功能强大、通信快速、实时性好等特点。但在实际串口通信的应用中,在串口高波特率大信息量的数据通信时,会出现丢失数据的问题。此时如果只是增加串口类的缓存容量是不能根本解决问题的。本文就是从此实际中遇到的问题出发,分析了问题形成的原因,并结合实际开发的经验,给出了一种解决问题的方法。

    关键词:C# 串行类 丢失数据 队列

    中图分类号:TP311

                  1.

    前言

    C # 串行类( SerialPort ) Visual Studio 2005 中一个新增的类,它为应用程序提供了通过串口收发数据的简便方法。C # 串行类具有功能强大、通信快速、实时性好等特点[1]。该类用于控制串行端口文件资源,提供同步 I/O 和事件驱动的 I/O、对管脚和中断状态的访问以及对串行驱动程序属性的访问。SerialPort 类支持:ASCIIEncodingUTF8Encoding等几乎所有编码格式2

    2.

    C#串口通信的一般实现方法及潜存的问题

    串口有两种读取方式,一种是同步的,另外一种就是基于事件的异步读取方式。因为同步接收会阻塞线程所以在大数据量通信时常采用异步方法读取。

    在通信之前要对串口对象做一个初始化,这包括设置PortName(串口号)、BaudRate(波特率)、Parity(奇偶校验)、DataBits(数据位数)等,在此就不赘述了。

    由于SerialPort类的封装,屏蔽了很多通信细节。所以异步串口通信的实现逻辑很简单。我们只须要为SerialProt类的DataReceived事件绑定一个处理函数,然后就可以在该函数中实现对串口数据的读取。假设该函数名为GetStrFromPort,其实现示例如下。

    Public void GetStrFromPort( object sender, SerialDataReceivedEventArgs e )

    {

    string str = null;

     

    str = serialprot.ReadTo( "/n/r" ); //读到该帧数据结束处

    serialport.DiscardInBuffer(); //清除缓存中的内容

    DealWithProtStr( str ); //处理接收到的数据

    }


    - 1 -

    大多串口程序都会采用这种思路来实现串口通信。即先接收数据,然后处理数据,并在完成数据处理后,再次等待接收新数据。但这种实现方法在串口高速率大信息量通信时,会出现丢失数据的情况。

    数据丢失的原因在于数据接收与数据处理同在一个线程中,如果数据处理时间较长,来不及接收的数据只能暂存于缓存中。一旦缓存满了,新到的数据就会冲刷掉未来的及接收的数据,从而造成数据的丢失。此时如果只单单增加缓存的容量是不能根本解决问题的。这也是我们在实际应用中遇到的问题。

                  3.

    丢失数据问题的解决办法

    有鉴于此,我们解决问题的思路就是将数据接收与数据处理分离开来,使数据接收得到最快的时间响应。通过在实际中的反复实验,我们最终采用了多线程加数据池来解决此问题。

    设计思路如下:数据接收与数据处理分别在两个线程中进行,数据接收线程负责数据接收并将接收的数据存入数据池中;数据处理线程负责从数据池中读取数据和处理数据。程序设计思路如图1-1所示。

    由图1-1可以看出,两个线程有可能会同时访问数据池。因此为使数据接收得到最快的时间响应,最好不要选用像数组这样数据结构。因为此类数据结构在多线程中操作时必须频繁地加锁解锁,在一定程度上会降低程序的性能。所以我们选用队列Queen作为数据池的数据结构。

    队列在顺序存储方面非常有用。数据对象在队列的一端插入,另一端移除。而且当两个线程同时访问队列,如果一个线程只负责数据存入,另一个线程只负责操作数据读取时,不会出现多线程的资源争用的问题,所以不必使用加锁解锁操作,从而提高了程序的运行效率。

     

    1-1 多线程加数据池模式的串口通信设计示意图


    http://www.paper.edu.cn

           

    下面是程序的伪代码。

    数据接收线程:

    ReceiveThread() { string str = ReceiveFormPort(); //从串口读取数据 queue. Enqueue( str ); //将数据存入队列 }

    数据处理线程

    DealData()

    {

    while( true ) //循环检测队列

    {

    if( queue.Count >= 1 ) //队列中有数据

    {

    string data = queue.Dequeue(); //将数据出队

    DealWithReceiveData( data ); //处理数据

    }

    }

    }

    通过这种多线程加数据池的方法,我们就可以将数据接与数据处理独立开来,从而使串口接收事件得到最快的速度响应。从而达到我们消除丢失数据的问题。

    4.

    结束语

    通过利用多线程和数据池,我们解决了C#串口类,在高波特率通信时丢失数据的问题。该设计模式是非常强健的。它在处理高速串口通信时能够最大程度的保证通信的正确性。

     

    参考文献:

    [1] Schildt H. C # 完全手册》 [M]. 北京:电子工业出版,2005

    [2] Microsoft. MSDN 2005(Microsoft Developer Network)

    [3] Robison S, Harvey B.Profession C # [M]. America: Wrox Press Inc, 2005.

    [4] 李渊博. 《基于WindowsCE.NET的串口通信及应用》.中国科技论文在线,2005

    展开全文
  • 1.串口初始化配置//串口二初始化配置 void usart2_init(u32 bound) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; //开启GPIO时钟和...

    1.串口初始化配置

    //串口二初始化配置
    void usart2_init(u32 bound)
    {
    	GPIO_InitTypeDef GPIO_InitStructure;
    	USART_InitTypeDef USART_InitStructure;
    	NVIC_InitTypeDef NVIC_InitStructure;
    	
    	//开启GPIO时钟和串口2时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    	
    	//配置串口2参数
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;//PA2:发送
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3:接收
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    	
    	//串口参数设置
    	USART_InitStructure.USART_BaudRate = bound;//波特率
    	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    	USART_InitStructure.USART_StopBits = USART_StopBits_1;
      USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
      USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
      USART_InitStructure.USART_Parity = USART_Parity_No;
      USART_Init(USART2, &USART_InitStructure);
    	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启中断,中断处理函数用于接收数据
      USART_Cmd(USART2, ENABLE);                    //使能串口 
    	
    	//NVIC内部中断向量管理配置
      NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
    	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化NVIC寄存器
    }
    

    2.利用串口发送数据

    //发送一个字符
    void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t ch)
    {
    	//发送一个字节数据到USART
    	USART_SendData(pUSARTx, ch);
    	
    	//等待发送数据寄存器为空
    	while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
    }
    
    //发送一个字符串
    void Usart_SendString(USART_TypeDef* pUSARTx, char* str)
    {
    	unsigned int k = 0;
    	do
    	{
    		//逐个字节发送
    		Usart_SendByte(pUSARTx, *(str + k));
    		k++;
    	}while(*(str + k) != '\0');
    	
    	//等待发送完成
    	while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET);
    }

    3.串口发送数据重定向到串口调试助手,输出调试信息。

    //重定义fputc函数 
    int fputc(int ch, FILE *f)
    {      
    	while((USART2->SR&0X40)==0);//循环发送,直到发送完毕   
            USART2->DR = (u8) ch;      
    	return ch;
    }

    4.串口接收数据

    u8 USART2_RX_BUF[USART_REC_LEN];   //串口二接收数据缓存
    u16 USART2_RX_STA = 0;//接收到的有效字节数目
    void USART2_IRQHandler(void)                    //串口2中断服务程序
    {
        u8 tmp;
        if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收中断
        {
            tmp = USART_ReceiveData(USART2);  //读取接收到的数据
            if(tmp != 0x00)
            {
                USART2_RX_BUF[USART2_RX_STA] = tmp;
                USART2_RX_STA++;
            }
      }
    } 
    

    这里需要定义两个全局变量,第一个是接收数据的缓存,第二个是数据计数器,用来统计接收到的数据的数量。注意,有人可能会想到我可不可以直接在中断处理函数内部做一些处理操作,我的建议是不要,而是通过上诉最简单的方式。原因有两个,第一,这种方式思路清晰,第二,这种方式不会出现数据因为处理延时而丢失的问题,毕竟串口通信还是比较快的过程,如果花费过多的时间在中断处理函数中,可能导致意想不到的后果。另外,调试串口接收数据的时候,可能会出现问题,因为调试的过程中你的程序中途暂停执行了,但是不能保证发送方也暂停执行,所以会漏掉部分信息,常见的就是调试的时候只出现了第一个字节的数据,这是因为前面说的,毕竟串口通信还是比较快的。另外,串口接收的基础是在串口初始化的时候将接收中断打开。

    //主函数中通过串口发送数据,同时检测是否有数据到来,如果有判断是否为OK,如果是,则退出循环,否则再次发送,直到发送成功
    do
    {
    	//发送数据
    	Usart_SendString(USART2, "AT");
    				
    	//等待接收成功后回应的结果
    	delay_ms(3000);
    				
    	printf("send status:");
    	//判断是否发送成功
    	while(j < USART2_RX_STA)
    	{
    		printf("%c", USART2_RX_BUF[j]);
    		if((USART2_RX_BUF[j-1] == 'O' || USART2_RX_BUF[j-1] == 'o') && (USART2_RX_BUF[j] == 'K' || USART2_RX_BUF[j] == 'k'))
    		{
    			flag = 1;//发送成功
    			USART2_RX_STA = 0;
    			j = 0;
    			break;
    		}
    		j++;
    	}
    }while(flag == 0);

    其中flag是一个标志,flag==0代表数据发送失败,flag==1代表数据发送成功,此时将退出循环发送程序。

    最后,硬件平台:stm32f103zet6

    展开全文
  • 串口接收时丢数据问题解决方案

    千次阅读 2019-04-13 13:13:40
    串口接收时丢数据问题解决方案
  • 串口通信丢失数据结局方案——C#

    千次阅读 2015-01-07 12:06:29
    串口通信的一般思路是:先接收数据,然后处理数据,并在数据处理之后再次等待接收新的数据。但这种方法的缺点是,在串口高速率大信息量通信时,会出现丢失数据的情况。  丢失数据的原因是数据接收和数据处理再同一...
  • 串口通信数据丢失的问题

    千次阅读 2017-06-06 11:45:59
    担任去中兴软创合作的项目,...昨天调试我写的串口通信程序,发现0x00的数据无法接收。在网上找了一下,发现有不少人有遇到这个问题。 今天早上来,把程序改过了,现在可以很好地接收到0x00数据了。   参考了一些资料 ...
  • STM32 串口数据丢失问题

    千次阅读 2012-07-04 15:03:58
    我的串口发送程序: USART_SendData(USART2, ‘c’);...打印出来的信息显示我的两个数据,要丢失一个。不管是但不还是同步。所以 在之前加上:USART_ClearFlag(USART2,USART_FLAG_TC);  USART_SendData(U
  • 采集后想将数据通过串口逐点输出到上位机,然后查看数据是否正确。AD7260是采用外部中断进行采集的,当AD7260的BUSY输出下降沿后,触发外部中断,这时CPU去采集数据串口输出部分,我先是这么做的:在中断中采集...
  • STM32串口第一个字节丢失问题的分析过程

    万次阅读 多人点赞 2014-11-10 23:39:21
    STM32 串口 发送 必须 先检测 状态,否则 第一个 字节 无法 发出,发送完毕,必须检测发送状态是否...接收端收到的数据为:0x02 0x03 0x04,第一个数据丢失。换成发送别的数值的数据,如0x06 0x0ff,则接收到0x0ff
  • STM32串口第一个字节丢失解决办法

    千次阅读 2017-02-08 11:56:50
    void USART_SendByte(USART_TypeDef* USARTx, uint8_t Data) { while(USART_GetFlagStatus(USARTx, USART_FLAG_TC)==RESET); USART_SendData(USARTx,Data); } while(USART_GetFlagStatus(USARTx, ... USART_F
  • 基于51 单片机的串口收发数据

    万次阅读 热门讨论 2018-10-23 20:43:00
    大多数51单片机用的都是11m晶振而只有少部分用的是奇葩的12m(楼主的就是),在12m晶振进行串口通信时切忌要将波特率设置为4800以下,应为12m晶振的波特率在9600以上误差很大容易丢失数据,动手能力强的可以折腾一下用...
  • 我现在要做一个全站仪的数据读取接口,由于不了解全站仪数据的发送方式,缓冲区大小该如何设置,才不会造成数据丢失? 比如我设置缓冲区大小为1024,我一次性发送2048个字节的数据,那么缓冲区只有1024个字节的数据,剩下...
  • arduino串口中断数据

    千次阅读 2018-12-14 20:45:16
    之前用arduino些串口接收都是这样子的 ... while (Serial.available()) //时刻读取硬件串口数据 { comdata += char(Serial.read()); delay(2); } while (Serial.read() &gt;= 0) {} //清除串口缓存 ...
  • 51单片机串口通信 环形缓冲区队列(FIFO)

    千次阅读 多人点赞 2017-01-08 20:45:40
    环形缓冲区队列最近在做毕业设计刚好涉及到51单片机,简单的研究一下发现51单片机串口只有一个字节的缓存,如果遇到单片机串口中断没有及时处理SBUF的值或者串口中断长时间未退出很容易照成数据丢失,于是就自己写了...
  • 我用zedboard的板子与PC机通信,用 ``` xil__printf ``` 打印中文时偶尔会出现乱码,用ascii码进行对照,...我的编码是GBK,通信协议115200, 8, n, 1 (8数据位,无校验位,1停止位)。 各位大侠有什么解法吗?
  • freeRTOS丢失串口数据

    千次阅读 2014-11-19 00:03:09
    说freeRTOS是刚好使用了freeRTOS,其实对于抢占
  • 最近在linux系统中写了个串口接收程序,发送端依次从0x00~0xFF发送字符,但接收端某些字符老接收不到,分析及其解决方法如下: 一、只接收到数据: 05 06 07 08 09 0a   解决此问题之前我们先看...
  • 安卓 串口读取数据遇到的问题

    千次阅读 2016-06-07 10:56:47
    安卓串口操作,在网上一定会找到很多关于谷歌的开源项目,把它的源码拿过来之后,经过编译发现无法读取数据。 接下来就是寻找收发数据失败原因的过程。 1、在Application中出现InvalidParameterException的...
  • 常用串口调试工具比较(详细)

    万次阅读 2018-03-30 08:55:43
    目前有许多免费的串口调试工具,比较常用的有:1、友善串口调试助手(v2.6.5)优点: 1)使用方便,不丢包; 2)串口自动识别,支持COM9以上串口; 3)支持多串口调试; 4)支持历史发送记录; 5)广泛支持各种...
1 2 3 4 5 ... 20
收藏数 11,311
精华内容 4,524
关键字:

串口数据丢失