arduino: delaymicroseconds ()


8

Hàm delayMicroseconds () hoạt động như thế nào. Từ những gì tôi hiểu, bộ đếm gộp của timer0 được đặt thành 64. Đối với đồng hồ 16 MHz, cho 4.0uS mỗi lần đếm. Tôi có một chút bối rối về toán học để có được khoảng 1uS?


4
Các tài liệu nói "Chức năng này hoạt động rất chính xác trong phạm vi 3 micro trở lên. Chúng tôi không thể đảm bảo rằng delayMicroseconds sẽ thực hiện một cách chính xác cho sự chậm trễ-lần nhỏ hơn." Các tài liệu cho micros()biết "Trên các bo mạch Arduino 16 MHz (ví dụ Duemilanove và Nano), chức năng này có độ phân giải bốn micro giây (tức là giá trị trả về luôn là bội số của bốn)."
RedGrittyBrick

Câu trả lời:


8

Mã nguồn cho chức năng này được ghi lại khá tốt và có thể tìm thấy trong /usr/share/arduino/hardware/arduino/cores/arduino/wires.c trên các hệ thống Linux. Các hệ thống Windows sẽ có đường dẫn tương tự với tệp dây.c. Hãy nỗ lực tìm kiếm các tập tin và duyệt qua nó. Bây giờ chỉ tập trung vào chức năng duy nhất này, nó không phụ thuộc vào bất kỳ chức năng nào khác.

Bằng cách kiểm tra mã bạn sẽ nhận thấy rằng đó không phải là về bộ định thời, tất cả là về chu kỳ hướng dẫn. Mã này phụ thuộc rất nhiều vào việc tối ưu hóa trình biên dịch hoàn toàn giống với bạn đối với nhà phát triển thư viện. Đó là một giả định của tác giả! Số lượng chu kỳ CPU 'bị cháy' theo từng lệnh được ghi lại rõ ràng trong tài liệu tập lệnh của Atmel AVR .

Đầu tiên, giá trị độ trễ được kiểm tra bằng 1, trong trường hợp đó, chỉ cần trả về từ thói quen đã sử dụng trong một phần triệu thời gian của CPU.

Sau đó, giá trị độ trễ được nhân với bốn ( <<=2). Các __asm__-loop biên dịch thành một vòng lặp chu kỳ 4 CPU. 4 chu kỳ × 4 = 16 chu kỳ. 16MHz / (4 × 4) = 1MHz, mất 1 chúng tôi thời gian chu kỳ, độ phân giải mà chúng tôi đang theo sau.

-2 micrô giây cuối cùng (trước khi vòng lặp được khởi động) một lần nữa là một sự điều chỉnh trên trình biên dịch được giới thiệu. Gọi __asm__-code từ C yêu cầu một số hướng dẫn bổ sung để lưu các thanh ghi CPU.

Đối với một Arduino bình thường @ 16MHz, chỉ có đoạn mã sau sẽ được biên dịch:

/* Delay for the given number of microseconds.  Assumes a 8 or 16 MHz clock. */
void delayMicroseconds(unsigned int us)
{
        // calling avrlib's delay_us() function with low values (e.g. 1 or
        // 2 microseconds) gives delays longer than desired.
        //delay_us(us);
        // for the 16 MHz clock on most Arduino boards

        // for a one-microsecond delay, simply return.  the overhead
        // of the function call yields a delay of approximately 1 1/8 us.
        if (--us == 0)
                return;

        // the following loop takes a quarter of a microsecond (4 cycles)
        // per iteration, so execute it four times for each microsecond of
        // delay requested.
        us <<= 2;

        // account for the time taken in the preceeding commands.
        us -= 2;

        // busy wait
        __asm__ __volatile__ (
                "1: sbiw %0,1" "\n\t" // 2 cycles
                "brne 1b" : "=w" (us) : "0" (us) // 2 cycles
        );
}

BTW: Mã được biên dịch khá chính xác, nhưng lưu ý những điều sau: Trên Arduino có các ngắt thời gian được cấu hình mà hầu hết không biết. Khi một ngắt được nhận trong quá trình thực thi delayMicroseconds(), thời gian delayMicroseconds()sẽ bị sai. Tất nhiên bạn có thể dừng ngắt trước khi gọi delayMicroseconds()và kích hoạt chúng sau đó, nhưng điều đó một lần nữa ảnh hưởng đến độ chính xác về thời gian theo thời lượng của mã được biên dịch để bật / tắt.


Hoặc nếu bạn chưa cài đặt Arduino IDE, tệp này có sẵn tại github.com/arduino/Arduino/blob/master/hardware/arduino/cores/ Lỗi
microtherion

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.