Sử dụng đúng một ngắt thay đổi pin


10

Tôi đang cố gắng sử dụng các ngắt thay đổi pin để phát hiện các nút nhấn. Cho đến bây giờ tôi chưa bao giờ làm việc với các loại ngắt này và có một số vấn đề, vì vậy tôi muốn chắc chắn rằng đây có phải là cách sử dụng đúng không.

Nếu tôi có bảng dữ liệu đúng, những điều sau đây phải được thực hiện để sử dụng ngắt thay đổi pin:

  1. Đặt mã PIN bạn muốn kiểm soát trong đăng ký PCMSK
  2. Cho phép đăng ký mã PIN để kiểm soát ngắt thay đổi pin (PCICR)
  3. Kích hoạt ngắt
  4. Sử dụng vectơ ngắt tương ứng

Dự án: Tâm trạng đơn giản, Màu sắc được điều khiển thông qua 4 nút.

Thiết lập:

  • Atmega168A-PU
  • 4 công tắc nút bấm mini
  • MOSFET để điều khiển đèn LED RGB 3 watt của tôi

Đây là mã tôi đang sử dụng không hoạt động như mong đợi:

#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#define BUTTON1 (1<<PC5) 
#define BUTTON2 (1<<PC4) 
#define BUTTON3 (1<<PC3) 
#define BUTTON4 (1<<PC2) 

#define GREEN   (1<<PB1) 
#define BLUE    (1<<PB2) 
#define RED     (1<<PB3) 

void init() {

        // enable LED
        DDRB |= GREEN;
        DDRB |= BLUE;
        DDRB |= RED;

        // button pullups
        PORTC |= BUTTON1;
        PORTC |= BUTTON2;
        PORTC |= BUTTON3;
        PORTC |= BUTTON4;

        // pin change interrupts for buttons
        PCMSK1 |= PCINT13;
        PCMSK1 |= PCINT12;
        PCMSK1 |= PCINT11;
        PCMSK1 |= PCINT10;

        // enable pin change for buttons
        PCICR |= PCIE2;

        sei();

}

ISR(PCINT2_vect) {

                PORTB = BLUE;
}


void ledTest() {

                PORTB ^= RED;
                _delay_ms(250);
                PORTB ^= RED;
                _delay_ms(250);
                PORTB ^= RED;
                _delay_ms(250);
                PORTB ^= RED;


                PORTB ^= BLUE;
                _delay_ms(250);
                PORTB ^= BLUE;
                _delay_ms(250);
                PORTB ^= BLUE;
                _delay_ms(250);
                PORTB ^= BLUE;

                PORTB ^= GREEN;
                _delay_ms(250);
                PORTB ^= GREEN;
                _delay_ms(250);
                PORTB ^= GREEN;
                _delay_ms(250);
                PORTB ^= GREEN;
}

int main() {

        init();
        ledTest();

        _delay_ms(500);
        PORTB |= GREEN;

        while(1) {
                _delay_ms(100);
        }
}

Lưu ý: Các nút nên được công bố. Vì tôi đang cố gắng từng bước một và không nên bật đèn LED, tôi đã bỏ qua nó ở đây.

Câu hỏi: Cách tôi đang cố gắng sử dụng các ngắt có đúng không?

Sự cố với thiết lập của tôi:

  • Các nút1-3 hoàn toàn bị bỏ qua.
  • Nút 4 đang kích hoạt thiết lập lại atmega

Những điều tôi đã kiểm tra:

  • Các nút không được kết nối với mã PIN đặt lại
  • Các nút được kết nối đúng với GND nếu được nhấn
  • Các nút không được kết nối với GND nếu không được nhấn
  • Các nút hoạt động độc đáo nếu tôi sử dụng chúng mà không bị gián đoạn, ví dụ:

    if (! (PINC & BUTTON4)) {PORTB ^ = BLUE; }

  • Tinh thể ngoài / tinh thể trong 16MHZ
  • Bất kỳ lỗi trong định tuyến
  • Tôi đang sử dụng một tụ điện 100nF giữa PWR và GND trên atmega
  • VCC (7), GND (8), GND (22), AVCC (20) được kết nối (vì tôi không cần ISF, nó không được kết nối)

Bạn cần cờ PCIE1 (không phải PCIE2) và PCINT1_vect (không phải PCINT2)
microtherion

Tại sao PCIE1? Tôi đang sử dụng Đăng ký C, vì vậy nếu tôi đếm thì đó sẽ là A (PCIE0), B (PCIE1), C (PCIE2)? Dù sao, tôi đã thử nó với PCIE1 nad PCINT1_vect và không có phản ứng nếu tôi nhấn các nút.
echox

1
Có thể có một chút rủi ro khi giả định tính chất động học trong các bài tập như vậy. Trong trường hợp cụ thể này, bạn sẽ gần như đúng, ngoại trừ ATmega168 không có cổng A. Trong mọi trường hợp, tôi đã đi qua biểu dữ liệu và sơ đồ chân. Một mẹo nhỏ nữa là bạn đang sử dụng PCIE2, nhưng cài đặt các bit trong PCMSK1; điều đó không thể đúng được (Thật không may, tôi không biết tại sao bản phác thảo sửa đổi của bạn vẫn không hoạt động).
microtherion

Cảm ơn, tôi cũng hiểu rằng sự kết hợp của phần mềm gỡ lỗi phụ thuộc vào phần cứng tự xây dựng là không dễ dàng ;-)
echox

Câu trả lời:


14

Ngắt thay đổi pin thường không phải là một cách tốt để phát hiện các hành động của nút. Điều này là do các nút cơ bị nảy, và bạn sẽ nhận được rất nhiều ngắt vô nghĩa, và sau đó bạn vẫn phải thực hiện các thao tác gỡ lỗi.

Một cách tốt hơn là có một ngắt định kỳ, như cứ sau 1 ms (tốc độ 1 kHz). Đó là một thời gian dài trên hầu hết các bộ xử lý, vì vậy phần nhỏ thời gian dành cho ngắt sẽ nhỏ. Đơn giản chỉ cần lấy mẫu trạng thái nút mỗi ngắt. Khai báo trạng thái nút mới nếu bạn đã thấy trạng thái mới 50 ms liên tiếp. 50 ms dài hơn hầu hết các nút bật lên, nhưng vẫn đủ ngắn để con người không chú ý hoặc quan tâm đến độ trễ.

Lưu ý rằng theo cách này, bạn cũng có thể xử lý nhiều nút trong cùng một ngắt 1 ms định kỳ. Tất cả bạn cần là một bộ đếm cho mỗi nút.

Thêm về thời gian ra mắt:

Đôi khi, như trong trường hợp này, ai đó nói rằng 50 ms là thời gian gỡ lỗi quá dài. Điều này không đúng với các nút thông thường được nhấn bởi con người. Nó có thể là một vấn đề có lẽ trong các ứng dụng rất quan trọng về thời gian như đồng hồ bấm giờ, nhưng cho đến nay tôi vẫn chưa gặp phải một vấn đề nào. Tôi đã thử nghiệm điều này vào đầu những năm 1980, và nhiều người khác cũng vậy.

Đúng là thời gian bật nút bấm thông thường là khoảng 10 ms, với khoảng 25 ms. Yếu tố giới hạn về thời gian phát hành là nhận thức của con người. 50 ms ngắn hơn một chút so với nơi mọi người bắt đầu nhận thấy sự chậm trễ khi họ không tìm kiếm nó. Thậm chí sau đó, phải mất một thời gian lâu hơn để nó gây phiền nhiễu. Trong một số trường hợp, con người có thể phát hiện ra sự khác biệt giữa độ trễ 50 ms và 0 ms nếu họ đặc biệt tìm kiếm nó , nhưng điều đó hoàn toàn khác với việc nhấn nút và nhìn thấy điều gì đó xảy ra và không nghĩ về độ trễ.

Do đó, 50 ms là thời gian gỡ lỗi tốt vì độ trễ nằm dưới giới hạn nhận thức trong các ứng dụng thông thường, thấp hơn giới hạn phiền toái và cao hơn thời gian thoát của hầu hết các công tắc. Tôi đã tìm thấy các công tắc bật lên gần như vậy, vì vậy bạn cũng có thể đẩy đến giới hạn nhận thức vì không có gì để mất.

Tôi đã thực hiện nhiều sản phẩm với các nút gỡ lỗi firmware bằng thời gian gỡ lỗi 50 ms. Không một lần khách hàng đề cập đến thậm chí nhận thấy sự chậm trễ. Tất cả đều chấp nhận các nút là hoạt động tốt mà không có vấn đề.


1
50ms có thể quá dài đối với một số trường hợp (thông thường, 10-20ms là giới hạn nhận thức của con người và điều đó là đủ để tranh luận), nhưng phương pháp được mô tả ở đây là cách để đi.
Laszlo Valko

1
@Laszlo: Không, 50 ms không quá dài đối với trường hợp thông thường. Xem thêm vào câu trả lời của tôi.
Olin Lathrop

Tôi đã thử 50ms hoạt động tốt với tôi :-) Tôi vẫn tò mò tại sao ngắt thay đổi pin không hoạt động (bên cạnh công cụ nảy), nhưng điều này hoạt động :-) Cảm ơn.
echox

1

Ngắt thay đổi pin là một cách tốt hơn để gỡ lỗi hơn bỏ phiếu. Ngắt thường đi qua một số logic như D-Flip Flop hoặc D-Latch. Mặc dù điều này là đúng, nhưng khó hơn để thực hiện thói quen gỡ lỗi này với trình biên dịch cấp cao hơn. Khi ngắt xảy ra, cờ ngắt không bị xóa và kích hoạt ngắt sẽ bị xóa cho đến khi xảy ra độ trễ. Khi độ trễ đã xảy ra, trạng thái của pin được kiểm tra và nếu nó vẫn ở trạng thái đã cho đã kích hoạt trạng thái ngắt của nút được thay đổi và cờ ngắt được xóa và bật ngắt được đặt. Nếu không ở trạng thái gây ra đồng tu, kích hoạt ngắt được đặt và trạng thái giữ nguyên. Điều này giải phóng bộ xử lý cho các nhiệm vụ khác. Định kỳ làm gián đoạn thời gian lãng phí trong chương trình.


-1

"Ngắt thay đổi pin thường không phải là một cách tốt để phát hiện các hành động của nút."

Sai lầm. PC INT là lựa chọn tốt nhất. Nếu bạn sử dụng bỏ phiếu để kiểm tra trạng thái của một nút, hầu hết thời gian sẽ không có gì được thực hiện. Bạn lãng phí nhiều thời gian CPU quý giá. PC INT cho phép các hành động chỉ được thực hiện theo yêu cầu.

"Điều này là do các nút cơ bị nảy, và bạn sẽ nhận được rất nhiều ngắt vô nghĩa, và sau đó bạn vẫn phải thực hiện thao tác gỡ lỗi."

Đúng về việc nảy. Tuy nhiên, bạn KHÔNG BAO GIỜ nên gỡ bỏ một nút / chuyển đổi bên trong một thói quen ngắt (cùng lý do: lãng phí thời gian của CPU). ISR có nghĩa là thực sự ngắn và hiệu quả, khôn ngoan về mã. Chỉ cần sử dụng gỡ lỗi phần cứng. Giữ phần mềm của bạn sạch sẽ!

Việc gỡ lỗi phần cứng thuận tiện hơn, xem tại đây / RC gỡ lỗi + Trình kích hoạt Schmitt để tham khảo. Tôi đã sử dụng nó vô số lần với PC INT, nó không bao giờ thất bại.

Vì vậy, có, bạn có thể (và nên) sử dụng PC INT để có trạng thái nút. Nhưng bạn cũng phải sử dụng công cụ gỡ lỗi phần cứng thích hợp.


2
Việc gỡ lỗi phần mềm là một cách tiếp cận hợp lệ và hầu hết thời gian sử dụng thêm CPU là không liên quan. Nói rằng bạn thường nên gỡ lỗi trong phần cứng là tốt nhất. Nói rằng bạn phải sử dụng gỡ lỗi phần cứng trong mọi trường hợp chỉ là sai.
Olin Lathrop

Trong hầu hết các ứng dụng, bộ điều khiển luôn chạy không tải, chạy vòng lặp chính. Ngoài ra, thời gian CPU cần thiết để thực hiện kiểm tra trạng thái IO và có khả năng tăng một biến là tối thiểu. Việc thực hiện gỡ lỗi đơn giản trong phần mềm gần như là "miễn phí", chi phí phần cứng. Và đừng cười vài xu, lắp ráp cũng tốn tiền và nếu bạn chạy khối lượng trung bình đến cao của sản phẩm thì không đáng kể. Đúng là thời gian ISR nên được giữ ngắn, nhưng đó hầu như không phải là một đối số trong trường hợp này. Nó có thể quan trọng hơn nếu PC INT ISR bắn 50 lần liên tiếp do bị nảy.
Rev1.0

@Nelson, 'lãng phí thời gian của CPU' trong một số ứng dụng chứ không phải ở nhiều ứng dụng khác. Bạn nên đủ điều kiện trả lời cho tình huống trong đó thời gian CPU là rất quan trọng.
dùng1139880
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.