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

Jak napisać funkcję w C do zliczania przerwań logicznych zer?

Kubbaz 28 Lip 2006 21:35 2784 24
REKLAMA
  • #1 2860014
    Kubbaz
    Poziom 26  
    Posty: 1237
    Pomógł: 9
    Ocena: 30
    Witam

    Mam pewien problem. Otóż nie bardzo wiem jak napisać funkcję czy kawałek kodu w C, tak aby ten potrafił zliczać przerwania (czyli logiczne zera). Mam na myśli taki program, który rozpoznawałby ilość przerwań (od 1 do 10) i na tej podstawie dokonywał jakiegoś wyboru (powiedzmy, że ustawiałby jakiś port na stan wysoki).
    Obecny fragment kodu na jakim się "bawię", wygląda tak:

    #include <avr/io.h>
    #include "priv.h"
    
    int main ()
    {
    	PD0_OH; // pin PD0 ustawiony jako wyjście na stanie wysokim
    	delayms(1);  // odczekanie 1ms na przeładnowanie 
    	PD0_IH; // pin PD0 ustawiony jako wejście na stanie wysokim
    		
    	for (;;)
    	{
    		if(bit_is_clear(PIND,0)) // jeśli na PD0 jest logiczne 0, wtedy:
    		{
    			PB6_OH;      // zapalana jest dioda LED
    			delayms(5); // odczekanie 5ms
    			PB6_OL;      // zgaszenie diody LED
    		}
    	};
    	return (0);
    }


    Fakt, że nie wiele, ale program oznajmia przerwania syngnalizując to zapaleniem diody. Dodam, że te przerwania powodowane są przez tarcze telefoniczną....zapewne wielu z was zaczynało podobnie.....
    Proszę o pomoc w tym temacie.

    Za wszelką pomoc z góry serdecznie dziękuje pozdrawiam. Kubbaz.
  • REKLAMA
  • #2 2860160
    Samuraj
    Poziom 35  
    Posty: 2792
    Pomógł: 286
    Ocena: 616
    Niestety nie widzę tutaj żadnego przerwania, to jest praca w pętli.
    Jeśli pracujesz na mikrokontolerze AVR można ustawiąc aby reagował na opadające zbocze i w obsłudze przerwania zwiększać jedną ze zmiennych.
    Nie podam konkretnego kodu, bo nie mam pod ręką żadnego kompilkatora a nie chce wypisywać, bzdur.
  • REKLAMA
  • #3 2860197
    Kubbaz
    Poziom 26  
    Posty: 1237
    Pomógł: 9
    Ocena: 30
    Samuraj napisał:

    Jeśli pracujesz na mikrokontolerze AVR można ustawiąc aby reagował na opadające zbocze i w obsłudze przerwania zwiększać jedną ze zmiennych.


    i o to mi chodzi :), dzięki za pomoc....co prawda dalej nie wiem jak ma wyglądać kod, i jaką funkcję zastosować, aby program reagował na opadające zbocze, ale może gdzieś poszukam jeszcze coso tym, jednakże wszelakie kod mile widziane :).
  • #4 2860199
    zolciak
    Poziom 15  
    Posty: 163
    Pomógł: 6
    Ocena: 9
    Fragment obsługi przerwania w gcc wygląda mnie wiecej tak:
    
    SIGNAL (SIG_INTERRUPT0)
    {
    zmienna=1;
    }
    

    W momęcie gdy zostanie wywołane przerwanie zewnętrzne INT0 zmienna przyjmie wartość 1.

    Pozdrawiam

    ps. konfikurację przerwania (zbocza) wykonuje się ustawiając odpowiednie bity rejestru MCUCR.
  • #6 2860250
    Samuraj
    Poziom 35  
    Posty: 2792
    Pomógł: 286
    Ocena: 616
    Napisz na jakim AVR pracujesz to sklecę coś na szybkiego, w wolnej chwili :D

    Dodano po 13 [minuty]:

    Tak w wolnej chwili dla ATmega8535

    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    static uint8_t LICZ_PRZER;
    
    SIGNAL(SIG_INTERRUPT0)     
    // przerwanie na INT0 
    {
        LICZ_PRZER++;
    }
    
    
    void main(void)
    {
    	//Ustawienie rejestrów
        GICR = 0x40;
        MCUCR = 0x02;
    
    	//Port B jako wyjscie
    	DDRB = 0xFF;
    
        //włącz przerwania
        sei();    
    
    	//główna pętla programu
    	while(1)
    	{
    		//Po 5 przerwaniach ustaw port B na 0x55
    		if (LICZ_PRZER==5) PORTB = 0x55;
    
    		//Po 10 przerwaniach ustaw port B na 0xFF
    		if (LICZ_PRZER>10) PORTB = 0xFF;
    	}
    }
    
  • #8 2861433
    Procekk
    Poziom 12  
    Posty: 77
    Pomógł: 3
    Atmega8 ma podobnie, wieksze atmegi, np. 128 mają już trochę inne nazwy rejestrów.
    Strony 64-66 w dokumentacji.
    Ustawiasz MCUCR (rodzaj wywołania przerwania) i GICR (włączenie przerwań).
    Obsługa przerwania przez
    SIGNAL(SIG_INTERRUPT0) lub SIGNAL(SIG_INTERRUPT1) w zależności które przerwanie chcesz odpalić INT0 czy INT1. Powodzenia.
  • #9 2861468
    Kubbaz
    Poziom 26  
    Posty: 1237
    Pomógł: 9
    Ocena: 30
    Jeśli mógłbyśmi wyjaśnić co oznacza " 0x55 " oraz " 0xFF " - czy są to stany portów ?? Czy ATmega8535 jest podobny pod względem architetkury do ATmeag8 ?

    i jeszcze jedno: który z portów B jest ustawiany jako wyjście?? przyznam, że ja uzywam do tego "SBI"...
    Samuraj napisał:
    //Port B jako wyjscie
    DDRB = 0xFF;
  • #10 2861546
    Procekk
    Poziom 12  
    Posty: 77
    Pomógł: 3
    0xFF (hex) = 255 (dec) = 11111111 (bin) :) Po prostu posyłasz na dany port 0xFF i wszystkie wyjścia tego portu masz w stanie wysokim (po uprzednim odpowiednim skonfigurowaniu portów jak to jest zrobione na początku podesłanego wcześniej programiku - DDRB - data direction register port B - wszystko masz w dokumentacji).
  • #11 2861553
    ashpl
    Poziom 13  
    Posty: 50
    Pomógł: 2
    Ocena: 4
    Są to zmienne w systemie szesnastkowym wystarczy je przekształcić na wartości binarne i już wiadomo które porty sa ustawione w stan wysoki. np dla wartości 0xFF = 11111111, a dla wartosci 0x55 wygląda tak: 10101010.
    A wysłanie do rejestru DDRB wartości 0xFF ustawia wszystkie piny portu B jako wyjście.
  • REKLAMA
  • #12 2861612
    Kubbaz
    Poziom 26  
    Posty: 1237
    Pomógł: 9
    Ocena: 30
    ashpl napisał:

    la wartości 0xFF = 11111111, a dla wartosci 0x55 wygląda tak: 10101010


    jakie to proste - dzięki za informacje

    Dodano po 3 [godziny] 59 [minuty]:

    w trakcie kompilacji kodu
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    static uint8_t LICZ_PRZER;
    
    SIGNAL(SIG_INTERRUPT0)     
    // przerwanie na INT0
    {
        LICZ_PRZER++;
    }
    
    
    void main(void)
    {
       //Ustawienie rejestrów
        GICR = 0x40;
        MCUCR = 0x02;
    
       //Port B jako wyjscie
       DDRB = 0xFF;
       PORTB = 0xFF;
    
        //włącz przerwania
        sei();   
    
       //główna pętla programu
       while(1)
       {
          //Po 5 przerwaniach ustaw port B na 0x55
          if (LICZ_PRZER<5) PORTB = 0x55;
    
          //Po 10 przerwaniach ustaw port B na 0xFF
          if (LICZ_PRZER>5) PORTB = 0xFF;
       }
    } 


    kompilator zgłasza kilka ostrzeżeń:

    WinAVR napisał:
    > "make.exe" all
    avr-gcc -g -Wall -O2 -mmcu=atmega8 -c -o telefon.o telefon.c
    telefon.c:8: warning: return type defaults to `int'
    telefon.c:14: warning: return type of 'main' is not `int'
    telefon.c:34:3: warning: no newline at end of file

    telefon.c: In function `SIGNAL':
    telefon.c:10: warning: control reaches end of non-void function
    avr-gcc -g -Wall -O2 -mmcu=atmega8 -Wl,-Map,telefon.map -o telefon.elf telefon.o
    avr-objdump -h -S telefon.elf > telefon.lst
    avr-objcopy -j .text -j .data -O ihex telefon.elf telefon.hex
    avr-objcopy -j .text -j .data -O binary telefon.elf telefon.bin
    avr-objcopy -j .text -j .data -O srec telefon.elf telefon.srec
    avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex telefon.elf telefon_eeprom.hex
    avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O binary telefon.elf telefon_eeprom.bin
    avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O srec telefon.elf telefon_eeprom.srec

    > Process Exit Code: 0


    i nie wiem czy to przez te ostrzeżenia czy z innej przyczyny, ale wsad nie działa poprawnie.
    Hmmm....może źle coś połączyłem:

    dioda LED, sygnalizująca ilość przerwań jest podłączona właściwie do GND i PB6, a tarcza powodująca przerwania podłączona jest do PD2->INT0 i VCC - czy coś jest nie tak ??

    bo z kodu źródłowego wynika, że jeśli ilość przerwań jest mniejsza niż 5, to dioda LED gaśnie (bo wcześniej jest zapalona -> DDRB = 0xFF; PORTB = 0xFF; ), a gdy ilość przerwań jest większa niż 5, to dioda LED się zapala.
  • #13 2864081
    matgaw
    Poziom 15  
    Posty: 198
    Pomógł: 4
    Ocena: 3
    Te wartości do MCUCR i GICR musisz sobie sam policzyć zgodnie z dokumentacją do ATmegi8 bo to był przykład do 8535 a raczej nie będą się zgadzać.

    A warningi biorą się stąd, że zamiast void main(void) powinno być int main(void) i przed klamrą kończącą return 0;
  • #14 2864182
    ashpl
    Poziom 13  
    Posty: 50
    Pomógł: 2
    Ocena: 4
    Nie wiem jak jest z mikroprockami, ale czy deklaracja zmiennej LICZ_PRZER nie powinna wygladać tak:

    static uint8_t LICZ_PRZER=0;


    Bo na PC jak sie programuje sie w C++ i przy deklaracji zmiennej nie ma przypisanej odrazu liczby, to ta zmienna może przyjmować dowolną wartość :|
  • #15 2864214
    Procekk
    Poziom 12  
    Posty: 77
    Pomógł: 3
    Kubbaz, jestem ciekaw jak podpinasz tą tarcze do INT0. Bo póki co to widać że przerwanie włączyłeś dobrze, wyzwalane będzie zboczem opadającym.
  • REKLAMA
  • #16 2864716
    Kubbaz
    Poziom 26  
    Posty: 1237
    Pomógł: 9
    Ocena: 30
    matgaw napisał:
    Te wartości do MCUCR i GICR musisz sobie sam policzyć zgodnie z dokumentacją do ATmegi8 bo to był przykład do 8535 a raczej nie będą się zgadzać.

    Poszukam w manualu i jak mi się uda je znaleźć, to je zmienie.

    matgaw napisał:
    zamiast void main(void) powinno być int main(void) i przed klamrą kończącą return 0;

    Także zmienie.


    Procekk napisał:
    jak podpinasz tą tarcze do INT0

    Kubbaz napisał:

    tarcza powodująca przerwania podłączona jest do PD2->INT0 i VCC


    matgaw napisał:
    MCUCR i GICR musisz sobie sam policzyć zgodnie z dokumentacją do ATmegi8


    W manualu na stronie 284 w tabeli rejestrów znalazłem pewne wartości dla tych dwóch rejestów:

    GICR = 0x3B (lub 0x5B)
    MCUCR = 0x35 (lub 0x55)


    czy to o te wartości chodzi?? bo faktycznie są różne od tych "przykładowych" do 8535.

    PS. W załączniku dodaje Manual ATMega8:).
    -> http://www.teslabox.host.sk/Manual_ATMega8.pdf
    GDYBY TEN URL NIE DZIAŁAŁ TO PISZCIE

    Dodano po 12 [minuty]:

    hhmmmmmm.......

    Po wprowadzeniu niezbędnych zmian, procesor dalej nie reaguje poprawnie.

    Zmieniony kod wygląda następująco:

    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    static uint8_t LICZ_PRZER=0;
    
    SIGNAL(SIG_INTERRUPT0)     
    // przerwanie na INT0
    {
        LICZ_PRZER++;
    }
    
    
    int main(void)
    {
       //Ustawienie rejestrów
        GICR = 0x3B; //zgodnie ze str.284 manuala 
        MCUCR = 0x35;//zgodnie ze str.284 manuala
    
       //Port B jako wyjscie na stanie wysokim -> dioda LED na PB6 jest zapalona 
       DDRB = 0xFF;
       PORTB = 0xFF;
    
        //włącz przerwania
        sei();   
    
       //główna pętla programu
       while(1)
       {
          //Jeśli przerwań jest mniej niż 5, to port B ustawiany jest na 0x55, czyli PB6 na stan niski
          if (LICZ_PRZER<5) PORTB = 0x55;
    
          //Jeśli przerwań jest więcej niż 5, to port B ustawiany jest na 0xFF, czyli PB6 na stan wysoki
          if (LICZ_PRZER>5) PORTB = 0xFF;
       }
       return (0);
    }


    WinAVR napisał:
    > "make.exe" all
    avr-gcc -g -Wall -O2 -mmcu=atmega8 -c -o telefon.o telefon.c
    telefon.c:8: warning: return type defaults to `int'
    telefon.c: In function `SIGNAL':
    telefon.c:10: warning: control reaches end of non-void function
    avr-gcc -g -Wall -O2 -mmcu=atmega8 -Wl,-Map,telefon.map -o telefon.elf telefon.o
    avr-objdump -h -S telefon.elf > telefon.lst
    avr-objcopy -j .text -j .data -O ihex telefon.elf telefon.hex
    avr-objcopy -j .text -j .data -O binary telefon.elf telefon.bin
    avr-objcopy -j .text -j .data -O srec telefon.elf telefon.srec
    avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex telefon.elf telefon_eeprom.hex
    avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O binary telefon.elf telefon_eeprom.bin
    avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O srec telefon.elf telefon_eeprom.srec

    > Process Exit Code: 0


    Pewną rzeczą, której nie mogę zrozumieć jest poniższa linja kodu:

    //włącz przerwania
        sei();

    co to "sei ();" oznacza ??

    Oraz to, że w pętli while jest argument ( "1" )...... czyli pętla ma się wykonywać aż napotka .... no właśnie co??

    Dodano po 17 [minuty]:

    Nie wiem dokłądnie jak to jest w programowaniu mikrokontrolerów, ale przed programem głównym jest funkcja SIGNAL(SIG_INTERRUPT0), która już wiem co robi - ok, ale ona nie jest użyta w pętli programu głównego, tylko zmienna z tej funkcji....czy to poprawnie ?
  • #17 2865078
    Procekk
    Poziom 12  
    Posty: 77
    Pomógł: 3
    sei(); służy do tego abyś mógł obsługiwać przerwania. Teraz jak zmieniłes GICR na 0x3B to ja nie wiem.. nie włączasz przerwania INT0. Zobacz sobie na rejestr GICR, musisz na 7 bit (bit #6 licząc od 0) dać "1" czyli 01000000, czyli 64 dziesiętnie, czyli 40 hex (0x40), było dobrze. W MCUCR ustawiasz sobie konkretnie jak to przerwanie ma się uaktywniać, skoro bawisz sie tylko w INT0 to interesować Cie powinny tylko bity ISC01 i ISC00, czyli, np. chcesz aby przerwanie generowane było przez jakąkolwiek zmiane stanu logicznego na INT0, wpisujesz do MCUCR wartość 0x01, chcesz żeby zbocze opadające - piszesz MCUCR=0x02 (ISC01=1 ISC00=0).
    Poza tym, właśnie nie wiem jak ta "tarcza" działa, ale proponuje INT0 przez rezystor do VCC, INT0 przez kondensatorek, np. 100nF do masy, i dodatkowo przez tarczę do masy, jeśli np. tarcza robi zwarcie na swoich 2 stykach w momencie zdarzenia które Cię interesuje.. no ale nie wiem jak taka tarcza działa. Jeśli tak to piszesz MCUCR=0x02; GICR=0x40; i powinno działać.
    ---
    co do while ona sie wykonuje do momentu kiedy "1" będzie jedynką, może troche śmiesznie ale tak ja to rozumiem, czyli zawsze :D często pisze się jeszcze for( ; ; ) { } - podobny skutek, procesor nie moze ot tak poprostu skończyć programu na "end."
    ---
    SIGNAL to taka procedurka która wykonuje się zawsze po wystąpieniu przerwania, jak sama nazwa wskazuje - przerywa działanie jakiejś pętli programu głownego, jak się wykona to wraca. Wszystko jest ok, SIGNAL nie umieszczamy w funkcji main();
  • #18 2865175
    Kubbaz
    Poziom 26  
    Posty: 1237
    Pomógł: 9
    Ocena: 30
    Wielkie DZIĘKI Procekk za obszerna wyjaśnienie :).

    Procekk napisał:
    jak ta "tarcza" działa

    - w spoczynku tarcza daje logiczne 0,
    - w trakcie naciągania tarczy (kręcenia) tarcza daje logiczną 1,
    - po puszczeniu tarczy np. z cyfry 7, tarcza w równych odstępach czasu daje 7 przerwań
    - i powraca do punktu wyjścia, czyli logiczne 0.


    hm......czy ten stan początkowy (logiczne 0) też jest widziany przez procesor jako przerwanie ??

    Procekk napisał:
    INT0 przez rezystor do VCC, INT0 przez kondensatorek, np. 100nF do masy, i dodatkowo przez tarczę do masy


    przyznam szczerze, że nie widzę tego połączenia:?:, mógłbyś jakoś narysować swoją wizję tych połączeń, tak abym mógł je odtworzyć u siebie na procku ?
    Procekk napisał:

    co do while ona sie wykonuje do momentu kiedy "1" będzie jedynką, może troche śmiesznie ale tak ja to rozumiem, czyli zawsze Very Happy często pisze się jeszcze for( ; ; ) { } - podobny skutek


    Jestem "ZA" częstszym uzywaniem nieskończonego for'a......jakoś bardziej to "widze".

    Spróbuje pozmieniać z powrotem rejestr GICR na 0x40, i MCUCR na 0x01 lub 0x02. Może zamienie pętle while na tego for'a....zobacze.

    Jutro dam znać o efektach zmian.
  • #19 2865465
    Samuraj
    Poziom 35  
    Posty: 2792
    Pomógł: 286
    Ocena: 616
    Zmiana pętli nic nie da, choć by dlatego że to w rezultacie jest to samo tylko inaczej zapisane. Zobacz na przykład:

    
       //główna pętla programu 
       while(1) 
       { 
          //Jeśli przerwań jest mniej niż 5, to port B ustawiany jest na 0x55, czyli PB6 na stan niski 
          if (LICZ_PRZER<5) PORTB = 0x55; 
    
          //Jeśli przerwań jest więcej niż 5, to port B ustawiany jest na 0xFF, czyli PB6 na stan wysoki 
          if (LICZ_PRZER>5) PORTB = 0xFF; 
       }
    


    a tutaj z for

    
       //główna pętla programu 
       for (;;) 
       { 
          //Jeśli przerwań jest mniej niż 5, to port B ustawiany jest na 0x55, czyli PB6 na stan niski 
          if (LICZ_PRZER<5) PORTB = 0x55; 
    
          //Jeśli przerwań jest więcej niż 5, to port B ustawiany jest na 0xFF, czyli PB6 na stan wysoki 
          if (LICZ_PRZER>5) PORTB = 0xFF; 
       }
    


    Nie wiedze praktycznie żadnej różnicy w zapisie, można by to jeszcze przejrzeć w pliku wynikowym i porównać co jest bardziej efektywne.

    Co do zmiennych w rejestrach GICR i MCUCR to nie przepisuj z manulala tylko zapisz wartości w systemie binarnym i odczytaj poszczególne bity (1 ustawiona 0 nie). Poszczególne bity oznaczają odpowiednie rzeczy i tak np w ATmega8 w rejestrze MCUCR bit 0 oznaczony jako ISC00 a bit 1 jako ISC01.
    Odpowiednie ustawienie tych bitów powoduje różne reakcje na przerwanie w tym przypadku INT0 (poczytaj stronę 65 pdf'a).
    Jak zapewne zauważysz w rejestrze tym istnieją też bity odpowiedzialne za przerwanie INT1 oraz za tryb obniżonego poboru prądu (SLEEP).
    Tak więc podawanie wartości 0x35 czy też 55 bez znajomości odpowiednich bitów nic nie daje.
    Co do tarczy to proponuję na początek dać switcha i sprawdzić czy reaguj procesor prawidłowo na przerwania (pomiędzy INT0 a masę).
    Co do schematu to nic trudnego tak jak zaproponował Procekk wejście INT0 podciągnij przez rezystor np. 1k do plusa i pomiędzy wyjście a masę daj kondensator (jest to rozwiązanie eliminujące drgania styków które mogą się pojawić z chwilą nie określonych stanów).

    A i na koniec jeszcze jedno, proponuje ściągnąć najnowsze AVRStudio 4 i pobawić się symulatorem. To odpowie na wieeeele kolejnych pytań.
  • #20 2865489
    piotr_go
    Konstruktor DIY elektronika
    Posty: 2904
    Pomógł: 94
    Ocena: 3337
    Fragment mojego kodu z obsługą przerwania:

    #include <io.h>
    #include <interrupt.h>
    #include <sig-avr.h>
    
    
    typedef unsigned char bool;
    typedef unsigned char u08;
    typedef unsigned short u16;
    typedef unsigned long u32;
    
    
    SIGNAL (SIG_INTERRUPT0)
    {
    	//obsługa przerwania
    
    
    	outp(0x40, GIFR);
    }
    
    
    void main(void){
    
    	/* falling edge on Int0 generates an interrupt */
    	outp(0x02, MCUCR);
    	/* enable interrupt Int0 */
    	outp(0x40, GIMSK);
    
    
    	outp(0x40, GIFR);
    	sei(); /* set global interrupt enable */
    
    	while(1){
    		// coś tam, coś tam
    	}
    }
    
    


    Pisany był dość dawno temu pod at90s8515.
    Może sie przyda.
    Niestety dawno nie pisałem niczego pod avry i bardziej nie moge pomóc.
    Chociaż może i moge :)
    Załączam plik.
    Załączniki:
    • haraleit.pdf (282.7 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #21 2865662
    Procekk
    Poziom 12  
    Posty: 77
    Pomógł: 3
    for czy while - Twój wybór, raczej niczego tu nie zmienia.
    ---
    Tarcza.. hmm.. tak jak pisał przedmówca - Samuraj - jeśli coś Ci nie wychodzi, spróbuj podpiąć jakiś switch którym mogłbyś zwierać dwa styki. No i zgodnie z tym co napisałem, warto linie INT0 podciągnąć w takim przypadku rezystorkiem, np 10k do Vcc. To pierwsza rzecz. Następnie od linii INT0 daj jakiś kondensatorek, tak jak pisałem - te 100nF, z drugiej strony kondensatorek podłącz do masy. Nie mam jak tego narysować :) Ale w miare jasno opisuje?
    Dobra teraz część trzecia. Mam rozumieć że tarcza ma jakieś wyprowadzenie, które ma stan "L" lub "H" ("H"=Vcc?) - chodzi o jedną "końcówkę"? To po prostu podepnij tą końcówkę do INT0, nie wiem czy rezystor podciągający ma wtedy sens. Jeśli w spoczynku masz logiczne 0, pożniej naciągasz i masz 1, puszczasz i masz z cyfry 7 siedem zboczy opadających to wiadomo - to co Ci pisałem o rejestrach GICR i MCUCR tak musisz je na bank ustawić. Procesor powinien zliczać tylko momenty kiedy tarczę puszczasz i zmieniają się stany z 1 na 0. Potestuj sobie i daj znac, powinno to działać, kondensatorek jak najbardziej się przyda, wydatek niewielki a i w programie nie trzeba przejmować się jakimiś opóźnieniami. Czyli MCUCR=0x02; GICR=0x40;
    ----
    Czy stan logiczny 0 będzie widziany jako przerwanie? - Nie, przy tym ustawieniu tylko falling edge - zbocze opadające (tab. strona 64) generuje przerwanie.
    ----
    teraz postaraj się wygenerować jakieśprzerwanie przez INT0, na początek proponuję z SIGNAL(SIG_INTERRUPT0) dać jakiś mały liczniczek, albo coś co zmieniałoby Ci stan jakiegoś wyjścia, tak abyś mógł zobaczyć że to rzeczywiście działa. I wtedy weż oprócz podłączonego do INT0 rezystorka, kondensatorka, daj jakiś przewodzik, drugą końcówką tykaj masy - coś powinno się dziać :D
    Pozdrawiam, powodzenia, to nie jest trudne :wink:
    ----
    O jeszcze tak na przyszłość.. zamiast pisać np GICR=0x40 napisz sobie GICR = (1 << INT0); a zamiast pisać MCUCR = 0x02; napisz MCUCR = (1<< ISC01); będzie czytelniej, nie pogubisz się w kodzie. No i jeśli dużo piszesz, dużo używasz nazw rejestrów (a to w sumie podstawa) przeliczanie wartości HEX na wartości poszczególnych bitów jest... (małe niedomówienie) ...wiadomo :) Trza sobie ułatwiać :wink:.
  • #22 2866574
    Kubbaz
    Poziom 26  
    Posty: 1237
    Pomógł: 9
    Ocena: 30
    Procekk napisał:

    próbuj podpiąć jakiś switch którym mogłbyś zwierać dwa styki
    linie INT0 podciągnąć w takim przypadku rezystorkiem, np 10k do Vcc
    od linii INT0 daj jakiś kondensatorek, tak jak pisałem - te 100nF, z drugiej strony kondensatorek podłącz do masy


    czyli tak : ;)
    Jak napisać funkcję w C do zliczania przerwań logicznych zer?
    Powyższy układzik przetestowałem na poniższym kodzie:

    #include <avr/io.h>
    #include "priv.h"
    
    int main ()
    {
       PD0_OH; // pin PD0 ustawiony jako wyjście na stanie wysokim
       delayms(1);  // odczekanie 1ms na przeładnowanie
       PD0_IH; // pin PD0 ustawiony jako wejście na stanie wysokim
          
       for (;;)
       {
          if(bit_is_clear(PIND,4)) // jeśli na PD4 jest logiczne 0, wtedy:
          {
             PB6_OH;      // zapalana jest dioda LED
             delayms(5); // odczekanie 5ms
             PB6_OL;      // zgaszenie diody LED
          }
       };
       return (0);
    }


    I układ się spisuje bardzo ładnie - reaguje prawidłowo (przy wciśnięciu switcha zapala się dioda LED).

    Jednakże po skompilowaniu kodu właściwego ze zmianą rejestru MCUCR z 0x35 na 0x02 czy nawet 0x01,
    Procekk napisał:
    Czyli MCUCR=0x02; GICR=0x40;
    układ dalej nie chce współpracować ..... czy to przez ten rejestr MCUCR, o którym mówił Samuraj ??:

    Samuraj napisał:
    Co do zmiennych w rejestrach GICR i MCUCR to nie przepisuj z manulala tylko zapisz wartości w systemie binarnym i odczytaj poszczególne bity (1 ustawiona 0 nie). Poszczególne bity oznaczają odpowiednie rzeczy i tak np w ATmega8 w rejestrze MCUCR bit 0 oznaczony jako ISC00 a bit 1 jako ISC01.
    Odpowiednie ustawienie tych bitów powoduje różne reakcje na przerwanie w tym przypadku INT0 (poczytaj stronę 65 pdf'a).


    jeszcze spróbuje pogrzebać na 65 stronie manuala ATMEGA8.
    Dam znać jak będzie jakiś postęp .... lub jego brak ;).
  • Pomocny post
    #23 2866856
    Procekk
    Poziom 12  
    Posty: 77
    Pomógł: 3
    
    #include <avr/io.h>
    #include <stdlib.h>
    #include <avr/interrupt.h>
    
    #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))	
    #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
    #define LEDB6_ON sbi(DDRB,PB6);sbi(PORTB,PB6)
    #define LEDB6_OFF sbi(DDRB,PB6);cbi(PORTB,PB6)
    
    unsigned uint8_t b;
    
    SIGNAL(SIG_INTERRUPT0)
    {
      if (b==1)
      {
        LEDB6_ON;
        b=0;
      }
      else
      {
        LEDB6_OFF;
        b++;
      }
    }
    
    int main(void)
    {
      MCUCR = (1 << ISC01);
      GICR = (1 << INT0);
      b=1;
      sei();
    
      while(1)
      {
    
      }
    }
    

    a przy diodzie nie ma rezystorka?
    ---
    Kiedyś coś podobnego pisałem i >>działało<< na mega16, w mega8 robi się identycznie. Powinno być ok, schemat jest ok, jedynie ta dioda.. - rozumiem że rezystorek w szeregu z nią jest, tylko nie na schemacie. Zawsze możesz jeszcze pobawić się bitami ISC00 i ISC01. Np. MCUCR = (1 << ISC01) | (1 << ISC00); - reakcja na zbocze narastające, lub MCUCR = (1 << ISC00); - każda zmiana stanu logicznego.
  • #24 2866900
    Kubbaz
    Poziom 26  
    Posty: 1237
    Pomógł: 9
    Ocena: 30
    Pokwapiłem się przetłumaczyć fragment ze strony 65 manuala ATMEGA8 dotyczący przerwań na pinie INT0. Wygląda on następoująco:
    Manual ATMega8 napisał:

    • Bit 6 – INT0: External Interrupt Request 0 Enable
    When the INT0 bit is set (one) and the I-bit in the Status Register (SREG) is set (one),
    the external pin interrupt is enabled. The Interrupt Sense Control0 bits 1/0 (ISC01 and
    ISC00) in the MCU general Control Register (MCUCR) define whether the external
    interrupt is activated on rising and/or falling edge of the INT0 pin or level sensed. Activity
    on the pin will cause an interrupt request even if INT0 is configured as an output. The
    corresponding interrupt of External Interrupt Request 0 is executed from the INT0 Interrupt
    Vector.


    Tłumaczenie napisał:
    • Bit 6 - INT0: Zewnętrzne polecenie przerywające 0 Włączone
    Kiedy bit INT0 jest ustawiony (1) i I-bit w statucie rejestrów (SREG) jest ustawiony (1),
    wtedy zewnętrzne wyjście przerywające jest włączone. Czujnik przerwań0 bitów 1/0 (ISC01 i
    ISC00) w generalnym kontrolerze rejestrow procesora określa czy zewnętrzne
    przerwanie jest aktywne na wznoszącym się i/albo opadającym zboczu pinu INT0 lub poziomu czułości. Aktywność
    na tym pinie (INT0) może powodować polecenie przerywające nawet wtedy, gdy INT0 jest skonfigurowany jako wyjście.
    Odpowiadające przerwanie zewnętrznego polecenia przerywającego 0 jest wykonene z INT0 wskazanego przerwania.


    Z tego co wyczytałem to oprócz tego, że bit INT0 musi być ustawiony, to jeszcze jakiś I-bit w SREG - dopiero wówczas INT0, czyli zewnętrzne wyjście przerywające będzie aktywne.

    Poza tym poniżej porzetłumaczyłem też to o czym mówił Samuraj:

    Samuraj napisał:
    Co do zmiennych w rejestrach GICR i MCUCR to nie przepisuj z manulala tylko zapisz wartości w systemie binarnym i odczytaj poszczególne bity (1 ustawiona 0 nie). Poszczególne bity oznaczają odpowiednie rzeczy i tak np w ATmega8 w rejestrze MCUCR bit 0 oznaczony jako ISC00 a bit 1 jako ISC01.
    Odpowiednie ustawienie tych bitów powoduje różne reakcje na przerwanie w tym przypadku INT0.


    Manual ATMega8 napisał:

    Table 32. Interrupt 0 Sense Control

    ISC01 | ISC00 | Description
    _____|_______|__________________________________________________________
    0 | 0 | The low level of INT0 generates an interrupt request.
    0 | 1 | Any logical change on INT0 generates an interrupt request.
    1 | 0 | The falling edge of INT0 generates an interrupt request.
    1 | 1 | The rising edge of INT0 generates an interrupt request.


    Tłumaczenie napisał:

    Tabela 32. Czujnik kontrolujący przerwania (INT0)

    ISC01 | ISC00 | Opis
    ______|_______|__________________________________________________________
    0 | 0 | Niski poziom sygnału INTO powoduje przerwania.
    0 | 1 | Jakakolwiek zmiana stanu logicznego sygnału na INT0 powoduje przerwania..
    1 | 0 | Falujące zbocze sygnału na INT0 powoduje przerwania.
    1 | 1 | Wznoszące się zbocze sygnału na INT0 powoduje przerwania.


    Mimo tego, dalej nie wiem "z czym to się je" i jak te bity ustawić, tak aby mój program cokolwiek zaczął działać......jeśli ktoś pomógł rozszyfrować te ustawianie bitów, byłbym wdzięczny.

    Dodano po 1 [minuty]:

    widzę, że Procekk mnie ubiegł .....:D

    Dodano po 7 [minuty]:

    Procekk......czy ten kod Ci się kompiluje?? bo mi wywala dwa błędy ;|

    WinAVR napisał:
    > "make.exe" all
    avr-gcc -g -Wall -O2 -mmcu=atmega8 -c -o telefon.o telefon.c
    telefon.c:10: error: parse error before "b"
    telefon.c:10: warning: type defaults to `int' in declaration of `b'
    telefon.c:10: warning: data definition has no type or storage class
    telefon.c:13: warning: return type defaults to `int'
    make.exe: *** [telefon.o] Error 1

    > Process Exit Code: 2


    i czy ta pętla while(1) na być pusta ??

    Dodano po 2 [minuty]:

    Procekk napisał:
    a przy diodzie nie ma rezystorka?

    nie ma rezystorka, bo to jest "taka" ciekawa dioda LED :).
  • #25 2884459
    Kubbaz
    Poziom 26  
    Posty: 1237
    Pomógł: 9
    Ocena: 30
    Witam po kilkudniowej przerwie.
    Otóż czas zamknąc temat, ponieważ projekt został zakończony pomyślnie.
    Temat zostanie zamknięty 7.08.2006.

    Mikrokontroler ATMEGA8 zlicza przerwania z tarczy telefonicznej i odpowiednio wyświetla wybierane cyfry na segmentowym wyświetlaczu LED.

    Dla "potomnych" załączam pomoc naukową, którą się posługiwałem przy pisaniu softu do procka "Obsługa przerwań na ATMEGA8 w języku C" - prosto objaśniłem jak używać i jak ustawić dwa ważnych przy przerwaniach rejestrów, bez kopania w manualu - GICR i MCUCR :).

    Dziękuję wszytkim za zainteresowanie i pomoc w tym temacie.
    Pozdrawiam. Kubbaz
    Załączniki:
    • Interrupts Service for ATMEGA8 C Code.pdf (197.83 KB) Musisz być zalogowany, aby pobrać ten załącznik.

Podsumowanie tematu

✨ Dyskusja dotyczyła implementacji funkcji w języku C na mikrokontrolerze AVR (głównie ATmega8) do zliczania przerwań generowanych przez logiczne zera (przerwania na zboczu opadającym) z tarczy telefonicznej. Omówiono konfigurację rejestrów GICR i MCUCR, które odpowiadają za włączenie i ustawienie rodzaju przerwania zewnętrznego INT0. Przedstawiono przykładowy kod obsługi przerwania z wykorzystaniem funkcji SIGNAL(SIG_INTERRUPT0), gdzie w procedurze obsługi przerwania inkrementowana jest zmienna licznikowa. Wyjaśniono znaczenie wartości hexadecymalnych 0x40 (włączenie przerwania INT0 w GICR) oraz 0x01 i 0x02 (ustawienia zbocza w MCUCR). Podkreślono konieczność włączenia globalnych przerwań instrukcją sei(). Dyskutowano również o poprawnym ustawieniu portów (np. DDRB=0xFF dla wyjścia) oraz o interpretacji wartości portów w systemie binarnym (np. 0xFF = 11111111, 0x55 = 01010101). Poruszono kwestie sprzętowe, takie jak podłączenie tarczy telefonicznej do pinu INT0, stosowanie rezystora podciągającego do Vcc oraz kondensatora filtrującego do masy. Wskazano, że stan początkowy tarczy (logiczne 0) nie generuje przerwania, a przerwania liczone są na zboczu opadającym. Ostatecznie projekt zakończono sukcesem – mikrokontroler ATmega8 poprawnie zliczał przerwania z tarczy i sterował wyświetlaczem segmentowym. Załączono także uproszczone wyjaśnienie konfiguracji rejestrów przerwań dla potomnych użytkowników.
Wygenerowane przez model językowy.
REKLAMA