Ардуїно час зберігання за допомогою millis () не є точним чи правильним?


9

Я використовую Arduino для запису деяких даних. У моєму ескізі Arduino я також використовував millis()функцію, щоб я міг відслідковувати час, за який приймається кожне значення, яке я вимірюю. Однак я помітив, що терміни невірні. Наприклад, 30 секунд у реальному житті виходить лише за 10 секунд (складений приклад).

Чи правильно я кажу, що функція затримки Arduino впливає на тривалість використання часу millis()? Іншими словами, припустимо, у мене затримка 50мс, це означає, що millis()функція також зупиняється на цю тривалість, а потім продовжується і так далі протягом тривалості з'єднання? Я помітив це, коли спробував побудувати деякі дані та виявив, що частота піків у моїх даних була занадто частою, враховуючи час, який минув. Тож я хочу знати, чи це міркування для цієї невідповідності термінів, і якщо так, то як я це виправити, щоб я міг тримати час виникнення кожного зразка?

Щоб дати деякий контекст, ось мій ескіз:

#include <eHealth.h>    

unsigned long time;
// The setup routine runs once when you press reset:
void setup() {
  Serial.begin(9600);  
}

// The loop routine runs over and over again forever:
void loop() {

  float ECG = eHealth.getECG();
  time = millis();
  Serial.print(time);
  Serial.print(" ");
  Serial.print(ECG, 5); 
  Serial.println("");    

  delay(50);
}

Ви використовуєте одну з офіційних дощок Uno?
Пітер Блумфілд

1
Фактичні терміни замість складених значень (послідовний монітор, який відмічає часові позначки ліній ідеально), ймовірно, допоможе з'ясувати, що відбувається.
Ігнасіо Васкес-Абрамс

3
Обчислення запускається millis()перериванням, тому delay()не повинно впливати на нього.
мікротерйон

У мене така ж проблема, але лише коли я інтегрую її (millis ()) у складний код. Я думаю, що складність коду впливає на його точність, оскільки він все більше затримується зі складністю коду. Чи є спосіб уникнути цього? можливо, використовуючи розділений модуль RTC?
Josip7171

Відповіді:


10

millis()приводиться в дію переривання, тому delay()це не вплине, принаймні, не на базі ATmega.

Це не означає, що millis()це абсолютно точно. Кожна галочка таймера не дорівнює 1 мс, але становить 1,024 мс. Ця помилка поступово накопичується, поки не буде здійснено виправлення. Це можна побачити в реалізації обробника переривань TIMER0_OVF (переповнення таймера 0).

Іншим джерелом неточності є сам генератор / кристал, який не є точно 16 МГц. Це досить близько, і поки температура не змінюється занадто сильно, є відносно стабільною.

Вищезазначене означає, що у вас може бути близько 1 мс при використанні millis(). Це не схоже на вашу проблему.

Іншим потенційним питанням може бути те, що getECG()робиться - це може бути дуже повільним.

float eHealthClass::getECG(void)
    {
        float analog0;
        // Read from analogic in. 
        analog0=analogRead(0);
        // binary to voltage conversion
        return analog0 = (float)analog0 * 5 / 1023.0;   
    }

analogRead() повільно, але не так повільно, щоб впливати на цикл, як цей.

Ще одна проблема, яку я бачив у людей - це коли вони змінюють тактову частоту, але неправильно змінюють дошки.txt. Це означає, що константи, які використовуються в millis()реалізації, помиляються, а часи - неправильні.

Якщо ви дійсно хочете читати значення кожні 50 мс, набагато кращим способом реалізації цього є виконання наступного

static long lastUpdate;

if (millis() - lastUpdate > 50)
{
    lastUpdate = millis();
    //Do stuff
}

Нам дійсно потрібно було б побачити часові позначки, які ви отримуєте. Якщо ви насправді бачите 30-ті, які відображаються як 10-ті, значить, є щось інше на роботі.


2
Зверніть увагу, що для Uno годинник не працює на кристалах, а просто використовує керамічний резонатор, який менш точний, ніж кристал.
jfpoilpret

@jfpoilpret Ах, добре знати. Дивлячись на схему , це був би пристрій CSTCE16M0V53-R0 Murata CERALOCK .
Кріс О

Резонатори мають низьку початкову толерантність (часто 0,5-2%) і погану стабільність температури, але якщо калібрувати хронометричні петлі під час їх використання, вони можуть бути нормальними, доки температура не рухатиметься.
Кібергібони

2
Millis () все ще працює на таймері, який відзначає кожні 1,024 мс, але вони додають компенсацію помилок у вигляді збільшення, коли змінна вимірювача помилок стає занадто високою. Я думаю, що насправді це алгоритм Романа Блек. Тому час повинен бути набагато ближче до 1 мс. github.com/arduino/Arduino/blob/master/hardware/arduino/cores/…
EternityForest

Для тих, хто все ще цікавиться, дивіться коментар, який я опублікував у відповідь Дж. Роберта, я не хотів відповідати своєю власною відповіддю, оскільки у мене її немає, я просто перефразував проблему.
користувач3284376

2

Якщо переривання буде вимкнено протягом будь-якої значної eHealth.getECG()тривалості виклику дробу , millis()кількість рахунків може відстати. В іншому випадку millis()слід повернути набагато точніший час, ніж описані вами 3х помилки.

Ви сказали, що ваш вибірковий сигнал виявляється вищим за частотою, ніж очікували, що може статися, якщо частота вибірки буде нижчою, ніж ви планували. Ви припускаєте частоту вибірки 20 Гц? Ваш цикл може зайняти досить тривалість, ніж 50 мс, що ви побачите в друковані часи, але вони все одно повинні відстежувати годинний час. Якщо ви цього не врахували, але припускали 50 мс / зразок, ви побачите очевидне прискорення даних.

Якщо це не проблема, наступним кроком буде перемикання виводу під час вашого перебування loop()та вимірювання частоти результуючої квадратної хвилі за допомогою вимірювача частоти (деякі недорогі DVM можуть це зробити) або «сфери застосування». Те ж саме зробіть із порожнім loop(). Перший експеримент визначатиме вашу реальну швидкість або інтервал вибірки; другий підкаже, чи millis()(тобто, частота timer0) - це те, що ви очікували.


1
Я пограв з цим далі і зрозумів, що проблема полягає не в роботі Arduino, функція millis () здебільшого працює дуже добре, деякі значення не відрізняються від відстані 8 мс (затримка), але від того, що Ви сказали, що цього слід очікувати. Описана нами 3-х помилка стосується Python-ої речі, яку я використовую для отримання даних. Будь-яка ідея, що це може бути результатом, я використовую Python's Pyserial, і це повільно, як пекло.
користувач3284376

Я не знаю достатньо про вашу реалізацію, щоб дати вам більше, ніж 1/2 @ 'гадаю, але сторона Python досить повільна, щоб скидати зразки?
JRobert

0

Те ж саме. Можу додати, що якщо перерви вимкнено, вимірюваний час - це "реальний час". У будь-якому випадку, я не розумію, чому ця затримка, тому що якщо цикл триватиме занадто довго, все-таки millis () повинен повертати значення в реальному часі (тільки з більшою відстані між кожним значенням)


1
На що посилається "те саме тут"? Відповіді повинні стояти самостійно, оскільки StackExchange може повторно замовляти речі (на відміну від форуму). Тож "те саме тут" може означати що завгодно залежно від того, на яку відповідь / питання постає ваша відповідь.
Нік Гаммон

Це повідомлення було б більш доречним як коментар, хоча (правда, у вас немає достатньої репутації).
Greenonline

Вибачте, але, коли ви щось відповідаєте, це очевидно, що він переглядає головне повідомлення, інакше це буде коментар
user48711
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.