精华内容
下载资源
问答
  • 通过C#实现串口通信,里面的代码展示了如何监听计算机中的串口解析数据或者发送数据,做串口开发的可以参考
  • 1、实时解析串口数据并绘制相关曲线 | 2、串口单独一个进程(不影响GUI刷新) | 3、曲线、串口参数可配置、可保存
  • 此程序是基于对话框的MFC程序,能够做到串口实时通信,并且将数据展示到编辑框,而且并对获得的数据进行解析,主要处理的数据是GPGGA报文,安装环境请对照安装包提示,有问题可以发邮件交流学习,liaoby@jmev.com
  • 最近项目中接到一个需求,需要对接硬件流速仪,实时获取数据并保存到数据库.根据了解得到硬件支持XPH通讯、标准MODBUS通讯两种格式。支持RS-232、RS-485通讯总线。支持9600波特率. 在调试之前需要先要下载RXTX的jar包...

    最近项目中接到一个需求,需要对接硬件流速仪,实时获取数据并保存到数据库.根据了解得到硬件支持XPH通讯、标准MODBUS通讯两种格式。支持RS-232、RS-485通讯总线。支持9600波特率.

    在调试之前需要先要下载RXTX的jar包,win64位下载地址:链接:https://pan.baidu.com/s/1jGTbarFctOqEAsHh-4IfcA 提取码:7cu9 );将解压后的rxtxParallel.dll和rxtxSerial.dll两个文件放在C:\Windows\System32目录下,这样该包才能被正常的加载和调用。

    代码如下:

    
    
    
    import gnu.io.*;
    import org.springframework.boot.ApplicationArguments;
    import org.springframework.boot.ApplicationRunner;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.io.Serializable;
    import java.math.BigInteger;
    import java.util.*;
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.LinkedBlockingQueue;
    
    
    
    @Component
    @Order(value = 1)
    public class ContinueRead extends Thread implements SerialPortEventListener ,ApplicationRunner,Serializable { // SerialPortEventListener
        // 监听器,我的理解是独立开辟一个线程监听串口数据
    // 串口通信管理类
        static CommPortIdentifier portId;
    
        /* 有效连接上的端口的枚举 */
    
        static Enumeration<?> portList;
        InputStream inputStream; // 从串口来的输入流
        static OutputStream outputStream;// 向串口输出的流
        static SerialPort serialPort; // 串口的引用
        // 堵塞队列用来存放读到的数据
        private BlockingQueue<String> msgQueue = new LinkedBlockingQueue<String>();
        //用来存放原始数据
        static LinkedList<Double> linkedList = new LinkedList();
    
        @Override
        /**
         * SerialPort EventListene 的方法,持续监听端口上是否有数据流
         */
        public void serialEvent(SerialPortEvent event) {//
    
            switch (event.getEventType()) {
                case SerialPortEvent.BI:
                case SerialPortEvent.OE:
                case SerialPortEvent.FE:
                case SerialPortEvent.PE:
                case SerialPortEvent.CD:
                case SerialPortEvent.CTS:
                case SerialPortEvent.DSR:
                case SerialPortEvent.RI:
                case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
                    break;
                case SerialPortEvent.DATA_AVAILABLE:// 当有可用数据时读取数据
                    byte[] readBuffer = null;
                    int availableBytes = 0;
                    try {
                        availableBytes = inputStream.available();
                        while (availableBytes > 0) {
                            readBuffer = ContinueRead.readFromPort(serialPort);
                            String needData = printHexString(readBuffer);
                            System.out.println(new Date() + "真实收到的数据为:-----" + needData);
                            availableBytes = inputStream.available();
                            msgQueue.add(needData);
                        }
                    } catch (IOException e) {
                    }
                default:
                    break;
            }
        }
    
        /**
         * 从串口读取数据
         *
         * @param serialPort 当前已建立连接的SerialPort对象
         * @return 读取到的数据
         */
        public static byte[] readFromPort(SerialPort serialPort) {
            InputStream in = null;
            byte[] bytes = {};
            try {
                in = serialPort.getInputStream();
                // 缓冲区大小为一个字节
                byte[] readBuffer = new byte[1];
                int bytesNum = in.read(readBuffer);
                while (bytesNum > 0) {
                    bytes = MyUtils.concat(bytes, readBuffer);
                    bytesNum = in.read(readBuffer);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (in != null) {
                        in.close();
                        in = null;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return bytes;
        }
    
    
        /**
         * 通过程序打开COM4串口,设置监听器以及相关的参数
         *
         * @return 返回1 表示端口打开成功,返回 0表示端口打开失败
         */
        public int startComPort() {
            // 通过串口通信管理类获得当前连接上的串口列表
            portList = CommPortIdentifier.getPortIdentifiers();
    
            while (portList.hasMoreElements()) {
                // 获取相应串口对象
                portId = (CommPortIdentifier) portList.nextElement();
    
                System.out.println("设备类型:--->" + portId.getPortType());
                System.out.println("设备名称:---->" + portId.getName());
                // 判断端口类型是否为串口
                if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
                    // 判断如果COM4串口存在,就打开该串口
                    if ("COM3".equals(portId.getName())) {
                        try {
                            // 打开串口名字为COM_4(名字任意),延迟为1000毫秒
                            serialPort = (SerialPort) portId.open(portId.getName(), 1000);
    
                        } catch (PortInUseException e) {
                            System.out.println("打开端口失败!");
                            e.printStackTrace();
                            return 0;
                        }
                        // 设置当前串口的输入输出流
                        try {
                            inputStream = serialPort.getInputStream();
                            outputStream = serialPort.getOutputStream();
                        } catch (IOException e) {
                            e.printStackTrace();
                            return 0;
                        }
                        // 给当前串口添加一个监听器
                        try {
                            serialPort.addEventListener(this);
                        } catch (TooManyListenersException e) {
                            e.printStackTrace();
                            return 0;
                        }
                        // 设置监听器生效,即:当有数据时通知
                        serialPort.notifyOnDataAvailable(true);
    
                        // 设置串口的一些读写参数
                        try {
                            // 比特率、数据位、停止位、奇偶校验位
                            serialPort.setSerialPortParams(9600,
                                    SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
                                    SerialPort.PARITY_NONE);
                        } catch (UnsupportedCommOperationException e) {
                            e.printStackTrace();
                            return 0;
                        }
                        return 1;
                    }
                }
            }
            return 0;
        }
    
        @Override
        public void run() {
            // TODO Auto-generated method stub
            try {
                System.out.println("--------------任务处理线程运行了--------------");
                while (true) {
                    // 如果堵塞队列中存在数据就将其输出
                    if (msgQueue.size() > 0) {
                        String vo = msgQueue.peek();
                        String vos[] = vo.split("  ", -1);
                        getData(vos);
                        sendOrder();
                        msgQueue.take();
                    }
                }
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    
        /**
         * @Description: 发送获取数据指令
         * @Param:
         * @return:
         * @Author: LiangZF
         * @Date: 2019/1/3
         */
        public void sendOrder() {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            int i = 1;
            if (i == 1) {
                // 启动线程来处理收到的数据
                try {
                    byte[] b = new byte[]{0x01, 0x03, 0x00, 0x00, 0x00, 0x0E, (byte) 0xC4, 0x0E};
                    System.out.println("发送的数据:" + b);
                    System.out.println("发出字节数:" + b.length);
                    outputStream.write(b);
                    outputStream.flush();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    serialPort.close();
                    e.printStackTrace();
                } finally {
                    try {
                        if (outputStream != null) {
                            outputStream.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        /**
         * @Description:通过数组解析检测数据
         * @Param: [vo]
         * @return: void
         * @Author: LiangZF
         * @Date: 2019/1/4
         */
        public void getData(String[] vos) {
            // 数组不为空
            if (vos != null || vos.length != 0) {
                // 流速数据
                double wind_direction = getNum(vos[4], vos[5]);
                linkedList.add(wind_direction);
                System.out.println("linkedList = " + linkedList);
                System.out.println(wind_direction);
            }
        }
    
        // 16转10计算
        public double getNum(String num1, String num2) {
            BigInteger bigint=new BigInteger(num1+num2, 16);
            int numb=bigint.intValue();
            return numb/100.00;
        }
    
    
        // 字节数组转字符串
        private String printHexString(byte[] b) {
    
            StringBuffer sbf = new StringBuffer();
            for (int i = 0; i < b.length; i++) {
                String hex = Integer.toHexString(b[i] & 0xFF);
                if (hex.length() == 1) {
                    hex = '0' + hex;
                }
                sbf.append(hex.toUpperCase() + "  ");
            }
            return sbf.toString().trim();
        }
    
    
    
    
    
    
    
    
        @Override
        public void run(ApplicationArguments args) throws Exception {
            ContinueRead cRead = new ContinueRead();
            System.out.println("asdasd");
            int i = cRead.startComPort();
            if (i == 1) {
                // 启动线程来处理收到的数据
                cRead.start();
                try {
                    //根据提供的文档给出的发送命令,发送16进制数据给仪器
                    byte[] b = new byte[]{0x01, 0x03, 0x00, 0x00, 0x00, 0x0E, (byte) 0xC4, 0x0E};
                    System.out.println("发送的数据:" + b);
                    System.out.println("发出字节数:" + b.length);
                    outputStream.write(b);
                    outputStream.flush();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } finally {
                    try {
                        if (outputStream != null) {
                            outputStream.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            } else {
                return;
            }
        }
    }
    

    工具类:

    
    
    import java.math.BigInteger;
    
    public class MyUtils {
    
        /**
         * 合并数组
         *
         * @param firstArray  第一个数组
         * @param secondArray 第二个数组
         * @return 合并后的数组
         */
        public static byte[] concat(byte[] firstArray, byte[] secondArray) {
            if (firstArray == null || secondArray == null) {
                if (firstArray != null)
                    return firstArray;
                if (secondArray != null)
                    return secondArray;
                return null;
            }
            byte[] bytes = new byte[firstArray.length + secondArray.length];
            System.arraycopy(firstArray, 0, bytes, 0, firstArray.length);
            System.arraycopy(secondArray, 0, bytes, firstArray.length, secondArray.length);
            return bytes;
        }
    
        public static void main(String[] args) {
            BigInteger bigint=new BigInteger("0403", 16);
            int numb=bigint.intValue();
            System.out.println(numb/100.00);
        }
    }
    
    展开全文
  • 1、最近有个想做一个传感器数据实时显示的上位机,常规的数据打印太频繁了,无法直观的看出数据的变化。 python下的上位机实现起来简单一点,网上找了一些python界面Tkinter相关资料和python串口的demo.测试实现了...

    1、最近有个想做一个传感器数据实时显示的上位机,常规的数据打印太频繁了,无法直观的看出数据的变化。

    python下的上位机实现起来简单一点,网上找了一些python界面Tkinter相关资料和python串口的demo.测试实现了简单的数据显示。

     

    Mark 一下问题点:

    最大的问题点在于对bytes型数据的拼接:之前的串口解析的代码是在python 2.7平台上实现的,

    切换到python3.0之后,测试失踪无法通过。幸而找到了大神相助。

    python 2.7code:

      1 import os
      2 import time
      3 import sys, traceback
      4 from serial.serialutil import SerialException
      5 from serial import Serial
      6 
      7 import struct
      8 import binascii
      9 
     10 
     11 class Arduino:
     12     def __init__(self, port="/dev/ttyUSB0", baudrate=115200, timeout=0.5):
     13         
     14         self.port = port
     15         self.baudrate = baudrate
     16         self.timeout = timeout
     17         self.encoder_count = 0
     18         self.writeTimeout = timeout
     19         self.interCharTimeout = timeout / 30.
     20 
     21         self.WAITING_FF = 0
     22         self.WAITING_AA = 1
     23         self.RECEIVE_LEN = 2
     24         self.RECEIVE_PACKAGE = 3
     25         self.RECEIVE_CHECK = 4
     26         self.HEADER0 = 0xff
     27         self.HEADER1 = 0xaa
     28         self.REC_CMD = 5
     29         self.count   = 0
     30         self.data1   = 0
     31         self.data2   = 0
     32         self.error_flag = 0
     33         self.SUCCESS = 0
     34         self.FAIL = -1
     35 
     36         self.receive_state_ = self.WAITING_FF
     37         self.receive_check_sum_ = 0
     38         self.payload_command = ''
     39         self.payload_ack = ''
     40         self.payload_args = ''
     41         self.payload_len = 0
     42         self.byte_count_ = 0
     43         self.receive_message_length_ = 0
     44     
     45         self.mutex = threading.Thread.allocate_lock()
     46             
     47         # An array to cache analog sensor readings
     48         self.analog_sensor_cache = [None] * self.N_ANALOG_PORTS
     49         
     50         # An array to cache digital sensor readings
     51         self.digital_sensor_cache = [None] * self.N_DIGITAL_PORTS
     52     
     53     def connect(self):
     54         try:
     55             print "Connecting to Arduino on port", self.port, "..."
     56             self.port = Serial(port=self.port, baudrate=self.baudrate, timeout=self.timeout, writeTimeout=self.writeTimeout)
     57             # The next line is necessary to give the firmware time to wake up.
     58             time.sleep(1)
     59             state_, val = self.get_baud()
     60             if val != self.baudrate:
     61                 time.sleep(1)
     62                 state_, val  = self.get_baud()   
     63                 if val != self.baudrate:
     64                     raise SerialException
     65             print "Connected at", self.baudrate
     66             print "Arduino is ready."
     67 
     68         except SerialException:
     69             print "Serial Exception:"
     70             print sys.exc_info()
     71             print "Traceback follows:"
     72             traceback.print_exc(file=sys.stdout)
     73             print "Cannot connect to Arduino!"
     74             os._exit(1)
     75 
     76     def open(self): 
     77         self.port.open()
     78 
     79     def close(self): 
     80         self.port.close() 
     81     
     82     def send(self, cmd):
     83         self.port.write(cmd)
     84 
     85     def receiveFiniteStates(self, rx_data):
     86         if self.receive_state_ == self.WAITING_FF:
     87             #print str(binascii.b2a_hex(rx_data))
     88             if rx_data == '\xff':
     89                 self.receive_state_ = self.WAITING_AA
     90                 self.receive_check_sum_ =0
     91                 self.receive_message_length_ = 0
     92                 self.byte_count_=0
     93                 self.payload_ack = ''
     94                 self.payload_args = ''
     95                 self.payload_len = 0
     96                 self.count = 0
     97 
     98         elif self.receive_state_ == self.WAITING_AA :
     99              if rx_data == '\xaa':
    100                  self.receive_state_ = self.REC_CMD
    101              else:
    102                  self.receive_state_ = self.WAITING_FF
    103         elif self.receive_state_ == self.REC_CMD:
    104              self.count+=1
    105              if self.count == 1:
    106                 self.data1,=struct.unpack("B",rx_data)
    107              elif self.count == 2:
    108                   self.data2,=struct.unpack("B",rx_data)
    109                   self.receive_state_ = self.RECEIVE_LEN
    110                   if self.error_flag == 0 and self.data1 != 0:
    111                      self.error_flag = 1
    112                   if self.data2 != 0 and self.error_flag == 0:
    113                      self.error_flag = 1   
    114         elif self.receive_state_ == self.RECEIVE_LEN:
    115              self.receive_message_length_, = struct.unpack("B",rx_data)
    116              self.receive_state_ = self.RECEIVE_PACKAGE
    117         elif self.receive_state_ == self.RECEIVE_PACKAGE:
    118              if self.byte_count_==0:
    119                  self.payload_ack = rx_data
    120              else:
    121                  self.payload_args += rx_data
    122              self.byte_count_ +=1
    123              #print "byte:"+str(byte_count_) +","+ "rece_len:"+str(receive_message_length_)
    124              if self.byte_count_ >= self.receive_message_length_:
    125                  self.receive_state_ = self.RECEIVE_CHECK
    126 
    127         elif self.receive_state_ == self.RECEIVE_CHECK:
    128             #if(rx_data == (unsigned char)receive_check_sum_)
    129             if 1:
    130                 self.receive_state_ = self.WAITING_FF
    131                 #print str(binascii.b2a_hex(value))
    132                 #left, right, = struct.unpack('hh', value)
    133                 #print "left:"+str(left)+", right:"+str(right)
    134                 return 1 
    135             else:
    136                 self.receive_state_ = self.WAITING_FF
    137         else:
    138             self.receive_state_ = self.WAITING_FF;
    139         return 0
    140 
    141     def recv(self, timeout=0.5):
    142         timeout = min(timeout, self.timeout)
    143         ''' This command should not be used on its own: it is called by the execute commands   
    144             below in a thread safe manner.  Note: we use read() instead of readline() since
    145             readline() tends to return garbage characters from the Arduino
    146         '''
    147         c = ''
    148         value = ''
    149         attempts = 0
    150         c = self.port.read(1)
    151         #print str(binascii.b2a_hex(c))
    152         while self.receiveFiniteStates(c) != 1:
    153             c = self.port.read(1)
    154             #print str(binascii.b2a_hex(c))
    155             attempts += 1
    156             if attempts * self.interCharTimeout > timeout:
    157                 return 0
    158         return 1
    159             
    160     def recv_ack(self):
    161         ack = self.recv(self.timeout)
    162         return ack == 'OK'
    163 
    164     def execute(self, cmd):
    165         self.mutex.acquire()
    166         
    167         try:
    168             self.port.flushInput()
    169         except:
    170             pass
    171         
    172         ntries = 1
    173         attempts = 0
    174         
    175         try:
    176             self.port.write(cmd)
    177             res = self.recv(self.timeout)
    178             while attempts < ntries and res !=1 :
    179                 try:
    180                     self.port.flushInput()
    181                     self.port.write(cmd)
    182                     res = self.recv(self.timeout)
    183                 except:
    184                     print "Exception executing command: " + str(binascii.b2a_hex(cmd))
    185                 attempts += 1
    186         except:
    187             self.mutex.release()
    188             print "Exception executing command: " + str(binascii.b2a_hex(cmd))
    189             return 0
    190         
    191         self.mutex.release()
    192         return 1
    193 
    194     def get_baud(self):
    195         ''' Get the current baud rate on the serial port.
    196         '''
    197         cmd_str=struct.pack("4B", self.HEADER0, self.HEADER1, 0x01, 0x00) + struct.pack("B", 0x01)
    198         if (self.execute(cmd_str))==1 and self.payload_ack == '\x00':
    199            val, = struct.unpack('I', self.payload_args)
    200            return  self.SUCCESS, val 
    201         else:
    202            return self.FAIL, 0
    203 
    204     def get_check_sum(self,list):
    205         list_len = len(list)
    206         cs = 0
    207         for i in range(list_len):
    208             #print i, list[i]
    209             cs += list[i]
    210         cs=cs%255
    211         return cs
    212         
    213     def stop(self):
    214         ''' Stop both motors.
    215         '''
    216         self.drive(0, 0)
    View Code

    在python 3.6 version 中就该修改部分代码:

     问题在于bytes类型的拼接:

    以下的拼接是正确的:

    bytes('','ascii')+bytes([1,2,3,4,5,6,7,8,9])
    bytes('','ascii')+bytes([1,2,3,4,5,6,7,8,9])+bytes([1,2,3,4,5,6,7,8,9])

    也即是:bytes类型的拼接的初始变量要声明为:bytes('','ascii')

    如果声明为其它类型:比如字符串,执行时会直接报错。

    即:python2.7代码块中:40行以及94行的声明:

    (1)将:40行和94行的
    self.payload_args = ''
    改为:
    self.payload_args = bytes('','ascii')
    (2)将:121行赋值命令:
    self.payload_args += rx_data
    修改为:
    self.payload_args +=  bytes(rx_data)
    View Code

     源码已上传到github:链接

    目前单纯实现了串口数据的查询:

     

    转载于:https://www.cnblogs.com/sshbit/p/10283185.html

    展开全文
  • QT实时绘制串口数据

    2018-07-20 22:22:04
    采用多线程方法,主线程解析数据和绘图,子线程接收数据,QWT绘图,有历史回顾功能
  • Java串口实时显示

    2014-03-24 15:03:58
    本代码用Java编写,串口通信,把收到的串口数据解析用图像实时显示在java界面上
  • Qt qextserial进行串口数据采集,qcustomplot进行绘图,曲线实时显示横纵坐标辅助线 目的、要求: A.读取RS422接口接收到的全部数据; 1.通过接口读取板卡采集的数据,采用多线程,读取数据和解析数据在主线程,...

    Qt qextserial进行串口数据采集,qcustomplot进行绘图,曲线实时显示横纵坐标辅助线

    目的、要求:

    A.读取RS422接口接收到的全部数据;

    1.通过接口读取板卡采集的数据,采用多线程,读取数据和解析数据在主线程,绘制曲线在另一个新的线程。COM和API接口见附件1.板卡用户手册。

    2.根据接收到的数据,需要先判定是返参帧A还是返参帧B,每一帧具有27个字节,每帧依据“帧头”和“校验和”来判定。

    需要注意:

    a)数据流起始位置并不一定是“帧头”。

    b)数据流中可能存在无效的数据包,需要注意判定逻辑,以免丢失有效数据。

    B.能够依据协议对数据进行解析并存储;

    1.要求对返参帧A和返参帧B数据分别解析,详细的解析与处理要求见附件2。附件2中需要用到的解析协议见附件3。

    2.将接收到的返参帧A和返参帧B分别存储在文档不同的sheet中,文档格式为".xlsx",允许用户在软件界面上以点击按钮的形式选择数据存储开始/结束,允许用户选择设置路径。

    3.存储内容包括附件2表中全部解析内容,每一项解析内容对应存储在文档中一列,存储数据为解析后未经数据处理的数据。

    C.对解析后的一些数据,以曲线的形式显示。

    1.软件需对返参帧A和返参帧B的部分解析内容进行实时曲线绘制,需要绘制曲线的参数见附件4。共15个曲线图。

    2.通过“选项卡”的形式将不同类型曲线放置在不同选项卡页面中。

    3.要求曲线能根据接收解析后的数据点进行动态实时更新,从右向左,横坐标代表点的个数,曲线对应的横坐标刻度要一同向左更新移动。

    4.要求曲线窗口有图标题,有横纵坐标标题;如果一个曲线窗口中有多条曲线,要求用不同颜色区分,对不同曲线有标注;用户可选择仅显示其中某一条或某两条曲线;

    5.曲线要求正常显示为1000个数据点,缓存区要求存180000个数据点,可在曲线窗口上左右拖拽以查看180000中的各个1000个数据点的显示区间,超出180000个数据点缓存区后,每进入一个新的数据点,则顺次清除一个原数据点。曲线横、纵坐标范围允许用户调整,可进行2、4、6、8倍的4档放大曲线局部判读。

    6.鼠标移动到曲线上的数据点上时,要求有指向横、纵坐标的辅助线。

    简介:

    考虑到这个要移植到硬件上,到时候交叉编译后的Qt环境需要串口模块的支持。所以选用了第三方的chua串口通讯模块qextserial进行串口通讯。绘图使用的第三方的qcustomplot。串口模块放到线程里,数据处理和绘图部分放到了主线程。这个地方主要麻烦的是对通讯帧的解析。首先分为A B两种mo's模式,每个字节对应的有不同的含义。有些字节的某几位对应的不同的含义。剩下的就是数据的辅助线问题了。辅助线继承了QCustomPlot,然后重写了鼠标事件和其他的一些事件。

    效果:

    代码:

    #ifndef MHCUSTOMPLOT_H
    #define MHCUSTOMPLOT_H
    
    #include "mhtracer.h"
    #include "qcustomplot.h"
    #include <QObject>
    #include <QList>
    
    class MhCustomPlot : public QCustomPlot
    {
        Q_OBJECT
    public:
        MhCustomPlot(QWidget *parent = 0);
    
    protected:
        virtual void mouseMoveEvent(QMouseEvent *event);
        virtual void enterEvent(QEvent *event);
        virtual void leaveEvent(QEvent *event);
        //virtual void mouseDoubleClickEvent(QMouseEvent *event);
    //signals:
        //void legendDoubleClickChilden(QCPLegend *legend,  QCPAbstractLegendItem *item, QMouseEvent *event);
    public:
        //设置是否显示鼠标追踪器
        //是否显示
        void showTracer(bool show);
        // 是否显示鼠标追踪器
        bool isShowTracer(){return m_isShowTracer;}
    
    private:
        bool m_isShowTracer;//是否显示追踪器(鼠标在图中移动,显示对应的值)
        MhTracer *m_xTracer;//x轴
        MhTracer *m_yTracer;//y轴
        QList<MhTracer *> m_dataTracers;//
        MhTraceLine  *m_lineTracer;//直线
    };
    
    #endif // MHCUSTOMPLOT_H
    
    #include "mhcustomplot.h"
    
    MhCustomPlot::MhCustomPlot(QWidget *parent)
        :QCustomPlot(parent)
        ,m_isShowTracer(false)
        ,m_xTracer(Q_NULLPTR)
        ,m_yTracer(Q_NULLPTR)
        ,m_dataTracers(QList<MhTracer *>())
        ,m_lineTracer(Q_NULLPTR)
    {
    
    }
    //设置是否显示鼠标追踪器
    //是否显示
    void MhCustomPlot::showTracer(bool show)
    {
        m_isShowTracer = show;
        if(m_xTracer)
            m_xTracer->setVisible(m_isShowTracer);
        ///
        if(m_yTracer)
        {
            m_yTracer->setVisible(m_isShowTracer);
        }
        foreach (MhTracer *tracer, m_dataTracers)
        {
            if(tracer)
                tracer->setVisible(m_isShowTracer);
        }
        if(m_lineTracer)
            m_lineTracer->setVisible(m_isShowTracer);
    }
    
    void MhCustomPlot::mouseMoveEvent(QMouseEvent *event)
    {
        QCustomPlot::mouseMoveEvent(event);
    
        if(m_isShowTracer)
        {
            //当前鼠标位置(像素坐标)
            int x_pos = event->pos().x();
            int y_pos = event->pos().y();
    
            //qDebug() << "x_pos:" << x_pos << "y_pos:" << y_pos;
    
            //像素坐标转成实际的x,y轴的坐标
            float x_val = this->xAxis->pixelToCoord(x_pos);
            float y_val = this->yAxis->pixelToCoord(y_pos);
    
            if(Q_NULLPTR == m_xTracer)
                m_xTracer = new MhTracer(this, MhTracer::XAxisTracer);//x轴
            m_xTracer->updatePosition(x_val, y_val);
    
            if(Q_NULLPTR == m_yTracer)
                m_yTracer = new MhTracer(this, MhTracer::YAxisTracer);//y轴
            m_yTracer->updatePosition(x_val, y_val);
    
            int nTracerCount = m_dataTracers.count();
            int nGraphCount = graphCount();
            if(nTracerCount < nGraphCount)
            {
                for(int i = nTracerCount; i < nGraphCount; ++i)
                {
                    MhTracer *tracer = new MhTracer(this, MhTracer::DataTracer);
                    m_dataTracers.append(tracer);
                }
            }
            else if(nTracerCount > nGraphCount)
            {
                for(int i = nGraphCount; i < nTracerCount; ++i)
                {
                    MhTracer *tracer = m_dataTracers[i];
                    if(tracer)
                    {
                        tracer->setVisible(false);
                    }
                }
            }
            for (int i = 0; i < nGraphCount; ++i)
            {
                MhTracer *tracer = m_dataTracers[i];
                if(!tracer)
                    tracer = new MhTracer(this, MhTracer::DataTracer);
                tracer->setVisible(true);
                tracer->setPen(this->graph(i)->pen());
                tracer->setBrush(Qt::NoBrush);
                tracer->setLabelPen(this->graph(i)->pen());
                auto iter = this->graph(i)->data()->findBegin(x_val);
                double value = iter->mainValue();
    //            double value = this->graph(i)->data()->findBegin(x_val)->value;
                tracer->updatePosition(x_val, value);
            }
    
            if(Q_NULLPTR == m_lineTracer)
                m_lineTracer = new MhTraceLine(this,MhTraceLine::Both);//直线
            m_lineTracer->updatePosition(x_val, y_val);
    
            this->replot(QCustomPlot::rpQueuedReplot);//曲线重绘
        }
    }
    
    void MhCustomPlot::enterEvent(QEvent *event)
    {
        //QCustomPlot::enterEvent(event);
        //qDebug() << "鼠标进入";
        m_isShowTracer = true;
        if(m_xTracer)
            m_xTracer->setVisible(m_isShowTracer);
        if(m_yTracer)
        {
            m_yTracer->setVisible(m_isShowTracer);
        }
        foreach (MhTracer *tracer, m_dataTracers)
        {
            if(tracer)
                tracer->setVisible(m_isShowTracer);
    
        }
        if(m_lineTracer)
            m_lineTracer->setVisible(m_isShowTracer);
        this->replot(QCustomPlot::rpQueuedReplot);
    }
    
    void MhCustomPlot::leaveEvent(QEvent *event)
    {
        //QCustomPlot::leaveEvent(event);
        //qDebug() << "鼠标离开";
        m_isShowTracer = false;
        if(m_xTracer)
            m_xTracer->setVisible(m_isShowTracer);
        if(m_yTracer)
        {
            m_yTracer->setVisible(m_isShowTracer);
        }
        foreach (MhTracer *tracer, m_dataTracers)
        {
            if(tracer)
                tracer->setVisible(m_isShowTracer);
        }
        if(m_lineTracer)
            m_lineTracer->setVisible(m_isShowTracer);
        this->replot(QCustomPlot::rpQueuedReplot);
    }
    
    //void MhCustomPlot::mouseDoubleClickEvent(QMouseEvent *event)
    //{
    //    QCustomPlot::mouseDoubleClickEvent(event);
    //}
    

     

    exe地址(百度网盘链接):

    链接:https://pan.baidu.com/s/1YeYbY32FM1Ol1FKvdLUUJA 
    提取码:tr0d 

    QQ:921673516  QQ群:511450936  邮箱:yue_xusy@163.com

    展开全文
  • 最近在做测试心电的项目,我用QT开发了一个简单的界面,实时显示底层采集到的心电数据波形图,由于完全靠自己开发,所以很苦恼,在网上也查了不少资料,也问了一些老师,最后基本完成了,由于网上查资料看到类似案例...

    最近在做测试心电的项目,我用QT开发了一个简单的界面,实时显示底层采集到的心电数据波形图,由于完全靠自己开发,之前也没有类似经验,所以很苦恼,在网上也查了不少资料,也问了一些老师,最后基本完成了,由于网上查资料看到类似案例资料并不多,也不齐全,所以将自己的心得分享出来,大家一起讨论。由于是初学者,所以有不对或者需要改进的地方请各位大佬指出,共同学习,共同进步。以下贴上示例代码及解析。
     

    读取串口部分借鉴于Quartz010的文章《如何在QT中读取串口数据》

    http://blog.csdn.net/zz709196484/article/details/66474917  这是博客网址
     
    大致思路就是子线程去读取串口数据并传送到主线程,主线程在用widget对象画图实时显示波形图

    这里推荐一下我的个人技术博客网站,蹭点点击量,目前正在搭建中,慢慢优化。http://1414805054.xyz/

    一、在main.cpp定义一个自己封装的类myapp的对象w,在myapp界面中new出两个button按钮用于开关控制和

    QComboBox复选框选择串口端口号,并定义出自己封装好的画图的类的对象,并设置布局。项目结构如下图:

     

    二、直接贴上代码

    myapp.h

    #ifndef MYAPP_H
    #define MYAPP_H
    
     
    #include <QWidget>
    #include "widget.h"
    #include <QTimer>
    
     
    #include <QComboBox>
    #include <QPushButton>
    #include <QLineEdit>
    #include <QLabel>
    #include <QDebug>
    #include <QPalette>
    #include <QTextEdit>
    #include "mythread.h"
    
     
    class myapp : public QWidget
    {
        Q_OBJECT
    public:
        explicit myapp(QWidget *parent = 0);
    
     
    signals:
        void close_serial(char*);//向子线程传递信号关闭串口
    
     
    public slots:
          void setplay(float data1);//传数据
    
     
          void on_btn_clicked();//打开串口按钮槽函数
          void closeit();//关闭按钮槽函数
        void get_value2()
        {
            
            w2->setvote(data, setval,statu);//设置画图状态及数据
    
     
      
        }
    
     
    private:
        int  setval;
        float data;
        Widget *w2;
        QPushButton *btn,*closebtn;
        QComboBox *box;
        //QTextEdit *TB;
        QString port1;//串口端口号
        int statu,j;
        MyThread *mthread;//开辟子线程,以第三方库封装的模式
    };
    
     
    #endif // MYAPP_H

      myapp.cpp主要做了一些界面的布局,和连接与断开串口的操作

    #include "myapp.h"
    #include <QVBoxLayout>
    #include <QHBoxLayout>
    #include "widget.h"
    
    myapp::myapp(QWidget *parent) : QWidget(parent)
    {
        setWindowTitle("心电图");
        //setMinimumSize(800,600);
        setFixedSize(1200,800);
        data = 0;
        setval = 1;
        //w1 = new Widget;
        w2 = new Widget;
        //w3 = new Widget;
        QPalette palette;
        palette.setBrush(QPalette::Background,QBrush(QPixmap("./Tim").scaled(this->size())));
        setPalette(palette);
    
     
        btn = new QPushButton("显示心电图");
        btn->setFixedSize(100,30);
        closebtn = new QPushButton("关闭");
        closebtn->setFixedSize(100,30);
        //TB= new QTextEdit();
    
     
        box = new QComboBox();
        box->setFixedSize(100,30);
        box->addItem("COM1");
        box->addItem("COM2");
        box->addItem("COM3");
        box->addItem("COM4");
        box->addItem("COM5");
        box->addItem("COM6");
        box->addItem("COM7");
        box->addItem("COM8");
        box->addItem("COM9");
        box->addItem("COM10");
        box->addItem("COM11");
        box->addItem("COM12");
        box->addItem("COM13");
        box->addItem("COM14");
    //当然这里可以做成自己识别端口号,我这里是随便做个demo调试
     
        QHBoxLayout *hbox1 = new QHBoxLayout;
        hbox1->addWidget(btn);
        hbox1->addWidget(closebtn);
        hbox1->addWidget(box);
    
     
        QVBoxLayout *vbox1 = new QVBoxLayout;
        vbox1->addLayout(hbox1);
        //vbox1->addWidget(w1);
        vbox1->addWidget(w2);
        //vbox1->addWidget(TB);
    
     
        setLayout(vbox1);
        closebtn->setEnabled(false);
    
     
        connect(btn, SIGNAL(clicked()), this, SLOT(on_btn_clicked()));
        connect(closebtn,SIGNAL(clicked()),this,SLOT(closeit()));//监听两个按钮信号
    }
    void myapp::setplay(float data1)
    {
        data = data1;
        setval = 10;
        get_value2();//调画图函数
    
     
    }
    
     
    void myapp::on_btn_clicked()
    {
            statu = 1;
            btn->setEnabled(false);//设置按钮使能
            closebtn->setEnabled(true);
            qDebug()<<"open ok"<< endl;
            port1 = box->currentText();//获取端口号
            qDebug()<<port1<< endl;
            mthread =new MyThread(port1);
            connect(mthread,SIGNAL(setsenddata(float)),this,SLOT(setplay(float)),Qt::QueuedConnection);
    	//接收子线程传输数据的信号
            mthread->start();//开启线程
     
    }
    
     
    
     
    void myapp::closeit()
    {
        statu = 0; 
        closebtn->setEnabled(false);
        btn->setEnabled(true);
        connect(this,SIGNAL(close_serial(char*)),mthread,SLOT(close_mthread_serial(char*)));
        char *a="2";
        emit this->close_serial(a);//发送关闭的信号
        delete mthread;//销毁子线程
    
     
    }

     

    mythread.h
    
    
    #ifndef MYTHREAD_H
    #define MYTHREAD_H
    
     
    #include <QObject>
    #include <QDebug>
    #include <QThread>
    #include "qextserialbase.h"
    #include "win_qextserialport.h"
    #include <QPushButton>
    class MyThread : public QThread
    {
            Q_OBJECT
    public:
    
     
        MyThread(QString port1);
        void run();
    
     
    signals:
        void setsenddata(float data);//向主线程发送接收到的串口数据
    
     
    public slots:
        void read_serial_data();//读取串口数据
        void close_mthread_serial(char *st);//关闭
    private:
        Win_QextSerialPort *mycom;
        QString port;
        float data;
    };
    
     
    #endif // MYTHREAD_H
    

     

    mythread.cpp

          在这里会做一些串口初始化的工作,以及和下位机定义的数据解析方式,这里有点值得注意的是,读取要同步,下位机发多少,我们读多少,因为我之前出现过一个现象就是,到后面界面会越来越卡顿,我初步排查是由于串口buffer空间的问题导致。当然也许是其他原因,但是我判断mycom->bytesAvailable()>= 9后再每次从串口读取9个字节:mycom->read(9)后,就解决了这个问题。

    #include "mythread.h"
    
     
    MyThread::MyThread(QString port1)
    
    
     
    {
        port = port1;
    }
    void MyThread::run()
    {
        //重写run()函数初始化串口
        mycom = new Win_QextSerialPort(port,QextSerialBase::EventDriven);//读取串口采用事件驱动模式
        mycom->open(QIODevice::ReadWrite);//读写方式打开
        mycom->setBaudRate(BAUD115200);//波特率
        mycom->setDataBits(DATA_8);//数据位
        mycom->setParity(PAR_NONE);//奇偶校验
        mycom->setStopBits(STOP_1);//停止位
        mycom->setFlowControl(FLOW_OFF);//控制位
        mycom->write("1");//向下位机发送1告诉它开始发送数据
        connect(mycom,SIGNAL(readyRead()),this,SLOT(read_serial_data()));//有数据就读
    }
    void MyThread::read_serial_data()
    {
        if(mycom->bytesAvailable()>= 9)
        {
            qDebug()<<mycom->bytesAvailable() << endl;
            QByteArray temp;
            temp = mycom->read(9);//每串数据为9个字节
              union dat{
                char a[4];
                int x;
            };
            dat data_serial;
            data_serial.a[0] = 0;
            data_serial.a[1] = temp[8];
            data_serial.a[2] = temp[7];
            data_serial.a[3] = temp[6];
            data = data_serial.x*2.4/256/8288607*10000;//提取有效数据位,根据需要的数据设计的算法
            emit setsenddata(data);//发送数据给主线程
            qDebug() <<data ;
    
     
        //TB->insertPlainText(temp.toHex()+"  ");
          }
    }
    void MyThread::close_mthread_serial(char *st)
    {
        mycom->write(st);//告知下位机读端已关闭
        qDebug() <<"close ok"<<st<<endl;
        mycom->close();//关闭子线程
    
     
    }

     

    widget.h

    波形的绘制在这里完成,先申明一个画家,然后再给他一只调好的画笔,先画好一个坐标轴,draw()方法里面则是动态更新心电波形的逻辑。

    #ifndef WIDGET_H
    #define WIDGET_H
    
     
    #include <QWidget>
    #include <QPainter>
    #include <QPen>
    #include <QDebug>
    
    class Widget : public QWidget
    {
        Q_OBJECT
    
     
    public:
        Widget(QWidget *parent = 0,float pwidth = 0.5);
        ~Widget();
        void paintEvent(QPaintEvent *event)
        {
    
     
            QPainter p(this);
            QPen pen;
     
            pen.setColor(QColor("green"));笔的颜色
            pen.setWidth(3);//笔的粗细
            p.setPen(pen);
    
     
            QFont font;//画text的大小
            font.setPixelSize(30);//请画家并给画家一支调好的笔
    
     
            p.drawLine(0, height()/2, width(), height()/2);//X轴
            p.drawLine(0, height()-5, 0, 5);//Y轴
    
     
            pen.setColor(QColor("red"));
            p.setPen(pen);
            p.setFont(font);
            p.drawText(QPoint(width()-15, height()/2-5), "S");//横坐标
            p.drawText(QPoint(10, 15), "mv");//纵坐标
    #if 1
            pen.setColor(QColor("gray"));//网格
            pen.setWidth(1);
            p.setPen(pen);
            for(int i=10; i<width(); i+=10)
                p.drawLine(i, 0, i, height()-5);
            for(int j=10;j<height(); j+=10)
                p.drawLine(0, j, width(), j);
            pen.setColor(QColor("red"));
            pen.setWidth(10);
            p.setPen(pen);
            font.setPixelSize(16);
            p.setFont(font);
            p.drawText(QPoint(5, height()/2+15), "0");
            float a= 0.2;
    
     
            for(int k= 50;k<width();k+=50)
             {
                pen.setColor(QColor("white"));
                pen.setWidth(3);
                p.setPen(pen);
                p.drawLine(k, 0, k, height()-5);
                QString data = QString("%1").arg(a);
                pen.setColor(QColor("red"));
                pen.setWidth(10);
                p.setPen(pen);
                p.drawText(QPoint(k+5, height()/2+15), data);
                a=a+0.2;//横轴代表时间,每小格0.04s,每大格0.2s
    
     
            }
    
     
    #endif
    
     
            p.translate(-fresh, 0);
            pen.setColor(QColor("red"));
            pen.setWidth(penwidth);
            p.setPen(pen);
            p.drawPath(path);//曲线图(波形)
    
     
            QPainter set_p(this);
            //QPen set_pen;
            set_p.translate(-set_fresh, 0);
    //        set_pen.setColor(QColor("green"));
    //        set_pen.setWidth(3);
    //        set_p.setPen(set_pen);
    //        set_p.drawPath(set_path);//参考线
            //set_p.drawLine(QPoint(0, height()-setval), QPoint(width(), height()-setval));
    
     
        }
    public slots:
        void draw()
        {
            if(statu == 1)
            {
                path.lineTo(QPoint(x+=penwidth, height()/2-vote));//每个数据的纵坐标路径
                if(x > width())//画满
                fresh+=penwidth;
    //        set_path.lineTo(QPoint(set_x+=set_penwidth, height()-vote-10));
    //        if(set_x > width())//画满
    //            set_fresh+=set_penwidth;
                update();自动刷新
            }
        }
    
     
        void setvote(float value, int set,int status)//最关键的一个方法!!!要向显示电压信号直接调
    这个方法就可以了
        {
            vote = value;//传入的数据值
            setval = set;
            statu = status;
            draw();
        }
    
     
    private:
    
     
        QPainterPath path, set_path;
        float fresh, set_fresh;//滚屏
        float penwidth, set_penwidth;//滚屏速度
        float x, set_x;
        int  setval,statu;
        float vote;
    
     
    };
    
    
    #endif // WIDGET_H
    
     
    widget.cpp

     思路是通过描点连线的方式,画出心电波形图

    #include "widget.h"
    #include <QPalette>
    
     
    Widget::Widget(QWidget *parent, float pwidth)
        : QWidget(parent),penwidth(pwidth)
    {
        QPalette pal(palette());
        pal.setColor(QPalette::Background, Qt::black);
        setAutoFillBackground(true);
        setPalette(pal);
    
     
        path.moveTo(QPoint(10, height()-5));
        set_path.moveTo(QPoint(10, height()-5));
        vote = 0;
        setval = height()-10;
        x = 0;
        set_x = 10;
        fresh = 0;
        set_fresh = 0;
    
     
        setFixedHeight(300);
    
     
    }
    
     
    Widget::~Widget()
    {
    
     
    }
    
    三、串口代码就省略了,大家有需要看的可以去看我前面借鉴的大佬的博客
    附上效果图:

    心电波形图

    测试的正弦波形图

    四、总结

         之所以用线程读取数据,是因为一开始主线程读取数据的时候因为程序执行,也或许是画图影响反应事件
    驱动信号的原因,导致接收数据与下位机发送数据不匹配,会丢失一部分数据,也做过算法改进,仍然不行,
    后面采取开辟子线程读取串口,主线程显示,就没有这个问题了。总之在绘图上需要计算频率以及幅值,使图
    形清楚明了。

    展开全文
  • 最近项目有一个空气检测仪,需要得到空气检测仪的实时数据,保存到数据库当中。根据了解得到,硬件是通过rs485进行串口通讯的,需要发送16进制命令给仪器,然后通过轮询来得到数据。  需要先要下载RXTX的jar包,...
  • 最近项目有一个空气检测仪,需要得到空气检测仪的实时数据,保存到数据库当中。根据了解得到,硬件是通过rs485进行串口通讯的,需要发送16进制命令给仪器,然后通过轮询来得到数据。需要先要下载RXTX的jar包,win64...
  • 间隔50ms发送一次数据给上位机,但是ReceiveData()函数好像并不能把这些数据区分开来,而是把几次的数据当成一个整体了,导致数据解析出问题,请问如何解决? 例子如下: 1.间隔50ms或者发送,每次发送5个字节...
  • labview实时数据接收分析与存储,主要是数据包的解析,需要根据具体情况转换数据解析代码
  • C# 上位机串口调试工具实时显示

    千次阅读 多人点赞 2017-04-27 09:31:20
    深感愧疚,最近在忙着做一个上位机PC软件,功能是能够正常接收串口传输来的数据并解析这些数据中对我们有用的数据,另外,为了更加直观的观察这些数据代表的意义,我们还有一个目的就是讲这些数据实时地绘画出来,也...
  • GPS数据解析

    2017-02-02 20:57:00
    如何高效的处理从GPS模块接收到的数据帧,是GPS驱动设计的重点,本文使用状态机的思想来处理GPS输出的串口数据流,相对于定时从串口环形bufer取数据包然后依次解析有更高的实时性并且单片机负荷更低。 2. GPS数据...
  • 源码解析 void CMFCSerialPortDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);...
  • 最近有个需求,通过rk3399连接耀华与柯力称重设备,读取实时称重数据,主要方式是,通过串口读取实时数据,对实时数据进行解析 正文 1.打开串口,通过串口读取数据,对应的串口地址需要对应接入的具体com口,每个...
  • 我用Qt5写的串口调试程序,现在需要把数据转换成实时动态图,听说需要定义数据格式和进行数据解析,我不太懂,希望大神给一些建议,准备用QCustomPlot来画的。
  • Android串口通信是很多行业比较重要的一项技术,既然有通信,就一定存在着数据,而且多数情况下,这个数据有着共同的特点,数据量大、实时性强、数据格式固定等。串口通信大多以字节数组的形式相互传送,通过串口的...
  • OpenMV 发送色块跟踪的坐标,Arduino 实时接收解析色块坐标值 OpenMV 发送数据相对来说比较简单,Arduino 的串口接收字符串也比较简单,有专门的字符串读取函数,Serial.readString()。但这个函数的实时性很差,有 ...
  • 根据设计分析,单片机通过摄像头提取JPGE图像,通过wifi8266模块,将数据一帧一帧实时传输到TCP客户端程序,虽然串口图传显示程序有,但是TCP类型的较少,所以需要制作TCP客户端程序的demo进行显示,如有需要,后续...
  • 非常无奈,官网资料不太够,“实时传输显示LCD数据”是什么东东,去哪儿弄lcd的资料,还是定制器件。 那就只能靠硬破解了,其实也比较简单,把各种情况下的数据对应关系罗列,按照小学生找规律的方法慢慢搞就是了。...
  • 纸飞机串口助手是一款超好用的串口调试助手。具有很多功能,其亮点有语法高亮、实时绘图、数值显示、实时FFT以及正则匹配和分类显示,其他常见的功能也...实时绘图、实时频谱它还可以解析数据进行实时绘图,既可以...
  • 这篇文章是“树莓派查询天气,通过串口彩屏/7299点阵实时显示”的一部分,主要介绍使用Java查询雅虎天气并解析Json返回数据,这里只是将获得的实时天气、未来十天的天气等信息,解析并打印出来,为下一步做准备。...
  • QT编写的串口设备调试工具终极版

    千次下载 热门讨论 2013-12-20 13:39:19
    4:实时显示收发数据字节大小以及串口状态。 高级功能: 1:可自由管理需要发送的数据,每次只要从下拉框中选择数据即可,无需重新输入数据。 2:可模拟设备回复数据,需要在主界面开启模拟设备回复数据。当接收到...
  • 多功能串口调试助手

    2015-12-01 17:29:15
    (1)可以进行实时监控串口插拔,自动添加串口 (2)字符串形式发送,HEX格式发送,自动发送,多条发送(可以手动也可以自动),串口接收数据曲线显示, (3)还可以解析传感器数据并曲线显示,是传感器采集系统分析...
  • VREP Regular API提供了串口操作的相关函数,可以对串口进行打开、关闭和读写: ...VREP通过串口读取传感器实时发送的数据并进行解析。    传感器通过串口发送2种数据: 解算后的姿态角和气压高度等数据  ...
  • LabVIEW上位机与串口通信

    千次阅读 2017-08-21 17:16:52
    主要功能包括:对帧中的类型字节进行解析,并多通道显示在示波器上帧偏差校正(这个一般人可能都没有做,造成数据丢失,而我这只要串口传输的数据没错,就能无错漏的解析每一帧)实时显示读取的每个字节...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 126
精华内容 50
关键字:

串口数据实时解析