Một chức năng có thể được gọi tự động khi một đầu vào thay đổi?


21

Hiện tại, bản phác thảo của tôi đang kiểm tra một pin đầu vào mỗi lần vòng quanh vòng lặp chính. Nếu nó phát hiện ra một sự thay đổi, nó sẽ gọi một chức năng tùy chỉnh để đáp ứng nó. Đây là mã (được cắt bớt các yếu tố cần thiết):

int pinValue = LOW;

void pinChanged()
{
    //...
}

void setup()
{
    pinMode(2, INPUT);
}

void loop()
{
    // Read current input
    int newValue = digitalRead(2);

    // Has the input changed?
    if (newValue != pinValue) {
        pinValue = newValue;
        pinChanged();
    }
}

Thật không may, điều này không phải lúc nào cũng hoạt động chính xác cho những thay đổi rất ngắn trên đầu vào (ví dụ: xung ngắn), đặc biệt là nếu loop()chạy chậm một chút.

Có cách nào để làm cho Arduino phát hiện thay đổi đầu vào và tự động gọi chức năng của tôi không?


1
Những gì bạn đang tìm kiếm cho nó là một ngắt bên ngoài
Butzke

Câu trả lời:


26

Bạn có thể làm điều này bằng cách sử dụng các ngắt bên ngoài. Hầu hết Arduinos chỉ hỗ trợ điều này trên một số chân hạn chế. Để biết chi tiết đầy đủ, xem tài liệu trên attachInterrupt().

Giả sử bạn đang sử dụng Uno, bạn có thể làm như thế này:

void pinChanged()
{
    //...
}

void setup()
{
    pinMode(2, INPUT);
    attachInterrupt(0, pinChanged, CHANGE);
}

void loop()
{
}

Điều này sẽ gọi pinChanged()bất cứ khi nào thay đổi được phát hiện trên ngắt ngoài 0. Trên Uno, tương ứng với chân GPIO 2. Việc đánh số ngắt ngoài là khác nhau trên các bảng khác, vì vậy điều quan trọng là phải kiểm tra tài liệu liên quan.

Có những hạn chế đối với phương pháp này mặc dù. pinChanged()Chức năng tùy chỉnh đang được sử dụng như một thói quen dịch vụ ngắt (ISR). Điều đó có nghĩa là phần còn lại của mã (mọi thứ trong loop()) tạm thời bị dừng trong khi cuộc gọi đang thực hiện. Để tránh làm gián đoạn bất kỳ thời điểm quan trọng nào, bạn nên đặt mục tiêu tạo ra ISR càng nhanh càng tốt.

Cũng cần lưu ý rằng không có ngắt nào khác sẽ chạy trong ISR của bạn. Điều đó có nghĩa là bất cứ điều gì dựa vào các ngắt (như lõi delay()millis()chức năng) có thể không hoạt động đúng bên trong nó.

Cuối cùng, nếu ISR của bạn cần thay đổi bất kỳ biến toàn cục nào trong bản phác thảo, chúng thường được khai báo là volatile, ví dụ:

volatile int someNumber;

Điều đó quan trọng bởi vì nó báo cho trình biên dịch rằng giá trị có thể thay đổi bất ngờ, do đó, nên cẩn thận không sử dụng bất kỳ bản sao / bộ nhớ lỗi thời nào của nó.


liên quan đến "các xung ngắn" được đề cập trong câu hỏi, có thời gian tối thiểu mà pin phải ở trạng thái để kích hoạt ngắt không? (rõ ràng nó sẽ ít hơn nhiều so với bỏ phiếu, điều này phụ thuộc vào những gì khác đang diễn ra trong vòng lặp)
sachleen

1
@sachleen Điều đó sẽ hoạt động miễn là nó không xảy ra trong quá trình thực thi chức năng ISR (như được giải thích trong câu trả lời); đó là lý do tại sao pinChanged()nên càng ngắn càng tốt. Do đó, thông thường thời gian tối thiểu phải là thời gian để thực hiện pinChanged()chức năng.
jfpoilpret

2
+1 cho câu trả lời rất chi tiết này bao gồm tất cả những thứ bất tử người ta phải quan tâm khi sử dụng ngắt!
jfpoilpret

3
Ngoài việc khai báo các quả cầu được chia sẻ volatile, nếu biến toàn cục rộng hơn 1 byte, như một số số, bạn phải bảo vệ chống lại sự gián đoạn thay đổi pin xảy ra giữa các lần truy cập byte của chương trình. Một câu lệnh như someNumber +=5;liên quan đến việc thêm các byte thấp và thêm các byte cao có kèm theo. Hai (nhiều hơn, cho các biến rộng hơn) không được chia cho một ngắt. Tắt các ngắt và khôi phục chúng trước và sau khi hoạt động (tương ứng) là đủ.
JRobert

@sachleen - liên quan đến kích thước xung tối thiểu. Thật khó để tìm thấy một câu trả lời chắc chắn trong biểu dữ liệu, nhưng đánh giá theo thời gian cho các ngắt thay đổi pin, chúng được chốt trong vòng nửa chu kỳ. Khi ngắt được "ghi nhớ", nó sẽ được ghi nhớ cho đến khi ISR ​​khởi động và xử lý nó.
Nick Gammon

5

Bất kỳ trạng thái thay đổi nào trên bất kỳ mã pin nào được định cấu hình là đầu vào kỹ thuật số đều có thể tạo ra một ngắt. Không giống như các vectơ duy nhất cho các ngắt gây ra bởi INT1 hoặc INT2, tính năng PinChangeInt sử dụng một vectơ phổ biến và sau đó Interrupt Service Routine (còn gọi là ISR) cho vectơ này cần xác định xem pin nào đã thay đổi.

May mắn thay Thư viện PinChangeInt làm cho điều này dễ dàng.

PCintPort::attachInterrupt(PIN, burpcount,RISING); // attach a PinChange Interrupt to our pin on the rising edge
// (RISING, FALLING and CHANGE all work with this library)
// and execute the function burpcount when that pin changes

0

Trong trường hợp bạn muốn phát hiện điện áp vượt qua ngưỡng , thay vì chỉ đơn thuần là CAO hoặc THẤP, bạn có thể sử dụng bộ so sánh tương tự. Ví dụ phác thảo:

volatile boolean triggered;

ISR (ANALOG_COMP_vect)
  {
  triggered = true;
  }

void setup ()
  {
  Serial.begin (115200);
  Serial.println ("Started.");
  ADCSRB = 0;           // (Disable) ACME: Analog Comparator Multiplexer Enable
  ACSR =  bit (ACI)     // (Clear) Analog Comparator Interrupt Flag
        | bit (ACIE)    // Analog Comparator Interrupt Enable
        | bit (ACIS1);  // ACIS1, ACIS0: Analog Comparator Interrupt Mode Select (trigger on falling edge)
   }  // end of setup

void loop ()
  {
  if (triggered)
    {
    Serial.println ("Triggered!"); 
    triggered = false;
    }

  }  // end of loop

Điều này có thể hữu ích cho những thứ như máy dò ánh sáng, trong đó bạn có thể cần phát hiện sự thay đổi từ (giả sử) 1V sang 2V trên đầu vào.

Mạch ví dụ:

nhập mô tả hình ảnh ở đây

Bạn cũng có thể sử dụng Bộ thu hình đầu vào trên bộ xử lý, sẽ nhớ thời gian chính xác của một số đầu vào nhất định, bằng cách lưu số lượng Timer / Counter hiện tại 1. Điều này cho phép bạn lưu trữ thời điểm chính xác (gần như chính xác) mà sự kiện sự quan tâm đã xảy ra, thay vì đưa ra độ trễ (có thể là vài micro giây) trước khi ISR ​​có thể được sử dụng để nắm bắt thời gian hiện tại.

Đối với các ứng dụng quan trọng về thời gian, điều này có thể giúp tăng độ chính xác.

Ứng dụng ví dụ: Biến Arduino của bạn thành máy kiểm tra tụ điện

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.