Waktu presisi tinggi pada Arduino untuk komunikasi serial

11

Saya menggunakan Arduino Uno untuk mengirim informasi waktu dan tegangan melalui port serial ke Python untuk plot. Namun, interval waktu antara stempel waktu berturut-turut tampaknya meningkat dari waktu ke waktu, memengaruhi plot saya. Ini terutama benar ketika baud rate diatur ke 9600, di mana perbedaan waktu awal saya mungkin 1320 dan meningkat menjadi 16400 setelah periode waktu yang relatif singkat. Ketika laju ini mencapai maksimum 115200 bps, perubahannya lebih lambat dan kurang terlihat, dari sekitar 1340 hingga 1500 bahkan setelah jangka waktu pengiriman yang relatif lama. Semua waktu diberikan dalam mikrodetik.

Saya ingin tahu apakah saya dapat mengurangi atau menghilangkan efek ini, dan jika tidak mengerti mengapa itu ada. Saya telah membaca hal-hal tentang gangguan dan keterlambatan yang menyebabkan hal ini, tetapi saya tidak sepenuhnya menghargai kompleksitas elektronik yang ada dan ingin tahu:

  1. Bisakah saya mendapatkan ketepatan waktu yang lebih besar?
  2. Apa yang menyebabkan perubahan waktu ini?

Inilah yang saat ini saya miliki:

#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;
        }
      }
    }
  }
}
pengguna3284376
sumber
Apa yang Anda maksud dengan "tepat"? Waktu yang diberikan oleh counter akan cukup tepat, akurat dan dengan resolusi yang baik. Apakah Anda ingin waktu menjadi deterministik (yaitu selalu sama)?
Cybergibbons
Maaf, ya saya kira itulah yang saya maksudkan, agar perbedaan di antara mereka konsisten dan jika tidak, alasan mengapa mereka tidak
user3284376
Tambahkan stempel waktu di ujung PC daripada di ujung Arduino, atau gunakan modul RTC (real time clock). Modul RTC cukup murah untuk ditemukan di berbagai toko web, hanya memastikan bahwa toko terhubung ke lembar data. Metode lain adalah memprogram timer dan menggunakan layanan interupsi rutin untuk mendapatkan waktu yang cukup akurat.
jippie
Apa yang eHealth.getECG()harus dilakukan Apakah panggilan itu selalu berlangsung dalam jumlah waktu yang sama?
jfpoilpret
Bisakah Anda menentukan berapa lama "periode waktu yang relatif singkat" berlangsung? Apakah selalu sama setelah me-restart Arduino?
jfpoilpret

Jawaban:

4

Gunakan timer dan ISR (interupsi servis rutin) untuk membuat timing menjadi lebih akurat.

Lihatlah Bukti Konsep Konsep interrupt 1ms saya . Idenya adalah untuk memiliki detak jantung 1ms yang cukup akurat dalam sistem yang dapat digunakan untuk memicu peristiwa lain. Dalam PoC digunakan untuk berkedip LED pada ½Hz, tetapi memiliki akses ke variabel baru millisecondCounterdan secondCountermemungkinkan Anda untuk memicu peristiwa dalam loop utama pada saat-saat yang sewenang-wenang (tetapi waktunya akurat).

jippie
sumber
2
PoC Anda sangat menarik tetapi memiliki kelemahan (mudah diperbaiki) karena ia membaca nilai 2-byte sementara interupsi diaktifkan (dalam loop()), nilai ini sedang dimodifikasi oleh ISR. Itu bisa terjadi yang loop()membaca nilai buruk (di tengah modifikasi oleh ISR). Saya telah memposting komentar di blog Anda tentang itu.
jfpoilpret
@ jfpoilpret poin menarik yang Anda buat di sana, tidak pernah terpikir akan terjadi setengah jalan mengambil nilai dari RAM. Saya akan memeriksa pembongkaran malam ini dan memperbarui artikel. Mungkin alasan yang baik untuk menulis artikel lain juga: o)
jippie
Saya membuat sampel dari PoC Anda dan bisa melihat masalah terjadi setidaknya setiap 10 detik pada UNO saya. Tapi tentu saja dalam kenyataannya itu sangat tergantung pada apa yang Anda lakukan di loop(): sampel saya baru saja mendapatkan nilai milidetik, bandingkan dengan nilai baca sebelumnya dan jika perbedaan> 0 (selain reset counter ke 0), tampilkan pesan.
jfpoilpret
@ jfpoilpret tidak pernah benar-benar memperhatikannya. Saya hanya menggunakannya sebagai detak jantung untuk memantau keranjang makanan untuk kucing saya dan membuat lampu kilat LED ketika kucing saya akan berpotensi kecewa ...; o) Ini pasti akan mengubah cara saya menggunakan ISR di masa depan.
jippie
1
Ini menunjukkan kristal yang terhubung ke blok ATMEGA16U2 dan resonator yang terhubung ke ATMEGA328P-PU. 16U2 adalah untuk antarmuka serial, 328P adalah "The Arduino". Yang cukup menarik, 16U2 dapat mendorong clock-nya ke chip lain, misalnya 328P.
Udo Klein
3

Saya dapat memikirkan beberapa hal yang dapat mempengaruhi "konsistensi" dari waktu penulisan serial:

  • ukuran data yang akan dicetak

ini mungkin hal yang paling jelas untuk dipikirkan, tetapi memang semakin banyak Anda mencetak, semakin banyak yang diperlukan untuk menanganinya.

Solusi: cetak format string menjadi string yang dikenal panjang.

  • menggunakan serial buffered

pada unix Anda dapat mengakses port serial menggunakan cara buffered atau unbuffered. Menggunakan cara buffered untuk waktu yang lama mungkin membuatnya sedikit lebih lambat karena buffer mengisi, biasanya itu terjadi ketika data masuk lebih cepat daripada Anda membacanya ...

Solusi: gunakan baris serial yang tidak disadap ( misalnya : di Darwin / OSX itu /dev/cu.usbmodemXXXbukan /dev/tty.usbmodemXXX)

  • prioritas penghitung waktu

sepertinya Anda menggunakan interupsi TC, dan AVR memiliki prioritas dalam cara interupsi ditangani, saya tidak tahu urutan prioritas untuk Atmega328, dan itu bukan salah satu fitur yang paling banyak didokumentasikan, jadi saya tidak tahu seberapa aman TC0 versus interupsi UART.

Solusi: lihat lebih lanjut dalam dokumentasi / lembar data tentang prioritas interupsi dan ubah timer jika diperlukan; dan / atau melakukan tes tanpa menjalankan timer lainnya.

  • data yang Anda baca memerlukan lebih banyak waktu untuk dibaca dari waktu ke waktu

beberapa driver perlu rata-rata atau melakukan beberapa operasi di atas nilai sebelumnya, sehingga semakin banyak nilai yang Anda ukur, semakin lama buffernya, dan semakin lama waktu yang dibutuhkan untuk menghitung nilai, hingga Anda telah mencapai ukuran maksimum buffer.

Solusi: lihat kode sumber perpustakaan yang Anda gunakan, dan optimalkan, hapus kalkulasi jika ada atau pertimbangkan waktu pemrosesan yang semakin tinggi.

  • menghindari overhead kerangka Arduino

tetapi jika Anda benar - benar ingin mengoptimalkan output serial dari Arduino, Anda harus menghindari menggunakan overhead Arduino ... Tapi itu cara yang kurang elegan dan nyaman untuk digunakan.

Saya cukup yakin ada hal-hal lain yang saya lewatkan, tetapi itu adalah hal pertama yang akan saya periksa sebelum menggali lebih jauh.

HTH

zmo
sumber
2

Kode Anda termasuk durasi output dalam pengukuran selanjutnya. Jadi tergantung pada panjang output Anda akan mengukur waktu yang berbeda. Ini dapat diperbaiki dengan memformat ke output panjang tetap.

Masalah berikutnya adalah bahwa UNO memiliki timebase yang sangat buruk. Lihat di sini untuk perbandingan berbagai jenis Arduino vs referensi waktu DCF77.

Kesimpulan: jika Anda membutuhkan pengaturan waktu yang tepat, dapatkan Arduino dengan kristal atau gunakan RTC. Saya sangat merekomendasikan DS3231 / DS3232 RTC karena biasanya ini mencapai akurasi 2 ppm.

Udo Klein
sumber