logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[ATmega16][c] zmiana wartosci zmiennej przez zewn przerwanie

Altarir 13 Sty 2011 21:09 1766 12
REKLAMA
  • #1 9001943
    Altarir
    Poziom 11  
    Witam, chcę zrobić zegarek na LCD, w którym godziny i minuty ustawiane są za pomocą przycisków. Na razie zrobiłem go w wersji bez przerwań (funkcja if) i teraz chcę przerobić tak, by ustawiać je za pomocą zewnętrznych przerwań. Niestety zegarek sobie liczy a wciśnięcia przycisków są ignorowane.

    Może mi ktoś napisać co ja tu robię źle? Zgóry dzięki za pomoc

    #define F_CPU 16000000L
    
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    
    
    #include "lcd.h"
    
    volatile uint8_t flag1=0;
    volatile uint8_t flag2=0;
    
    //----------------------------------------------------------przerwania
    	ISR(INT0_vect) {
    
    	flag1 = 1;                 //przy int0 ustaw flage1 na 1
    
    	}	
    
    	ISR(INT1_vect) { 
    
    	flag2 = 1;                //przy int1 ustaw flage2 na 1
    
    	}	
    
    
    	void int0_init( void )
    {
        MCUCR = (1<<ISC01);             // enable negative edge on INT0
        GICR = (1<<INT0);               // enable INT0
    }
    
    	void int1_init( void )
    {
        MCUCR = (1<<ISC11);             // enable negative edge on INT0
        GICR = (1<<INT1);               // enable INT0
    }
    
    
    //------------------------------------------------------------------------
    
    
    void main()
    
    
    
    {
    	unsigned char s;  //sekundy
    	s = 0;
    	unsigned char m;  //minuty
    	m = 0;
    	unsigned char g;  //godziny
    	g = 0;
    	
    
      	DDRB  = 0x00;
      	PORTB = 0xFF;
    
    	InitLCD(LS_BLINK|LS_ULINE);
    
    	LCDClear();
    
    	sei();
    	
    	while (flag1 == 1)                   
    	{
    	m +=1;
    	}
    
    	while (flag2 == 1)
    	{
    	g +=1;
    	}
    
    	while(1)
    	{
    		_delay_ms(1000);
    		s = s + 1;	
    		
    		if (s> 59)
    		{
    		s = 0;
    		m = m + 1;
    			if (m > 59)
    			{
    			m = 0;
    			g = g + 1;
    				if (g>23)
    				{
    				g = 0;
    				m = 0;
    				s = 0;
    				}
    			}
    		}
    	
    		LCDWriteIntXY(10,0,s,2);
    		LCDWriteStringXY(9,0,":");
    		LCDWriteIntXY(7,0,m,2);
    		LCDWriteStringXY(6,0,":");
    		LCDWriteIntXY(4,0,g,2);
    		LCDWriteStringXY(16,0," ");
    			
    	}
    
    }
    
  • REKLAMA
  • #3 9002252
    Altarir
    Poziom 11  
    A może tak jaśniej? Nie każdy się urodził programistą C
  • REKLAMA
  • #4 9002291
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Skoro masz sprawdzanie flag z przerwania PRZED nieskończoną pętlą, to czego oczekujesz po swoim programie? Jeśli nie urodziłeś się programistą, to po to wymyślono książki o programowaniu.

    A to tylko pierwszy - zasadniczy - błąd, bo jest ich tam dużo więcej...

    4\/3!!
  • Pomocny post
    #5 9002307
    mirekk36
    Poziom 42  
    Dokładnie, w pętli głównej w ogóle nie obsługujesz hmmm tych przycisków.... a jeśli uważasz że je obsługujesz to spróbuj napisać dlaczego tak uważasz może łatwiej będzie cię naprowadzić. Bo tak to sporo jest pomieszane niestety :(
  • #6 9002378
    Altarir
    Poziom 11  
    Nie uważam, C się dopiero uczę i wiem, że kod ma zapewne sporo błędów. Jakby nie miał, nie prosiłbym o pomoc.

    OK, jeden błąd poprawiłem, wrzuciłem sprawdzanie flag do pętli głównej.

    Dalej nie działa.
  • REKLAMA
  • #8 9002571
    mirekk36
    Poziom 42  
    Altarir napisał:

    OK, jeden błąd poprawiłem, wrzuciłem sprawdzanie flag do pętli głównej.


    No to jak chcesz taką drogą, to wrzucaj poprawiony kod żeby było widać co kombinujesz i w którą stronę to dzięki temu łatwiej będzie cię dalej naprowadzać.

    I spróbuj własnie opisać np tak zrobiłeś obsługę przycisków - chodzi o te krótkie fragmenty kodu gdzie próbujesz zwiększać czy zmniejszać jakieś tam zmienne. Bo w sumie przykład podałeś krótki i przejrzyście napisany - tyle że troszkę namieszane ale spokojnie, wyjdziesz z tego "zaraz" ;)
  • #9 9002964
    Altarir
    Poziom 11  
    OK. W komentarzach napisalem co mi sie wydaje, ze sie dzieje w programie, Będe wdzięczny za wskazanie w których miejscach to co mi sie wydaje rozbiega sie z tym co jest w rzeczywistości :)

    #define F_CPU 16000000L
    
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    
    
    #include "lcd.h"
    
    volatile uint8_t flag1=0;
    volatile uint8_t flag2=0;
    
    //------------------------------------------------------------------------
    	ISR(INT0_vect) { //przerwanie INT1, jesli natapi (czyli jesli wcisne przycisk) to flag1 ustawia sie na 1
    
    	flag1 = 1;
    
    	}	
    
    	ISR(INT1_vect) { //przerwanie INT1, jesli natapi to flag2 ustawia sie na 1
    
    	flag2 = 1;
    
    	}	
    
    
    	void int0_init( void )
    {
        MCUCR = (1<<ISC01);             // przerwanie INT0, zbocze opadajace
        GICR = (1<<INT0);               // wlacz INT0
    }
    
    	void int1_init( void )
    {
        MCUCR = (1<<ISC01);             // przerwanie INT1, zbocze opadajace
        GICR = (1<<INT1);               // enable INT1
    }
    
    
    //------------------------------------------------------------------------
    
    
    void main()
    
    
    
    {
    	unsigned char s;  //sekundy
    	s = 0;
    	unsigned char m;  //minuty
    	m = 0;
    	unsigned char g;  //godziny
    	g = 0;
    	
    	
    
    
    	/* Linia PB będzie wejściem z podciągnięciem do VCC */
      	DDRB  = 0x00;
      	PORTB = 0xFF;
    
    	//Inicjalizacja LCD
    	InitLCD(LS_BLINK|LS_ULINE);
    
    	//czyszczenie LCD
    	LCDClear();
    
    
    	sei();  //wlaczenie przerwan.
    	
    	
    
    	while(1)    //nieskonczona petla
    	{
            
            
     	while (flag1 == 1)	    //sprawdzenie czy flag1 jest w stanie 1
    	{
    	m +=1;				//jesli tak, to m zwieksza sie o 1.
    	}
    
    	while (flag2 == 1)	     //jak wyzej tylko dla int1
    	{
    	g +=1;
    	}
    
           	
    	//-------------------ten fragment odpowiada za liczenie godzin, minut, sekund
    		_delay_ms(1000);
    		s = s + 1;	
    		
    		if (s> 59)
    		{
    		s = 0;
    		m = m + 1;
    			if (m > 59)
    			{
    			m = 0;
    			g = g + 1;
    				if (g>23)
    				{
    				g = 0;
    				m = 0;
    				s = 0;
    				}
    			}
    		}
    	//------------------
    
    	//-----------------tak byly roziwazane przyciski do tej pory:
    	
    	
    	//if(!(PINB & 0x01))
            //{
            //m +=1;
    	  //if (m > 59)
    		//{
    		//m = 0;
    		//}
             // _delay_ms(20);
             //} 
    	
    	
    	//if(!(PINB & 0x02))
             //{
              //g += 1;
    	  //if (g>23)
    		//{
    		//g = 0;
    		//}
          // _delay_ms(20);
          //}
    
    	//wyswietlanie zmiennych na LCD
    
    		LCDWriteIntXY(10,0,s,2);
    		LCDWriteStringXY(9,0,":");
    		LCDWriteIntXY(7,0,m,2);
    		LCDWriteStringXY(6,0,":");
    		LCDWriteIntXY(4,0,g,2);
    		LCDWriteStringXY(16,0," ");
    	}
    }
    
  • REKLAMA
  • #10 9003370
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Moje pytanie wciąż pozostaje aktualne - kiedy miałoby niby przestać powiększać minuty czy godziny i niby dlaczego? Innymi słowy - jaki mechanizm spowoduje, że zmienne z przerwania nagle przestaną być równe 1?

    4\/3!!
  • #11 9004108
    Altarir
    Poziom 11  
    Dodałem ustawianie flag z powrotem na 0. Nadal jednak nic sie nie dzieje po naciśnięciu przycisku. Wygląda więc na to, że program nie reaguje na przerwanie i nie zwiększa minut czy godzin w ogóle.

    #define F_CPU 16000000L
    
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    
    
    #include "lcd.h"
    
    volatile uint8_t flag1=0;
    volatile uint8_t flag2=0;
    
    //------------------------------------------------------------------------
       ISR(INT0_vect) { //przerwanie INT1, jesli natapi to flag1 ustawia sie na 1, 
    	flag1 = 1;
    
    	
    	}	 
    
       ISR(INT1_vect) { //przerwanie INT1, jesli natapi to flag2 ustawia sie na 1, 
    
    	flag2 = 1;
    
    	
    	}	
       
    
    
       void int0_init( void )
    {
        MCUCR = (1<<ISC01);             // przerwanie INT0, zbocze opadajace
        GICR = (1<<INT0);               // wlacz INT0
    }
    
       void int1_init( void )
    {
        MCUCR = (1<<ISC01);             // przerwanie INT1, zbocze opadajace
        GICR = (1<<INT1);               // enable INT1
    }
    
    
    //------------------------------------------------------------------------
    
    
    void main()
    
    
    
    {
       unsigned char s;  //sekundy
       s = 0;
       unsigned char m;  //minuty
       m = 0;
       unsigned char g;  //godziny
       g = 0;
       
       
    
    
       /* Linia PB będzie wejściem z podciągnięciem do VCC */
         DDRB  = 0x00;
         PORTB = 0xFF;
    
       //Inicjalizacja LCD
       InitLCD(LS_BLINK|LS_ULINE);
    
       //czyszczenie LCD
       LCDClear();
    
    
       sei();  //wlaczenie przerwan.
       
       
    
       while(1)    //nieskonczona petla
       {
           
           
        while (flag1 == 1)       //sprawdzenie czy flag1 jest w stanie 1
       {
       m +=1;            //jesli tak, to m zwieksza sie o 1.
    
       _delay_ms(200);
    
        flag1 = 0;       //po 200 ms z powrotem flag1 na 0
    
       }
    
       while (flag2 == 1)        //jak wyzej tylko dla int1
       {
       g +=1;
    
       _delay_ms(200);
    
        flag2 = 0;
       }
    
              
       //-------------------ten fragment odpowiada za liczenie godzin, minut, sekund
          _delay_ms(1000);
          s = s + 1;   
          
          if (s> 59)
          {
          s = 0;
          m = m + 1;
             if (m > 59)
             {
             m = 0;
             g = g + 1;
                if (g>23)
                {
                g = 0;
                m = 0;
                s = 0;
                }
             }
          }
       //------------------
    
       //-----------------tak byly roziwazane przyciski do tej pory:
       
       
       //if(!(PINB & 0x01))
            //{
            //m +=1;
         //if (m > 59)
          //{
          //m = 0;
          //}
             // _delay_ms(20);
             //}
       
       
       //if(!(PINB & 0x02))
             //{
              //g += 1;
         //if (g>23)
          //{
          //g = 0;
          //}
          // _delay_ms(20);
          //}
    
       //wyswietlanie zmiennych na LCD
    
          LCDWriteIntXY(10,0,s,2);
          LCDWriteStringXY(9,0,":");
          LCDWriteIntXY(7,0,m,2);
          LCDWriteStringXY(6,0,":");
          LCDWriteIntXY(4,0,g,2);
          LCDWriteStringXY(16,0," ");
       }
    } 
  • #12 9004461
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Te linie:

       void int0_init( void ) 
    { 
        MCUCR = (1<<ISC01);             // przerwanie INT0, zbocze opadajace 
        GICR = (1<<INT0);               // wlacz INT0 
    } 
    
       void int1_init( void ) 
    { 
        MCUCR = (1<<ISC01);             // przerwanie INT1, zbocze opadajace 
        GICR = (1<<INT1);               // enable INT1 
    }

    Są błędne, bo ustawiasz nową wartość kasując starą. Powinieneś skorzystać z operatorów bitowych ("|=", "&=~", "^="). Pozatym zobacz, że dla INT1 i INT0 "ustawiasz" (patrz poprzednie zdanie) zawsze bit ISC01, a przecież on jest tylko dla jednego z tych przerwań.

    No i teraz tak jakby dochodzimy do sedna tej części problemu - przecież te dwie funkcje do konfigurowania przerwań od przycisków w ogóle nie są wywoływane, więc...

    P.S. Ten zegar będzie niezbyt dokładny...

    4\/3!!
  • #13 9005236
    Altarir
    Poziom 11  
    Uff, pokombinowałem, znalazłem na stronie atmela przykładowy kod w asemblerze do obsługi dwóch przycisków przerwaniami i nareszcie mam jakiś sensowny wynik. Konfigurację przerwań zmieniłem, i wrzuciłem w dobre miejsce. Godziny i minuty mogę już ustawiać, więc uznaję, że program działa :).

    Dziękuję za naprowadzanie mnie na właściwą drogę

    Ostatecznie kod programu wygląda tak:
    #define F_CPU 16000000L
    
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    
    
    #include "lcd.h"
    
    volatile uint8_t flag1=0;
    volatile uint8_t flag2=0;
    
    //------------------------------------------------------------------------
    	ISR(INT0_vect) { //przerwanie INT1, jesli natapi to flag1 ustawia sie na 1
    	flag1 = 1;
    
    	}	
    
    	ISR(INT1_vect) { //przerwanie INT1, jesli natapi to flag2 ustawia sie na 1
    	flag2 = 1;
    
    	}	
    
    
    //------------------------------------------------------------------------
    
    void main()
    
    {
    	unsigned char s;  //sekundy
    	s = 0;
    	unsigned char m;  //minuty
    	m = 0;
    	unsigned char g;  //godziny
    	g = 0;
    	
    	DDRD  = 0x00;				//port D jako wejscie
      	PORTD = 0xFF;
    
    	MCUCR = 0x0f;             // ustaw przerwanie INT0 i INT1, zbocze narastajace
        GICR = (1<<INT0) | (1<<INT1);               // wlacz INT0 i INT1
    
    
    	/* Linia PB będzie wejściem z podciągnięciem do VCC */
      	DDRB  = 0x00;
      	PORTB = 0xFF;
    
    	//Inicjalizacja LCD
    	InitLCD(LS_BLINK|LS_ULINE);
    
    	//czyszczenie LCD
    	LCDClear();
    
    
    	sei();  //wlaczenie przerwan
    	
    	
    
    	while(1)    //nieskonczona petla
    	{
    
    	while (flag1 == 1)	//sprawdzenie czy flag1 jest w stanie 1
    	{
    	m +=1;				//jesli tak, to zwieksz m o 1, i ustaw flag1 z powrotem na 0.
    	if (m > 59)
    			{
    			m = 0;
    			}
    
    	flag1 = 0;
    	}
    
    	while (flag2 == 1)	//jak wyzej tylko dla int1
    	{
    	g +=1;
    	if (g > 23)
    			{
    			g = 0;
    			}
    
    	flag2 = 0;
    	}
    	
    	//-------------------ten fragment odpowiada za liczenie godzin, minut, sekund, dziala
    		_delay_ms(997);
    		s = s + 1;	
    		
    		if (s> 59)
    		{
    		s = 0;
    		m = m + 1;
    			if (m > 59)
    			{
    			m = 0;
    			g = g + 1;
    				if (g>23)
    				{
    				g = 0;
    				m = 0;
    				s = 0;
    				}
    			}
    		}
    	//------------------
    
    	//-----------------tak byly roziwazane przyciski do tej pory:
       
       
       //if(!(PINB & 0x01))
            //{
            //m +=1;
         //if (m > 59)
          //{
          //m = 0;
          //}
             // _delay_ms(20);
             //}
       
       
       //if(!(PINB & 0x02))
             //{
              //g += 1;
         //if (g>23)
          //{
          //g = 0;
          //}
          // _delay_ms(20);
          //}
    
    	//wyswietlanie zmiennych na LCD	
    
    		LCDWriteIntXY(10,0,s,2);
    		LCDWriteStringXY(9,0,":");
    		LCDWriteIntXY(7,0,m,2);
    		LCDWriteStringXY(6,0,":");
    		LCDWriteIntXY(4,0,g,2);
    		LCDWriteStringXY(16,0," ");
    
    	}
    
    }
    



    PS wiem, że zegarek nie będzie zbyt dokładny, ale mi to nie przeszkadza, nie zamierzam go dalej wykorzystywać. Jedynym celem pisania tego programu było nauczenie się obsługi LCD i zewnętrznych przerwań w C.
REKLAMA