2017-02-17 15 views
5

Tôi đang viết ngắt vi điều khiển cần bổ sung bù đắp cho một trong các bộ đếm thời gian phần cứng của nó. Tuy nhiên, do cách bộ đếm giờ hoạt động, cách tiếp cận ngây thơ có thể giới thiệu một lỗi off-by-one tùy thuộc vào thời gian thực hiện ngắt liên quan đến đồng hồ prescaler.Làm cách nào để tránh lỗi này khi thêm bù đắp cho bộ hẹn giờ phần cứng đã được đặt trước?

timing diagram of ISR off-by-one error

Tôi đang sử dụng timer 1 trên ATmega328P (= Arduino) cho việc này. Tôi có nó được thiết lập trong chế độ bình thường với một/8 prescaler, và sáng sử dụng bộ đếm thời gian chụp gián đoạn để kích hoạt này; mục tiêu của ngắt là đặt bộ đếm thời gian tràn chính xác period chu kỳ sau sự kiện kích hoạt quá trình chụp đầu vào (trong trường hợp trình kích hoạt xảy ra trong khi ngắt khác hoặc tình huống khác bị ngắt).

(Tôi đang lạm dụng đầu ra PWM để kích hoạt hai nguồn chính optotriacs tại một giai đoạn AC thay đổi bù đắp, mà không cần phải ghi tất cả thời gian CPU vào nó, ngắt được kích hoạt bởi một máy dò không qua trên giai đoạn chính.)

mã cho ISR sẽ là một cái gì đó như thế này:

uint_16 period = 16667; 

ISR(TIMER1_CAPT_vect){ 
    TCNT1 = TCNT1 - ICR1 - period + (elapsed counter ticks during execution); 
} 

khoảng cách quan trọng ở đây là một từ khi TCNT1 được đọc từ và khi nó sau đó được ghi vào một lần nữa. Theo tôi biết, không có cách nào để đọc trực tiếp trạng thái của bộ đếm trước, vì vậy tôi không nghĩ rằng có thể chỉ áp dụng một chênh lệch khác dựa trên thời gian ISR.

Tôi chỉ có thể đặt lại bộ đặt trước trước ISR (GTCCR |= _BV(TSM); GTCCR |= _BV(PSRSYNC); GTCCR &= ~_BV(TSM);) để đồng bộ hóa, nhưng vẫn giới thiệu bù trừ ngẫu nhiên cho bộ đếm thời gian phụ thuộc vào thời gian ISR.

Cách tiếp cận khác mà tôi đang xem xét là sử dụng bộ hẹn giờ để tạo đồng bộ ngắt với bộ đếm trước. Tôi đã sử dụng cả hai đầu ra so sánh đăng ký trên bộ đếm thời gian 1, nhưng bộ đếm thời gian 0 chia sẻ bộ đếm trước để nó có thể được sử dụng. Tuy nhiên, việc thực hiện ngắt thời gian có thể bị trì hoãn bởi một khối ngắt hoặc 'cli' khác, vì vậy việc này không được đảm bảo để hoạt động.

Làm cách nào để tôi có thể viết gián đoạn để tránh lỗi này?

+1

Tôi giả định tính toán 'TCNT1' không phải là _always_ tắt một (thời gian 2?), Chỉ _sometimes_ (thời gian 1)? – chux

+0

@chux có, 'TCNT1' chỉ thỉnh thoảng bị tắt một. Tôi không thực sự chắc chắn làm thế nào để giải thích nó trong lời nói nhưng biểu đồ thời gian tôi bao gồm cho thấy điều này xảy ra như thế nào. – AJMansfield

+0

Quy trình ISR có đủ nhanh để lấy mẫu và chắc chắn phát hiện một xung 'clk_Tn' không? 'Clk_Tn' có thể thiết lập một lá cờ mà ISR có thể chịu được không? – chux

Trả lời

1

Nếu bạn viết ISR như

ISR(TIMER1_CAPT_vect){ 
    int counter = TCNT1 - ICR1 - period + 3; 
    asm("nop"); 
    asm("nop"); 
    TCNT1 = counter; 
} 

việc viết TCNT1 nên diễn ra chính xác 24 chu kỳ sau khi đăng ký được đọc, do đó tại cùng một prescaler 'giai đoạn'. (Số lượng nop có thể được điều chỉnh nếu cần thiết, ví dụ: do các biến thể giữa các loại vi điều khiển khác nhau). Tuy nhiên, giải pháp này không thể tính đến sự thay đổi trong pha 'prescaler' diễn ra giữa thiết lập của ICR1 và việc đọc TCNT1.

Các vấn đề liên quan