Как запрограммировать Arduino Uno для сбора данных с помощью прерывания таймера и анализа этих данных в matlab?

Я работаю над проектом, где я хочу собрать данные датчика (от датчика), и я хочу проанализировать первые 20 образцов данных (например, найти диапазон, линию тренда и т. д.). Я знаю, как скомпилировать прерывание таймера в Arduino IDE (используя таймер ISR), но как бы я мог сделать это что-то подобное (таймер ISR) в MATLAB. Причина в том, что я хочу собрать свои сенсорные данные ровно на 20 Гц, и использование функции задержки может оказаться неточным. Кроме того, когда я запускаю примерную программу, которая собирает данные в MATLAB, мои частоты образца изменяются от 15 Гц до даже 24 Гц (как показано ниже) . У кого-нибудь есть какие-нибудь предложения о том, как я могу это сделать? Если вопрос недостаточно ясен, я могу подробнее остановиться на нем в комментариях.

Это мой код MATLAB:

clear all;
a = arduino('com4', 'uno');
i = 0;
v1 = zeros(1e4,1);
v2 = zeros(1e4,1);
x = zeros(1e4,1);
t = timer('TimerFcn', 'stat=false; disp(''Timer!'')',... 
                 'StartDelay',5,'Period', 1);
start(t)

stat=true;
tic
while(stat==true)
   %while i<60
    i = i + 1;
    v1(i) = readVoltage(a, 'A0');
    v2(i) = readVoltage(a, 'A1');
    x(i) = i;
    disp(x(i));
    pause(.00001);
   
  % end
end
toc


% %График зависимости напряжения от времени
v1 = v1(1:i);
v2 = v2(1:i);
x = x(1:i);

p = v1;
n = v2;
%График зависимости напряжения от времени
figure(1);
plot(x,p,'-',x,n,'-')
xlabel('Elapsed time (sec)')
ylabel('v')
title('Ten Seconds of voltage Data')
%set(gca,'xlim',[t(1) t(i)])
legend('v1', 'v2');

%
delete(t) % Всегда удалять объекты таймера после их использования.

Выход есть

>> Timer
     1

     2

     3

     4

     5

     6

     7

     8

     9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    62

    63

    64

    65

    66

    67

    68

    69

    70

    71

    72

    73

    74

    75

Timer!
    76

Elapsed time is 5.032553 seconds.
>> 

Прошу прощения за длинный вывод. Но, как вы можете видеть, я указал время паузы 0,00001, что должно дать мне значительно большую частоту дискретизации 20 Гц. Но я получаю только 76 сэмплов/5 секунд = 15,2 Гц. Кроме того, иногда, когда я запускаю эту программу, она может собирать 79sample/5secons или даже 121sample/5seconds. Это просто непоследовательно. Я надеялся решить эту проблему с помощью прерывания таймера, которое будет жестко закодировано в MATLAB для сбора данных ровно на частоте 20 Гц. Пожалуйста, дайте мне знать, что вы все думаете. Спасибо.

, 👍2

Обсуждение

Это Arduino SE, поэтому мы можем рассказать вам, как использовать прерывание таймера в Arduino. Но мы не являемся экспертами по Matlab, так что ваш вопрос здесь не по теме. В настоящее время частота дискретизации напрямую зависит от времени выполнения всех задействованных вызовов функций, включая " readVoltage ()", я думаю, вы этого не учли. Я не знаю, что именно делает эта функция и какая прошивка у вас есть на Arduino. В зависимости от этого вам, возможно, придется написать свою собственную прошивку, которая может быть лучше приспособлена к вашей цели. Функция "readVoltage ()" может быть слишком медленной., @chrisl

1. Я согласен с Крислом: это больше похоже на вопрос Matlab, чем на вопрос Arduino. 2. Я не думаю, что Matlab-это правильный выбор для выборки в реальном времени. Вместо этого вы могли бы позволить Arduino обрабатывать тайминги и отправлять данные через последовательный порт, а затем обрабатывать данные в Matlab., @Edgar Bonet

Задержка для matlab с arduino - известная проблема. Хорошим началом было бы изменить скорость связи по умолчанию на 9600 бод, @Dorian

В вашем названии говорится, что вы хотите собрать данные с помощью Uno и проанализировать их с помощью MATLAB, но ваше описание предполагает, что вы также пытаетесь собрать некоторые данные с помощью MATLAB. Какой из них правильный? Если это так, как говорится в названии, то MATLAB вообще не нуждается в выборке; ему нужно только прочитать собранные данные из Uno, постфактум., @JRobert

У вас есть Arduino в вашем проекте, который запускает циклы ISR с очень точными интервалами. Нет смысла добавлять время на стороне приемника. Просто отметьте данные и соберите их по мере поступления., @PMF


2 ответа


0

Каждая связь с Arduino занимает 20 мс, у вас есть два в цикле, так что в идеальных условиях вы могли бы получить 25 показаний в секунду. Смотрите здесь источник

Это также зависит от размера запрашиваемых данных.

Я думаю, что это именно то, что вы ищете, но я не могу дать вам никакого совета, так как у меня нет Matlab, а у Octave нет этой функции.

,

1

Я настроил таймер по-другому, используя его свойство UserData. Таймер будет обновлять данные каждый фиксированный период для заданного количества выборок.

close all;
clear all;

% Некоторые полезные константы.
NUM_SAMPLES = 20;
PERIOD = 0.05;

global a;
a = arduino('com4', 'uno');

% Инициализировать данные. Он будет обновляться по таймеру.
data.i = 0;
data.v1 = zeros(NUM_SAMPLES, 1);
data.v2 = zeros(NUM_SAMPLES, 1);
data.x = (1:NUM_SAMPLES) * PERIOD;

% Инициализировать таймер на фиксированный период для определенного количества выборок.
t = timer;
t.ExecutionMode = 'fixedRate';
t.Period = PERIOD;
t.TasksToExecute = NUM_SAMPLES;
t.TimerFcn = @TimerCallback;
t.UserData = data;

% Запустите таймер и дождитесь его завершения.
start(t);
wait(t);
stop(t);
data = t.UserData;  % Получить обновленные данные.
delete(t);

% График зависимости напряжения от времени.
figure(1);
plot(data.x, data.v1, '-', data.x, data.v2, '-');
xlabel('Прошедшее время (s)');
ylabel('Напряжение (V)');
title('Данные о напряжении');
st = sprintf("%0.3f seconds", NUM_SAMPLES * PERIOD);
subtitle(st);
legend('v1', 'v2');

function TimerCallback(obj, event)
    global a;
    obj.UserData.i = obj.UserData.i + 1;
    obj.UserData.v1(obj.UserData.i) = readVoltage(a, 'A0');
    obj.UserData.v2(obj.UserData.i) = readVoltage(a, 'A1');
end
,