MATLAB实现串口输入数据的实时绘图

MATLAB实现串口输入数据的实时绘图

  最近做了一个基于单片机的心率计,其中需要用计算机将波形数据以实时绘图的方式呈现出来。参考了一些网上的资料,写了一个简单的matlab程序,记录一下。

0 说明

  1. 基本原理:通过手指指尖的血流变化反映脉搏变化。传感器(KY-039,淘宝上可以搜到)的一端是红外二极管,一端是光敏三极管,脉搏引起的血流变化引发光强变化,进而导致电压变化。
  2. 脉搏信号被一个红外传感器采集后,经过放大滤波电路输入单片机,再经ADC,从串口输出。
  3. 输出在0-1023范围内,需要用两个字节表示。

1 创建串口对象

  创建串口对象s,并对其部分参数进行设置。下面只设置了一部分,当然,可以根据自己的需要进一步设置,比如波特率之类,可以运行这段代码后在工作区点开s查看:
串口对象

s=serial('com3');  % COM
s.BytesAvailableFcnMode='byte';  
s.InputBufferSize=4096;
s.OutputBufferSize=1024;
s.BytesAvailableFcnCount=100;
s.ReadAsyncMode='continuous';
s.Terminator='CR';

2 数据读取与转化

  打开串口,同时打开一个文件保存数据。

fopen(s);    % 打开串口
fid=fopen('serial_data.txt','wt');

  寻找读取起点:

init = 1;
while(init~='#')
    init = fread(s,1,'uint8');
end
out = fread(s,2,'uint8');  % 8bit读两次

  这里 ‘#’ 是一个标志字符(这是单片机代码中设置的),因为需要用两个字节表示一个点的值,#的作用就是让程序知道,从这里开始往后两个字节拼起来是一个数。这组数据是不用的(其实要用也可以,但不差这一个点的数据),之后再读取就只需循环:

out = fread(s,3,'uint8');

  注意out是一个列向量,out(1)是#,out(2)是数值的高8位,out(3)是低8位。
  接下来是对数据的转换,将两个8位二进制数位拼接转成一个十进制数:

num = out(2)*256+out(3);

  或者也可以将这个数存在out(1)中,反正 ‘#’ 已经达成使命,现在它反而变成了一个累赘。

3 绘图

  设置一个向量t作为横坐标,长度是InputBufferSize,纵坐标上下留出margin的空间。

hold on
grid on
InputBufferSize = 100;
margin = 50;
t = 1:InputBufferSize;

  用InputBuffer存放当前需要绘制区域内的所有数值,即它的长度也是InputBufferSize。那么画“一帧”的图像就是:

plot([1:i],InputBuffer(1,1:i),'-r');
axis([t(1) t(InputBufferSize) min(InputBuffer)-margin max(InputBuffer)+margin]);

4 绘制动态图像

  怎么让上述图像动起来呢?其实很简单,只要将每次新读进来的数据放到InputBuffer的最后,InputBuffer中所有元素向前移动一格,再把坐标轴右移1,就得到了下一帧图像的全部信息。让这个过程循环往复,图线就动起来了。

for i = 1:1000
    t=t+1;
    for j = 2:InputBufferSize  % 循环左移一格
        InputBuffer(j-1) = InputBuffer(j);
    end
    out = fread(s,3,'uint8');   % 一次读出3个字符
    out = out';  % 其实没什么必要
    num = out(2)*256+out(3);
    fprintf(fid,'%g\n',num);  % 存入文件
    InputBuffer(InputBufferSize) = num;
    plot(t,InputBuffer(1,:),'-r');
    axis([t(1) t(InputBufferSize) min(InputBuffer)-margin max(InputBuffer)+margin]);
    pause(0.001);
end

  如果想做得再好一点,能呈现最开始从0慢慢长到InputBufferSize过程中的图线,那就在这段之前加一段:

for i = 1:InputBufferSize
    out = fread(s,3,'uint8');   % 一次读出3个字符
    out = out';
    num = out(2)*256+out(3);
    InputBuffer(i) = num;
    fprintf(fid,'%g\n',num);
    plot([1:i],InputBuffer(1,1:i),'-r');
    axis([t(1) t(InputBufferSize) min(InputBuffer)-margin max(InputBuffer)+margin]);
    pause(0.001);
end

  与上面一段类似,只是这里固定坐标轴,且新数据只加在InputBuffer的最后。
  最后别忘了关掉串口和文件~

fclose(s);
fclose(fid);

5 完整代码

clear;
s=serial('com4');
s.BytesAvailableFcnMode='byte';  % 串口设置
s.InputBufferSize=4096;
s.OutputBufferSize=1024;
s.BytesAvailableFcnCount=100;
s.ReadAsyncMode='continuous';
s.Terminator='CR';

fopen(s);    % 打开串口
fid=fopen('serial_data.txt','wt');
init = 1;
while(init~='#')
    init = fread(s,1,'uint8');
end
out = fread(s,2,'uint8');

hold on
grid on
InputBufferSize = 100;
margin = 50;
t = 1:InputBufferSize;
% InputBuffer = zeros(1,InputBufferSize);
for i = 1:InputBufferSize
    out = fread(s,3,'uint8');   % 一次读出3个字符
    out = out';
    num = out(2)*256+out(3);
    InputBuffer(i) = num;
    fprintf(fid,'%g\n',num);
    plot([1:i],InputBuffer(1,1:i),'-r');
    axis([t(1) t(InputBufferSize) min(InputBuffer)-margin max(InputBuffer)+margin]);
    pause(0.001);
end

for i = 1:1000
%     hold on
    t=t+1;
    for j = 2:InputBufferSize
        InputBuffer(j-1) = InputBuffer(j);
    end
    out = fread(s,3,'uint8');   % 一次读出3个字符
    out = out';
    num = out(2)*256+out(3);
    fprintf(fid,'%g\n',num);
    InputBuffer(InputBufferSize) = num;
    plot(t,InputBuffer(1,:),'-r');
    axis([t(1) t(InputBufferSize) min(InputBuffer)-margin max(InputBuffer)+margin]);
    pause(0.001);
end
fclose(s);
fclose(fid);

6 补充

  1. 如果需要中断运行,可以在命令行中Ctrl + C,但记得随后在命令行中输入fclose(s)以关闭串口,否则下次启动会报错。无论何种方式导致程序没有执行到fclose(s),都应在下次运行前手动关闭串口。
  2. 若开始运行时报错,先检查串口是否匹配,若匹配,再检查串口当前是否被其他程序占用,若没有,尝试重启MATLAB。(再不行,重启电脑,再不行我也不知道了2333
  3. 放几张运行结果图(更新了一张动图)
    在这里插入图片描述
    在这里插入图片描述

版权声明:本文为CSDN博主「Volumtuous」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_48510320/article/details/118945642

MATLAB实现串口输入数据的实时绘图

  最近做了一个基于单片机的心率计,其中需要用计算机将波形数据以实时绘图的方式呈现出来。参考了一些网上的资料,写了一个简单的matlab程序,记录一下。

0 说明

  1. 基本原理:通过手指指尖的血流变化反映脉搏变化。传感器(KY-039,淘宝上可以搜到)的一端是红外二极管,一端是光敏三极管,脉搏引起的血流变化引发光强变化,进而导致电压变化。
  2. 脉搏信号被一个红外传感器采集后,经过放大滤波电路输入单片机,再经ADC,从串口输出。
  3. 输出在0-1023范围内,需要用两个字节表示。

1 创建串口对象

  创建串口对象s,并对其部分参数进行设置。下面只设置了一部分,当然,可以根据自己的需要进一步设置,比如波特率之类,可以运行这段代码后在工作区点开s查看:
串口对象

s=serial('com3');  % COM
s.BytesAvailableFcnMode='byte';  
s.InputBufferSize=4096;
s.OutputBufferSize=1024;
s.BytesAvailableFcnCount=100;
s.ReadAsyncMode='continuous';
s.Terminator='CR';

2 数据读取与转化

  打开串口,同时打开一个文件保存数据。

fopen(s);    % 打开串口
fid=fopen('serial_data.txt','wt');

  寻找读取起点:

init = 1;
while(init~='#')
    init = fread(s,1,'uint8');
end
out = fread(s,2,'uint8');  % 8bit读两次

  这里 ‘#’ 是一个标志字符(这是单片机代码中设置的),因为需要用两个字节表示一个点的值,#的作用就是让程序知道,从这里开始往后两个字节拼起来是一个数。这组数据是不用的(其实要用也可以,但不差这一个点的数据),之后再读取就只需循环:

out = fread(s,3,'uint8');

  注意out是一个列向量,out(1)是#,out(2)是数值的高8位,out(3)是低8位。
  接下来是对数据的转换,将两个8位二进制数位拼接转成一个十进制数:

num = out(2)*256+out(3);

  或者也可以将这个数存在out(1)中,反正 ‘#’ 已经达成使命,现在它反而变成了一个累赘。

3 绘图

  设置一个向量t作为横坐标,长度是InputBufferSize,纵坐标上下留出margin的空间。

hold on
grid on
InputBufferSize = 100;
margin = 50;
t = 1:InputBufferSize;

  用InputBuffer存放当前需要绘制区域内的所有数值,即它的长度也是InputBufferSize。那么画“一帧”的图像就是:

plot([1:i],InputBuffer(1,1:i),'-r');
axis([t(1) t(InputBufferSize) min(InputBuffer)-margin max(InputBuffer)+margin]);

4 绘制动态图像

  怎么让上述图像动起来呢?其实很简单,只要将每次新读进来的数据放到InputBuffer的最后,InputBuffer中所有元素向前移动一格,再把坐标轴右移1,就得到了下一帧图像的全部信息。让这个过程循环往复,图线就动起来了。

for i = 1:1000
    t=t+1;
    for j = 2:InputBufferSize  % 循环左移一格
        InputBuffer(j-1) = InputBuffer(j);
    end
    out = fread(s,3,'uint8');   % 一次读出3个字符
    out = out';  % 其实没什么必要
    num = out(2)*256+out(3);
    fprintf(fid,'%g\n',num);  % 存入文件
    InputBuffer(InputBufferSize) = num;
    plot(t,InputBuffer(1,:),'-r');
    axis([t(1) t(InputBufferSize) min(InputBuffer)-margin max(InputBuffer)+margin]);
    pause(0.001);
end

  如果想做得再好一点,能呈现最开始从0慢慢长到InputBufferSize过程中的图线,那就在这段之前加一段:

for i = 1:InputBufferSize
    out = fread(s,3,'uint8');   % 一次读出3个字符
    out = out';
    num = out(2)*256+out(3);
    InputBuffer(i) = num;
    fprintf(fid,'%g\n',num);
    plot([1:i],InputBuffer(1,1:i),'-r');
    axis([t(1) t(InputBufferSize) min(InputBuffer)-margin max(InputBuffer)+margin]);
    pause(0.001);
end

  与上面一段类似,只是这里固定坐标轴,且新数据只加在InputBuffer的最后。
  最后别忘了关掉串口和文件~

fclose(s);
fclose(fid);

5 完整代码

clear;
s=serial('com4');
s.BytesAvailableFcnMode='byte';  % 串口设置
s.InputBufferSize=4096;
s.OutputBufferSize=1024;
s.BytesAvailableFcnCount=100;
s.ReadAsyncMode='continuous';
s.Terminator='CR';

fopen(s);    % 打开串口
fid=fopen('serial_data.txt','wt');
init = 1;
while(init~='#')
    init = fread(s,1,'uint8');
end
out = fread(s,2,'uint8');

hold on
grid on
InputBufferSize = 100;
margin = 50;
t = 1:InputBufferSize;
% InputBuffer = zeros(1,InputBufferSize);
for i = 1:InputBufferSize
    out = fread(s,3,'uint8');   % 一次读出3个字符
    out = out';
    num = out(2)*256+out(3);
    InputBuffer(i) = num;
    fprintf(fid,'%g\n',num);
    plot([1:i],InputBuffer(1,1:i),'-r');
    axis([t(1) t(InputBufferSize) min(InputBuffer)-margin max(InputBuffer)+margin]);
    pause(0.001);
end

for i = 1:1000
%     hold on
    t=t+1;
    for j = 2:InputBufferSize
        InputBuffer(j-1) = InputBuffer(j);
    end
    out = fread(s,3,'uint8');   % 一次读出3个字符
    out = out';
    num = out(2)*256+out(3);
    fprintf(fid,'%g\n',num);
    InputBuffer(InputBufferSize) = num;
    plot(t,InputBuffer(1,:),'-r');
    axis([t(1) t(InputBufferSize) min(InputBuffer)-margin max(InputBuffer)+margin]);
    pause(0.001);
end
fclose(s);
fclose(fid);

6 补充

  1. 如果需要中断运行,可以在命令行中Ctrl + C,但记得随后在命令行中输入fclose(s)以关闭串口,否则下次启动会报错。无论何种方式导致程序没有执行到fclose(s),都应在下次运行前手动关闭串口。
  2. 若开始运行时报错,先检查串口是否匹配,若匹配,再检查串口当前是否被其他程序占用,若没有,尝试重启MATLAB。(再不行,重启电脑,再不行我也不知道了2333
  3. 放几张运行结果图(更新了一张动图)
    在这里插入图片描述
    在这里插入图片描述

版权声明:本文为CSDN博主「Volumtuous」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_48510320/article/details/118945642

生成海报
点赞 0

Volumtuous

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

Matlab 与stm32单片机之间的串口通信

Matlab 与stm32单片机之间的串口通信 在我们用stm32做信号处理时,我时常需要用到Matlab对我们采集的数据进行分析,拟合。按照传统的方法,我们一般都会先将数据通过串口助手打印出来&#x

MATLAB实现串口输入数据的实时绘图

MATLAB实现串口输入数据的实时绘图 最近做了一个基于单片机的心率计,其中需要用计算机将波形数据以实时绘图的方式呈现出来。参考了一些网上的资料,写了一个简单的matlab程序,记录一下。 0 说明

Matlab 与stm32单片机之间的串口通信

Matlab 与stm32单片机之间的串口通信 在我们用stm32做信号处理时,我时常需要用到Matlab对我们采集的数据进行分析,拟合。按照传统的方法,我们一般都会先将数据通过串口助手打印出来&#x

基于8051单片机实现电子时钟+数字秒表设计

概述 电子时钟是一种利用数字电路来显示秒、分、时的计时装置,与传统的机械钟相比,它具有走时准确、显 示直观、无机械传动装置等优点,因而得到广泛应用。随着人们生活环境的不断改善和美化,在许