Висока точність часу на Arduino для послідовного зв'язку


11

Я використовую Arduino Uno для надсилання інформації про час і напругу через послідовний порт на Python для побудови графіку. Однак інтервал часу між послідовними позначками часу, схоже, збільшується з часом, що впливає на мою побудову. Це особливо актуально, коли швидкість передачі даних встановлюється на 9600, де мої початкові різниці в часі можуть бути 1320 і збільшуються до 16400 після відносно короткого проміжку часу. Коли ця швидкість досягається максимум 115200 bps, зміна відбувається повільніше і менш помітно, приблизно від 1340 до 1500 навіть після відносно тривалого запуску відправки. Усі часи наведені в мікросекундах.

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

  1. Чи можу я досягти більшої точності в термінах?
  2. Що обумовлює цю зміну часу?

Ось що я зараз маю:

#include <eHealth.h>

extern volatile unsigned long timer0_overflow_count;
float fanalog0;
int analog0;
unsigned long time;    

byte serialByte;
void setup() {
  Serial.begin(9600);
}

void loop() { 
  while (Serial.available()>0){  
    serialByte=Serial.read();
    if (serialByte=='S'){        
      while(1){
        fanalog0=eHealth.getECG();  
        // Use the timer0 => 1 tick every 4 us
        time=(timer0_overflow_count << 8) + TCNT0;        
        // Microseconds conversion.
        time=(time*4);   
        //Print in a file for simulation
        //Serial.print(time);
        //Serial.print(" ");
        Serial.print(fanalog0,5);
        Serial.print("\n");

        if (Serial.available()>0){
          serialByte=Serial.read();
          if (serialByte=='F')  break;
        }
      }
    }
  }
}

Що ви маєте на увазі під «точним»? Часи, що даються лічильником, будуть досить точними, точними та з хорошою роздільною здатністю. Ви хочете, щоб часи були детермінованими (тобто завжди однаковими)?
Кібергіббони

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

Додайте часову позначку на кінці ПК, а не в кінці Arduino, або використовуйте модуль RTC (годинник у режимі реального часу). Модулі RTC досить дешево знайти на різних веб-магазинах, просто переконайтеся, що магазин посилається на таблицю. Інший метод - запрограмувати таймер і використовувати процедуру переривання служби, щоб отримати досить точні терміни.
jippie

Що робить eHealth.getECG()? Чи завжди цей дзвінок триває однакову кількість часу?
jfpoilpret

Чи можете ви вказати, як довго триває "відносно короткий проміжок часу"? Чи завжди це те саме після перезавантаження Arduino?
jfpoilpret

Відповіді:


4

Використовуйте таймер та ISR (процедуру переривання обслуговування), щоб зробити час більш точним.

Погляньте на моє 1 мс приурочене переривання доказів концепції . Ідея полягає у тому, щоб у системі було досить точне серцебиття 1 мс, яке можна використовувати для запуску інших подій. У РоС використовується блимати світлодіод на ½Hz, але має доступ до нових змінних millisecondCounterі secondCounterдозволяє ініціюють подій в головному циклі при довільній (але точно часу) моменти.


2
Ваш PoC дуже цікавий, але у нього є недолік (його легко виправити) у тому, що він читає 2-байтове значення під час вмикання переривань (in loop()), це значення змінюється ISR. Може трапитися loop()неправильне значення (посеред модифікації ISR). Я опублікував коментар у вашому блозі про це.
jfpoilpret

@jfpoilpret цікавий момент, який ви робите там, ніколи не думав про переривання, що виникає на півдорозі, отримуючи значення з оперативної пам'яті. Я збираюся перевірити розбирання цього вечора та оновити статтю. Можливо, є
вагомий

Я створив зразок з вашої PoC і міг бачити, що проблема виникає щонайменше раз на 10 секунд у моєму ООН. Але звичайно, насправді це дуже залежить від того, що ви робите в своєму loop(): мій зразок щойно отримав значення мілісекунд, порівняйте його до попереднього значення зчитування, і якщо різниця> 0 (крім лічильника скидання до 0), відобразіть повідомлення.
jfpoilpret

@jfpoilpret ніколи не помічав цього. Я просто використовую це як серцебиття, щоб контролювати відра з їжею для моїх котів і робити світлодіодний спалах, коли мої коти будуть потенційно розчаровані ...; o) Це, безумовно, змінить спосіб, яким я буду користуватися ISR в майбутньому.
jippie

1
Він показує кристал, підключений до блоку ATMEGA16U2 і резонатор, підключений до ATMEGA328P-PU. 16U2 для послідовного інтерфейсу 328P - це "Arduino". Цікаво, що 16U2 зможе перевести годинник на інший чіп, наприклад, 328P.
Удо Кляйн

3

Я можу подумати про декілька речей, які можуть вплинути на "послідовність" часу серійного запису:

  • розмір даних для друку

це може бути найбільш очевидним, що потрібно придумати, але дійсно чим більше ви друкуєте, тим більше потрібно буде впоратися.

Рішення: друкуйте формат рядка в рядок відомої довжини.

  • за допомогою буферизованого серіалу

на unix ви можете отримати доступ до послідовного порту буферним або небуферованим способом. Тривале використання буферизованого способу може зробити його трохи повільніше, оскільки буфер заповнюється, як правило, це відбувається, коли дані надходять швидше, ніж ви читаєте їх ...

Рішення: використовуйте розблоковану послідовну лінію ( наприклад : у Darwin / OSX це /dev/cu.usbmodemXXXзамість /dev/tty.usbmodemXXX)

  • пріоритет таймерів

схоже, що ви використовуєте переривання TC, і AVR мають пріоритети в способі обробки переривань, я не знаю порядку пріоритетності для Atmega328, і це не одна з найбільш задокументованих функцій навколо, тому я не знаю наскільки безпечний TC0 порівняно з перериванням UART.

Рішення: шукайте далі в документації / таблиці про пріоритети перерв і, за необхідності, міняйте таймер; та / або робити тест, не запускаючи інший таймер.

  • дані, з яких ви читаєте, потребують більше часу для читання

деяким драйверам потрібно провести середнє значення або виконати деякі операції над попередніми значеннями, тому чим більше ви вимірюєте значення, тим довше буфер і тим довше потрібно обчислити значення, поки ви не досягнете максимального розміру буфера.

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

  • уникаючи накладних рам ардуїно

але якщо ви дійсно хочете оптимізувати серійний вихід з arduino, вам слід уникати використання ардуїнових накладних… Але це менш елегантно і зручно у використанні.

Я впевнений, що я пропускаю й інші моменти, але це перші речі, які я перевірив, перш ніж копати далі.

HTH


2

Ваш код включає тривалість виводу в наступних вимірах. Таким чином, залежно від тривалості виходу, ви будете вимірювати різні часи. Це можна зафіксувати, відформатувавши до виходу фіксованої довжини.

Наступне питання полягає в тому, що ООН має дуже погану часову базу. Подивіться тут для порівняння різних типів Arduino з посиланням на час DCF77.

Висновок: якщо вам потрібні точні терміни, або дістаньте Arduino зі стразами або йдіть на RTC. Я настійно рекомендую РТК DS3231 / DS3232, оскільки вони зазвичай досягають 2 ppm точності поза коробкою.

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