인터럽트에서 포트 조작을 사용하여 로터리 인코더를 읽으려고합니다. Uno에 대한 코드를 찾았으므로 핀 2와 3에 대한 포트 호출이 다릅니다. 메가에서는 각각 PORTH3와 PORTH4라고 생각합니다. 내 코드가 작동하지 않습니다. 내 포트가 잘못 되었습니까? 나는 이것에 대해 읽어 보았고 Bxxxxxxxx 부분을 완전히 이해하지 못했습니다. 이것이 잘못된 것 같습니다. 여기에 인터럽트 중 하나가있는 코드의 일부가 있습니다.
static int pinA = 2; // Our first hardware interrupt pin is digital pin 2 static int pinB = 3; // Our second hardware interrupt pin is digital pin 3 volatile byte aFlag = 0; // let us know when we"re expecting a rising edge on pinA to signal that the encoder has arrived at a detent volatile byte bFlag = 0; // let us know when we"re expecting a rising edge on pinB to signal that the encoder has arrived at a detent (opposite direction to when aFlag is set) volatile byte encoderPos = 0; //this variable stores our current value of encoder position. Change to int or uin16_t instead of byte if you want to record a larger range than 0-255 volatile byte oldEncPos = 0; //stores the last encoder position value so we can compare to the current reading and see if it has changed (so we know when to print to the serial monitor) volatile byte reading = 0; void setup () { pinMode(pinA, INPUT); // set pinA as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases) pinMode(pinB, INPUT); attachInterrupt(0, PinA, RISING); // set an interrupt on PinA, //looking for a rising edge signal and executing the "PinA" Interrupt Service Routine (below) attachInterrupt(1, PinB, RISING); // set an interrupt on PinB, //looking for a rising edge signal and executing the "PinB" Interrupt Service Routine (below) } void PinA() { //CCW cli(); //stop interrupts happening before we read pin values reading = PORTH & 0xC; // read all eight pin values then strip away all but pinA and pinB"s values if (reading == B00001100 && aFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin"s rising edge encoderPos --; //decrement the encoder"s position count bFlag = 0; //reset flags for the next turn aFlag = 0; //reset flags for the next turn } else if (reading == B00000100) bFlag = 1; //signal that we"re expecting pinB to signal the transition to detent from free rotation sei(); //restart interrupts }
코멘트
- 이 작업을 해본 적이 있습니까? 저도 Arduino Mega를 사용하여 3 개의 인터럽트가있는 Omron 인코더의 각도 위치를 추적하고 싶었습니다. 인덱스가 매번 0으로 재설정되는 인터럽트 중 하나 하나의 회전을 완료합니다. 방향 찾기를 위해 회전하는 마스트를 추적하는 데 사용하고 싶습니다. 코드는 있지만 완전한 것은 없습니다. 완료 되었습니까? [email protected]
답변
Re “핀 2와 3은 다릅니다. 메가에서는 각각 PORTH3와 PORTH4라고 생각합니다.”, Arduino 디지털 핀 2는 사실입니다. 3 개는 Uno와 Mega2560 보드의 서로 다른 포트에 속합니다.
Mega2560 “에는 6 개의 INTx 핀이 있고 Uno에는 2 개가 있습니다. Mega에서 INT0 … INT3은 PD0 … PD3이고 INT4, INT5는 PE4, PE5입니다. Uno에서 INT0, INT1은 PD2, PD3입니다. “328 (Uno)에서 외부 인터럽트를 OR”할 수 있습니까? 의 답변에서 적절한 마스크를 표시하는 몇 가지 루틴을 보여줍니다. 다른 Arduinos의 핀. “PCI에 다른 핀 사용”및 “ISR 프레임 워크 생성 스케치”섹션을 참조하십시오.
다음은 질문에 표시된 코드와 관련된 몇 가지 문제입니다.
-
aFlag
는 0으로 초기화되며 표시된 코드에서 0이 아닌 값으로 설정되지 않습니다. 따라서PinA()
의 첫 번째if
조건은 충족되지 않습니다. -
PinA()
는attachInterrupt()
호출에 의해 인터럽트에 연결된 인터럽트 핸들러입니다. 하드웨어가 인터럽트 처리기에 들어가기 전에 인터럽트를 비활성화하기 때문에 인터럽트 처리기가 인터럽트를 끌 필요가 없습니다. 즉,PinA()
에서cli()
를 삭제합니다. 마찬가지로 하드웨어가 RETI 명령이 실행될 때 인터럽트 상태를 복원하므로sei()
끝에있는sei()
를 삭제합니다. -
Arduino 소프트웨어 환경은 이름과 일치하는 이진 값으로
B00001100
와 같은 상수를 정의합니다. 즉, Arduino 소프트웨어 환경에서 상수B00001100
의 값은0B00001100
입니다. 제 생각에는 “어리 석고 불필요한 기능입니다. 이진 상수 값을 사용하려면 코드에서0B00001100
와 같은 표준 C 표기법을 사용하는 것이 좋습니다. -
encoderPos--
대신encoderPos --
를 작성하는 것을 변태로 간주하고 불필요한 공간을 삭제하는 것이 좋습니다.
p>
PinB()
인터럽트 핸들러를 표시하지 않았기 때문에 encoderPos++
사례. 표시된 코드로 판단하면 바운스 및 간헐적 오류를 올바로 처리하지 못하는 방법을 사용하고 있습니다. 다음에 대한 답변에 설명 된대로 핀 변경 인터럽트 및 상태 머신 방법을 사용하는 것이 좋습니다.
• Digispark를 사용하여 KY-040 로터리 인코더에서 읽기
• Arduino에서 상태 변경 방법으로 빠른 회전을 위해 RPS를 읽는 방법은 무엇입니까?
• PulseIn 대신 인터럽트를 사용하여 RC 수신기 채널 읽기
• “328 (Uno)에서 외부 인터럽트를 OR”할 수 있습니까?
답변
메가에서는 PINE으로 핀을 읽었습니다.
PinA의 코드는 다음과 같이 변경됩니다.
reading = PINE & 0b00110000; if(reading == 0b00110000 && aFlag) { encoderPos --; bFlag = 0; aFlag = 0; } else if (reading == 0b00010000) bFlag = 1;
I 여기에서 필요한 마스킹에 대한 훌륭한 토론을 찾았습니다. https://forum.arduino.cc/index.php?topic=561741.0