Matlab 实时读取串口并绘图

news2024/11/26 16:48:58

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 窗口保存到本地,或者在数据转换后保存到工作区,这里不再赘述。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【vscode】在本地加载远端环境并开发

【vscode】在本地利用远程服务器显卡跑代码 写在最前面vscode:远程到本地1、安装ssh插件2、添加服务器连接配置3、连接服务器4. SSH配置5. 在ssh中安装python解释器 vscode基本操作 🌈你好呀!我是 是Yu欸 🌌 2024每日百字篆刻时光…

Grafana告警(邮件)自定义模板配置

一年前给客户部署配置过grafana,告警配置也是用的原始的,客户在使用过程中只需要一些核心点信息,想要实现这个就需要用Grafana的自定义告警模板以及编辑邮件模板。 通知模板 模板信息的配置中查阅了相关资料,自己组装了一套&…

Android Framework学习笔记(3)----Binder

什么是Binder? Binder是linux IPC机制的其中一种。它贯穿于应用层,framework层,以及linux Core层。 什么是IPC? 跨进程通信, InterProcess Communication. IPC机制都有哪些? 通道信号量消息队列BinderSocket共享内…

(Java)数据结构——排序(第一节)堆排序+PTA L2-012 关于堆的判断

前言 本博客是博主用于复习数据结构以及算法的博客,如果疏忽出现错误,还望各位指正。 堆排序(Heap Sort)概念 堆排序是一种基于堆数据结构的排序算法,其核心思想是将待排序的序列构建成一个最大堆(或最小…

【C语言基础】:文件操作详解(后篇)

文章目录 一、文件的顺序读写1.1 顺序函数读写函数介绍1.2 fgetc函数和fputc函数1.3 fputs函数和fgets函数1.4 fprintf函数和fscanf函数1.5 fwrite函数和fread函数 二、文件的随机读写2.1 fseek函数2.2 ftell函数2.3 rewind函数 三、文件读取结束的判定3.1 feof函数 四、文件缓…

Linux操作系统的学习

Linux系统的目录结构 / 是所有目录的顶点目录结构像一颗倒挂的树 Linux常用命令 常见命令 序号命令对应英文作用1lslist查看当前目录下的内容2pwdprint work directory查看当前所在目录3cd [目录名]change directory切换目录4touch [文件名]touch如果文件不存在,新…

4. 依赖查找依赖注入

本小节源码:Spring-DI 1. 依赖查找 前面两个小节我们学习了如何将 Bean 对象分别以配置文件与注解的方式存入 Spring 中,然而通过 Bean 从 Spring 容器中取出的过程其实就是依赖查找,这里我简单归纳一下各种依赖查找的方式。 1.1 通过beanI…

【MySQL】索引篇

SueWakeup 个人主页:SueWakeup 系列专栏:学习技术栈 个性签名:保留赤子之心也许是种幸运吧 本文封面由 凯楠📸友情提供 目录 本系列传送门 1. 什么是索引 2. 索引的特性 3. 索引的分类 4. 索引的优点及缺点 优点 缺点 5.…

FPGA基于VCU的H265视频压缩,HDMI2.0输入,支持4K60帧,提供工程源码+开发板+技术支持

目录 1、前言免责声明 2、相关方案推荐我这里已有的视频图像编解码方案 3、详细设计方案设计框图FPGA开发板视频输入Video PHY ControllerHDMI 1.4/2.0 Receiver SubsystemVideo Processing SubsystemVideo Frame Buffer WriteZynq UltraScale VCUPetaLinux 系统制作VLC播放器工…

ElasticSearch的数据同步【Java实现】

文章目录 1、思路分析1.1、同步调用1.2、异步通知1.3、监听binlog1.4、如何选择 2、实现数据同步2.1、思路2.2、demo2.3、声明交换机、队列1)引入依赖2)声明队列交换机名称3)声明队列交换机 2.4、发送MQ消息2.5、接收MQ消息 3、代码链接分享 …

Quartz + SpringBoot 实现分布式定时任务

文章目录 前言一、分布式定时任务解决方案二、Quartz是什么?1.quartz简介2.quartz的优缺点 二、Quartz分布式部署总结 前言 因为应用升级,由之前的单节点微服务应用升级为集群微服务应用,所以之前的定时任务Spring Scheduled不再适用了&…

蓝桥备赛——组合数、其他技巧

对字符串进行permutations排列组合 from itertools import permutations a abc #对字符串进行permutations排列组合 for i in permutations(a,3):x .join(i)print (x,end ) print (\n------------------------------------) permutations后面的参数,第一个表示…

Canal 扩展篇

1.Canal介绍 GitHub - alibaba/canal: 阿里巴巴 MySQL binlog 增量订阅&消费组件 Canal 主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费,工作原理如下: Canal 模拟 MySQL slave 的交互协议,伪装自己为 M…

【原创】springboot+mysql宠物管理系统设计与实现

个人主页:程序猿小小杨 个人简介:从事开发多年,Java、Php、Python、前端开发均有涉猎 博客内容:Java项目实战、项目演示、技术分享 文末有作者名片,希望和大家一起共同进步,你只管努力,剩下的交…

Redis(二十)五大经典类型源码

文章目录 面试题源码核心Redis基本的数据结构(骨架)Redis数据库的实现Redis服务端和客户端实现其他 K-V实现怎样实现键值对(key-value)数据库的传统五大基本数据类型和新五大数据类型 5大数据结构底层C语言源码分析示例redisObject五大数据结构解析定义Debug Object keyString …

01 SQL基础 -- 初识数据库与安装

一、初识数据库 数据库是将大量数据保存起来,通过计算机加工而成的可以进行高效访问的数据集合。该数据集合称为数据库(Database, DB)。用来管理数据库的计算机系统称为数据库管理系统(Database Management System, DBMS) 1.1 DBMS 的种类 DBMS 主要通过数据的保存格式…

【WEEK7】 【DAY3】JDBC—数据库驱动【中文版】

2024.4.10 Wednesday 目录 10.JDBC10.1.数据库驱动10.1.1.驱动10.1.2.JDBC10.1.3.第一个JDBC程序10.1.3.1.创建一个普通项目10.1.3.2.导入数据库驱动10.1.3.3.编写测试代码10.1.3.4.DriverManager10.1.3.5.URL10.1.3.6.Connection10.1.3.7.Statement执行SQL的对象10.1.3.8.Res…

[大模型]Atom-7B-chat网页例子

# Atom-7B-chat## 环境准备在[autodl](https://www.autodl.com/)平台中租一个3090等24G显存的显卡机器,如下图所示镜像选择PyTorch-->2.0.0-->3.8(ubuntu20.04)-->11.8![Alt text](images/image-1.png)接下来打开刚刚租用服务器的JupyterLab,并…

Codeforces Round 937 (Div. 4)(A~E)

A. Stair, Peak, or Neither? 根据题意来就可以了 #include <bits/stdc.h> using namespace std;void solve(){int a,b,c;cin>>a>>b>>c;if(a<b and b<c){cout<<"STAIR"<<endl;}else if(a<b and b>c){cout<<…

Docker部署SpringBoot+Vue前后端分离项目

文章目录 1. 安装Docker1. 1 卸载旧版Docker1.2 配置yum仓库1.3 安装Docker1.4 添加自启动配置1.5 配置阿里云镜像加速1.6 测试 2. 安装Nginx2.1 拉取镜像2.2 安装Nginx2.3 测试 3. 安装MySQL3.1 拉取镜像3.2 安装MySQL3.3 连接MySQL 4. 部署SpringBoot项目4.1 Maven打包4.2 编…