Přerušení od libovolného tlačítka

Skusil som program upravit podla tvojich rad, este mi to nechce skompilovat, ale asi funckie sa mu nepacia

[code]
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

//# define F_CPU 8000000UL

#define SET(BAJT,BIT) ((BAJT) |= (1<<(BIT)))
#define RES(BAJT,BIT) ((BAJT) &= ~(1<<(BIT)))
#define NEG(BAJT,BIT) ((BAJT) ^= (1<<(BIT)))
#define TST(BAJT,BIT) ((BAJT) & (1<<(BIT)))

volatile unsigned char efekt=0;

void efekt1();
void efekt2();
void timer0Init(void);

int main(void)
{
timer0Init();
sei();

SET(DDRC,PC0);
SET(DDRC,PC1);
SET(DDRC,PC2);
SET(DDRC,PC3);
RES(DDRB,PB0);
RES(DDRB,PB1);
SET(PORTB,PB0);
SET(PORTB,PB1);	 
while(1)
{     
	switch (efekt)
	{
		case 1: efekt1();
		case 2: efekt2();
		default: continue;
	}
} 
return 0;  

}

ISR(TIMER0_COMP_vect)
{
if (TST(PORTB,PB0) == 0) efekt=1;
if (TST(PORTB,PB1) == 0) efekt=2;

}

void timer0Init(void)
{
TCCR0 = 1<<WGM01 | 1<<CS02 | 1<<CS00;
OCR0 = 26; // f = 11059200 / 1024 / 27 = 400 ==> T = 2.5ms
TIMSK |= 1<<OCIE0; // Timer/Counter0 Output Compare Match Interrupt Enable
}

/*efekt1()
{
//…
}

efekt2()
{
//…
}*/[/code]

Tak patrilo by sa napisat pod akym prekladacom, potazmo pod akou jeho verziou a pod akym prostredim si sa to pokusal prelozit.

Ak je to AVRstudio4.x a prekladac GCC, preloz si moj program (nezabudni do projektu/adresara vlozit aj ten *.h subor). Ak Ti pojde, budeme mudrejsi. A ak nie, tak potom nieco vymyslime.

AVR Studio 5 GCC

Uz som nieco napisal, prerušenie a tlacidla funguju, ale mam problem.
nechce mi vyhodnocovat podmienku if ((be==0) && (bf==0)) normalne by to malo byt ze podmienka plati ak be aj bf sa rovna 0. be a bf su premenne unsigned char, na zaciatku do nich zapisem 0.

Tak to skus odsimulovat. V principe (okrem toho ze v Tvojom texte chyba zatvorka, ale to bude urcite preklep) nema co podmienka nefungovat.

ano uz som to opravil, tam mi chýbali zátvorky.

Tu je zatial cely kod, este tam nie su poriesenie tie vystupy led. Zatial iba cez delay.
Tie tlacidla som dal na 8bit casovac, predelicka 256.
ta funkcia beep robi pipnutie pri zapnuti a vypnuti tlacidla.
Neviem ako poriešim to časovanie pre led, napr keby som chcel aby dva krat blikla jedna led(200ms) potom pauza napr 1000ms a potom zas 200ms. Dal by sa takto dynamicky menit ten casovac?

[code]
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

//# define F_CPU 8000000UL

#define SET(BAJT,BIT) ((BAJT) |= (1<<(BIT)))
#define RES(BAJT,BIT) ((BAJT) &= ~(1<<(BIT)))
#define NEG(BAJT,BIT) ((BAJT) ^= (1<<(BIT)))
#define TST(BAJT,BIT) ((BAJT) & (1<<(BIT)))

volatile unsigned char efekt=0;

void efekt1();
void efekt2();
void beep();

void timer0Init(void);

int main(void)
{
unsigned char pom=1;

SET(DDRC,PC0);
SET(DDRC,PC1);
SET(DDRC,PC2);
SET(DDRC,PC3);
RES(DDRB,PB0);
RES(DDRB,PB1);
SET(PORTB,PB0);
SET(PORTB,PB1);
SET(DDRD,PD7);
PORTC = 0b00000000;
	
OSCCAL = 0xA5;
	
timer0Init(); 
sei();
while(1)
{   
	switch (efekt)
	{
		case 0:
		{
		if (pom == 0)
		{
		beep();
		pom=1;
		}
		break;
		}
		case 1:
		{
			if ((pom==1) && (efekt==1))
			{
			beep();
			pom=0;
			}
			efekt1();
			break;
		}				
		case 2:
		{
			if ((pom==1) && (efekt==2))
			{
			beep();
			pom=0;
			}
			efekt2();
			break;
		}			
	}
} 
return 0;  

}

ISR(TIMER0_OVF_vect)
{
efekt = 0;
if (TST(PINB,PB0) == 0)
{
efekt=1;
}
if (TST(PINB,PB1) == 0)
{
efekt=2;
}
TCNT0 = 0;
}

void timer0Init(void)
{
SET(TCCR0,CS02);
//SET(TCCR0,CS00); // nastavenie predelicky
SET(TIMSK,TOIE0); // Timer/Counter0 Output Compare Match Interrupt Enable
}

void efekt1()
{
SET(PORTC,PC0);
_delay_ms(200);
RES(PORTC,PC0);
_delay_ms(200);
}

void efekt2()
{
SET(PORTC,PC3);
_delay_ms(400);
RES(PORTC,PC3);
_delay_ms(400);
}

void beep()
{
SET(PORTD,PD7);
_delay_ms(200);
RES(PORTD,PD7);
}[/code]

No a preco ten beep nestrcis do casovacovej prerusovacej rutiny?
Pouzivat delay dlhsie ako par us (pre nejake presne nacasovanie vzajomnych poloh hran signalov) je fakt zhovadilost :slight_smile:

Nechce sa mi lustit na aku frekvenciu je nastavene to prerusenie (je vhodne program okomentovat, aspon pre potreby konzultantov :slight_smile: )
Ale ak je to napr. 1ms, potom v napis v kode

         case 2:
         {
            if ((pom==1) && (efekt==2))
            {
            casovac_beep = PREDVOLBA_BEEP;
            pom=0;
            }
            efekt2();
            break;
         }         

alebo ak nechces beep predlzovat, tak potom

         case 2:
         {
            if ((pom==1) && (efekt==2))
            {

            if (casovac_beep ==0) casovac_beep = PREDVOLBA_BEEP;

            pom=0;
            }
            efekt2();
            break;
         }         

A v kode prerusenia vloz


ISR(TIMER0_OVF_vect)
{
   efekt = 0;
   if (TST(PINB,PB0) == 0)
   {
      efekt=1;
   }
   if (TST(PINB,PB1) == 0)
   {
      efekt=2;
   }   
   TCNT0 = 0;
} 
if (casovac_beep) {
   casovac_beep--; //casovac_beep = casovac_beep - 1
   SET(PORTD,PD7);
}
else RES(PORTD,PD7);

“casovac_beep” je nejaka volatile premenna, ktorej velkost musi byt taka, aby obsiahla Tebou potrebne casove oneskorenie.

Kod:

void beep()
{
SET(PORTD,PD7);
_delay_ms(200);
RES(PORTD,PD7);
}

zahod :slight_smile:

SET(PORTD,PD7); aspon napis ako SET(PORTD,BEEP),

myslim ze napisat

#define BEEP PD7

nebude problem a kod bude citatelnejsi. Tebe sa teraz citatelny samozrejme zda, no konzultant straca vela casu studovanim a to aj mnohych od odpovedi odradza. Pred cca rokom to tu uz bolo k nejakemu prispevku riesene. O rok bude bezpecne necitatelny aj samemu tvorcovi kodu., pisem z vlastnej skusenosti.

Dakuje za rady, uz som to opravil podla tvojich rad.
Mam ale problem vymysliet ako spravit jednoducho efekty kde by sa dynamicky menil cas, napr blik…blik…blik…blik.
Skusal som uz nieco bez pouzitia _delay

[code]ISR(TIMER1_COMPA_vect)
{
TCNT1 = 0;
switch (efekt)
{
case 0:
{

		break;
	}
	case 1:
	{	
		if (counter == 1)
		{
		NEG(PORTC,PC0);
		NEG(PORTC,PC1);	
		NEG(PORTC,PC2);
		NEG(PORTC,PC3);
		counter=0;				
		} 
		else
		{
		NEG(PORTC,PC0);
		NEG(PORTC,PC1);
		NEG(PORTC,PC2);
		NEG(PORTC,PC3);
		counter=1;			
		}
		break;
	}	[/code]

toto iba preblikuje s rovnakou periodou.

tu som sa este pokusil spravit ze dva krat blikne jedna dioda/dve, a dva krat druha dioda, ja by som ešte ale chcel dat medzi ne pauzu, nejako pozmenit ten register aby nepocital do nastavených 200, ale do 1000

[code]
TCNT1 = 0;
OCR1A = 200;
case 2:
{

		if (counter > 4 && counter < 9)
		{
		NEG(PORTC,PC0);
		NEG(PORTC,PC1);	
		counter++;
		}
		if (counter == 9) counter=4;
		
		if (counter < 5 && counter > 0 )
		{
		NEG(PORTC,PC2);
		NEG(PORTC,PC3);
		counter--;			
		}
		if (counter == 0) counter =5;
			
		break;
	}		[/code]

jajaj, to su veci :slight_smile:

napriklad


#define SVIETI_1 100
#define NESVIETI_1 120
#define SVIETI_2 40
#define NESVIETI_1 75
#define SVIETI_3 124
#define NESVIETI_3 567
#define SVIETI_4 234
#define NESVIETI_4 42

#define MAX_PREDVOLBA 4


#define ROZSVIET_LED   RES(PORTB, PB3) // napriklad
#define ZHASNI_LED      SET(PORTB, PB3) // napriklad

volatile static uint16_t predvolba[MAX_PREDVOLBA * 2], cnt_predvolba;
volatile static uint8_t cnt_led;


int main(void)

    predvolba[0] = SVIETI_1;
    predvolba[1] = NESVIETI_1;

    predvolba[2] = SVIETI_2;
    predvolba[3] = NESVIETI_2;

    predvolba[4] = SVIETI_3;
    predvolba[5] = NESVIETI_3;

    predvolba[6] = SVIETI_4;
    predvolba[7] = NESVIETI_4;

   // predvolieb si samozrejme mozes zvojit kolko chces, nie iba pre styri periody :-)


   cnt_predvolba = predvolba[0];
   cnt_led = 0;
 
    fn_init_casovac_s_prerusenim();

   for(;;)
   {
    // bla bla bla
   }

// niekde vo funkcii ktora sa vola z prerusenia

ISR(TIMER1_COMPA_vect)
{
   //   TCNT1 = 0;  toto je z Tvojho sw a je to blbost ako to mas v tom tvojom zdrojaku. 
  // Nastav si taky mod, pri ktorom sa TCNT resetuje samo.
  // inak si do cisteho hw riesenia zavadzas nezmyslenu neurcitost, 
  // kym sa sw dostane k realizacii nulovania. Takto program nikdy netvor.

// ...

   if (cnt_predvolba) {
      cnt_predvolba--;
   }
   else {
       cnt_led++;
       if (cnt_led >= (2*MAX_PREDVOLBA)) cnt_led = 0;

       cnt_predvolba = predvolba[cnt_led];
       // samozrejme sa toto da zapisat aj inak, napriklad nasledove
       // sice tym usetris tym RAM, spotrebujes vsak viac Flash 
       // a sw spomalis.
       /*
          switch (cnt_led) {
              case 0 : {
                 cnt_predvolba = SVIETI_1;
                 break;
              } 
              case 1 : {
                 cnt_predvolba = NESVIETI_1;
                 break;
              } 
              // ....
              case 6 : {
                 cnt_predvolba = SVIETI_4;
                 break;
              } 
              case 7 : {
                 cnt_predvolba = NESVIETI_4;
                 break;
              } 
          }

       */
   }
   if (cnt_led & 0x01) ROZSVIET_LED;
   else ZHASNI_LED;

// ...

Ahojte
Potreboval by som poradit ohladom stlacenia tlacitka v atmege8. Jedna sa o to ze ak je tlacitko stlacene 0-200ms nerob nic. 200ms -1s urob akciu. Viac ako 1s nerob nic. Tlacitko som dal na vstup ktory testujem kazde 10ms cez prerusenie Timeru 0. Nie je mi jasne akym stylom spravit aby sa rozlisovali tie casy. Pocitat prerusenia a podla toho urcit aky cas ubehol alebo ako? Za vsetky odpovede som vdacny.

presne tak :slight_smile:

Predpokladam ze bude treba pocitat pocet preruseni pomocou nejakej premennej, ktora sa bude inkrementovat len v pripade ze tlacitko je stlacene ze? Tu podmienku treba dat do hlavneho programu alebo do prerusenia?

Tak ked testujes tlacitko pod prerusenim a to zaroven urcuje (moze urcovat) casovu zakladnu, vyzera byt v celku logicke pocitat cas pod prerusenim :slight_smile:

Ahojte takze pocitanie preruseni je uspesne odskusane ale neviem ako mam spravit jednu vec: ked pocet preruseni pri stlaceni tlacitka dosiahne urcity pocet mal by zapnut nejaky vystup na 2 sek. a vypnut ho.
Casovku by som pouzil pomocou T1 (prerusenie kazde 2sek.) ale neviem ako ju spustat pri splneni podmienok a ako vypnut lebo prerusenie mi ide neustale kazde 2 sek.
Dakujem

A co tak sa vykaslat na T1 a pocitat 2s v ramci toho prerusenia :slight_smile: ?

Martin vrela vdaka za tip, tak toto mi vobec nenapadlo. Ja sa tu trapim s T1 treti den a pozeram ze by sa to dalo aj inak. No idem na to… :slight_smile:

To je v pohode. Tolko sa tu stale omiela, ze na rozne udalosti treba vyuzivat HW a najlepsie este kazdy s vlastnym prerusenim, ze sa niet co divit :slight_smile:

Ale je to prepruzenie tiez casto tu uvadzaneho protipolu, robit vsetko v hlavnej slucke a na kazde oneskorenie a cakanie pouzit pause().

Pravda je niekde uprostred. Najlepsie voditko, ktore sa mi osvedcilo je zkontrolovat, ci sa system niekde zbytocne neflaka cakanim na nieco. Ak je tento cas vacsi ako 1-5us, treba vymysliet ako cinnost mcu presmerovat na nieco zmysluplne. Tiez hafo vnorenych preruseni nemusi byt to prave orechove. Kazdym volanim prerusenia sa system zase (aj ked velmi malicko, ale ak sa tie “malicka” zrataju a je ich hodne…) zdrzuje pracou na zasobniku. Celkom dobry system je spravit si nejaku rozumnu casovu zakladnu, napr. 1ms a v ramci nej napchat rutinky, ktore trvaju par instrukcii. Ako napriklad vyhodnotit tlacitko, nastavit nejake udalosti od casu (v tomto pripade s granularitou 1ms), presne zopnut, vypnut vystup. Tieto ulohy sa hravo zmestia do par desiatok az stovak us. Vsetko ostatne mozes robit v hlavnej slucke, alebo spustanim samostatnych prerusovacich uloh ako napriklad zapis udajov prijatych cez UART do EEPROM cez nejaky RX/TX buffer.

Pri tej 1ms rutine si ako prve zabezpec indikaciu, ci tato casova rutine nie je v sklze a meraj cas trvania 1ms rutiny a cas trvania hlavnej slucky. Vyhodnocuj maximalne casy. Na zaklade toho vies, kolko rezervy z procesora mas alebo ci nieco netreba prepisat tak, aby to trvalo kratsie.
Cas a sklz prerusenia vyhodnotis tak, ze po preruseni od casovaca nastavis nejaku internu premennu na TRUE. Po ukonceni uloh z prerusenia ju nastavis na FALSE. Hned na zaciatku po nastaveni premennej na TRUE, povol prerusenie od casovaca. Akonahle pride dalsie prerusenie od casovaca, najprv skontroluj hodnotu premennej. Ak je TRUE, nastav si priznak, ze je rutina v sklze (mozes aj pocitat kolko krat) a rutinu opusi. Ak je hodnota FALSE, nastav ju na TRUE a pokracuj dalej.
Takymto sposobom sa system nezruti od pretecenia zasobnika, lebo ten prvy test bude trvat urcite daleko menej ako 1ms :slight_smile:.
Cas trvania rutiny urcis tak, ze si na konci prerusenia (ak medzitym nie je nastaveny priznak pretecenia) odpamatas cas v casovaci a to je vysledny cas trvania. To preto, ze rutina sa spustila, ked bola hodnota casovaca rovna nule (alebo OCRx ? v tejto chvili presne neviem, ale ak aj, tak chyba nebude vacsia ako jeden tik casovaca).

Pod 1ms si zase pocitaj vlasne hodiny napr v 16b premennej s krokom 1ms. Cas trvania hlavnej slucky zistis odpamatanim hodnoty na jej zaciatku a odpocitanim od hodnoty pri dalsom prechode zaciatkom. Vyhodnocuj a uchovavaj (staci v RAM, nemusi to byt hned EEPROM aj ked ani to nie je na zavadu hlavne pri vyp/zap zariadenia) maximalnu hodnotu.

Ak Ti nieco bude obcas v zaraideni blbnut a sklz a max. casy trvania budu v norme, mas istotu, ze system neblbne pre nedostatok vykonu. To je casto velmi dolezite. Obcas sa podari napisat sw, ktory sa pri urcitej konstelacii behu, komunikacii, vyhodnotenia a spracovania periferii sprava cudne, akurat sa velmi tazko tato situacia analyzuje, lebo sa neda nasimulovat. Informacia o casoch behu jednotlivych casti su potom neocenitelnou pomockou pre hladanie zahady.

MEranie casu ti tiez napovie, ake rutinky mozes nechat v hl. slucke, ci naopak ich z nej vlozit pod 1ms prerusenie. Ak nieco musis spravit 1x za 100ms, napriklad zap/vyp rele (rychlejsie to aj tak nema zmysel) a hl. slucka v najhorsom pripade trva 12ms, kludne rutinu mozes nechat v hl. slucke. Ak ale hl. slucka obcas trva 250ms, treba sa nad vecou lepsie zamysliet.