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

[attiny45][C/AVRgcc] Przerwanie z tact switcha - debouncing

overheat 25 Sty 2011 02:34 3774 22
  • #1 9053280
    overheat
    Poziom 9  
    Witam! (Dobry wieczór?)

    Przeczesałem "cały internet" i znalazłem wiele rozwiązań mojego problemu, ale żadne spośród tych, które zastosowałem nie przyniosło oczekiwanych rezultatów. A problem - może się wydawać - jest banalny, gdyż chodzi o obsługę zewnętrznego przerwania ze zwykłego tact switcha.

    Mikrokontroler steruje za pomocą PWM jasnością diody. PWM działa (lub jak kto woli: "gro i burcy") i to nie jest tematem tego wątku. Przyciskanie switcha powoduje przejście w kolejne tryby jasności (różne wypełnienie PWM) oraz wyłączenie diody.

    Zastosowałem sprzętową filtrację zakłóceń ze switcha. Problem polega na tym, że gdy nie zastosuję kondensatora (schemat), zachodzi debouncing, a przerwanie jest wywoływane wiele razy. Gdy go zastosuję, uC reaguje przerwaniem na co 10-te wciśnięcie switcha.
    [attiny45][C/AVRgcc] Przerwanie z tact switcha - debouncing

    - Czy konfiguracja obwodów jest poprawna?
    - Jak dobrać wartości rezystora oraz kondensatora?
    - Czy zastosować programowy debouncing? Jak powinien wyglądać poprawny kod?
    - Jak w ogóle (z zachowaniem elektronicznego ZEN) podłączyć i obsłużyć zwykły switch w C?

    Poniżej zamieszczam kod źródłowy programu. Jest do bólu prosty. Zwracam się z prośbą do forumowiczów o garść porad dla początkującego ;-)

    Dzięki!
    #include <avr/io.h>
    #include <avr/sleep.h>
    #include <avr/interrupt.h>
    #include <util/delay.h>
    
    #define set_pwm(value) OCR1B=value 
    
    volatile unsigned int pwm = 0;
    
    void start_pwm(void){
        /* use PWM B on timer 1 (8-bit PWM) */
        GTCCR = _BV(PWM1B) | _BV(COM1B1);
        
        /* start timer 1 */
        TCCR1 = _BV(CS10);
    
        /* Set PWM value to 230 */
        set_pwm(250);
    
        /* Enable OC1B (PB4) as output and set to low. */
        DDRB |= _BV(DDB4);
        PORTB &= ~(_BV(PORTB4));
    
        /* Enable Timer1 Interrupt for system_timer update */
        TIMSK = _BV(TOIE1);
    
    }
    
    void stop_pwm(void){
        // disable Timer1 overflow
        TIMSK &= ~(_BV(TOIE1));
        // disable PWM output and stop PLL
        GTCCR = 0;
    }
    
    void switch_mode(void) {
    	start_pwm();
    	if(pwm==0) {
    		set_pwm(80);
    	}
    	else if (pwm==1) {
    		set_pwm(250);
    	}
    	else if (pwm==2) {
    		stop_pwm();
    	}
    	
    	if(++pwm == 3)
    		pwm = 0;
    	_delay_ms(500);
    }
    
    ISR(INT0_vect)
    {
    	switch_mode();
    }
    
    
    int main (void)
    {
    	DDRB 	&= 	~_BV(PB2); 					//PB2 as input
    
    	MCUCR 	|=  _BV(ISC00) | _BV(ISC01); 	//rising edge int0
    	GIMSK 	|= 	_BV(INT0);  				//enable int0
    
    	start_pwm();
    	sei();
    
    	for(;;) {
    	}
        return (0);
    }
    
  • #2 9053301
    zumek
    Poziom 39  
    overheat napisał:
    ...Przeczesałem "cały internet" i ...

    ...niepotrzebnie. A wystarczyło dokładniej przestudiować budowę portu w dokumentacji swojego uC, by dowiedzieć się, że w takiej konfiguracji jaką masz, to pin PB2/INT0 wisi sobie w powietrzu (HiZ). Jak wciśniesz przycisk i kondensator jest rozładowany, to masz jedno zbocze 'rising', a po puszczeniu przycisku i jego ponownym wciśnięciu nic się nie dzieje, bo kondensator nie ma się jak rozładować.
    Zajrzyj do dokumentacji i przemyśl jeszcze raz swój projekt.
  • #4 9056236
    overheat
    Poziom 9  
    OK. Przy odrobinie pracy rozwiązałem problem i debouncing działa przez software. Dzięki ogromne!

    Powstał za to nowy problem: PWM steruje diodą mocy. Dioda podłączona jest przez tranzystor BC337. Niestety nawet przy 0 w rejestrze OCR0B dioda świeci daleko od swojej nominalnej jasność (czyli takiej, jakby podłączyć ją klasycznie przez rezystor do VCC). Gdzie tkwi szkopuł, który umożliwi rozhulania światła na maksimum?

    Załączam kod:
    #include <avr/io.h>
    #include <avr/sleep.h>
    #include <avr/interrupt.h>
    #include <util/delay.h>
    
    #define set_pwm(value) OCR0B=value 
    
    void start_pwm(void){
    
    	TCCR0A 	|=	_BV(WGM01) | _BV(WGM00);
    	TCCR0A 	|=	_BV(COM0B1) | _BV(COM0B0);
    	TCCR0B 	|= 	_BV(CS00);
    
    	DDRB 	|= 	_BV(PB1);
    	PORTB 	&= 	~_BV(PB1);
    	set_pwm(254);
    }
    
    void switch_mode(void) {
    	static int pwm = 0;
    	if(pwm==0) {
    		set_pwm(190);
    	}
    	else if (pwm==1) {
    		set_pwm(0);
    	}
    	else if (pwm==2) {
    		set_pwm(254);
    	}
    	
    	if(++pwm == 3)
    		pwm = 0;
    	_delay_ms(100);
    }
    
    ISR(INT0_vect)
    {
    	cli();
    	uint16_t a = 0;
    	uint16_t count = 0;
    	for(a=0; a<500; a++)
    		if (bit_is_clear(PINB, 2))
    			count++;
    
    	if(count>=150)
    		switch_mode();
    	sei();
    }
    
    
    int main (void)
    {
    	DDRB 	&= 	~_BV(PB2); 					//PB2 as input
    	PORTB 	|= 	_BV(PB2); 					//PB2 pullup
    
    	MCUCR 	|=  _BV(ISC01); 				//falling edge int0
    	GIMSK 	|= 	_BV(INT0);  				//enable int0
    
    	start_pwm();
    	sei();
    
    	for(;;) {
    	}
        return (0);
    }
    
    
    
    
  • #5 9056633
    dondu
    Moderator na urlopie...
    Tak na szybko to podłącz diodę odwrotnie (tzn przez rezystor do Vcc) i zapalaj zerem na wyjściu. Chodzi o to, że wtedy będzie płynął przez nią większy prąd, bo taka jest charakterystyka wyjść procesora.

    programu nie sprawdzałem.

    Dodano po 2 [minuty]:

    Nie doczytałem że przez tranzystor ją puszczasz .... hmmm.
  • #6 9056678
    overheat
    Poziom 9  
    Może dlatego że steruję nią prądowo, powinienem dostarczyć jej większe napięcie?
  • #7 9056808
    janbernat
    Poziom 38  
    Może być parę spraw.
    Jaka częstotliwość oscylatora?
    Bo przy dość dużej trzeba dać równolegle do opornika idącego z procesora do bazy tranzystora kondensator 10-100nF.
    No a LED zawsze się steruje prądowo- a nie napięciem.
  • #8 9057055
    overheat
    Poziom 9  
    1MHz. Bez preskalera. Zastanawia mnie natomiast to, dlaczego przy timerze clk/256 dioda zaczyna bardzo wyraźnie ("stroboskopowo") mrugać. 1/256 MHz to prawie 4kHz, czyli nie powinno być widać migania. Czegoś nie rozumiem?

    Kondensator nic nie zmienił.
  • #10 9057113
    overheat
    Poziom 9  
    dondu napisał:
    A jak masz ustawiony timer - rzuć kodem.
    Cytat:

    #define set_pwm(value) OCR0B=value

    void start_pwm(void){

    TCCR0A |= _BV(WGM01) | _BV(WGM00);
    TCCR0A |= _BV(COM0B1) | _BV(COM0B0);
    TCCR0B |= _BV(CS00);

    DDRB |= _BV(PB1);
    PORTB &= ~_BV(PB1);
    set_pwm(254);
    }
    Wszystko jest też powyżej. Doczytałem też (https://www.elektroda.pl/rtvforum/topic1471227.html), że do sterowania diodą mocy potrzebny jest MOSFET. Czy to może być źródło problemu?
  • #11 9057328
    dondu
    Moderator na urlopie...
    Co do diody to Ci nie podpowiem, bo nie używałem takiej, ale jeżeli znalazłeś, że MOSFET to pewnie tak. Możesz jeszcze spróbować układu Darlingtona na 2 tranzystorach.

    Drobna uwaga dot. cli() i sei() - w funkcji przerwania nie musisz ich podawać, bo są one odpowiednio automatycznie wykonywane na początku i na końcu funkcji.

    Jaką masz ustawioną w kompilatorze wartość kwarcu bo w kodzie nie widzę?
  • #12 9057356
    overheat
    Poziom 9  
    1000000 (1MHz) [8MHz z flagą CKDIV8]. Spróbuję ten układ zmontować.

    // edit: Układ Darlingtona rozwiązał sprawę ;-)
  • #13 9057462
    Konto nie istnieje
    Poziom 1  
  • #14 9057471
    overheat
    Poziom 9  
    Przycisk poprawiony i działa bardzo dobrze. Dzięki za pomoc!
  • #15 9060472
    dondu
    Moderator na urlopie...
    jeszcze jedna uwaga do kodu:

    ISR(INT0_vect) 
    { 
    ...
       for(a=0; a<500; a++) 
          if (bit_is_clear(PINB, 2)) 
             count++; 
    
       if(count>=150) 
          switch_mode(); 
    ...
    } 


    Poradziłeś sobie z drganiami przycisku, ale na przyszłość wystrzegaj się czekania w przerwaniu, gdyż stopujesz cały mikrokontroler na ten czas.

    Raczej zastosuj inne przerwanie wywoływane następnym timerem np. 50 razy na sekundę i tam odliczaj ilość ms do ustabilizowania przycisku.
  • #17 9062039
    overheat
    Poziom 9  
    OK. Switch rozwiązany. Mam natomiast o wiele większy problem:

    Attiny45 steruje przez tranzystor (układ Darlingtona) diodą mocy (3W, do ~300mA). Chcę zasilić cały układ. Skonstruowałem (rysunek) na układach LM317 stabilizator napięcia oraz prądu.
    [attiny45][C/AVRgcc] Przerwanie z tact switcha - debouncing

    Rysunek pierwszy: Okazuje się że w zależności czy dioda jest włączona, bądź wyłączona, napięcie w układzie waha się od ~3 do 6V. Druga sprawa jest taka, że dioda świeci bardzo słabo. Prąd który przez nią płynie jest rzędu max. 150mA (50% mocy). Nawet jeśli zrezygnuję ze stabilizatora natężenia, to stabilizator napięcia ogranicza mi prąd wpływający do układu.

    Rysunek drugi: Nie jest to problem sterowania przez uC, gdyż dioda podłączona bezpośrednio do stabilizatorów również słabo świeci.

    Jak jednocześnie uzyskać w układzie stabilne ~3.5V (bez wahań przy diodzie włączonej/wyłączonej - dla poprawnej pracy uC) oraz prąd rzędu 300-320mA na diodzie (ale nie więcej, aby jej nie spalić)?

    Powinienem zupełnie osobno zasilić uC przez układ stabilizujący napięcie, a osobno diodę stabilizatorem natężenia? Czy wówczas tranzystor pomiędzy takimi dwoma "subobwodami" będzie mógł działać jak switch?


    // edit: na rysunkach pominąłem wiele elementów (żeby nie zaciemniać) jak np. kondensatory-odszumiacze, rezystor przy tranzystorze, etc.
  • #18 9062085
    janbernat
    Poziom 38  
    Na pewno zasilić oddzielnie procesor- napięciem stabilizowanym.
    LM317 ma ogranicznik termiczny- więcej nie pozwoli.
    P.S.
    LED w kolektorze z opornikiem ograniczającym prąd.
    Bo zobacz- spdek napięcia na złączu 0.6V albo na darlingtonie ze 2V.
    Na LED- jeszcze 2.5-3V.
    To jak ten biedny procesor zasilany z 5V ma to wysterować?
  • #19 9062529
    overheat
    Poziom 9  
    janbernat napisał:
    Na pewno zasilić oddzielnie procesor- napięciem stabilizowanym.
    LM317 ma ogranicznik termiczny- więcej nie pozwoli.
    P.S.
    LED w kolektorze z opornikiem ograniczającym prąd.
    Bo zobacz- spdek napięcia na złączu 0.6V albo na darlingtonie ze 2V.
    Na LED- jeszcze 2.5-3V.
    To jak ten biedny procesor zasilany z 5V ma to wysterować?
    Na ten moment układ wygląda następująco:
    [attiny45][C/AVRgcc] Przerwanie z tact switcha - debouncing
    Jednak gdy go włączyłem jeszcze bez diody D1, to mało co uC nie wyparował (sic!). Rozumiem, że duży prąd "produkowany" przez górny LM317 wdarł się do układu z uC? Czy powinienem również dać diodę ograniczającą "cofanie się" prądu przy GND uC przed kolejną próbą? Co zrobić wówczas z tact-sitchem? To miałeś na myśli?
  • #20 9065162
    janbernat
    Poziom 38  
    Skąd Ty bierzesz takie schematy?
    Co robi dioda przy IC1?
    Po co Ci źródło prądowe (IC2) do zasilania LED?
    Podłącz IC1 zgodnie z notą katalogową, ustaw 5V i dopiero wkładaj procesor.
    Wyrzuć IC2 i zamiast tego wstaw rezystor o wartości (Uzas-Uled)/Iled.
    Między bazę a masę tranzystora wstaw opornik 10-100k na wszelki wypadek.
  • #21 9067201
    Fredy
    Poziom 27  
    Dioda D1 spowoduje tylko to że napięcie będzie zależeć od temperatury. Wywal ją koniecznie i tak jak pisze mój przedmówca - zanim włożysz procek ustaw niepiecie 5V na procek. Drugi układ pełni funkcję ogranicznika prądu maksymalnego.Rezystorem R3 będziesz ustawiać prąd max według zależności Imax=1.25/R3.
    No i koniecznie dodaj drugi tranzystor aby zrobić Darlingtona albo musisz zastosować tranzystor o b.dużej becie. Musisz ustalić włąściwą wartość rezystora bazowego ( nie może być on zbyt dużej wartości - szacunkowo R=Idiody/ beta tranzystora.
    Znacznie lepiej byłoby przerobić ten układ na sterowanie tranzystorem PNP. Wtedy procek by zwierał bazę do masy , a w takiej konfiguracji procek może sterować większym prądem.
  • #22 9067239
    overheat
    Poziom 9  
    Faktycznie. Macie rację - poprawiłem układ w/g rad i działa o wiele lepiej. Z perspektywy jednej nocy, schemat który załączyłem faktycznie wygląda zabawnie ;-) Warto się czasami przespać z problemem.

    @Fredy: Czy nie lepszy byłby mosfet w takim przypadku?
  • #23 9067305
    janbernat
    Poziom 38  
    PNP- nie.
    Bo zwierać to on może- ale odciąć to już nie.
    Oczywiście zależy to od napięcia zasilania.
    Mosfet jest lepszy- ale trzeba wybrać taki który się otworzy przy wysterowaniu z 5V.
REKLAMA