AVR GCC: čtení stavu PINu portu v subr. ext. přerušení INT4

Diskuze a poradna o programátorech a programování různých obvodů

Moderátor: Moderátoři

Zpráva
Autor
Uživatelský avatar
FHonza
Příspěvky: 1443
Registrován: 20 lis 2012, 01:00
Bydliště: Praha

#16 Příspěvek od FHonza »

Přerušení se nevnořují do sebe. Po vstupu do přerušení se uloží obsah PC do SP, ten se sníží. SREG se automaticky neukládá (proto již vzpomínané volatile). Je zakázáno globální přerušení. Po návratu (RETI) se vyzvedne PC a globální přerušení se povolí. Zkontrolují se příznaky přerušení a případně se obslouží dle priority. Příznaky přerušení se dají (ovšem ne všechny) vymazat zápisem jedničky do příslušného bitu.

Uživatelský avatar
lesana87
Příspěvky: 3296
Registrován: 20 zář 2014, 02:00

#17 Příspěvek od lesana87 »

frpr666 píše:@lesana87
s tím vnořováním samo do sebe nesouhlasím. Myslím, že tam bylo něco jako že se z ISR vrátí řízení zpět, provede se alespoň jedna instrukce a pak se zase (případně) zavolá ISR.
FHonza píše:Přerušení se nevnořují do sebe...Je zakázáno globální přerušení.
Ale on hned třetím příkazem v obsluze přerušení povoluje globální přerušení, takže když na vstupu přerušení INT4 vznikne zákmit dřív, než se dokončí obsluha, přerušení se vyvolá znovu a vnoří se do nedokončené obsluhy.

Uživatelský avatar
frpr666
Příspěvky: 1051
Registrován: 28 pro 2009, 01:00

#18 Příspěvek od frpr666 »

@lesana87
aha, to je pravda, to je pravda. Pokud si explicitně povolí přerušení během ISR a je nahozený flag, tak nastane rekurze ISR (a přetečení zásobníka...).

Kód: Vybrat vše

ISR(INT4_vect)
{
 //...
 sei(); // fail, tohleto zpusobi vecnou rekurzi ISR.
 //...
} 
Tak takhle tedy NE!

Uživatelský avatar
lesana87
Příspěvky: 3296
Registrován: 20 zář 2014, 02:00

#19 Příspěvek od lesana87 »

Přerušení se do sebe vnoří maximálně tolikrát, kolik zákmitů vznikne na INT vstupu, takže to zas taková tragedie, jak popisuješ, nebude.

Enkoder
Příspěvky: 12
Registrován: 29 bře 2016, 02:00

#20 Příspěvek od Enkoder »

Tak už to krásně chodí, děkuju:

ISR(INT4_vect)
{
CLEAR_BIT(EIMSK,INT4); // zakaž přerušení od INT4
unsigned char stavE3=0;
stavE3=CHECK_BIT(PINE,3);
if (stavE3)
{
NastavovanaHodnota++;
}
else
{
NastavovanaHodnota--;
}
_delay_ms(5);

SET_BIT(EIMSK,INT4); // povol přerušení od INT4 a
SET_BIT(EIFR,INTF4); // a smaž logickou jedničkou příznak INT4
}

začíná ale zlobit samotný enkoder, asi ty kondíky nedělají dobrotu, spínač enkoderu je přeci jen zkratuje, nebo je enkoder nekvalitní (testováno na logickém analyzátoru).

Já si myslím, že vnořit se do probíhajícího přerušení může asi jen přerušení s vyšší prioritou. Jedno samo do sebe ne. Přiklánim se k názoru Honzy. A ikdyž se globální INT zakáže a povolí, není to důvod ke znovuvyvolání tohoto přerušení uvnitř probíhajícího. Tak to aspoň bylo při mých dávných pokusech s 8051, Ale nedokážu to plně posoudit na kolik v tom hraje roli to GCC a na kolik je to dáno samotným procesorem.

edit1: to přerušení se může vyvolat hned několikrát za sebou, tím, že se příznak přerušení během probíhajícího přerušení znovunastaví, ale asi ne, že by došlo ke vnoření

Uživatelský avatar
lesana87
Příspěvky: 3296
Registrován: 20 zář 2014, 02:00

#21 Příspěvek od lesana87 »

A jak tedy vysvětlíš to, že se ti najednou přestalo připočítávat po dvou? Po sobě se ti ta přerušení mohou vyvolávat i teď, jediné co jsi odstranil, že se ti nemůžou vyvolávat přes sebe. A proč tam to přerušení od INT4 zakazuješ, když se podle tebe nemůžou do sebe vnořovat? :)

Kondenzátorama přímo na kontaktech enkodéru ho pošleš hodně rychle do kytek.

Enkoder
Příspěvky: 12
Registrován: 29 bře 2016, 02:00

#22 Příspěvek od Enkoder »

to lesana:

(ty globální přerušení jsem smazal už dřív skákalo to ještě po větších skocích s malou pauzou)

Odpověď proč to počítalo dvakrát:
Bylo to asi proto, že se zareaguje na první vzestupnou hranu - spustí se poprvé ISR (INT4_vect) , vzápětí vzniknou zákmity, při těchto zákmitech se znovu nastaví příznak pro obsloužení přerušení, ale podprogram běží dál pauzou, kde se se to časově přenese do doby kdy už žádné zákmity nejsou. Zůstal tam ale požadavek na to přerušení, který se obsloužil tím, že se podprogram přerušení spustil podruhé, proto to počítalo po dvou.
Novou úpravou - zakázáním INT4 po dobu podprogramu přerušení a hlavně shozením požadavku EIFR INTF4 na přerušení, jsem ten druhý požadavek na obsloužení zrušil. (čert ví, proč to nefunguje bez součinnosti s EIMSK - vidíš, mohl bych ještě vyzkoušet)

mohl bych se Tě zeptat, proč to neskákalo po třech :-)

spíš by mě zajímalo, zda je třeba to chování hledat v céčku, nebo na straně hardware. Spíš bych řekl, že tomu diktuje hardware

ošetření zákmitů na spínači se řeší jeho překlenutím kondíkem, otázka je, jak velkým, ale i malý vyvíjí destrukční proud... vybíjí se přeci jen okamžitě z 5 Volt na nulu

Enkoder
Příspěvky: 12
Registrován: 29 bře 2016, 02:00

#23 Příspěvek od Enkoder »

tak jsem vyzkoušel odebrat
na začátku:
CLEAR_BIT(EIMSK,INT4); // zakaž přerušení od INT4
a na konci :
SET_BIT(EIMSK,INT4); // povol přerušení od INT4
a chodí to taky
(občas vynechá enkodér jednu polohu, nebude moc kvalitní)

Hlavní nedostatek byl pravděpodobně v tom, že jsem požadavek na druhé přerušení nenuloval jedničkou takto:
SET_BIT(EIFR,INTF4); // smaž logickou jedničkou příznak INTF4
(jak na to upozornil Honza)

Uživatelský avatar
FHonza
Příspěvky: 1443
Registrován: 20 lis 2012, 01:00
Bydliště: Praha

#24 Příspěvek od FHonza »

Zakazovat a poté povolovat přerušení v obsluze přerušení je zbytečné. Při vstupu do obsluhy přerušení je automaticky zakázáno, při návratu povoleno. Jediné co má smysl je mazat požadavek na další přerušení.

Doslova:
The I-bit is cleared by hardware after an interrupt has occurred, and is set by
the RETI instruction to enable subsequent interrupts.

Uživatelský avatar
mtajovsky
Příspěvky: 3694
Registrován: 19 zář 2007, 02:00
Bydliště: Praha

#25 Příspěvek od mtajovsky »

Enkoder píše:ošetření zákmitů na spínači se řeší jeho překlenutím kondíkem ...
To je sice také možné, ale ne dost dobré. Ošetření zákmitů se dělá tak, že se v přerušení poznačí nová úroveň na vstupu a spustí se časovač, dejme tomu 3 ms. Po jeho vypršení se zkontroluje, jestli úroveň na daném vstupu zůstala zachována a když ano, vezme se signál na vstupu jako platný. Když ne, byl to planý impuls. Přijde-li tedy na vstup série zákmitů, časovač se opakovaně restartuje, naposledy s poslední hranou. Po 3 ms se pak přečte výsledná úroveň.

Uživatelský avatar
frpr666
Příspěvky: 1051
Registrován: 28 pro 2009, 01:00

#26 Příspěvek od frpr666 »

Enkoder s potlačením rušení pomocí časovače:

Kód: Vybrat vše

// file: main.c
//* chip: attiny13a

#include <avr/interrupt.h>
#include <avr/io.h>

#define BCLR(n,bit) (n)&=~(_BV(bit))
#define BSET(n,bit) (n)|=(_BV(bit))

// Disable INT0 interrupt
#define INT0_STOP {\
 BCLR(GIMSK,INT0);\
}

// Enable INT0 interrupt
#define INT0_START {\
 BSET(GIFR,INTF0);\
 BSET(GIMSK,INT0);\
}

// Start timer, preset 100 ticks
#define TIM_START {\
 TCNT0=(256-100);\
 TCCR0B=_BV(CS00);\
}

// Stop timer
#define TIM_STOP {\
 TCCR0B=0;\
}

//-------------------------
volatile uint16_t enc_value;
uint16_t enc_print;

//-------------------------
ISR(INT0_vect) //PB1
{
  if(bit_is_set(PINB, 0)) // PB0
  {
    enc_value++;
  }
  else
  {
    if(enc_value > 0)
    {
      enc_value--;
    }
  }
  INT0_STOP;
  TIM_START;
}

//-------------------------
ISR(TIM0_OVF_vect)
{
  TIM_STOP;
  INT0_START;
}

//-------------------------
void setup( void)
{
// The low level selected for INT0_vect
  MCUCR = 0x00;

// Enable TIM0_OVF interrupt
  BSET(TIMSK0, TOIE0);
  TIM_START;
  sei();
}

//-------------------------
void loop( void)
{
  cli();
  enc_print = enc_value;
  sei();
  // ...
  // print(enc_print);
  // ...
}

//-------------------------
int main( void)
{
  setup();
  for(;;)
  {
    loop();
  }
}
//-------------------------
//EOF

Mimo to: hardwarově se přidává RC článek na každý vstup: http://www.electroschematics.com/wp-con ... wiring.png

Enkoder
Příspěvky: 12
Registrován: 29 bře 2016, 02:00

#27 Příspěvek od Enkoder »

díky, RC článek se zdá být na ochranu kontaktů dobrý nápad, a co na to logický obvod TTL nebo procesor, který nemá rád otálení zakázaném pásmu logických úrovní - nejspíš to bude vyžadovat navíc smittův klopný obvod..

Odpovědět

Zpět na „Programování PIC, ATMEL, EEPROM a dalších obvodů“