Arduino Mega 2560 piny přerušení a mapování portů pomocí rotačního kodéru

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:

  1. aFlag je inicializován na nulu a v zobrazeném kódu není nikdy nastaven nenulově. První if podmínka v PinA() tedy nikdy není splněna.

  2. PinA() je obsluha přerušení spojená s přerušením pomocí vašich attachInterrupt() 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á, odstranit cli() v PinA(). Podobně odstraňte sei() na konci PinA(), protože hardware po provedení instrukce RETI obnoví stav přerušení.

  3. 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á konstanta B00001100 hodnotu 0B00001100. Podle mého názoru je tato „hloupá a zbytečná funkce; navrhuji, abyste ve svém kódu používali standardní notaci C jako 0B00001100, pokud chcete použít hodnoty binárních konstant.

  4. Psaní encoderPos -- místo encoderPos-- považuji za perverzi a navrhuji tento zbytečný prostor odstranit.

  5. Vzhledem k tomu, že jste neobjevili obslužný program přerušení PinB(), nevím, jak se chystáte zpracovat encoderPos++ 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

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *