Stránka 1 z 2

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

Napsal: 29 bře 2016, 20:39
od Enkoder
ahoj,
mohu chtít v podprogramu ext. přerušení INTn číst stav pinu nějaké brány?
nedaří se mi takový to vstup přečíst.
tohle mi nechodí, ikdyž logický analyzátor ukazuje na PE3 log1, čte se do proměnné stavB pořád jen nula:

#define CHECK_BIT(BYTE,BIT)(BYTE&=(1<<BIT))
unsigned int NastavovanaHodnota=0; // globální proměnné
unsigned char stavB=0, pomocna=0;

ISR(INT4_vect)
{
cli();
stavB= ((PORTE & 0x08)>>3);
//stavB= CHECK_BIT(PORTE,3); // <<< nebo takto taky nechodí
sei();
switch(stavB)
{
case 0: NastavovanaHodnota--; break;
case 1: NastavovanaHodnota++; break;
default: pomocna++; break;
}
}

čtený pin PE3 mám při startu nastavený jako vstup DDRE=0xE7;
Děkuju předem

Napsal: 29 bře 2016, 20:56
od lesana87
Jestli se tak snažíš číst mechanický enkodér, tak ti tam můžou dělat neplechu zákmity. V obsluze přerušení povoluješ přerušení. Nevím, jak si s možnou reentrancí poradí samotné Cčko, ale ty tam používáš globální proměnné a to není dobré, to přerušení se může vyvolat několikrát po sobě a několikrát se do sebe vnořit.
Hlavní chyba bude ale v tom, že čteš PORTE a ne PINE.

Napsal: 29 bře 2016, 21:21
od frpr666

Kód: Vybrat vše

// enkoder demo:

#define CHECK_BIT(BYTE,BIT) ((BYTE)&(1<<(BIT)))

volatile unsigned int NastavovanaHodnota = 0; // globální proměnné

ISR(<TBD>)  // tohle je přerušení spouštěné hranou na pinu<>PE3
{
  unsigned char stavE3;

  stavE3 = CHECK_BIT(PORTE, 3); // PE3?

  if (stavE3)
  {
    NastavovanaHodnota--;
  }
  else
  {
    NastavovanaHodnota++;
  }
}
CHECK_BIT(BYTE,BIT) vrací 0, pokud je vstup v 0, jinak vrací jakoukoliv nenulovou hodnotu
Myslím že v gcc v avr-libc je už toto makro hotové, stačí jej použít:

Kód: Vybrat vše

sfr_defs.h:#define bit_is_set(sfr, bit) (_SFR_BYTE(sfr) & _BV(bit))
Edit1: To je kouzlo jazyka C, x=0 -> false, x<>0 -> true
Edit2: Jo, má tam být PINE. To je pravda...

Napsal: 29 bře 2016, 21:24
od lesana87
Máš tam tu samou školáckou chybu jako Encoder, čteš PORTE, ale máš číst PINE.

Napsal: 29 bře 2016, 21:31
od FHonza
Rozhodně globální proměnné musí být "volatile". Pak je překladač umístí vždy do datové paměti a ne do registrů. Tohle je (v závislosti na další části programu a kvůli optimalizaci) často zdrojem chyb.

Tj. definici napiš jako:

Kód: Vybrat vše

volatile unsigned char ...
a ještě mně prosim prozraďte kterej Atmel má PORTE :)

Napsal: 29 bře 2016, 21:33
od Enkoder
ahoj, díky za reakce, jste rychlejší, toto je reakce na první odpověď:

díky už se to konečně pohlo, směr je je rozpoznán, čítá to ale většinou po dvou, až to poladím, dám vědět.

globální proměnné používám proto, abych je mohl zobrazit na displeji mimo podprogram přerušení.

v podprogramu přerušení po přečtení vstupu nechám čekat 10ms

na konci podprogramu přerušení shazuji bit příznaku pro čekající přerušení (je to tak?) CLEAR_BIT(EIFR,4);
protože další přerušení bývá obvykle za delší dobu než 200ms

to "několikrát se do sebe vnořit", to je pro mně novinka, je to opravdu tak?

díky moc

Napsal: 29 bře 2016, 21:35
od lesana87
FHonza píše:a ještě mně prosim prozraďte kterej Atmel má PORTE :)
Nevím, kterej je Atmel, ale AVR třeba ATmega64, 128, 640, 1280...

Napsal: 29 bře 2016, 21:44
od lesana87
Enkoder píše:na konci podprogramu přerušení shazuji bit příznaku pro čekající přerušení (je to tak?) CLEAR_BIT(EIFR,4);
Když před tím povolíš přerušení, tak je to k ničemu, pokud se EIFR,4 nastaví, přerušení se okamžitě vyvolá znovu (a EIFR se tím následně shodí) a tím se vnoří samo do sebe (přeruší se vykonávaná obsluha INT4 a zavolá se znovu ta samá obsluha INT4).

Napsal: 29 bře 2016, 21:45
od FHonza
jasně no. nějak sem na ně zapomněl ... omlouvám se

Napsal: 29 bře 2016, 21:53
od FHonza
Když chceš v přerušení zakázat další přerušení, tak po vstupu do obsluhy přerušení vynuluj příslušný bit v EIMSK. Na konci před opětovným povolením v EIMSK vymaž příslušný bit v EIFR zápisem jedničky. Opravdu se nuluje zápisem jedničky.

Napsal: 29 bře 2016, 21:56
od frpr666
Nastav si na začátku, aby externí přerušení bylo spouštěné hranou.

Kód: Vybrat vše

The falling edge of INTn generates asynchronously an interrupt request.
The rising edge of INTn generates asynchronously an interrupt request.
Potom nemusíš nic "čistit", všechno se udělá "samo". Nakonec ty globální proměnné nejsou tak špatné. Asi jediný způsob jak předat něco z / do ISR().

http://www.mikrocontroller.net/articles ... C3.B6schen

Napsal: 29 bře 2016, 21:58
od lesana87
Zákmity na INT vstupu mu to "samo" neošetří, když má povolené přerušení.

Napsal: 29 bře 2016, 21:59
od FHonza
frpr666 píše:Nakonec ty globální proměnné nejsou tak špatné.
Nejsou, ale musí být volatile když jsou použity v přerušení.

Napsal: 29 bře 2016, 22:03
od frpr666
@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.

Napsal: 29 bře 2016, 22:13
od Enkoder
:D to je fajn parta tady, jsem mezi inteligenty
PORTE má arduino s ATmega2560
k enkoderu jsem dal odpory 10k a kondíky 33nF.
budu sledovat diskuzi, opravím to až zítra

void Inicializace_INT4(void)
{
EICRB |= (1 << ISC41) | (1 << ISC40); // reakce přerušení INT4 na vzestupnou hranu
SET_BIT(EIMSK,4); // povol přerušení od INT4
}

díky moc