在 MATLAB 上實現一個 UART 數位波型顯示器
[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
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'
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);
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);
}
}
之前實驗的影片: