การใช้งานที่ถูกต้องของการขัดจังหวะการเปลี่ยนพิน


10

ฉันกำลังพยายามใช้การขัดจังหวะการเปลี่ยนพินเพื่อตรวจจับปุ่มกด จนถึงตอนนี้ฉันไม่เคยทำงานกับการขัดจังหวะแบบนี้และมีปัญหาบางอย่างดังนั้นฉันจึงต้องการตรวจสอบให้แน่ใจว่านี่เป็นการใช้งานที่ถูกต้องหรือไม่

หากฉันได้รับแผ่นข้อมูลถูกต้องสิ่งต่อไปนี้จะต้องทำเพื่อใช้ขัดจังหวะการเปลี่ยนพิน:

  1. ตั้งค่า PIN ใดที่คุณต้องการควบคุมในการลงทะเบียน PCMSK
  2. เปิดใช้งานการลงทะเบียน PIN สำหรับการเปลี่ยนการควบคุมการขัดจังหวะพิน (PCICR)
  3. เปิดใช้งานการขัดจังหวะ
  4. ใช้เวกเตอร์ขัดจังหวะที่สอดคล้องกัน

โครงการ: Simple Moodlamp, ควบคุมสีด้วยปุ่ม 4 ปุ่ม

ติดตั้ง:

  • Atmega168A-PU
  • สวิตช์ปุ่มกดขนาดเล็ก 4 ปุ่ม
  • MOSFETS เพื่อควบคุมไฟ LED RGB 3 วัตต์ของฉัน

นี่คือรหัสที่ฉันใช้ซึ่งใช้งานไม่ได้ตามที่คาดไว้:

#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);
        }
}

หมายเหตุ: ปุ่มควรจะถูกหักออก เนื่องจากฉันพยายามทำตามขั้นตอนนี้และไม่ควรจะเป็นอย่างยิ่งสำหรับการเปิดไฟ LED ฉันจึงเพิกเฉยที่นี่

คำถาม:วิธีที่ฉันพยายามใช้อินเทอร์รัปต์นั้นถูกต้องหรือไม่?

มีปัญหากับการตั้งค่าของฉัน:

  • Buttons1-3 จะถูกละเว้นโดยสิ้นเชิง
  • Button4 กำลังเรียกใช้การรีเซ็ต atmega

สิ่งที่ฉันตรวจสอบ:

  • ปุ่มต่างๆไม่ได้เชื่อมต่อกับ PIN รีเซ็ต
  • ปุ่มเชื่อมต่อกับ GND อย่างถูกต้องหากกด
  • ปุ่มไม่ได้เชื่อมต่อกับ GND หากไม่ได้กด
  • ปุ่มทำงานได้ดีถ้าฉันใช้มันโดยไม่ขัดจังหวะเช่น:

    ถ้า (! (PINC & BUTTON4)) {PORTB ^ = BLUE; }

  • 16MHZ คริสตัลภายนอก / คริสตัลภายใน
  • ข้อผิดพลาดใด ๆ ในการกำหนดเส้นทาง
  • ฉันใช้ตัวเก็บประจุ 100nF ระหว่าง PWR และ GND กับ atmega
  • VCC (7), GND (8), GND (22), AVCC (20) เชื่อมต่อกัน (เนื่องจากฉันไม่ต้องการ AREF, ไม่ได้เชื่อมต่อ)

คุณต้องตั้งค่าสถานะ PCIE1 (ไม่ใช่ PCIE2) และ PCINT1_vect (ไม่ใช่ PCINT2)
microtherion

ทำไมต้อง PCIE1 ฉันใช้การลงทะเบียน C ดังนั้นถ้าฉันนับว่าเป็น A (PCIE0), B (PCIE1), C (PCIE2)? อย่างไรก็ตามฉันลองใช้กับ PCIE1 nad PCINT1_vect และไม่มีการตอบสนองใด ๆ หากฉันกดปุ่ม
echox

1
อาจมีความเสี่ยงเล็กน้อยในการใช้ความเป็นไปได้ในการมอบหมายดังกล่าว ในกรณีนี้คุณเกือบจะถูกต้องยกเว้นว่า ATmega168 ไม่มีพอร์ต A ไม่ว่าในกรณีใดฉันไปตามแผ่นข้อมูลและ pinout เคล็ดลับอีกข้อหนึ่งคือคุณใช้ PCIE2 แต่ตั้งบิตใน PCMSK1; มันอาจจะไม่ถูกต้อง (น่าเสียดายที่ฉันไม่รู้ว่าทำไมภาพร่างที่คุณแก้ไขยังไม่ทำงาน)
microtherion

ขอบคุณฉันยังเข้าใจว่าการรวมกันของการแก้จุดบกพร่องซอฟแวร์ซึ่งขึ้นอยู่กับตัวเองสร้างฮาร์ดแวร์ไม่ว่าง่าย ;-)
echox

คำตอบ:


14

การขัดจังหวะการเปลี่ยนพินมักจะไม่ใช่วิธีที่ดีในการตรวจจับการกระทำของปุ่ม นี่เป็นเพราะปุ่มกดเด้งและคุณจะได้รับการขัดจังหวะโดยไม่มีความหมายมากมายจากนั้นคุณยังต้องทำการ debouncing ต่อไป

วิธีที่ดีกว่าคือมีการขัดจังหวะเป็นระยะเช่นทุก 1 ms (อัตรา 1 kHz) นั่นเป็นเวลานานสำหรับตัวประมวลผลส่วนใหญ่ดังนั้นเวลาที่ใช้ในการขัดจังหวะจึงมีน้อย เพียงแค่กดปุ่มสถานะทุกครั้งที่ขัดจังหวะ ประกาศสถานะปุ่มใหม่ถ้าคุณเห็นสถานะใหม่ 50 ms ในแถว 50 ms นั้นยาวกว่าการเด้งปุ่มส่วนใหญ่ แต่ก็ยังสั้นพอที่มนุษย์จะไม่สังเกตเห็นหรือสนใจเกี่ยวกับความล่าช้า

โปรดทราบว่าวิธีนี้คุณสามารถจัดการกับปุ่มหลายปุ่มในอินเทอร์รัปต์ 1 ms เดียวกันได้ สิ่งที่คุณต้องมีคือหนึ่งตัวนับสำหรับแต่ละปุ่ม

เพิ่มเติมเกี่ยวกับเวลา debounce:

บางครั้งเช่นในกรณีนี้บางคนบอกว่า 50 ms เป็นเวลา debounce นานเกินไป สิ่งนี้ไม่เป็นความจริงสำหรับปุ่มธรรมดาที่มนุษย์กด อาจเป็นปัญหาในแอพพลิเคชั่นที่มีความสำคัญต่อเวลาเช่นนาฬิกาจับเวลา แต่จนถึงตอนนี้ฉันยังไม่พบเจอ ฉันทดสอบเรื่องนี้ในช่วงต้นทศวรรษ 1980 และคนอื่น ๆ อีกมากมายก็มีเช่นกัน

มันเป็นความจริงที่เวลาตีกลับของปุ่มกดทั่วไปอยู่ที่ประมาณ 10 มิลลิวินาทีโดยประมาณ 25 มิลลิวินาที ปัจจัย จำกัด เวลา debounce คือการรับรู้ของมนุษย์ 50 ms สั้นกว่าที่ผู้คนเริ่มสังเกตเห็นความล่าช้าเล็กน้อยเมื่อไม่ได้มองหา ถึงอย่างนั้นมันก็ใช้เวลานานกว่าที่มันจะน่ารำคาญ อาจเป็นไปได้ในบางกรณีที่มนุษย์สามารถตรวจจับความแตกต่างระหว่างความล่าช้า 50 ms และ 0 ms หากพวกเขากำลังมองหามันโดยเฉพาะแต่มันค่อนข้างแตกต่างจากการกดปุ่มและมองเห็นบางสิ่งบางอย่างเกิดขึ้น

50 ms จึงเป็นเวลาดีบั๊กเนื่องจากความล่าช้าต่ำกว่าขีด จำกัด การรับรู้ในแอปพลิเคชันทั่วไปวิธีต่ำกว่าขีด จำกัด การรบกวนและสูงกว่าช่วงเวลาตีกลับของสวิตช์ส่วนใหญ่ ฉันได้พบสวิตช์ที่เด้งมานานเกือบแล้วดังนั้นคุณอาจผลักดันขีด จำกัด การรับรู้เนื่องจากไม่มีอะไรจะหลวม

ฉันได้ทำผลิตภัณฑ์หลายอย่างด้วยปุ่ม debounce เฟิร์มแวร์โดยใช้เวลา debounce 50 ms ลูกค้าไม่เคยพูดถึงแม้จะสังเกตเห็นความล่าช้า พวกเขาทั้งหมดยอมรับว่าปุ่มทำงานได้ดีโดยไม่มีปัญหา


1
50ms อาจยาวเกินไปสำหรับบางกรณี (โดยปกติแล้ว 10-20ms เป็นข้อ จำกัด ของการรับรู้ของมนุษย์และน่าจะเพียงพอสำหรับการเปิดตัว) แต่วิธีการที่อธิบายไว้ที่นี่เป็นวิธีที่จะไป
Laszlo Valko

1
@ Laszlo: ไม่ 50 ms ไม่นานเกินไปสำหรับกรณีทั่วไป ดูเพิ่มเติมที่คำตอบของฉัน
Olin Lathrop

ฉันพยายาม 50 มิลลิวินาทีซึ่งทำงานได้ดีสำหรับฉัน :-) ฉันยังคงสงสัยว่าทำไมการเปลี่ยนพินขัดจังหวะไม่ทำงาน (ข้างสิ่งที่เด้ง) แต่ก็ใช้งานได้ :-) ขอบคุณ
echox

1

การขัดจังหวะการเปลี่ยนพินเป็นวิธีที่ดีกว่าในการดีกว่าการโพล การขัดจังหวะมักจะผ่านตรรกะบางอย่างเช่น D-Flip Flop หรือ D-Latch แม้ว่าสิ่งนี้จะเป็นจริงมันก็ยากที่จะใช้รูทีน debounce นี้กับคอมไพเลอร์ระดับที่สูงขึ้น เมื่ออินเตอร์รัปต์เกิดขึ้นแฟล็กการขัดจังหวะจะไม่ถูกล้างและการเปิดใช้การอินเตอร์รัปต์จะถูกล้างจนกว่าจะเกิดความล่าช้า เมื่อการหน่วงเวลาเกิดขึ้นสถานะของพินจะถูกตรวจสอบและหากยังคงอยู่ในสถานะที่กำหนดซึ่งก่อให้เกิดการขัดจังหวะสถานะของปุ่มจะเปลี่ยนไปและการตั้งค่าอินเตอร์รัปต์จะถูกล้างและการตั้งค่าอินเตอร์รัปต์ หากไม่อยู่ในสถานะที่ทำให้เกิดการเริ่มต้นการเปิดใช้งานอินเทอร์รัปต์จะถูกตั้งค่าและสถานะจะยังคงเหมือนเดิม สิ่งนี้จะทำให้ตัวประมวลผลว่างสำหรับงานอื่น ๆ การขัดจังหวะเป็นระยะจะทำให้เสียเวลาในโปรแกรม


-1

"การขัดจังหวะการเปลี่ยนพินมักจะไม่ใช่วิธีที่ดีในการตรวจจับการกระทำของปุ่ม"

ไม่ถูกต้อง. PC INT เป็นตัวเลือกที่ดีที่สุด หากคุณใช้การสำรวจความคิดเห็นเพื่อตรวจสอบสถานะของปุ่มจะไม่มีการดำเนินการใด ๆ เป็นส่วนใหญ่ คุณเสียเวลาอันมีค่าของ CPU มาก PC INT อนุญาตให้ดำเนินการตามคำขอเท่านั้น

"นี่เป็นเพราะปุ่มกดเด้งและคุณจะได้รับการขัดจังหวะโดยไม่มีความหมายมากมายจากนั้นคุณก็ยังต้องทำการเดบิวต์ต่อไป"

ถูกต้องเกี่ยวกับการตีกลับ แต่คุณไม่ควรเปิด / ปิดปุ่ม / สวิตช์ภายในรูทีนการขัดจังหวะ (ด้วยเหตุผลเดียวกัน: เสียเวลาของ CPU) ISR นั้นหมายถึงว่าสั้นและมีประสิทธิภาพและใช้โค้ดได้จริง เพียงแค่ใช้การเปิดตัวฮาร์ดแวร์ รักษาซอฟต์แวร์ของคุณให้สะอาด!

การเปิดใช้ฮาร์ดแวร์จะสะดวกกว่าดูที่นี่ / การเรียกคืน RC + ทริกเกอร์ Schmittสำหรับการอ้างอิง ฉันใช้มันนับครั้งไม่ถ้วนกับ PC INT มันไม่เคยล้มเหลว

ใช่คุณสามารถ (และควร) ใช้ PC INT เพื่อรับสถานะปุ่ม แต่คุณต้องใช้การ debouncing ฮาร์ดแวร์ที่เหมาะสม


2
การ debouncing ซอฟต์แวร์เป็นวิธีการที่ถูกต้องและส่วนใหญ่แล้วค่าใช้จ่าย CPU เพิ่มเติมเล็กน้อยนั้นไม่เกี่ยวข้อง การบอกว่าคุณควร debounce ในฮาร์ดแวร์เป็นคำถามที่ดีที่สุด การบอกว่าคุณต้องใช้การเปิดตัวฮาร์ดแวร์ในทุกกรณีก็ผิดพลาด
Olin Lathrop

ในแอปพลิเคชั่นส่วนใหญ่คอนโทรลเลอร์กำลังทำงานโดยไม่ได้ใช้งานเป็นส่วนใหญ่อย่างไรก็ตามให้รันลูปหลัก นอกจากนี้เวลา CPU ที่ต้องใช้ในการตรวจสอบสถานะ IO และการเพิ่มขึ้นของตัวแปรนั้นมีเพียงเล็กน้อย การใช้งาน debouncing อย่างง่ายในซอฟต์แวร์เกือบจะเป็น "ฟรี" และฮาร์ดแวร์ต้องเสียเงิน และอย่าหัวเราะเยาะสองสามเซ็นต์เงินค่าใช้จ่ายในการประกอบก็ดีเช่นกันและถ้าคุณใช้ผลิตภัณฑ์ระดับปานกลางถึงมากมันก็ไม่สำคัญ ความจริงที่ว่าเวลาของ ISR ควรจะสั้น แต่ก็แทบจะไม่เป็นข้อโต้แย้งในกรณีนี้ มันอาจสำคัญกว่าหาก PC INT ISR ยิง 50 ครั้งติดต่อกันเนื่องจากการกระดอน
Rev1.0

@Nelson เรื่อง 'เสียเวลาของ CPU' มีความสำคัญในบางแอปพลิเคชันและไม่ใช่ในหลาย ๆ แอปพลิเคชัน คุณควรปรับคำตอบให้เหมาะสมกับสถานการณ์ที่เวลา CPU มีความสำคัญ
user1139880
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.