Sự khác nhau giữa Ngắt và lấy mẫu cho nút phần cứng?


8

Tôi có một nút phần cứng tôi đã kết nối với một ngắt, nhưng vấn đề của tôi là nó bị nảy một chút, làm cho nút nhấn không đáng tin cậy. Tôi nghĩ rằng rất nhiều vấn đề này sẽ được giải quyết bằng cách lấy mẫu trong vòng lặp chính, nhưng điều đó chỉ cảm thấy sai về mặt kỹ thuật.

Các ngắt có thích hợp hơn cho truyền thông nội mạch hay các ngắt cũng thích hợp cho các chuyển mạch phần cứng? Nếu vậy những kỹ thuật gỡ lỗi nào tôi có thể sử dụng?

Tôi đã thử giữ một biến hẹn giờ và kiểm tra nó theo thời gian hiện tại, độ trễ và các kỹ thuật khác. Có vẻ như việc trả lại quá nhanh không thành vấn đề.



Không có gì sai khi lấy mẫu trong vòng lặp chính, nếu bạn phản ứng trong vòng lặp chính. Ngắt là thích hợp hơn nếu bạn muốn phản ứng không đồng bộ. Đôi khi bạn làm, và đôi khi bạn không.
Eugene Ryabtsev

Cách tốt nhất để gỡ lỗi là bộ lọc thông thấp đơn giản.
lucas92

Câu trả lời:


8

Tranh luận là một câu hỏi thường gặp. Bạn sẽ có thể tìm thấy ... số lượng trang web gần như không giới hạn về chủ đề này. Smith cũng nhận xét về bản PDF được đọc rộng rãi của Jack Ganssle về chủ đề này. Và với tất cả những câu trả lời này, bạn đã có cả phương pháp phần cứng và phần mềm.

Tôi sẽ thêm vào "tài liệu" này một chút bằng cách chủ yếu nói về những ý tưởng chưa được đề cập tốt. Nhưng trước khi tôi làm, một hoặc hai điểm:

  1. Việc gỡ lỗi trong phần cứng tương tự có thể đạt được kết quả mà bạn không thể đạt được bằng cách chuyển đổi "quan sát" chỉ bằng kỹ thuật số trên cơ sở định kỳ bằng cách bỏ phiếu hoặc thậm chí bằng các sự kiện thay đổi pin phần cứng. Nhưng bạn có thể làm "đủ tốt" cho tất cả ý định và mục đích, bằng kỹ thuật số. Hầu như không ai ngày nay sử dụng các giải pháp gỡ lỗi tương tự bên ngoài. Nhưng tôi đã sử dụng tất cả mọi thứ, từ kéo dài xung bằng cách sử dụng một lần chụp (74121) đến các kỹ thuật được đề cập bởi Jack Ganssle ở đây .
  2. Đối với những người chỉ lập trình nhúng và hoàn toàn không thích tìm hiểu về điện tử, công tắc gỡ lỗi có lẽ là một trong hai bộ kỹ năng cơ bản cần thiết. Đèn LED hoạt động có lẽ là một trong những khác. Và bằng cách này, tôi không có nghĩa là chỉ có một kỹ năng này. Tôi có nghĩa là có thể làm điều đó theo một số cách. Vì vậy, bạn thực sự làm cần thiết phải hoàn toàn thấu hiểu những gì Jack Ganssle viết về, và vẫn còn nhiều, liên quan đến công tắc.

Vì tôi đã đề cập đến việc kéo dài xung bằng cách sử dụng 74121 và vì Jack Ganssle không đề cập đến nó và cũng không có ai ở đây cả, nên tôi cũng có thể cung cấp liên kết bổ sung này dưới dạng đọc thêm đề nghị sử dụng 74121 hoặc 555 dưới dạng một lần hẹn giờ cho công tắc gỡ lỗi.


Bây giờ, để làm điều này thông qua quan sát với một vi điều khiển.

Tôi thường sử dụng một máy trạng thái để xử lý tranh luận. Điều này hầu như luôn được điều khiển bởi một bộ đếm thời gian "nhịp tim" thông thường mà tôi đặt thành khoảng , nếu có thể. (Tôi thường KHÔNG sử dụng các sự kiện ngắt kích hoạt cạnh vì một số lý do.)8ms

Máy trạng thái trông như thế này:

sơ đồ

mô phỏng mạch này - Sơ đồ được tạo bằng CircuitLab

Giá trị DEBOUNCED cho công tắc có thể mang các giá trị "không hoạt động", "hoạt động" và "không xác định". Bằng cách này, bạn có thể đảm bảo rằng phần mềm của bạn sẽ đợi cho đến khi giá trị chuyển đổi lắng xuống sau khi khởi tạo. Nhưng thông thường, tôi không bận tâm với điều đó. Tôi thay thế giá trị "không xác định" bằng một số giá trị mặc định và thay vào đó chỉ sử dụng hệ thống giá trị nhị phân.

Máy trạng thái được nhập bằng cách trước tiên đặt giá trị được gỡ lỗi về mặc định và sau đó nhập trạng thái "THAY ĐỔI" của máy trạng thái. Ở mỗi khoảng thời gian (thường là nếu tôi có thể thoát khỏi nó), tôi sẽ đọc giá trị chuyển đổi hiện tại và thực hiện cập nhật trạng thái hiện tại và có thể, giá trị được gỡ lỗi. Sau đó tôi mới thoát ra. Mã mức cao sau đó chỉ truy cập vào trạng thái được công bố.8ms

Nếu nó quan trọng với tôi, tôi cũng có thể giữ trạng thái được công bố trước đó. Trong những trường hợp này, khi tự cập nhật trạng thái đã phát hành, trước tiên tôi sẽ sao chép trạng thái đó sang 'trạng thái đã được công bố trước'. Sau đó tôi có thể sử dụng cặp giá trị để xác định xem đã có chuyển đổi được công bố chưa. Đôi khi, tôi không quan tâm đến việc chuyển đổi. Đôi khi, tôi làm. Vì vậy, nó phụ thuộc. Nhưng trong mọi trường hợp, tôi chỉ muốn biết về những chuyển đổi đã được công bố. Tôi không bao giờ quan tâm đến việc chuyển đổi runt . Vì vậy, mã mức cao không bao giờ sử dụng bất kỳ trạng thái nội bộ nào mà máy trạng thái sử dụng cho công việc riêng của mình.

Một trong những điều tốt đẹp về phương pháp này là tôi có thể gỡ bỏ toàn bộ cổng chuyển đổi cùng một lúc. Và tôi cũng có thể làm điều đó mà không cần một nhánh trong mã ngắt. Điều này có nghĩa là mã gỡ lỗi rất nhanh và ngắn cho chiều rộng cổng của vi điều khiển (thường rộng 8 bit.) Một ví dụ từ Atmel AT90 cho thấy cách đạt được điều này bằng cách sử dụng sự kiện ngắt Timer0:

.equ    SWPORTPINS  =   PINB
.def    SwRawCurr   =   r4
.def    SwRawPrev   =   r5
.def    SwState     =   r6
.def    SwDebCurr   =   r7
.def    SwDebPrev   =   r8

            ; Debounce the input switches.

                mov     SwRawPrev, SwRawCurr
                in      SwRawCurr, SWPORTPINS
                mov     Timer0Tmp1, SwRawCurr
                eor     Timer0Tmp1, SwRawPrev
                mov     Timer0Tmp0, Timer0Tmp1
                or      Timer0Tmp1, SwState
                mov     SwState, Timer0Tmp0
                mov     Timer0Tmp0, Timer0Tmp1
                com     Timer0Tmp0
                and     Timer0Tmp1, SwDebCurr
                and     Timer0Tmp0, SwRawCurr
                or      Timer0Tmp1, Timer0Tmp0
                mov     SwDebPrev, SwDebCurr
                mov     SwDebCurr, Timer0Tmp1

Bây giờ, ví dụ này hiển thị toàn bộ thỏa thuận, bao gồm các giá trị chuyển đổi được công bố trước đó và hiện tại. Và nó cũng thực hiện tất cả các chuyển đổi trạng thái cần thiết. Tôi không hiển thị việc khởi tạo mã này. Nhưng những điều trên có ý nghĩa về việc máy trạng thái hoạt động dễ dàng như thế nào và cần ít mã để làm như vậy. Nó khá nhanh và đơn giản và không yêu cầu phân nhánh (đôi khi liên quan đến các chu kỳ bổ sung cũng như không gian mã bổ sung.)


Tôi thích sử dụng thời gian vì việc thử nghiệm lâu dài với nhiều người khác nhau sử dụng thiết bị mà tôi đã làm việc trong quá khứ đã đưa tôi đến đó. Tôi đã thử thời gian dài hơn và khi tôi làm như vậy, tôi bắt đầu thấy mọi người nói với tôi rằng "khả năng đáp ứng" không đủ "nhanh". (Ngày nay, với những đứa trẻ lớn lên làm việc chơi game "bắn chúng" theo thời gian thực, tôi thậm chí có thể rút ngắn nó hơn nữa. Chúng sẽ phàn nàn cay đắng về sự chậm trễ thậm chí do TV kỹ thuật số hiện đại gây ra trong việc thiết lập và hiển thị khung hình.)8ms

Một số người sẽ có cảm giác rất rõ ràng về mức độ rõ ràng và phản ứng của một hệ thống. Sắc nét và đáp ứng có nghĩa là mẫu thường xuyên hơn, không ít hơn. Nhưng cá nhân, tôi thấy thời gian quan sát chấp nhận được. (Tuy nhiên, tôi không tìm thấy thời gian đủ tốt ngay cả đối với tôi.)20ms

Xin lưu ý rằng máy trạng thái mà tôi đã đề cập trước tiên phải nhập trạng thái CÀI ĐẶT và sau đó ở đó thêm một lần nữa trước khi giá trị cho DEBOUNCED được cập nhật. Vì vậy, nhấn một nút và giữ nó, ngay cả trong trường hợp tốt nhất, sẽ yêu cầu các bóng bán dẫn này:

  1. thay đổi từ THIẾT LẬP sang THAY ĐỔI
  2. thay đổi từ THAY ĐỔI sang THIẾT LẬP
  3. ở lại CÀI ĐẶT, cập nhật DEBOUNCED

Vì vậy, một trạng thái mới được công bố đòi hỏi tối thiểu 3 khoảng thời gian mẫu để đạt được.

Một nút ấn sẽ cần ít nhất 6 lần mẫu để chuyển từ không hoạt động, sang hoạt động và sau đó trở lại không hoạt động.


Tôi đã đề cập đến các chi tiết ở trên để hoàn toàn rõ ràng rằng thời gian mẫu là có nghĩa là nó nằm ở đâu đó trong khoảng để đi từ không hoạt động đến một kết quả được công bố hoạt động được công nhận. Và sẽ mất thêm trước khi trạng thái có thể trở lại không hoạt động. Đó là tối thiểu để trải qua toàn bộ chu kỳ nút ấn. 168ms 2416ms<t24ms 4024ms40ms<t48ms

Sử dụng thời gian mẫu dài hơn sẽ có thời gian dài hơn tương ứng. Sử dụng Tôi đã đề cập là "chấp nhận được" đối với tôi khi đó có nghĩa là khoảng cho toàn bộ chu kỳ nút ấn . Và đó là nhận thẳng lên vào khu vực nơi người ta có xu hướng thông báo. Tôi chắc chắn không thích "cảm giác" nếu nó dài hơn thế. 10020ms100ms<t120ms

Nếu bạn đi theo con đường này, đừng nên ung dung về việc sử dụng thời gian mẫu dài hơn. Nếu bạn phải, thì tôi nghĩ bạn cũng phải thực hiện nhiều thử nghiệm với người dùng / người tiêu dùng.

Và nếu bạn đang phát triển mã cho bàn phím gõ, thì hãy sử dụng thời gian ngắn hơn. Kỷ lục cho một người đánh máy đã được thiết lập cách đây hàng thập kỷ ở mức 217 wpm. Điều này dẫn đến khoảng một khóa cứ sau . Những người đánh máy như thế đang nhấn nhiều phím theo thứ tự được kiểm soát. Để có được hiệu suất tốt cho những người đánh máy rất nhanh bằng cách sử dụng hệ thống chuyển tiếp rơle sậy ướt thủy ngân, tôi thấy rằng hoạt động tốt. 245ms2ms


thời gian bật thay đổi từ 0 đối với công tắc thủy ngân thành kiểu "vài" ms đối với công tắc vi xúc giác đến 30ms đối với công tắc bật tắt cồng kềnh, vì vậy 8ms là một con số tốt khi xem xét tăng thời gian thoát khi bị lão hóa.
Tony Stewart Sunnyskyguy EE75

@ TonyStewart.EEsince'75 Tôi đã chọn thử nghiệm rộng rãi với người dùng sử dụng thiết bị với nhiều loại công tắc khác nhau và con số 8 ms xuất phát từ việc chưng cất tất cả công việc đó. (Tôi đã không lo lắng quá nhiều về "lý thuyết" vì thực tế xây dựng và tạo ra các công tắc, và sự đa dạng của chúng, khiến cho việc thu thập và phân tích dữ liệu đó có vẻ khó khăn.) Tôi luôn sử dụng 8 ms, vì có thể, vì có vẻ như vậy trở thành điểm hấp dẫn với kinh nghiệm viết phần mềm lâu năm chỉ hoạt động và khi các khiếu nại sau bán hàng đi đến một con số chính xác (dù sao đi nữa, dù sao đi nữa.)
jonk

@ TonyStewart.EEsince'75 Nhân tiện, thử nghiệm này bao gồm việc sử dụng rơle lau sậy thủy ngân như một phần của các công tắc chính được sử dụng trong bàn phím (mà theo tôi, dường như không còn được thực hiện nữa.) Tôi đi lấy mẫu 1-2 giây (tùy thuộc vào đơn vị.)
jonk

Đó là ánh sáng sân vườn laser mà tôi đã đề cập một lần trước đây .. có các công tắc điều khiển từ xa màng xúc giác với thời gian nảy thấp nhưng lập trình viên đã làm cho chúng chuyển đổi với tốc độ 10Hz để người ta phải giải phóng chúng trong <100ms nếu không thì tắt nguồn. ? .trên một lưu ý khác .. Bàn phím đàn piano của Yamaha cực kỳ nhanh và hỗ trợ cuộn qua 10 phím trong khi chỉ có bàn phím IBM PC gốc mới hỗ trợ cuộn qua cạnh hàng đầu thực sự. Kể từ đó, tất cả các bàn phím là các nét đầu tiên đều dẫn đầu và sau đó kéo theo rollover, đó là một Pita cho kỹ năng đánh máy kém như của tôi
Tony Stewart Sunnyskyguy EE75

@ TonyStewart.EEsince'75 Khu vực lấy mẫu chuyển đổi này là một điểm nhức nhối. Sự ra đời của micros giá rẻ với khả năng gỡ lỗi bên ngoài và công tắc không biết áp dụng, thêm vào sự thiếu hiểu biết của lập trình viên nhúng, có nghĩa là tôi thực sự tìm thấy vấn đề với hầu hết MỌI công cụ nhúng với bàn phím hoặc nút ấn. Họ TẤT CẢ làm việc khủng khiếp, trong lựa chọn của tôi. Và tôi nghĩ rằng điều đó chủ yếu là do các lập trình viên có ít hoặc không có kinh nghiệm, chỉ cần 'google nó lên và áp dụng nó' mà không cần suy nghĩ. Đôi khi, muối mã của họ với các điểm bỏ phiếu ngẫu nhiên, thậm chí. Đó là rác. Khó chịu Thật dễ dàng để có được đúng.
jonk

5

Việc gỡ lỗi có thể được thực hiện trong phần mềm bằng cách che dấu IRQ cho thời gian thoát hoặc trong phần cứng bằng cách thêm một tụ giữ với thời gian nảy RC = T> của bạn trong khoảng từ 1 đến 15ms tùy thuộc vào kích thước của công tắc.

  • ví dụ: pullup 100k và 0,1μF trên switch = 10ms @ 63% hoặc ~ 8ms ở mức 50% Vdd hoặc nếu sử dụng cổng kích hoạt Schmitt @ 1.33V = Vil từ 5V hoặc ~ 73% V + ~ 12ms

4

Để thực hiện hủy bỏ SW, ghi lại dấu thời gian của sự kiện hiện tại và kiểm tra độ trễ từ sự kiện hợp lệ cuối cùng:

#define DELAY_DEBOUNCE       150

uint32_t    __ts_lastpress = 0;

ISR(some_vector)
{
    uint32_t    now = millis(); // some timer tick counter

    if ( now - __ts_lastpress < DELAY_DEBOUNCE )
        return; // ignore it

    __ts_lastpress = now;
    // do the job here
}

CẬP NHẬT: với ít sửa đổi, bạn có thể đăng ký nhấp đúp:

#define DELAY_DEBOUNCE       150
#define DELAY_DOUBLE_CLICK   600

uint32_t    __ts_lastpress = 0;

ISR(some_vector)
{
    uint32_t    now = millis(); // some timer tick counter

    if ( now - __ts_lastpress < DELAY_DEBOUNCE )
        return; // ignore it

    // do the job here
    if ( now - __ts_lastpress < DELAY_DOUBLE_CLICK )
    {
        // it is double click
    }
    else
    {
        // it is single click
    }

    __ts_lastpress = now;
}

2

Ngắt chắc chắn là tuyệt vời cho chuyển đổi phần cứng là tốt. Bằng cách sử dụng các ngắt, bạn sẽ tránh được sự lãng phí lớn về tài nguyên và có thể là năng lượng, đặc biệt nếu bạn đang làm việc với các thiết bị chạy bằng pin.

Ngoài ra, khi mã của bạn ngày càng lớn hơn, bạn sẽ thấy rằng việc thực hiện các ngắt cho các nút thậm chí còn dễ dàng hơn so với việc bỏ phiếu trong vòng lặp chính của bạn.

Đối với việc thảo luận của bạn, nó có thể là một vấn đề mã hóa. Tôi thường sử dụng bộ đếm thời gian ~ 10ms để gỡ lỗi, trong khi kiểm tra việc phát hành nút. Hãy chắc chắn cũng tạm thời vô hiệu hóa nút ngắt trong khi bạn gỡ bỏ nó, vì vậy thói quen ngắt không được thực hiện nhiều lần.

Nếu bạn vẫn gặp sự cố, hãy đăng mã ở đây, để chúng tôi có thể giúp đỡ.


1

Điều này khá giống với Câu trả lời của Tony Stewart, nhưng tôi nghĩ nó có thể được mở rộng một số.

Các sơ đồ hàng đầu là cho một ngắt trên thấp hoặc trên cạnh rơi. Các sơ đồ dưới cùng là cho một ngắt trên cao hoặc cạnh tăng.

sơ đồ

mô phỏng mạch này - Sơ đồ được tạo bằng CircuitLab

cá nhân, với chi phí của một tụ điện, nó đáng để tôi sử dụng nó, thay vì lo lắng nếu phần mềm của tôi bị lỗi.

Lưu ý rằng như Tony Stewart đã nói, hằng số thời gian trong mạch này là 10ms hoặc . Nó sẽ mất khoảng từ ba đến năm hằng số (tùy thuộc vào độ nhạy của vi điều khiển của bạn để nút tự thiết lập lại, vì vậy nếu vi điều khiển của bạn có vấn đề với việc lặp lại chức năng ngắt, đó có thể là nguyên nhân và bạn có thể cần phải điều chỉnh nắp / điện trở để làm cho ngắt không xảy ra nhiều lần (Nghĩa là, chỉ khi ngắt của bạn được thiết lập để hoạt động trên tín hiệu cao hoặc thấp, và không phải là cạnh tăng hay giảm.10 k Ω * 1 μ F )(RC10kΩ1μF)

Liên quan đến tranh luận về phần cứng


1
Cả hai phiên bản đều hoạt động cho cả cạnh + ve hoặc -ve, đặc biệt nếu chân ngắt có đặc tính đầu vào kiểu schmitt (nhiều do). Cả SW1 & SW2 đều trải qua sự đột biến hiện tại khi đóng cửa. Một số nút bấm nút carbon có thể cho kết quả khác với nút bấm vòm kim loại.
glen_geek

1

Con người chậm chạp, chúng ta không cần sự chú ý ngay lập tức của một vi mô trong phạm vi micro giây.

Tất nhiên, đây không phải là cách duy nhất và cũng không phải là cách đúng đắn nhưng tôi thấy thường hợp lý hơn khi thiết lập bộ hẹn giờ (nhiều micrô có dấu sys) để ngắt một khoảng thời gian cố định và chuyển trạng thái của pin thành một biến cho mã để kiểm tra sau. Bạn kết thúc với một var đầy tro trong khi nảy

Tro 10010110

nhưng tại một số thời điểm nhất định, bạn sẽ nhận được 4 giá trị này:
01111111 cạnh tăng vừa mới phát hành
nút 11111111 ở trạng thái ổn định lên
10000000 cạnh rơi chỉ cần
gỡ nút 00000000 ở trạng thái ổn định xuống

Tuy nhiên, hầu hết thời gian, tôi chỉ sử dụng một bộ đếm đặt lại trong khi nảy. Đó là nhanh chóng, thử nghiệm và dễ dàng để làm.
Nếu thất bại thì tôi thử một cái gì đó thông minh hơn từ tài liệu Ganssle mà người khác đề xuất!

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.