Snažím se použít manipulaci s porty v přerušeních ke čtení rotačního kodéru. Našel jsem kód pro Uno, takže volání portu pro piny 2 a 3 se liší. Myslím, že na Mega jsou PORTH3 a PORTH4. Můj kód nefunguje. Mám své porty špatně? Zkoušel jsem to přečíst a úplně nerozumím části Bxxxxxxxx. Myslím, že to může být nesprávné. Tady je část mého kódu s jedním z přerušení.
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 }
Komentáře
- Už jste to někdy zvládli? Také jsem chtěl pomocí Arduino Mega sledovat úhlovou polohu kodéru Omron se 3 přerušeními. Jedno z přerušení indexu se pokaždé resetuje na 0 dokončí jednu revoluci. Chci ji použít ke sledování rotujícího stožáru pro určení směru. Existují kousky kódu, ale nic není úplné. Je váš kompletní? [email protected]
Odpověď
Re „piny 2 a 3 se liší. Myslím, že na Mega jsou PORTH3 a PORTH4,“ je pravda, že Arduino digitální piny 2 a 3 patří k různým portům na deskách Uno vs Mega2560.
Mega2560 má šest pinů INTx, proti dvěma takovým na Uno. Na Mega jsou INT0 … INT3 PD0 … PD3 a INT4, INT5 jsou PE4, PE5. Na Uno jsou INT0, INT1 PD2, PD3. Všimněte si, že v odpovědi na Mohou být externí přerušení NEBO „d“ na „328 (Uno)? ukážu několik rutin, které zobrazí vhodné masky pro piny na různých Arduinos. Viz části „Použití jiných pinů pro PCI“ a „Skica generující rámec ISR“.
Zde je několik problémů s kódem zobrazeným v otázce:
-
aFlag
je inicializován na nulu a v zobrazeném kódu není nikdy nastaven nenulově. Prvníif
podmínka vPinA()
tedy nikdy není splněna. -
PinA()
je obsluha přerušení spojená s přerušením pomocí vašichattachInterrupt()
hovorů. Protože hardware zakáže přerušení předtím, než vstoupí do obslužné rutiny přerušení, není nutné, aby obslužná rutina přerušení vypínala přerušení. To znamená, odstranitcli()
vPinA()
. Podobně odstraňtesei()
na konciPinA()
, protože hardware po provedení instrukce RETI obnoví stav přerušení. -
Softwarové prostředí Arduino definuje konstanty jako
B00001100
s binárními hodnotami, které odpovídají názvu. To znamená, že v softwarovém prostředí Arduino má konstantaB00001100
hodnotu0B00001100
. Podle mého názoru je tato „hloupá a zbytečná funkce; navrhuji, abyste ve svém kódu používali standardní notaci C jako0B00001100
, pokud chcete použít hodnoty binárních konstant. -
Psaní
encoderPos --
místoencoderPos--
považuji za perverzi a navrhuji tento zbytečný prostor odstranit. -
Vzhledem k tomu, že jste neobjevili obslužný program přerušení
PinB()
, nevím, jak se chystáte zpracovatencoderPos++
případ. Soudě podle zobrazeného kódu používáte metodu, která nebude správně zpracovávat chyby odskoku a občasné chyby. Navrhuji použít přerušení pin-change a metodu state-machine, jak je znázorněno v odpovědích na:
• Čtení z rotačního kodéru KY-040 s Digisparkem
• Jak číst RPS pro rychlé střídání s metodou změny stavu v Arduinu?
• Čtení kanálů RC přijímače pomocí Interrupt místo PulseIn
• Mohou být externí přerušení NEBO d společně na 328 (Uno)?
Odpověď
Na mega byste číst piny pomocí PINE.
Takže váš kód v PinA by se změnil na:
reading = PINE & 0b00110000; if(reading == 0b00110000 && aFlag) { encoderPos --; bFlag = 0; aFlag = 0; } else if (reading == 0b00010000) bFlag = 1;
I našel skvělou diskusi hovořící o zde požadovaném maskování: https://forum.arduino.cc/index.php?topic=561741.0