你好,
造成串口数据丢失的原因有很多,比如硬件物理层链路的干扰、串口发送接收端串口参数配置不匹配等。
首先,可以用串口调试软件(这里)在PC端采用与LabVIEW相同的参数配置,验证一下硬件链路是否可靠,参数是否设置正确;
若测下来有问题,可考虑调整配置参数,改善串口连接线的抗干扰能力等方法解决。
若测下来一切OK,则考虑是否是程序的问题。
看到你程序中VISA Read的byte count设为50,不知道这样配置有什么原因吗?还有能否说明下蓝牙的数据格式是什么?这样有助于分析是否是程序造成了数据的丢失。
至于读30秒数据送去FFT的实现,个人认为可以使用FIFO Buffer。Buffer大小正好可以容纳30秒的数据。初始化的时候buffer清零。每次收到数据都添加到buffer中。每当数据添加后,即判断buffer是否满。如果是,则说明已经buffer中已经包含了当前时刻前30秒的采样点。这样即可使用buffer中的数据作为FFT的输入。由于是FIFO,用户不用考虑buffer溢出和删除过期数据的问题。
具体实现可以参考 Help>>Find Examples...>> Search "FIFO"的例子。
Good Luck~
非常感谢你的回答。
我蓝牙设备是把10位的AD转换的数据发送到PC,用的是PIC单片机,然后发送的时候是00**,****,**** 四位,四位发送,所以最大值应该是hex 3FF,最小值000。
Labview我只了解一点点, VISA Read的byte count设为50是随便设的,因为我要采集30秒或者60秒(最好可调)的数据,然后发送做FFT。不知道您能否帮我?
我用hyper ternimal来做串口通信,得到的结果是想要的结果,请参照
然后我用example里面的advanced visa write and read.vi,结果也是想要的1FF,但是,我尝试调节Wait Until Next ms Multiple Function的输入时,数据就会丢失。
再次感谢!
Baicy
你好,
请问当PC端程序运行时,蓝牙串口是否已经在发送数据?
如果是这样,那PC端程序一开始收到的第一个数据应该是不确定的。
如果蓝牙设备是在PC端程序运行后开始发送数据,可以试一下这样的scenario:
1. 运行程序,打开蓝牙设备串口,运行一段时间;
2. 停止程序运行(不关闭程序窗口);
3. 再次运行程序,并且不打开蓝牙设备串口;
如果此时程序还能接收到一些字符,则说明每次开始运行状态不一致可能是初始化没有清除receive buffer导致的。
这个问题可以通过VISA Flush I/O Buffer.vi 避免。 😉
我使用了VISA Flush I/O Buffer.vi来初始化清除receive buffer。
我的蓝牙设备的确在连接的时候就发送数据,也就是说在运行labview前就可以在发送数据。
所以问题没有解决。我在想是不是可以让蓝牙发送一个判断数据,然后再接受。 labview 只有在接收到这个判断的数据后才开始接受处理数据。
我可以修改控制蓝牙的单片机来发送这个数据,请问用labview 怎么样实现这个判断。
我不知道这样是否可行,多谢赐教。
我们可以自定义通信的协议来保持Master/Slaver之间通信的同步,方法有很多,这里仅提供一些思路供参考:
1. 简单的通信协议,来避免收到无效数据。
蓝牙设备(Slaver):初始化为[等待状态],接收PC端(Master)程序发送的串口数据;蓝牙设备接收到“开始发送命令”(某特定Byte or Bytes)后进入[数据发送状态],开始发送数据;在蓝牙设备在[数据发送状态]下轮询接收PC端的“停止发送命令”,一旦接收到该命令,进入[等待状态],停止数据发送。
PC端程序(Master):初始化,发送“开始发送命令”,接收数据,发送“停止发送命令”,程序结束。
2. 如果你的应用实时性要求不高,可以在蓝牙设备发送数据中间隔一段时间插入一个标志位(该标志位需与数据有区别)这样PC端程序可以将该字符串之后的接收到的数据作为有效数据,而丢弃该字符串之前的数据。
这种在数据中插入同步标志位的方法实现比较简单,PC端程序只需设置一标志位,并对接收到的每个数据加以判断,一旦发现同步标记,则将标志位置1,表示之后的数据位有效数据。
3. 前两种协议都比较简单。如果需要可靠地数据通信,可采用帧来发送数据,比如<CMD><DATA LEN><DATA><CRC 校验>,将若干个数据放在一帧中一起发送给PC。这样需要在蓝牙单片机和PC端LabVIEW程序上均实现帧的封装和解析函数,实现起来相比较之前两种方法复杂。
解决数据同步问题的方法有很多,可以权衡项目需求选择最适合的方法。 😉
我觉得第二个方案最简单。
蓝牙现在发送的数据格式是 00**,****,****,return.
所以我想检测到第一个return才开始接受数据,但是不知道怎么检测实现这个功能。可以用case,但是如何判断第一个return呢?
谢谢!
还有一个问题,我想要采集30秒的数据做fft,无论我怎么改循环的次数(300改到30000),显示的FFT的X轴从0-0.5,不是正确的频率读数。这又是什么原因?
谢谢
你好,
对于第一个问题,我认为比较适用生产者消费者模型(这里)。将VISA串口数据接收预处理(生产者)和数据分析FFT(消费者)分别放在两个while循环中,并用队列、信号量等手段实现循环间数据交换。
需要说明的是,在生产者循环中,串口接收的数据最好进行一下预处理再加入队列,这样可以提高消费者处理数据的效率。预处理的方法就是按逗号将接收到的字符串划分,将划分后的字符串作为单元放入队列。此外,对于边缘情况,比如read buff末尾的字符串,需将其与下一次read开始位置的字符拼接成新字符串,存放到队列中。
对于return关键词的判断,可以放在消费者循环中。首先,我们需要一个标志位,可以在消费者循环上添加一个shift register来实现,将其初始化为False。其次,在消费者循环中放入一个case语句,当shift register为false,则每当从队列读取出一个单元,就将其与return比较一下,若不等则对shift register传回false,若相等则传回true。当shift register为true,则执行300次采样的for循环,循环中执行string to uint转换并将其放入数据队列中。最后,在true case中for循环之后,执行FFT等操作。
对于你第二个问题。令F为FFT转换得到的X轴归一化频率;f为信号频率;T为采样周期;fs为采样频率。则有F = f * T = f / fs,F是相对于采样频率的一种归一化频率[-1/2,1/2] 。实际上,对模拟信号的采样,是无限范围的实际频率变量f,向有限范围的离散频率变量F的映射。所以f = F * fs = F / T。