Thời gian chính xác cao trên Arduino cho giao tiếp nối tiếp


11

Tôi đang sử dụng Arduino Uno để gửi thông tin về thời gian và điện áp qua cổng nối tiếp tới Python để vẽ. Tuy nhiên, khoảng thời gian giữa các dấu thời gian liên tiếp dường như tăng theo thời gian, ảnh hưởng đến âm mưu của tôi. Điều này đặc biệt đúng khi tốc độ truyền được đặt thành 9600, trong đó chênh lệch thời gian ban đầu của tôi có thể là 1320 và tăng lên 16400 sau một khoảng thời gian tương đối ngắn. Khi tốc độ này được đặt ở mức tối đa là 115200 bps, sự thay đổi sẽ chậm hơn và ít được chú ý hơn, từ khoảng 1340 đến 1500 ngay cả sau một thời gian gửi tương đối dài. Tất cả thời gian được đưa ra trong micro giây.

Tôi muốn biết nếu tôi có thể giảm hoặc loại bỏ hiệu ứng này, và nếu không hiểu tại sao nó tồn tại. Tôi đã đọc những điều về sự gián đoạn và sự chậm trễ gây ra điều này, nhưng tôi không hoàn toàn đánh giá cao sự phức tạp của các thiết bị điện tử trong tay và muốn biết:

  1. Tôi có thể có được độ chính xác cao hơn trong thời gian?
  2. Điều gì gây ra sự thay đổi trong thời gian này?

Đây là những gì tôi hiện có:

#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;
        }
      }
    }
  }
}

Bạn có ý nghĩa gì bởi "chính xác"? Thời gian được đưa ra bởi bộ đếm sẽ khá chính xác, chính xác và có độ phân giải tốt. Bạn có muốn thời gian là xác định (tức là luôn luôn như vậy)?
Cyberg Ribbon

Xin lỗi, vâng tôi đoán đó là điều tôi muốn nói, vì sự khác biệt giữa chúng là nhất quán và nếu không, lý do tại sao chúng không phải là
user3284376

Thêm dấu thời gian ở cuối PC thay vì cuối Arduino hoặc sử dụng mô-đun RTC (đồng hồ thời gian thực). Các mô-đun RTC khá rẻ để tìm thấy trên các trang web khác nhau, chỉ cần đảm bảo rằng cửa hàng liên kết với biểu dữ liệu. Một phương pháp khác là lập trình bộ hẹn giờ và sử dụng thói quen dịch vụ ngắt để có thời gian chính xác hợp lý.
jippie

Không gì eHealth.getECG()làm gì? Cuộc gọi đó có luôn kéo dài cùng một khoảng thời gian không?
jfpoilpret

Bạn có thể chỉ định một "khoảng thời gian tương đối ngắn" kéo dài bao lâu không? Có phải nó luôn giống nhau sau khi khởi động lại Arduino?
jfpoilpret

Câu trả lời:


4

Sử dụng bộ hẹn giờ và ISR (thói quen phục vụ ngắt) để làm cho thời gian chính xác hơn.

Hãy xem Proof of Concept bị gián đoạn theo thời gian 1ms của tôi . Ý tưởng là có 'nhịp tim' 1ms chính xác hợp lý trong hệ thống có thể được sử dụng để kích hoạt các sự kiện khác. Trong PoC, nó được sử dụng để nháy đèn LED ở ½Hz, nhưng có quyền truy cập vào các biến mới millisecondCountersecondCountercho phép bạn kích hoạt các sự kiện trong vòng lặp chính vào các thời điểm tùy ý (nhưng được định thời gian chính xác).


2
PoC của bạn rất thú vị nhưng nó có một lỗ hổng (dễ sửa) trong thực tế là nó đọc giá trị 2 byte trong khi các ngắt được bật (in loop()), giá trị này được sửa đổi bởi ISR. Nó có thể xảy ra khi loop()đọc một giá trị xấu (ở giữa bản sửa đổi của ISR). Tôi đã đăng một bình luận trên blog của bạn về nó.
jfpoilpret

@jfpoilpret điểm thú vị bạn thực hiện ở đó, không bao giờ nghĩ đến một ngắt xảy ra một nửa lấy ra giá trị từ RAM. Tôi sẽ kiểm tra việc tháo gỡ tối nay và cập nhật bài viết. Có lẽ một lý do tốt để viết một bài viết khác: o)
jippie

Tôi đã tạo một mẫu từ PoC của bạn và có thể thấy sự cố xảy ra ít nhất 10 giây một lần trên UNO của tôi. Nhưng tất nhiên trong thực tế, nó phụ thuộc rất nhiều vào những gì bạn làm trong loop()mẫu của bạn : mẫu của tôi chỉ có giá trị mili giây, so với giá trị đọc trước đó và nếu chênh lệch> 0 (trừ bộ đếm đặt lại về 0), hiển thị thông báo.
jfpoilpret

@jfpoilpret không bao giờ thực sự chú ý đến nó. Tôi chỉ sử dụng nó như một nhịp đập để theo dõi các thùng thức ăn cho mèo của tôi và làm đèn flash LED khi mèo của tôi có khả năng thất vọng ...; o) Nó chắc chắn sẽ thay đổi cách tôi sử dụng ISR trong tương lai.
Jippie

1
Nó cho thấy một tinh thể được kết nối với một khối ATMEGA16U2 và một bộ cộng hưởng được kết nối với ATMEGA328P-PU. 16U2 dành cho giao diện nối tiếp, 328P là "Arduino". Điều thú vị là 16U2 sẽ có thể đẩy đồng hồ của nó sang một con chip khác, ví dụ như 328P.
Udo Klein

3

Tôi có thể nghĩ ra một vài điều có thể ảnh hưởng đến "tính nhất quán" của thời gian ghi nối tiếp:

  • kích thước của dữ liệu sẽ được in

đây có thể là điều rõ ràng nhất để nghĩ đến, nhưng thực sự bạn càng in nhiều thì sẽ càng mất nhiều thời gian để xử lý nó.

Giải pháp: in định dạng chuỗi thành một chuỗi có độ dài đã biết.

  • sử dụng bộ đệm nối tiếp

trên unix bạn có thể truy cập cổng nối tiếp bằng cách sử dụng bộ đệm hoặc cách không có bộ đệm. Sử dụng cách đệm trong một thời gian dài có thể làm cho nó chậm hơn một chút khi bộ đệm đầy, thường xảy ra khi dữ liệu đến nhanh hơn bạn đang đọc nó

Giải pháp: sử dụng dòng nối tiếp không có bộ đệm ( ví dụ : trên Darwin / OSX, /dev/cu.usbmodemXXXthay vì /dev/tty.usbmodemXXX)

  • ưu tiên của bộ tính giờ

Có vẻ như việc bạn sử dụng ngắt TC và các AVR có các ưu tiên trong cách xử lý các ngắt, tôi không biết thứ tự ưu tiên cho Atmega328 và đó không phải là một trong những tính năng được ghi chép nhiều nhất, vì vậy tôi không biết TC0 an toàn như thế nào so với ngắt UART.

Giải pháp: tra cứu thêm trong tài liệu / biểu dữ liệu về các ưu tiên ngắt và thay đổi bộ hẹn giờ nếu cần; và / hoặc làm một bài kiểm tra mà không có bộ đếm thời gian khác đang chạy.

  • dữ liệu bạn đang đọc mất nhiều thời gian hơn để đọc theo thời gian

một số trình điều khiển cần lấy trung bình hoặc thực hiện một số thao tác so với các giá trị trước đó, do đó, bạn càng đo nhiều giá trị, bộ đệm càng dài và thời gian tính toán giá trị càng lâu, cho đến khi bạn đạt kích thước tối đa của bộ đệm.

Giải pháp: xem xét mã nguồn của thư viện bạn đang sử dụng và tối ưu hóa nó, loại bỏ tính toán nếu có hoặc tính đến việc tăng thời gian xử lý đó.

  • tránh các khung arduino trên đầu

nhưng nếu bạn thực sự muốn tối ưu hóa đầu ra nối tiếp từ arduino, bạn nên tránh sử dụng arduino trên đầu. Nhưng cách sử dụng ít thanh lịch và thoải mái hơn.

Tôi khá chắc chắn rằng có những điểm khác tôi đang thiếu, nhưng đó là những điều đầu tiên tôi kiểm tra trước khi đào sâu hơn.

HTH


2

Mã của bạn bao gồm thời lượng của đầu ra trong các phép đo tiếp theo. Do đó tùy thuộc vào độ dài của đầu ra, bạn sẽ đo thời gian khác nhau. Điều này có thể được sửa chữa bằng cách hình thành đầu ra chiều dài cố định.

Vấn đề tiếp theo là UNO có cơ sở thời gian rất kém. Có một cái nhìn ở đây để so sánh các loại Arduino khác nhau so với tham chiếu thời gian DCF77.

Kết luận: nếu bạn cần thời gian chính xác, hãy lấy Arduino bằng pha lê hoặc đi RTC. Tôi rất có thể khuyên dùng DS3231 / DS3232 RTC vì chúng thường đạt được độ chính xác 2 ppm ngoài hộp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.