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

[C]atmega + switch = problem z kodem

paveo86 27 Kwi 2010 04:28 4718 24
REKLAMA
  • #1 8007383
    paveo86
    Poziom 10  
    Witam.

    Jestem tutaj nowy, więc witam wszystkich. Od zawsze nurtowały mnie urządzenia elektroniczne i ich zasada działania, ale nigdy nie miałem dość odwagi aby zacząć.....do niedawna.

    Znam podstawy elektroniki i wciąż sie uczę, poznaje także podstawy projektowania uC, lecz mam z tym problem, który wygląda następująco.
    Po przeczytaniu kursu AVRGCC z ''DIODY'', nadal nie mogę dojść do pewnego momentu, czyli do obsługi prostego switcha.

    tutaj jest kawałek kodu, który zapewne większość z WAS wie jak działa (obsługuje nimi narazie LEDy) . Tak więc poprosił bym o wskazówkę (nie mówie tu o gotowcu)
    poprostu kawałek jakiegoś polecenia lub cokolwiek co mogło by mnie naprowadzić na odpowiedz. Otóż nie wiem jak napisać tą częsc kodu, która pozwoli mi na to aby po wcisnięciu jednego z 4 switchy uruchamiała się jakaś sekwencja na LEDach i trwała do momentu wciśnięcia innego switcha i tak w kółko. Poniższy program robi to ale tylko, kiedy przytrzymuje switch, a ja chciał bym go nacisnąc raz i ''ma działać'' do momentu kiedy to zainicjuje kolejny podprogram kolejnym przyciskiem. Proszę naprwadę o pomoc bo myślę nad tym już ze 4 dni ;/ Z góry dziękuje.

     
    
    #include <avr/io.h>
    #include <util/delay.h>
    
    
     int main(void)
    {
    	DDRD = 0xff;
    	DDRC = 0x00;
    	PORTC = 0x03;
    	DDRB = 0x01;
    	while(1)
    	{
    		
    
    
    
    	
    	
    
             if(!(PINC & 0x01))
    
    			{
    
    
    			PORTB = 0xfE;
    
    			PORTD = 0xFE;
    			_delay_ms(300);
    			PORTD = 0xFD;
    			_delay_ms(300);
    			PORTD = 0xFB;
    			_delay_ms(300);
    			PORTD = 0xF7;
    	    	_delay_ms(300);
    			PORTD = 0xEF;
    			_delay_ms(300);
    			PORTD = 0xDF;
    	    	_delay_ms(300);
    	    	PORTD = 0xBF;
    		    _delay_ms(300);
    			PORTD = 0x7F;
    			_delay_ms(300);
    
               }
    
    
    			if(!(PINC & 0x02))
    			{
    
    			PORTD=0xff;
    			_delay_ms(1500);
    					PORTD=0x99;
    					_delay_ms(1500);
    // kolejne switche
    			
    }
    	}
    	}
    
    
    [/code]
  • REKLAMA
  • #2 8007388
    smajlas
    Poziom 12  
    Warunek zostaje spełniony tylko wtedy jeśli przycisk jest wciśnięty, więc wszystko w klamrze zostaje wykonane (ale tylko raz, pod warunkiem wystarczająco krótkiego naciśnięcia przycisku, lub wykonuje się ciągle jak trzymasz przycisk).
    Zrób np tak, że przyciśnięcie przycisku 1 nadaje jakiejś zmiennej, np 'a' wartość 1, naciśnięcie przycisku 2 nadaje jej wartość 2 itd... i teraz w zależności od wartości zmiennej wykonuj sekwencję 1, 2 albo dalej.
    Jesteś początkujący, więc możesz to zrobić za pomocą if, ale w tym przypadku warto poznać instrukcję switch
  • #3 8007651
    tadzik85
    Poziom 38  
    Poza tym funkcja _delay_ms może przyjąć maksymalny argument 262,2/F_CPU
  • REKLAMA
  • #4 8007837
    mirekk36
    Poziom 42  
    tadzik85 napisał:
    Poza tym funkcja delay_ms może przyjąc maksymalny argument 262,2/F_CPU


    tadzik85 już ci w jakimś innym poście zdaje się FreddieChopin zwrócił uwagę, że pleciesz bzdury z tym maksymalnym czasem dla _delay_ms() ---- a ty z uporem ..... dalej to samo. Weź doczytaj chociaż to co ci ludzie tłumaczą oraz sięgnij do pliku delay.h żeby doczytać sobie jak działa _delay_ms() oraz jakie można argumenty podawać i co się z tym wiąże - zamiast wkółko tą samą błędną podpowiedź komuś początkującemu udzielać.
  • #5 8007896
    tmf
    VIP Zasłużony dla elektroda
    tadzik, poza tym masz nieprawdziwe informacje. Z AVR-libc:

    Cytat:
    The maximal possible delay is 262.14 ms / F_CPU in MHz.

    When the user request delay which exceed the maximum possible one, _delay_ms() provides a decreased resolution functionality. In this mode _delay_ms() will work with a resolution of 1/10 ms, providing delays up to 6.5535 seconds (independent from CPU frequency). The user will not be informed about decreased resolution.


    Co do problemu - najlepiej po naciśnięciu przycisku ustawiać tak jak sugerowano jakąś flagę to sygnalizującą. Potem możesz jechać warunkami, ale to średniawy pomysł. Lepiej odpalić timer generujący przerwania o okresie takim jaki trwa najkrótszy krok sekwencji zmiany LEDa. W przerwaniu sprawdzasz czy flaga jest ciągle ustawiona, jeśli tak to sprawdzasz zmienną przechowującą informację na którym kroku sekwencji jesteśmy i realizującą dany krok sekwencji. Jest to trochę wyższa szkoła jazdy, ale warto od początku wyrabiać sobie nawyk myślenia "równoległego".
  • #6 8008643
    utak3r
    Poziom 25  
    Spróbuj w ten deseń (załóżmy, że klawisz (PORTA.B0) aktywny przy zwarciu do masy, dioda na PORTA.B1):

    
    while (...)
    ....
        if (~PORTA.B0) PORTA.B1 = ~PORTA.B1;
    ....
    end
    


    ...czyli: jeśli RA0 zwarte do masy (znaczek ~ oznacza negację, w przypadku zmiennych typu boolean 0 oznacza false) to zmień stan RA1 na odwrotny, niż był.
  • #7 8009448
    paveo86
    Poziom 10  
    utak3r - tak, owszem to zadziała i nawet wygląda jak przepisanie pinu A0 do A1. Robiłem tak i działa, kolejne wciskanie switchy zapala kolejne diody do momentu wcisnięcia kolejnego sw. Natomiast nie wykonam tym jakiejś ''całej procedury'' typu biegające światełko itd.

    Pomysły smajlas i tmf są przyznam naprawdę dobre, chodź w podpowiedzi tmf widzę że tak powiem ''czarną magię''.....jeszcze, chodź to kwestia czasu.
    Wróce wieczorkiem to pokombinuje coś ze zmiennymi jak radzi smajlas :)

    a co do _delay_ms() ...to wstyd się przyznać ale także nie wiem ile wynosi max czas delay (czyżby 6.5535 sekundy ? ) Wrócę to poszukam informacji o delay i zapewne postawie kolejne pytanie, chodź będe sie starał nie zawracać głowy byle czym. Dzięki WAM
  • #8 8010083
    utak3r
    Poziom 25  
    paveo86 napisał:
    chodź w podpowiedzi tmf widzę że tak powiem ''czarną magię''.....jeszcze, chodź to kwestia czasu.


    Aby zrealizować ten pomysł, poczytaj najpierw, jak odpalać timer i przerwania. W sumie to tylko brzmi groźnie, a trudne wcale nie jest.

    Wtedy robisz tak: w głównej pętli programu (while) po naciśnięciu guzika zmieniasz stan jakiejś zmiennej (np. bWlaczEfekt = 1). Natomiast funkcja obsługująca przerwanie, która jest odpalana co zadany czas automatycznie, sprawdza stan tej właśnie zmiennej. Prosty warunek "if" i heja :)

    Także, do lektury o timerach zapraszam :)
  • #9 8010155
    paveo86
    Poziom 10  
    utka3r --- Jak Ty mi to ładnie napisałęś :D ...aż chęci nabrałem, ox wnikam do sieci aby coś w końcu utworzyć. Przyznam że C jest wiele trudniejszy niż bascom ;/
  • #10 8010316
    mirekk36
    Poziom 42  
    paveo86 napisał:
    Przyznam że C jest wiele trudniejszy niż bascom ;/


    Źle mówisz dobry człowieku ;) ..... właśnie, że C jest o wiele łatwiejszy i daje dużo więcej możliwości, tyle że niestety brak jak do tej pory na rynku dobrej książki z kursem C od podstaw. Tw wszystkie kursy w necie, które traktują temat bardzo wybiórczo są niestety mocno ograniczone i nie pozwalają w pełni ocenić możliwości i jakości tego języka programowania.

    A do Bascoma masz po prostu tysiąc książek ;)
  • #11 8010749
    paveo86
    Poziom 10  
    mirekk36 - święta RACJA ! Rzeczywiście powodem są kursy które bywają zapewne mocno ograniczone i mało ''dokładnych'' opisów jest w sieci.

    Co do instrukcji ''switch'' udało mi się zmajstrować coś takiego (i przyznam że nie zwracając uwagi na drgania styków, program chodzi tak, jak chciałem):
    
    int main(void)
    {
    
    	 unsigned char x;
    
    
    	DDRD = 0xff;
    	DDRC = 0x00;
    	PORTC = 0x07;
    	DDRB = 0x01;
    	while(1)
    	{
    
    
    
             if(!(PINC & 0x01)) x=1;
             if(!(PINC & 0x02)) x=2;
             if(!(PINC & 0x04)) x=3;
    
    
             switch(x)
    
             {
             case 1:
    
    
            	 			PORTD = 0xFE;
            	 			_delay_ms(300);
            	 			PORTD = 0xFD;
            	 			_delay_ms(300);
            	 			PORTD = 0xFB;
            	 			_delay_ms(300);
            	 			PORTD = 0xF7;
            	 	    	_delay_ms(300);
            	 			PORTD = 0xEF;
            	 			_delay_ms(300);
            	 		
    
    
    
    
           break;
    
    
             case 2:
    
    
               	 			PORTD = 0xf7;
               	 			_delay_ms(300);
               	 			PORTD = 0x7F;
               	 			_delay_ms(300);
               	 			PORTD = 0xFE;
               	 			_delay_ms(300);
               	 			PORTD = 0xF0;
               	 	    	_delay_ms(300);
               	 		
    
             case 3:
    
    
               	 		  PORTD = 0x0a;
               	 			_delay_ms(300);
               	 			PORTD = 0x01;
               	 			_delay_ms(300);
               	 			PORTD = 0x20;
               	 			_delay_ms(300);
               	 			PORTD = 0x04;
               	 	    	_delay_ms(300);
               	 			
    
    
    
    
              break;
    
    
    
    
               }
    	}
    }
    
    


    Czy mógł by ktoś podpowiedzieć, jak zamiast pisać bez ustanku PORTD = 0x04, _delay_ms itd skrócić kod do prostrzej postaci, jak np przesuwanie bitu PORTD <<1 i przesuwa za każdym razem np. w 2 bity w lewo, za każdym razem czekając jakiś odcinek czasu, po czym wraca do początku ??
  • REKLAMA
  • #12 8011439
    smajlas
    Poziom 12  
    Nie wiem, czy w pełni zrozumiałem, ale widzę, że lubisz samodzielnie rozwiązywać problemy i myślisz. Więc tym razem propozycja: użyj pętli.
    
    char i; //zmienna licznikowa
    PORTB=0x01;
    for(i=0;i<8;++i)
    	{
    	waitms (250);
    	waitms (250);
    	PORTB<<=0x01;
    	
    	}
    

    W tym przypadku było to tzw "biegające światełko" - 8 diod podłączonych do kolejnych pinów portu B.
    Opis pętli znajdziesz w każdym kursie :)

    A propos kursów C:
    jeden z tzw "user friendly" kursów: Tutaj
  • Pomocny post
    #13 8012154
    tmf
    VIP Zasłużony dla elektroda
    Ja się z Mirkiem nie zgodzę, książek o C są tysiące. Oczywiście nie po Polsku. Podstawowy błąd jaki ludzie popełniają to założenie, że C na mikrokontrolery jest jakieś inne niż C na komputery. Nic bardziej mylnego. Zresztą dobrym przykładem jest ten wątek. Przecież gdyby autor chciał coś takiego zrobić na PC, tylko zamiast diod zrobić kolorowe kropki na ekranie, a mechaniczne switche zamienić na klikalne przyciski to rozwiązanie byłoby dokładnie takie samo! Raptem trzeba by wymienić z 5 linii kodu. A wiem co piszę, bo mam aplikację na AVR, która żywcem kompiluje się i działa na PC - jedyne, co musiałem zmienić to parę linijek w klasie odpowiedzialnej za wyświetlanie czegoś na LCD.
    Wracając do meritum - program, który pokazałeś jest fajny, ale IMHO ma poważną wadę - klawisze są blokowane na cały czas trwania sekwencji. Przy dłuższych sekwencjach to może być upiorne, bo będzie trzeba długo naciskać klawisz.
    Ja widziałbym rozwiązanie tak - określasz czas trwania najkrótszego kroku sekwencji. Odpalasz timer, tak, żeby co tak określony czas generował przerwanie. W pętli głównej, albo w przerwaniu sprawdzasz jaki klawisz jest naciśnięty. W zależności od tego zmieniasz flagę. Jeśli zmienił się wciśnięty klawisz to dodatkowo zerujesz dodatkową zmienna - numer_kroku. Jedziesz dalej z obsługa przerwania - sprawdzasz nr kroku i z tablicy ładujesz np. adres funkcji realizującej dany krok. Zwiększasz numer_kroku. Kończysz przerwanie. W ten sposób main masz puste, nic ci nie zamraża wykonywania programu (brak funkcji delay), procesor się nudzi i ma czas na realizowanie czegoś innego, albo idzie spać, a ty piszesz na swoim urządzeniu, że jest ekologiczne i redukuje ileśtam ton CO2 wyemitowanego do atmosfery.
  • #14 8017067
    paveo86
    Poziom 10  
    smajlas - Twoja podpowiedź działa ale nadal są jakieś problemy z czasem wciskania sw ;/ Postanowiłem więc poczytać nieco o timerach. Z tego co napisał TMF dobre rady ale jestem początkujący i tu jest problem ;/ jeśli dobrze rozumiem:

    1.Określam czas najkrótszej sekwencji (np.u mnie najkrótsza sekwencja zmiany stanu LED wynosi 100ms) czyli co 100ms mam spawdzać któy sw jest wciśnięty, czy to o to chodzi ?
    2.odpalam timer0 czo czas ustalony powyzej, aby generował przerwanie ?
    3.w przerwaniu lub w pętli głównej sprawdzam który przycisk jest wciśnięty
    4. jeśli jest to PINx to zmieniam flage na xx i zeruje zmienną ustaloną wcześniej ?
    5.sprawdzam numer kroku i z tablicy odczytuje adres funkcji realizującej daną sekwencje LED ? - tego nie rozumiem dokładnie
    6.zwiększam numer kroku
    7. następuje koniec przerwania

    Częśc z tych rzeczy nie rozumiem jeszcze, ale ostro czytam.

    edit:

    zmieniam nieco post bo po dokładniejszym wniknięciu w timery stwierdziłem że ten kawałek kodu był kretyński.

    edit:
    Dzięki Tmf. OK doszedłem do tego jak obsłużyć przerwanie z timera.
    Teraz inna bajka, powiedzcie mi tylko czy dobrze rozumiem, bo nie mogłem znaleść kawałka kodu na którym mógłbym się oprzeć. A więc tak:
    Chcę aby po przytrzymaniu SW Ledy obracały się coraz szybciej a więc, ustawiam sobie jakąs dodatkową zmienną p, i w pętli pisze że, jeśli SW1 wciśnięty, po każdym przekęceniu licznika zmienna p zwiększa się o 1 (p++) i zwraca nową wartość. Po minięciu np 30 takich okresów p>=30, p=0, Potem instrukcją switch załatwiam co ma robić jeżeli p=1 p=2 itd.... Czy dobrze myślę ? (Chodzi mi o zmienną prędkości, a więc myślę że trzeba tu wykorzystać zmianę jakiejś częstotliwości ?). I co zrobić aby nie używać delay tylko wykonać opóźnienie w pętli jakimś sposobem. może ktoś ma jakiś przykładowy kawałek kodu, niekoniecznie do LED ? Jest na elektrodzie kogut który po przytrzymaniu SW swiększa częstotliwość, ale nie ma ni kawałka kodu ;/
  • Pomocny post
    #15 8034560
    tmf
    VIP Zasłużony dla elektroda
    Skoro już używasz timera, to zrób to na timerze :) Najprościej tak, że ustawiasz timer w tryb CTC, procedura obsługi przerwania działa tak jak to wcześniej opisałem. Jeśli chcesz uzyskać przyśpieszenie po przytrzymaniu klawisza to zmieniasz tylko wartość rejestru porównania w trybie CTC na mniejsza, w efekcie kolejne przerwania będą przychodzić szybciej, czyli kolejne kroki sekwencji też się skrócą.
  • #16 8036139
    paveo86
    Poziom 10  
    Wielkie dzięki tmf, o to właśnie mi chodziło :) Resztę postaram się jakoś obczaić sam....
  • #17 8039223
    loks
    Poziom 12  
    To ja się podłącze pod post z przyciskiem:)
    Nurtuje mnie jedna rzecz, a mianowicie podłączenie przycisku do portu uP. Lepszym rozwiązaniem jest podłączenie przycisku z jednej strony do portu uP, a z drugiej strony do masy GND, czy do zasilania Vcc?
    Ja mam podłączony przycisk do zasilania i niestety on nie działa. Ani razu uP na wejściu portu nie zauważył, że jest stan wysoki. W czym jest problem?
    Dodam, że zależy mi na tym, aby przycisk był obsługiwany nie z portu w którym jest możliwość obsługi zewnętrznych przerwań. Korzystam z up atmega 8.
    Poniżej przedstawiam schemat podłączenia przycisków SW1, SW2, SW3, SW4, SW5.

    [C]atmega + switch = problem z kodem

    Jakieś pomysły?
    Dzięki.
    Pozdr,
    Łukasz.
  • #18 8040042
    tmf
    VIP Zasłużony dla elektroda
    A co polaryzuje pin IO kiedy przycisk jest rozwarty? Nic. Musisz dodać rezystor ściągający do masy. Stąd też częściej daje się przycisk między masę a port, bo można wykorzystać wewnętrznego pull upa. Chyba, że ktoś się bawi XMega - tam są też rezystory pull down.
  • #19 8040537
    loks
    Poziom 12  
    Łatwiej będzie mi podłączyć masę GND zamiast Vcc i podciągnąć port uP software'owo do Vcc przez rezystor pull-up.
    Tak z ciekawości, to jaka powinna być wartość rezystora zwierającego do masy?
    Pull-up to 4,7 kohm.
    Dzięki za pomoc.
    Pozdr,
    Łukasz.
  • #20 8041491
    tmf
    VIP Zasłużony dla elektroda
    Dokładnie taka sama. Wartość tej rezystancji jest bez większego znaczenia. Jeśli wykorzystasz wewnętrzne pull upy to pamiętaj, że one mają ok. 50kOm, w środowiskach o większych zakłóceniach to może być zbyt wiele.
  • REKLAMA
  • #21 8044534
    loks
    Poziom 12  
    Podłączyłem port PD5 do masy przez rezystor 4,7. Do portu PD5 podłączony jest SW1. Niestety nadal procesor nie widzi zmiany na wejściu portu.
    Może coś z programem jest nie tak.
    Poniżej listing:

    
     .include "m8def.inc"
    
     ;wektory przerwan
      .org $000	
      				rjmp reset
      
    ;************************************************************
     reset:  
     ldi	r16,high(RAMEND)		; Set Stack Pointer to top of RAM
     out	SPH,r16
     ldi	r16,low(RAMEND)			; ustawienie stosu
     out	SPL,r16
    ;************************************************************
     cli
     rcall Set_port_C		; inicjalizacja portu B
     sei				; set global interrupt enable
     clr r18			; licznik 1 - zapal, 2 zgas diody
     clr r1				; licznik impulsow SW1
     clr r2				; licznik cykli programu, kiedy nie nacisnieto SW1
     clr r3				; licznik wszystkich cykli w f-cji Zliczanie_impulsow
     Start:
     rcall Zliczanie_impulsow
     rcall Decyzja_SW1
     rjmp Start
    ;************************************************************
     Set_port_C:
     ; Define pull-ups and set outputs high
     ldi r16,(0<<PC5)|(1<<PC4)|(1<<PC3)|(1<<PC2)|(1<<PC1)|(1<<PC0)
     ; Define directions for port pins
     ldi r17,(0<<DDC5)|(1<<DDC4)|(1<<DDC3)|(1<<DDC2)|(1<<DDC1)|(1<<DDC0) 
     out PORTC,r16
     out DDRC,r17
     ; Insert nop for synchronization
     nop
     ret
    ;************************************************************
     Zapal_5_diod:
     ldi r16, 0x00
     out PORTC, r16
     nop
     ret
    ;************************************************************
     Zgas_diody:
     ldi r16, 0xFF
     out PORTC, r16
     nop
     clr r18					; zeruj licznik, po zgaszeniu diod
     ret
    ;************************************************************
     Zabawa_diodami:
     in r16, SREG
     push r16
     inc r18
     cpi r18, 0x01				; jezeli licznik=1 zapal diody
     brne Zgas					; jezeli licznik=2 zgas diody
     rcall Zapal_5_diod
     rjmp Koniec
     Zgas:
     rcall Zgas_diody
     Koniec:
     pop r16
     out SREG, r16
     ret
    ;************************************************************
     Zliczanie_impulsow:
     in r16, SREG
     push r16
     inc r3
     in r16, PORTC				; wczytanie stanu portów C do r16
     andi r16, 0x20				; zalozenie maski - na PORT PD5
     cpi r16, 0x20				; sprawdzenie, czy wcisnieto SW1 - czy = 1
     brne koniec9
     inc r1
     rjmp koniec8
     koniec9:
     inc r2
     koniec8:
     pop r16
     out SREG, r16
     ret
    ;************************************************************
     Decyzja_SW1:
     in r16, SREG
     push r16
     ldi r16, 0x47				; decyzja czy nacisnieto SW1 po 71 impulsach
     cp r3, r16 				; 0x47 = 71 (71 impulsow)
     brne koniec7
     cp r1, r2
     brlo koniec6				; decyzja - nie wcisnieto SW1
     rcall Zapal_5_diod			; decyzja - wcisnieto SW1 zapalenie diod
     ;rcall Zabawa_
    diodami		; decyzja - wcisnieto SW1
     nop
     koniec6:
     clr r1
     clr r2
     clr r3
     koniec7:
     pop r16
     out SREG, r16
     ret
    ;************************************************************
    
    


    Może wydłużyć czas próbkowania z 71(0x470 na 255 (0xFF)?Nie mam pomysłu jak zrobić obsługę SW1, aby działała.
    Pozdr,
    Łukasz.
  • #22 8044606
    tmf
    VIP Zasłużony dla elektroda
    Piszesz, że swiotch jest podłączony pod PD5, a inicjujesz PORTC? Druga rzecz - jak czytasz stan portu to czytaj z PINx a nie PORTx - w PORTx jest to co tam wpisałeś.
  • #23 8045462
    loks
    Poziom 12  
    Chodziło mi o port PC5 - PD5 to literówka;) A co do drugiej uwagi to bardzo trafna:)
    Przyznam się, że nie doczytałem.
    Wielkie dzięki.
    Pozdr,
    Łukasz.
  • #24 8125661
    paveo86
    Poziom 10  
    Witam po małej przerwie.
    Mam znów kilka pytań, ale proszę o wyrozumiałość, bo naprawdę dopiero zaczynam z u-kontrolerami.
    A więc tak, zrobiłem jak radziliście, niestety nie potrafie jeszcze pojąć w pełni timerów, chodź umiem już je ustawiać aby odliczały jakiś tam ''kwant'' czasu.
    Przeglądam forum i widzę tutaj jeszcze dziwniejsze dla mnie rzeczy, mianowicie nie potrafię pojąć analogii działania kilku timerów na raz, a więc nasówają mi się takie pytania:

    1. Każdy timer może działać niezależnie od siebie, nie zakłócając sie wzajemnie, chyba że sobie tego zarządam programowo, aby jeden timer oddziaływał w jakis sposób na drugi, czy tak ?

    2. Jak wygląda skok do jakiegoś podprogramu ? np chciał bym aby jakis program do obsługi czegokolwiek, np LED wykonywał sie bez przerwy do momentu kiedy zostanie wykryte nacisnięcie np innego przycisku i program wczesnieszy sie wyłączył a kolejny uruchomił. Musi być jakaś zasada prawda. Nie mogę do tego dojść, ponieważ mój program działa tak że dioda miga tylko przez jeden takt lub jedno opóźnienie, albo miga tylko kiedy trzymam przycisk, luuuub też zacznie migać i program na wciskanie następnych przycisków już nie odpowiada

    3. Jeśli np dla przycisku ustawię flagę która po wykryciu wcisnięcia ma zmienić swoją wartość, to czy po naciśnięciu kolejnego przycisku, muszę tą flage wyzerować ręcznie aby wcześniejszy program przestał działać tak ?

    Czy mógł by ktoś napisać kawałek takiego blokowego programu w C ? Będe wdzięczny. Bo nie wiem czy te podprogramy (czyli jakieś tam określone sekwencje działąnia na portach) mają być wszystkie we funkcji main ( a potem jest jakieś polecenie powodujące skok do mojej funkcji), czy w pętli while.

    4. Czy za pomoca jednego timera, który odlicza mi 20ms, mogę jednoczesnie skanować klawiature, wykorzystując to 20 ms jako funkcja czasu do migania diodami czy załaczania jakiegoś przekaźnika na dany okres czasu, i ogólnie czy to sie nie bedzie gryzło ze sobą ?
    Czy nie powinienem np okreslić czas tykania timera co np 20 ms i zapisać go do jakiejś zmiennej, a potem tą zmienną mogę zwiększać jak tylko chcę ?

    5. Nie potrafie tego sobie wyobrazić, wcześniej mój program wyglądał tak:

    
    PORTD = 0xEF;
    _delay_ms(300);
    PORTD = 0x09;
    _delay_ms(300); //<-- co wpisac w takim wypadku zamiast delay
    ....
    ...
    ... //gdzie umieścic tą sekwencje aby moza było ją uruchamiac w dowolnej chwili w programie
    ....
    .....itd
    


    chodzi mi o to samo tylko zamiast delay (które jak przeczytąłem potrafi opóźnic albo raczej zamrożić na czas jego trawania resztę programu), użyc właśnie licznika, który odliczy ileś tam (ms) a potem zmienna ten czas bedzie sobie zwiększała lub zmniejszała, czy dobrze myslę ?

    aha i ostanie pytanie ważne bardzo, przy wpisywaniu ISR(TIMER0_COMP_vect)
    podkreśla mi błąd, tak jakby eklips nie znał takich poleceń. Można napisąc to w inny sposób ?

    mam nadzieje ze nie zamotałem aż tak, ale nie potrafię dojść do ładu ;/ .....pomóżcie

    Dodam później kawałek mojego ''śmiesznego'' kodu, aby mógł ktoś ogarnąć jakie babole w nim występują że program nie chce działać tak jak bym sobie życzył ;/
  • Pomocny post
    #25 8127748
    janbernat
    Poziom 38  
    1.Każdy Timer działa niezależnie- to jest licznik sprzętowy działający jak zewnętrzny układ.
    To że został "wsadzony" w układ scalony OBOK procesora to tylko żeby użytkownikom było wygodniej.
    Dlatego nazywa się to "układem peryferyjnym", peryferiami itp.
    Takich "układów peryferyjnych" w mikroprocesorach jest dużo.
    Nie tylko liczniki ale też przetworniki ADC, RS i sporo innych.
    Większość z nich generuje jakieś przerwania.
    Dla avrgcc opis jest tu:
    http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
    Aby z nich skorzystać należy dopisać do programu:
    
    #include <avr/interrupt.h>
    

    3.flagę zeruje się czasem ręcznie, czasem robi to funkcja- w C nie ma chyba podprogramów- a czasem obsługa jakiegoś przerwania sama kasuje flagę.
    4.Można i nic się nie pogryzie.
    5.Stosowanie _delay() powinno być karalne.
    Procesor nic nie robi- tylko liczy pustą pętlę.
    Chyba nie blokuje przerwań- nie wiem jak to jest w avrgcc.
REKLAMA