Jeg prøver å bruke portmanipulering i avbrudd for å lese en roterende koderen. Jeg fant kode for en Uno, så portinnkallingen for pinne 2 og 3 er forskjellige. Jeg tror på Mega er de henholdsvis PORTH3 og PORTH4. Koden min fungerer ikke. Har jeg feil porter? Jeg har prøvd å lese opp dette, og jeg forstår ikke helt Bxxxxxxxx-delen. Jeg tror det kan være det som er feil. Her er en del av koden min med en av avbruddene.
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 }
Kommentarer
- Fikk du noen gang dette til å fungere? Jeg har også ønsket å bruke en Arduino Mega for å spore vinkelposisjonen til en Omron Encoder med 3 avbrudd. En av avbruddene for at han indekserer for å tilbakestille til 0 hver gang den fullfører en revolusjon. Jeg vil bruke den til å spore en roterende mast for å finne retning. Det er kodestykker, men ingenting er komplett. Er din komplett? [email protected]
Svar
Re “pins 2 og 3 er forskjellige. Jeg tror på Mega at de er henholdsvis PORTH3 og PORTH4”, det er sant at Arduino digitale pins 2 og 3 tilhører forskjellige porter på Uno vs Mega2560-kort.
Mega2560 har seks INTx-pinner, mot to slike på Uno. På Mega er INT0 … INT3 PD0 … PD3, og INT4, INT5 er PE4, PE5. På Uno er INT0, INT1 PD2, PD3. Merk, i et svar på Kan eksterne avbrudd være ELLER «d sammen på» 328 (Uno)? Jeg viser et par rutiner som vil vise passende masker for pinner på forskjellige Arduinos. Se seksjonene «Bruke andre pinner til PCI-er» og «ISR-framework-genererende skisse».
Her er noen problemer med koden som vises i spørsmålet:
-
aFlag
initialiseres til null, og blir aldri satt null på koden som vises. Så den førsteif
betingelsen iPinA()
oppfylles aldri. -
PinA()
er en avbruddshåndterer, koblet til avbrudd avattachInterrupt()
-anropene. Fordi maskinvare deaktiverer avbrudd før den kommer inn i en avbruddshåndterer, er det ikke noe behov for avbruddshåndtereren å slå av avbrudd. Det vil si at du slettercli()
iPinA()
. På samme måte sletter dusei()
på slutten avPinA()
fordi maskinvare gjenoppretter avbruddsstatus når en RETI-instruksjon kjøres. -
Arduino-programvaremiljøet definerer konstanter som
B00001100
med binære verdier som samsvarer med navnet. Det vil si at i Arduino-programvaremiljøet har konstantB00001100
verdien0B00001100
. Etter min mening er den «en dum og unødvendig funksjon. Jeg foreslår at du i koden din bruker standard C-notasjon som0B00001100
når du vil bruke binære konstantverdier. -
Jeg ser på å skrive
encoderPos --
i stedet forencoderPos--
som en perversjon og foreslår at du sletter det unødvendige rommet. -
Da du ikke har vist
PinB()
avbruddshåndtereren, vet jeg ikke hvordan du skulle håndtereencoderPos++
sak. Bedømt ut fra koden som vises, bruker du en metode som ikke vil håndtere sprett og intermitterende feil på riktig måte. Jeg foreslår at du bruker pin-endringsavbrudd og en tilstandsmaskinmetode, som illustrert i svar på:
• Lesing fra en KY-040 roterende koder med Digispark
• Hvordan lese RPS for rask rotasjon med statusendringsmetode i Arduino?
• Les RC-mottakerkanaler ved hjelp av Interrupt i stedet for PulseIn
• Kan eksterne avbrudd ELLER «d» på «328 (Uno)?
Svar
På mega leser du pinnene med PINE.
Så koden din i PinA ville endres til:
reading = PINE & 0b00110000; if(reading == 0b00110000 && aFlag) { encoderPos --; bFlag = 0; aFlag = 0; } else if (reading == 0b00010000) bFlag = 1;
I fant en flott diskusjon som snakket om maskeringen som kreves her: https://forum.arduino.cc/index.php?topic=561741.0