这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 高校专区 » 东师科技爱好者 » 秉着开源的原则,将MATLAB串口示波器的源代码发放出来,希望能给大家帮助(原创

共11条 1/2 1 2 跳转至

秉着开源的原则,将MATLAB串口示波器的源代码发放出来,希望能给大家帮助(原创)

菜鸟
2016-04-17 20:06:58     打赏

转载请注明作者:东北师范大学 黄兆伟

嗯~整个项目在MATLAB上做了大概四天,从对MATLAB的串口操作一无所知到现在做出一个小的7通道的16位无符号(有符号)整型串口示波器,接触到了很多MATLAB高大上的玩法,而且网上用matlab来做波形显示的参考资料不多,希望。将源代码发出来,供大家参考,废话不多说,马上上代码~代码分为四个文件,其中MATLAB串口代码三个,一层楼一个~首先是串口配置函数。接下来的每层楼都更新一个函数,并配上标注~

协会开论坛不容易,大家用了的话~能回帖的尽量回个贴~


close all;
clear all;
clc;

hold on      %这一句经测试是必要的,没有这句的话~波形显示的句柄好像无法调用

global t;
global x;
global m;
global ii;
global data;    %数据缓冲矩阵

data = [0];
t = [0];        %显示的时候为x轴变量,本质是采样点数
m = ones(7,1);  %m为数据存储矩阵,每一行为一个通道,从串口打开到结束,每一行的数据都存放于这个矩阵,接收到波形后可以进行数据分析、拟合
x = -100;       %x轴起始坐标
ii = 1;         %也是一个类似起始位的东西

h1 = plot(1,'b','MarkerSize',20);   %通道1的颜色与线粗,h1为句柄,以下同
h2 = plot(0,'g','MarkerSize',20);
h3 = plot(0,'r','MarkerSize',20);
h4 = plot(0,'c','MarkerSize',20);
h5 = plot(0,'m','MarkerSize',20);

h6 = plot(0,'y','MarkerSize',20);
h7 = plot(0,'k','MarkerSize',20);
H = [h1;h2;h3;h4;h5;h6;h7];         %所有通道句柄的入口矩阵,方便回调函数传参

title('Matlab Scope——东北师范大学电磁翼');   %本开源代码由东北师范大学——电磁翼小组(2016年4月17日)编写
legend('ch1','ch2','ch3','ch4','ch5','ch6','ch7',2);    %在左上角标注通道
%grid on;
xlabel('采样点数');             %标注X轴
ylabel('数值大小');             %标注Y轴
s = serial('COM18');            %选择串口~
s.BaudRate = 9600;              %选择波特率
s.DataBits = 8;                 %设置数据位数
s.StopBits = 1;                 %设置停止位
set(s,'Parity', 'none','FlowControl','none');   %无校验位,无流控制
s.ReadAsyncMode = 'continuous';                 %异步接收模式为连续
s.BytesAvailableFcnMode = 'byte';               %回调函数模式为字节
s.BytesAvailableFcnCount = 20;                  %每接收到20个字节,触发中断,调用回调函数,0xff,0xa5,0x5a(0x5b) 三位帧头+七位数据
s.BytesAvailableFcn = {@callback_16bit,H};      %回调函数地址,以及相应波形显示通道句柄

try
    fopen(s);                               %打开串口
catch err
    fprintf('串口打开失败。\n');
end

fprintf('串口打开成功\n');






关键词: MATLAB     串口     波形    

菜鸟
2016-04-17 20:14:45     打赏
2楼
function callback_16bit(s,BytesAvailable,p)
%function callback(s, p) 
% 串口接收中断的回调函数
global t; 
global x; 
global m; 
global ii;
global data;

n_bytes = s.BytesAvailable;         %获取串口接收到数据的个数

out = fread(s,[1 n_bytes],'uint8'); %将串口数据以一行8位整型的形式显示出来
mat = zeros(7,1);                   %8位转16位数据处理矩阵
data = [data out];                  %合并缓存矩阵

while(length(data) >= 17)           %当data长度大于17时,不停循环
if(data(1) == 255 && data(2) == 165 && data(3) == 90)   %有符号整型帧头 0xff,0xa5,0x5a
%确认为一帧数据
data(1:3) = [];             %清空帧头位
for i = 1:7                 %将7个通道的数据提取出来
mat(i,1) = data(1)*256+data(2);     %将两个8位数据合并成16位数据
if (mat(i,1) > 32768)               %提取符号位
mat(i,1) = -(65536-mat(i,1));   %求补码
end
data(1:2) = [];                     %清空提取到的data缓存数据
end
m = [m mat];    %合并波形显示矩阵
ii = ii + 1;    %计数+1
t = [t ii];     %合并采样点数矩阵
x = x +  1;     %移动x轴
for j = 1:7     %刷新7通道的显示句柄
set(p(j),'xdata',t,'ydata',m(j,1:length(t)));
end

elseif(data(1) == 255 && data(2) == 165 && data(3) == 91)   %无符号整型帧头 0xff,0xa5,0x5b
%确认为一帧数据
data(1:3) = [];     %同上
for i = 1:7
mat(i,1) = data(1)*256+data(2);
data(1:2) = [];
end
m = [m mat]; %读取帧数据
ii = ii + 1;
t = [t ii];
x = x +  1;
for j = 1:7
set(p(j),'xdata',t,'ydata',m(j,1:length(t)));
end
else
data(1) = [];       %如果不是帧头,则数据错误??跳过错误数据直到找到帧头
end
end

y = length(m(1,:));     %求m矩阵的列数
%     ymin = min(m(1:7,y)); %求同列的最小值
%     ymax = max(m(1:7,y)); %求同列的最大值
ymin = min(min(m));     %求整个矩阵的最小值
ymax = max(max(m));     %求整个矩阵的最大值
drawnow                 %更新图形窗口
%axis([x-150 x+150 ymin-10 ymax+20]);       %更新两轴
axis([x-150 x+150 -50 50]);
end 




菜鸟
2016-04-17 20:15:22     打赏
3楼

最后~关闭串口~

fclose(s);  

delete(s);  
clear s  
close all;  
clear all; 
clc;


菜鸟
2016-04-17 20:18:17     打赏
4楼

再来一条,单片机上数据传回函数~

//----------------------------------------
// 函数名称:send_matlab
// 功能说明:MATLAB串口示波器
// 参数说明:mode为0时,matlab波形显示为16位有符号整型,
//           mode为1时,matlab波形显示为16位无符号整型
//           CH1-CH7为7个通道波形数据
// 函数返回:无
// 修改时间:2016/4/17
// 备    注:
//----------------------------------------
void send_matlab(uint8 mode,int ch1, int ch2, int ch3, int ch4, int ch5, int ch6, int ch7)
{
    uint8 send_data[17]={0};
    uint8 i;
    send_data[0] = 0xff;
    send_data[1] = 0xa5;
    send_data[2] = 0x5a+mode;
    send_data[3] = (uint8)((ch1&0xff00)>>8);
    send_data[4] = (uint8)(ch1&0x00ff);
    send_data[5] = (uint8)((ch2&0xff00)>>8);
    send_data[6] = (uint8)(ch2&0x00ff);
    send_data[7] = (uint8)((ch3&0xff00)>>8);
    send_data[8] = (uint8)(ch3&0x00ff);
    send_data[9] = (uint8)((ch4&0xff00)>>8);
    send_data[10] = (uint8)(ch4&0x00ff);
    send_data[11] = (uint8)((ch5&0xff00)>>8);
    send_data[12] = (uint8)(ch5&0x00ff);
    send_data[13] = (uint8)((ch6&0xff00)>>8);
    send_data[14] = (uint8)(ch6&0x00ff);
    send_data[15] = (uint8)((ch7&0xff00)>>8);
    send_data[16] = (uint8)(ch7&0x00ff);
    
    for(i=0;i<17;i++)
    { 
        uart_send1(UART1,send_data[i]);
    }
}

 



菜鸟
2016-04-17 20:26:55     打赏
5楼

目前还有点小bug,只能通过代码来修改通道数。

偷偷的告诉大家,在串口示波器运行的时候也可以对回调函数的代码进行修改哦,例如通道数,x、y轴缩放~保存后立马就能在示波器上看到效果~祝大家代码无BUG~接下来几楼可能会插几张图片~代码和功能还将会持续更新~


菜鸟
2016-04-17 20:28:06     打赏
6楼

菜鸟
2016-04-17 20:33:52     打赏
7楼

菜鸟
2016-04-19 13:06:56     打赏
8楼

我又回来了,这次带来的更新可以看双路十通道波形,上面五个通道是第一路的,下面五个通道是第二路的,两个通道相互不影响,两通道的Y轴数量级可以不相同,初衷是想看5路幅值高的波形和5路幅值低的波形~


菜鸟
2016-04-19 14:49:27     打赏
9楼
close all;
clear all;
clc;

global t;
global m;
global x;
global ii;
global data;
global SUBP

data = [0];
t = [0];
m = ones(10,1);
x = 1;
ii = 1;

%波形图形部分设置
figure('NumberTitle', 'off', 'Name', '东北师范大学 电磁翼十路示波器');
SUBP(1) = subplot(211);
hold on
h1 = plot(0,'b','MarkerSize',25);
h2 = plot(0,'g','MarkerSize',25);
h3 = plot(0,'r','MarkerSize',25);
h4 = plot(0,'c','MarkerSize',25);
h5 = plot(0,'m','MarkerSize',25);

title('示波器通道1-5——东北师范大学电磁翼');   %本开源代码由东北师范大学——电磁翼小组(2016年4月19日)编写
legend('ch1','ch2','ch3','ch4','ch5',2);    %在左上角标注通道
xlabel('采样点数');             %标注X轴
ylabel('数值大小');             %标注Y轴

%第二路(6-10通道)波形设置
SUBP(2) = subplot(212);
hold on
h6 = plot(0,'b','MarkerSize',25);
h7 = plot(0,'g','MarkerSize',25);
h8 = plot(0,'r','MarkerSize',25);
h9 = plot(0,'c','MarkerSize',25);
h10 = plot(0,'m','MarkerSize',25);

title('示波器通道6-10——东北师范大学电磁翼');   %本开源代码由东北师范大学——电磁翼小组(2016年4月17日)编写
legend('ch6','ch7','ch8','ch9','ch10',2);    %在左上角标注通道
xlabel('采样点数');             %标注X轴
ylabel('数值大小');             %标注Y轴

H = [h1;h2;h3;h4;h5;h6;h7;h8;h9;h10];

%串口部分设置
s = serial('COM18');            %选择串口~
s.BaudRate = 19200;              %选择波特率
s.DataBits = 8;                 %设置数据位数
s.StopBits = 1;                 %设置停止位
set(s,'Parity', 'none','FlowControl','none');   %无校验位,无流控制
s.ReadAsyncMode = 'continuous';                 %异步接收模式为连续
s.BytesAvailableFcnMode = 'byte';               %回调函数模式为字节
s.BytesAvailableFcnCount = 100;                  %每接收到100个字节,触发中断,调用回调函数,0xff,0xa5,0x5a(0x5b) 三位帧头+七位数据
s.BytesAvailableFcn = {@callback_16bit,H};      %回调函数地址,以及相应波形显示通道句柄

try
    fopen(s);                               %打开串口
catch err
    fprintf('串口打开失败。\n');
end

fprintf('串口打开成功\n');

 


这个是之前那张图的程序,上下双路十通道示波器,基本满足一般需求,我们用的是蓝牙传输波形数据。OPEN_SERIAL.m 打开串口通信通道,并且配置图形显示方式


菜鸟
2016-04-19 20:14:36     打赏
10楼

function callback_16bit(s,BytesAvailable,p)
% 串口接收中断的回调函数
    global t;  
    global x;  
    global m;  
    global ii;
    global data;
    global SUBP
    
    %宏定义
    
    plot_length = 8000; %整个视图中,波形显示多少个点,
    x_down = 1500;
    x_up = 150;
    road1_ch_down = 1;
    road1_ch_up = 5;
    road2_ch_down = 1;
    road2_ch_up = 5;
    
    
    n_bytes = s.BytesAvailable;         %获取串口接收到数据的个数
    
    out = fread(s,[1 n_bytes],'uint8'); %将串口数据以一行8位整型的形式显示出来
    mat = zeros(10,1);                   %8位转16位数据处理矩阵
    data = [data out];                  %合并缓存矩阵
    
    while(length(data) >= 23)           %当data长度大于17时,不停循环
        if(data(1) == 255 && data(2) == 165 && data(3) == 90)   %有符号整型帧头 0xff,0xa5,0x5a
            %确认为一帧数据
            data(1:3) = [];             %清空帧头位
            for i = 1:10                 %将7个通道的数据提取出来
                mat(i,1) = data(1)*256+data(2);     %将两个8位数据合并成16位数据
                if (mat(i,1) > 32768)               %提取符号位
                    mat(i,1) = -(65536-mat(i,1));   %求补码
                end
                data(1:2) = [];                     %清空提取到的data缓存数据
            end
            m = [m mat];    %合并波形显示矩阵
            ii = ii + 1;    %计数+1
            t = [t ii];     %合并采样点数矩阵
            x = x +  1;     %移动x轴
            if(length(t) <= plot_length)
                for j = road1_ch_down:road1_ch_up     %刷新第一路的1-5通道显示
                    set(p(j),'xdata',t,'ydata',m(j,1:length(t)));
                end
                for j = (5+road2_ch_down):(5+road2_ch_up)     %刷新第二路的6-10通道的显示句柄
                    set(p(j),'xdata',t,'ydata',m(j,1:length(t)));
                end
            else
                for j = road1_ch_down:road1_ch_up     %刷新第一路的1-5通道显示
                    set(p(j),'xdata',t(length(t)-plot_length:end),'ydata',m(j,length(t)-plot_length:length(t)));
                end
                for j = (5+road2_ch_down):(5+road2_ch_up)     %刷新第二路的6-10通道的显示句柄
                    set(p(j),'xdata',t(length(t)-plot_length:end),'ydata',m(j,length(t)-plot_length:length(t)));
                end
            end
            
        elseif(data(1) == 255 && data(2) == 165 && data(3) == 91)   %无符号整型帧头 0xff,0xa5,0x5b
            %确认为一帧数据
            data(1:3) = [];     %同上
            for i = 1:10
                mat(i,1) = data(1)*256+data(2);
                data(1:2) = [];
            end
            m = [m mat]; %读取帧数据
            ii = ii + 1;
            t = [t ii];
            x = x +  1;
            
           if(length(t) <= plot_length)
                for j = road1_ch_down:road1_ch_up     %刷新第一路的1-5通道显示
                    set(p(j),'xdata',t,'ydata',m(j,1:length(t)));
                end
                for j = (5+road2_ch_down):(5+road2_ch_up)     %刷新第二路的6-10通道的显示句柄
                    set(p(j),'xdata',t,'ydata',m(j,1:length(t)));
                end
            else
                for j = road1_ch_down:road1_ch_up     %刷新第一路的1-5通道显示
                    set(p(j),'xdata',t(length(t)-plot_length:end),'ydata',m(j,length(t)-plot_length:length(t)));
                end
                for j = (5+road2_ch_down):(5+road2_ch_up)     %刷新第二路的6-10通道的显示句柄
                    set(p(j),'xdata',t(length(t)-plot_length:end),'ydata',m(j,length(t)-plot_length:length(t)));
                end
            end
            
        else
            data(1) = [];       %如果不是帧头,则数据错误??跳过错误数据直到找到帧头
        end
    end
    if(x <= x_down)
        ymin1 = min(min(m(1:5,1:end)));     %求整个矩阵的最小值
        ymax1 = max(max(m(1:5,1:end)));     %求整个矩阵的最大值
        ymin2 = min(min(m(6:10,1:end)));     %求整个矩阵的最小值
        ymax2 = max(max(m(6:10,1:end)));     %求整个矩阵的最大值
    else
        ymin1 = min(min(m(1:5,x-x_down:end)));     %求整个矩阵的最小值
        ymax1 = max(max(m(1:5,x-x_down:end)));     %求整个矩阵的最大值
        ymin2 = min(min(m(6:10,x-x_down:end)));     %求整个矩阵的最小值
        ymax2 = max(max(m(6:10,x-x_down:end)));     %求整个矩阵的最大值
    end
    
    drawnow                 %更新图形窗口
    set(SUBP(1),'XLim',[x-x_down x+x_up],'YLim',[ymin1-50 ymax1+50]);
    %set(SUBP(2),'XLim',[x-x_down x+x_up],'YLim',[ymin2-100 ymax2+100]);
    set(SUBP(2),'XLim',[x-x_down x+x_up],'YLim',[-450 +450]);
end 

 

这个是第二版的回调函数,之前发现当m数据量过大时(大概超过3W点左右)图形出现明显的滞后现象,所以增加了一个比较,将整个图形的点数限制在一定范围之内(点数限制变量为plot_length),完美解决,大家可以根据电脑差异更改这个值。


共11条 1/2 1 2 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]