Matlab 实时读取串口并绘图

Matlab 实时读取串口并绘图

Vofa+

Vofa+ 是一个很好的跨平台上位机软件,但是它无法保存数据,而且作者也并没有要继续更新的意思,保存数据功能应该是遥遥无期了。因此本文使用 Matlab 实时读取串口数据,并使用 plot 函数绘制。

vofa+ 里发送 float 型数据的协议是 justfloat,其具体规则如下:
在这里插入图片描述

下位机发送数据

下位机发送程序各有不同,下面是一个例子,使用的是 DSP28027 单片机,定义了全局变量 gTime 做时间向量:

void myPutVariableData_vofa(void)
{
    int   num = 6; // number of float variables to be sent
    float data[6]      = {0}; // float variables to be sent 
    uint16_t txBuf[14] = {0}; 
    float testData = 114514.0;
    float testW    = 10.0;

    txBuf[2 * num]     = 0x0000;
    txBuf[2 * num + 1] = 0x7f80;
    
    data[0] = testData;
    data[1] = testData;
    data[2] = testData;
    data[3] = testData;
    data[4] = testData;
    data[5] = sin(2 * 3.1415 * testW * gTime);

    memcpy(txBuf, (uint16_t *)data, num * sizeof(float));
    mySCI_sendDataBlocking(txBuf, 2 * num + 2);
}

Matlab 代码

使用 matlab 读取串口主要分为接收数据和协议解析,用的方法比较粗暴,直接读取串口然后判断帧尾。

Step 1. 设置串口

Matlab 中使用 serialportlist 命令查找电脑连接的串口,找到对应设备名称后在设置相关参数

devicelist = serialportlist' % This command shows the port connected.

baudrate        = 115200;
device          = "/dev/cu.usbserial-A700eG4x";
myPort          = serialport(device,baudrate); 
myPort.DataBits = 8;
myPort.StopBits = 1;
myPort.Parity   = "none";

Step 2. 设置数据缓冲区

设置绘图数据的个数和时间窗口大小,本文设置 6 个数据, 2000 个采样点的窗口,每一帧传输时间使用 d t = ( n ∗ 4 + 4 ) ∗ 8 BIT Baudrate dt = \frac{(n*4+4)*8 \text{BIT}}{\text{Baudrate}} dt=Baudrate(n4+4)8BIT 计算, n n n 为传输数据个数。然后将数据缓冲区都初始化为0:

varNum = 6;
buf    = 2000;
dt     = (varNum * 4 + 4) * 8 / baudrate;
time   = -dt*(buf/2):dt:dt*(buf/2-1);

dataBuf.var0 = zeros(buf,1);
dataBuf.var1 = zeros(buf,1);
dataBuf.var2 = zeros(buf,1);
dataBuf.var3 = zeros(buf,1);
dataBuf.var4 = zeros(buf,1);
dataBuf.var5 = zeros(buf,1);

这里也可以使用动态命名变量来初始化:

varNum = 6;
buf    = 2000;
dt     = (varNum * 4 + 4) * 8 / baudrate;
time   = -dt*(buf/2):dt:dt*(buf/2-1);


for i = 1:varNum
	namelist{i} = ['var',num2str(i-1)];
	dataBuf.(namelist{i}) = zeros(buf,1);
end

Step 3. 协议解析

协议解析主要是找到帧尾标志,使用 read() 读取4字节串口数据并判断是否是帧尾,找到帧尾就可以按照对应位置解析数据。转换 00 00 80 7F 为十进制数组 0 0 128 127 再进行判断,如果找到帧尾,就依次读取数据位(这里读取的是下一帧的数据,差一帧)。然后使用 circshift() 循环存储数据,让缓冲区的最后一位始终存储最新的数据。

因为数据是小端浮点数组(先发低位再发高位),所以使用 flip() 函数重新排序,然后将读取到的数据转换为 uint32,再使用 typecast() 函数转换为单精度浮点型数据。

dec2uint32 = @(dec)uint32(dec * [2^24, 2^16, 2^8, 2^0]');
temp = read(myPort,4,'uint8');
if prod(temp == [0 0 128 127])
    temp = read(myPort, varNum * 4, 'uint8');
    dataBuf.var0 = circshift(dataBuf.var0);
    dataBuf.var0(end) = typecast(dec2uint32(flip(temp(1:4))),'single');
    dataBuf.var1 = circshift(dataBuf.var1);
    dataBuf.var1(end) = typecast(dec2uint32(flip(temp(5:8))),'single');
    dataBuf.var2 = circshift(dataBuf.var2);
    dataBuf.var2(end) = typecast(dec2uint32(flip(temp(9:12))),'single');
    dataBuf.var3 = circshift(dataBuf.var3);
    dataBuf.var3(end) = typecast(dec2uint32(flip(temp(13:16))),'single');
    dataBuf.var4 = circshift(dataBuf.var4);
    dataBuf.var4(end) = typecast(dec2uint32(flip(temp(17:20))),'single');
    dataBuf.var5 = circshift(dataBuf.var5);
    dataBuf.var5(end) = typecast(dec2uint32(flip(temp(21:24))),'single');
end

同样这里可以使用动态变量命名简化代码:

temp = read(myPort,4,'uint8');
if prod(temp == [0 0 128 127])
    temp = read(myPort, varNum * 4, 'uint8');
    for i = 1:varNum
        dataBuf.(namelist{i})      = circshift(dataBuf.(namelist{i}),-1);
        dataBuf.(namelist{i})(end) = typecast(dec2uint32(flip(temp((i-1) * 4 + 1: i * 4))),'single');
    end
end

Step 4. 绘制数据

先建立 figure 对象,使用 while 判断窗体存在条件,持续绘制数据

h   = figure;
plotenabled = 0;

%%
while(ishandle(h))
    temp = read(myPort,4,'uint8');
    if prod(temp == [0 0 128 127])
        temp = read(myPort, varNum * 4, 'uint8');
        for i = 1:varNum
            dataBuf.(namelist{i})      = circshift(dataBuf.(namelist{i}),-1);
            dataBuf.(namelist{i})(end) = typecast(dec2uint32(flip(temp((i-1) * 4 + 1: i * 4))),'single');
        end
        plot(time, dataBuf.var5,'b-','LineWidth',1.5);
        if plotenabled == 0
            plotenabled = 1;
            grid on
            title('Matlab Serial Port Read','FontSize',14,'FontName','Times New Roman');
            xlabel('Time','FontSize',14,'FontName','Times New Roman');
            ylabel('Value','FontSize',14,'FontName','Times New Roman');
        end
    end
    plotenabled = 0;
end
  • 变量 plotenabled 用于首次绘图设置绘图参数,只有第一次绘图的时候会执行设置 title, xlabel, ylabel 等参数。

完整的 Matlab 代码如下:

%---------------------------------------
% This is the series port read script
%
% hu 2023-07-07 Created
% hu 2024-04-10 Test vofa+ protocol
%---------------------------------------

clc,clear,close all
devicelist = serialportlist' % This command shows the port connected.

baudrate        = 115200;
device          = "/dev/cu.usbserial-A700eG4x";
myPort          = serialport(device,baudrate); 
myPort.DataBits = 8;
myPort.StopBits = 1;
myPort.Parity   = "none";

varNum   = 6;
buf      = 2000;
dt       = (varNum * 4 + 4) * 8 / baudrate;
time     = -dt*(buf/2):dt:dt*(buf/2 - 1);

for i = 1:varNum
    namelist{i} = ['var',num2str(i-1)];
    dataBuf.(namelist{i}) = zeros(buf,1);
end
dec2uint32 = @(dec)uint32(dec * [2^24, 2^16, 2^8, 2^0]');

h   = figure;
plotenabled = 0;

%%
while(ishandle(h))
    temp = read(myPort,4,'uint8');
    if prod(temp == [0 0 128 127])
        temp = read(myPort, varNum * 4, 'uint8');
        for i = 1:varNum
            dataBuf.(namelist{i})      = circshift(dataBuf.(namelist{i}),-1);
            dataBuf.(namelist{i})(end) = typecast(dec2uint32(flip(temp((i-1) * 4 + 1: i * 4))),'single');
        end
        plot(time, dataBuf.var5,'b-','LineWidth',1.5);
        if plotenabled == 0
            plotenabled = 1;
            grid on
            title('Matlab Serial Port Read','FontSize',14,'FontName','Times New Roman');
            xlabel('Time','FontSize',14,'FontName','Times New Roman');
            ylabel('Value','FontSize',14,'FontName','Times New Roman');
        end
    end
    plotenabled = 0;
end
clc,clear,close all

绘制数据可以通过 fig 窗口保存到本地,或者在数据转换后保存到工作区,这里不再赘述。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/536570.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

性能分析-nginx(tomcat、nginx【配置】、负载均衡)

tomcat 像kyj项目请求直接对接 tomcat,tomcat的连接池就会直接影响“并发用户数” 如果这种情况下做性能测试的时候,并发用户数不能满足要求,可以适当加大线程池的配置。 如:项目性能测试发现项目所在机器,资源利用率…

hexo接入github Discussions评论系统

评论存储仓 可以是你的博客项目的(github)仓库,也可以单独新建一个评论存储仓库。 我的博客项目在gitee上,就以新建存储仓为例: 使用Discussions评论系统必须开通Discussions模块! 安装giscus插件 https://github.com/apps/…

书客、月影、欧普护眼大路灯哪款好?三款落地灯真实对比测评

作为在照明电器领域资深的评测员,我对市面上各种新颖的照明家电有着深入的探索和研究。大路灯能够提供舒适健康的照明光线,目前正受到许多用眼人群的广泛欢迎。,当然随着大路灯的普及,市场中也充斥着一些低劣的大路灯产品&#xf…

中国平安金融壹账通交付管理中心总经理崔羽先生受邀为第十三届中国PMO大会演讲嘉宾

全国PMO专业人士年度盛会 中国平安金融壹账通交付管理中心总经理崔羽先生受邀为PMO评论主办的2024第十三届中国PMO大会演讲嘉宾,演讲议题为“项目管理成与败,人才是第一要素”。大会将于5月25-26日在北京举办,敬请关注! 议题简要…

消息队列之-----------------zookeeper机制

目录 一、ZooKeeper是什么 二、ZooKeeper的工作机制 三、ZooKeeper特点 四、ZooKeeper数据结构 五、ZooKeeper应用场景 5.1统一命名服务 5.2统一配置管理 5.3统一集群管理 5.4服务器动态上下线 5.5软负载均衡 六、ZooKeeper的选举机制 6.1第一次启动选举机制 6.2非…

Java中的TCP通信

TCP通信 TCP通信Socket客户端ServerSocket服务端 例子:一发一收例子:多发多收异常捕获 例子:服务器与多个客户端同时通信多客户端通信架构服务端代码ServerReaderThread 服务端读数据线程 TCP通信 特点:面向连接、可靠通信 通信双…

[C++][算法基础]树的重心(树图DFS)

给定一颗树,树中包含 n 个结点(编号 1∼n)和 n−1 条无向边。 请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。 重心定义:重心是指树中的一个结点,如果将这个点删除后&a…

为什么越来越多的网工运维转行网络安全?

最近越来越多的网工运维小伙伴都在吐槽:干网工、运维多年,薪资还是5.6K,技术也遇瓶颈上不去,考虑转岗或者转行。其中大部分的网工运维小伙伴们纷纷瞄准了高薪高前景的网络安全工程师岗位 网络安全是怎样的岗位? 人才…

星抖短剧养猪,闲鱼出售金币,日收益50-200+,零成本副业项目

自3月31日推出以来,“星斗短剧”平台迅速获得了众多团队的关注和推崇,用户数量持续增长。 目前,已有超过26万的用户群体活跃在平台上。用户数量的庞大直接映射了市场的广阔和需求的多样性,为我们提供了赚取收益的良机。 公 众号…

自然语言处理、大语言模型相关名词整理

自然语言处理相关名词整理 零样本学习(zero-shot learning)词嵌入(Embedding)为什么 Embedding 搜索比基于词频搜索效果好? Word2VecTransformer检索增强生成(RAG)幻觉采样温度Top-kTop-p奖励模…

HarmonyOS实战开发-WebSocket的使用。

介绍 本示例展示了WebSocket的使用,包括客户端与服务端的连接和断开以及客户端数据的接收和发送。 WebSocket连接:使用WebSocket建立服务器与客户端的双向连接,需要先通过createWebSocket方法创建WebSocket对象,然后通过connect…

node express 请求参数接收方式汇总

express 安装使用 express官网 express 是node.js 中写后端服务比较流行的框架。 安装express npm install -g express安装 express-generator 相当于vue的cli 用来快速生成express项目 npx express-generator生成项目mynode -e是使用ejs模版 express -e mynodeexpress生成器生…

TouchGFX 控件附加 ClickListener 功能的方法介绍

1. 引言 TouchGFX 是专用于 STM32 的图形界面设计软件,可用来低成本开发优秀的图形界面,TouchGFX 现已变的越来越流行。为了帮助客户更加深入地理解和使用 TouchGFX ,本文介绍了 TouchGFX Designer 中的 Mixin 功能,从基础示例 B…

Docker核心特征

Docker的基本概念 Dockerfile:制作进行的文件,可以理解为制作镜像的一个清单。 镜像:用来创建容器的安装包,可以理解为给电脑安装操作系统的系统镜像。 容器:通过镜像来创建的一套运行环境,一个容器里可…

每日一题 — 将 x 减到 0 的最小操作数

思路: 题目要求是让我们从数组的最左端和最右端进行操作,这样的话解题的难度大大提升,我们可以用 正难则反 的思想: 题目中要求是减去数组中的数刚好等于X,我们可以转换成 数组中某一段的和等于 数组的总长减去X(sum -…

vue $set()使用复习总结

一维数据: this.$set(数组, 下标, 内容); this.$set(this.typeList, 1, 榴莲); 数组对象: this.$set( target要更改的数据源(可以是对象或者数组), key要更改的具体数据, value重新赋的值 ) 用法一: 循环外,单独使用 用法二 &…

仿真测试平台设计资料:921-6U CPCI卫星接口仿真测试平台

6U CPCI卫星接口仿真测试平台 一、设备概述 卫星接口仿真测试平台基于6U CPCI的结构,包含信号接口前板、后板,计算机主板、机箱、电源等硬件。硬件设计包括:信号接口前板、后板(直接遥测遥控、串行RS422、LVDS,模拟量输…

【MySQL】数据库开篇

SueWakeup 个人主页:SueWakeup 系列专栏:学习技术栈 个性签名:保留赤子之心也许是种幸运吧 本文封面由 凯楠📸友情提供 目录 本系列传送门 1. 什么是数据库? 2. 为什么使用数据库 3. 数据库的分类 4. NoSQL 与关系…

Springboot+vue的粮仓管理系统的设计与实现(有报告)。Javaee项目,springboot vue前后端分离项目。

演示视频: Springbootvue的粮仓管理系统的设计与实现(有报告)。Javaee项目,springboot vue前后端分离项目。 项目介绍: 采用M(model)V(view)C(controller&am…

服务器感染了.rmallox勒索病毒,如何确保数据文件完整恢复?

引言: 随着网络技术的发展,勒索病毒已经成为当今数字时代的一大威胁。近期出现的.rmallox勒索病毒更是引发了广泛关注。本文将深入探讨.rmallox勒索病毒的特点,并提供一系列应对这一威胁的高效策略。如果受感染的数据确实有恢复的价值与必要…