[2020/07/01] kSerial 在微控制器上將資料實時傳到 MATLAB 顯示分析
如要使用建議可以參考新版本的程式 http://kitsprout.logdown.com/posts/883899

[本文]
更新改良之前寫的 MATLAB 示波器功能,可直接透過藍牙連接,一個封包 2N + 4 byte,每個封包帶 N 個 int16 的資料。

MATLAB 部分沒有特別做優化,目前 250Hz 沒有問題,更新頻率更高會因為電腦 UART 或 MATLAB 方面等問題,顯示會變得不流暢,另外之前一直遇到隨時間增加導致延遲的問題暫時還無法解決,本來以為是因為儲存資料太多,但經過實驗後確定不是此問題,應該是 figure 不斷更新導致的,250Hz 下約 10000 筆資料後就會產生明顯延遲,所以目前無解,這次更新加入了自動找 Serial COM Port 的功能,可以自己尋找可用的 COM Port,減少設定的步驟,還有 packet loss rate 的檢測,速度快的時候大概丟包率大約 10%,有點大...,調低更新速率應該可以明顯降低丟包率,但拿來做實驗已經很夠用了。

目前比較常拿來用在感測器的資料分析與演算法的驗證上,像是加速度計、陀螺儀等。

連接方式:
只要透過 UART 轉 usb 直接連接到電腦,有 COM Port 就可以傳輸了,個人是比較常使用單晶片接藍牙從機 + 筆電藍牙功能來做實驗,不需要另外再接線到電腦。

Github → https://github.com/Hom-Wang/MATLAB/tree/master/serialOscilloscope

packet format
packetLens = int16Lens * 2 + 4

byte[0] = 'S'
byte[1] = data_01_H8
byte[2] = data_01_L8
byte[3] = data_02_H8
byte[4] = data_02_L8
byte[5] = data_03_H8
byte[6] = data_03_L8
...
byte[packetLens - 5] = data_n_H8
byte[packetLens - 4] = data_n_L8
byte[packetLens - 3] = check sum
byte[packetLens - 2] = '\r'
byte[packetLens - 1] = '\n'
serialOscilloscope.m link
close all
clear all

% ***********************

% **** set parameters

%comPort = 'COM5';

baudRate = 115200;
y_axisMax =  16000;
y_axisMin = -16000;
window_width = 800;
recvDataLens = 24;      % recvDataLens = int16Lens * 2 + 4

% ***********************


if rem((recvDataLens - 4), 2) > 0
    error('ERROR : recvDataLens must = int16Lens * 2 + 4');
end

% Auto find available serial port

delete(instrfindall);
info  = instrhwinfo('serial');
comPort = info.AvailableSerialPorts

% Serial config

s = serial(comPort, 'BaudRate', baudRate, 'DataBits', 8, 'StopBits', 1, 'Parity', 'none', 'FlowControl', 'none');
s.ReadAsyncMode = 'continuous';
fclose(s);
fopen(s);

% Init data

window_w = window_width;
window_d = window_w * 0.9;  % display window

window = -window_d;  
runtimes = 0;
recvData = 0;

fig1 = figure(1);
set(fig1, 'Position', [200, 100, 1600, 700], 'color', 'w');  % 1920*1080

signal = plot(runtimes, recvData);
axis([window, window + window_w, y_axisMin, y_axisMax]);
xlabel('runtimes');
ylabel('data');
grid on;
hold on;

state = 0;
%for i = 1 : 1000

while ishandle(fig1)
    n_bytes = get(s, 'BytesAvailable');
    if n_bytes == 0
        n_bytes = recvDataLens * 2;
    end
    recvData = fread(s, n_bytes, 'uint8');
    data_s = find(recvData == 83);

    dataNum = size(data_s, 1);
    if dataNum >= 1
        i = 1;
        while (i) & (dataNum >= 1)
            if (n_bytes - data_s(dataNum)) < recvDataLens
                dataNum = dataNum - 1;
            else
                i = 0;
            end
        end
    end

    if dataNum >= 1
        count = 0;
        for i = 1 : dataNum
            if (recvData(data_s(i) + recvDataLens - 2) == 13) & (recvData(data_s(i) + recvDataLens - 1) == 10)
                check = sum(recvData(data_s(i) + 1 : data_s(i) + recvDataLens - 4));
                if rem(check, 256) == recvData(data_s(i) + recvDataLens - 3)
                    count = count + 1;
                    runtimes = runtimes + 1;
                    for j = 2 : 2 : recvDataLens - 4
                        dataCov(j/2) = unsigned2signed(recvData(data_s(i) + j - 1) * 2^8 + recvData(data_s(i) + j));
                    end
                    data(:, runtimes) = transpose(dataCov);
                    state = 1;
                end
            end
        end

        if state == 1
            window = window + count;
            displayData = runtimes - window_d + 1;
            if displayData > 0
                times = [displayData : runtimes];
                plot(times, data(2, displayData : end), 'r', times, data(3, displayData : end), 'g', times, data(4, displayData : end), 'b');
            else
                times = [1 : runtimes];
                plot(times, data(2, :), 'r', times, data(3, :), 'g', times, data(4, :), 'b');
            end
            axis([window, window + window_w, y_axisMin, y_axisMax]);
            drawnow
            state = 0;

            fprintf('runtimes = %d\n', runtimes);
            fprintf('Acc.X = %d, Acc.Y = %d, Acc.Z = %d\n', data(2, end), data(3, end), data(4, end));
            fprintf('Gyr.X = %d, Gyr.Y = %d, Gyr.Z = %d\n', data(5, end), data(6, end), data(7, end));
            fprintf('Mag.X = %d, Mag.Y = %d, Mag.Z = %d\n', data(8, end), data(9, end), data(10, end));
        end
    end
end

fclose(s);
delete(s);

data = double(data);

% check packet loss rate

check = data(1, 2 : end) - data(1, 1 : end-1);
pl = 0;
for i = 1 : runtimes - 1
    if check(i) >= 2
        pl = pl + 1;
    end
end
plr = pl / (runtimes - 1) * 100;
fprintf('\ntotal packet = %d, packet loss = %d, rate = %.4f %%\n', runtimes, pl, plr);
Example
void Serial_SendDataMATLAB( int16_t *sendData, uint8_t lens )
{
  uint8_t tmpData[32] = {0};  // tmpData lens >= 2 * lens + 4
  uint8_t *ptrData = tmpData;
  uint8_t dataBytes = lens << 1;
  uint8_t dataLens = dataBytes + 4;
  uint8_t count = 0;
  uint16_t tmpSum = 0;

  tmpData[0] = 'S';
  while(count < dataBytes) {
    tmpData[count+1] = Byte8H(sendData[count >> 1]);
    tmpData[count+2] = Byte8L(sendData[count >> 1]);
    count = count + 2;
  }
  for(uint8_t i = 0; i < dataBytes; i++)
    tmpSum += tmpData[i+1];
  tmpData[dataLens - 3] = (uint8_t)(tmpSum & 0x00FF);
  tmpData[dataLens - 2] = '\r';
  tmpData[dataLens - 1] = '\n';

  do {
    Serial_SendByte(*ptrData++);
  } while(--dataLens);
}

int main( void )
{
  int16_t testLostRate = 0;
  int16_t IMU_Buf[10] = {0};

  while(1) {
    MPU9250_getData(IMU_Buf);
    IMU_Buf[0] = testLostRate++;
    Serial_sendDataMATLAB(IMU_Buf, 10);
    Delay_1ms(4);
  }
}

之前實驗的影片:

Comments

comments powered by Disqus