Histereza aTtiny13

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
Awatar użytkownika
joon
Użytkownik
Posty: 2076
Rejestracja: 30 cze 2007, 22:56
Lokalizacja: Kraków, Przemyśl, Warszawa
Kontakt:

Post autor: joon » 13 kwie 2013, 11:36

O jakim rejestrze teraz piszesz?

Awatar użytkownika
Dawid2379
Użytkownik
Posty: 318
Rejestracja: 17 lis 2010, 19:42
Lokalizacja: Kluczbork
Kontakt:

Post autor: Dawid2379 » 13 kwie 2013, 12:29

Wiec zmienielem troche program i dziła jak chciałem:) aczkolwiem musiałem zastosować delay
Film
http://www.youtube.com/watch?v=punKRmF2 ... e=youtu.be

Kod: Zaznacz cały

#define F_CPU 4800000UL
#include <stdio.h> 
#include <avr/io.h> 
#include <util/delay.h>
     
#define LED1 PB1
#define LED2 PB2
#define ADCIN PB4  

int main(void)  
{ 
   while(1) 
    {          
                     
 
  DDRB  |= (1<<LED1)|(1<<LED2);
  DDRB &=~ (1<<ADCIN); 
  ADCSRA |= (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1) ;   
  ADMUX  |= (1<<MUX1)|(1<<REFS0);

  
  int tab[5]; 
   int wynik = 0; 
   int i; 

   for(i=0;i<5;i++) 
    { 
     ADCSRA |= (1<<ADSC); 
        while(ADCSRA & (1<<ADSC)); 
              tab[i] = ADC; 
			     _delay_ms(50);
    } 
	    
    wynik =  (tab[0] + tab[1] + tab[2] + tab[3] + tab[4]) / 5 ; 

    if(wynik<700)      
    { 
         PORTB  &=~ (1<<LED1); 
        PORTB  &=~ (1<<LED2); 
    } 
    else if(wynik<750)      
    { 
        PORTB  &=~ (1<<LED1); 
        PORTB  |=  (1<<LED2); 
    } 
    else                  
    { 
       PORTB  |=  (1<<LED1);
	   PORTB  |=  (1<<LED2);
    } 
} 

}
Jakim rejestrze???

Awatar użytkownika
joon
Użytkownik
Posty: 2076
Rejestracja: 30 cze 2007, 22:56
Lokalizacja: Kraków, Przemyśl, Warszawa
Kontakt:

Post autor: joon » 13 kwie 2013, 12:57

To opóźnienie lepiej dać po wyświetleniu, a nie po każdym pomiarze- tak jest moja opinia ;)

Awatar użytkownika
Dawid2379
Użytkownik
Posty: 318
Rejestracja: 17 lis 2010, 19:42
Lokalizacja: Kluczbork
Kontakt:

Post autor: Dawid2379 » 13 kwie 2013, 13:33

Myśle że tak i tak byłoby ok skoro ładnie działa. Idąc dalej chciałbym uzyskać ciągły pomiar. Za właczenie tej opcji odpowiada bit ADATE w rejestrze ADSRA w Tiny13 oraz trzeba usunąć linijke:

Kod: Zaznacz cały

ADCSRA |= (1<<ADSC); 
        while(ADCSRA & (1<<ADSC)); 
Tak kod nie działa, co należałoby jeszcze zrobić? Też chciałbym mieć to z uśrednieniem wyniku.
edit:
Właściwie kiedy warto stosować ciągły pomiar a kiedy pojedyńczy jak wyżej w kodzie??

Awatar użytkownika
joon
Użytkownik
Posty: 2076
Rejestracja: 30 cze 2007, 22:56
Lokalizacja: Kraków, Przemyśl, Warszawa
Kontakt:

Post autor: joon » 13 kwie 2013, 13:41

Nie wiem, jeszcze do tego nie doszedłem ;)

Ale myślę że to niewiele zmieni- masz uśrednianie z 5 pomiarów, dodatkową zwłokę więc "dyskoteki" nie powinieneś mieć. U mnie podobny program steruje 8 ledami i nie mam takich problemów mimo braku uśredniania.

Awatar użytkownika
Dawid2379
Użytkownik
Posty: 318
Rejestracja: 17 lis 2010, 19:42
Lokalizacja: Kluczbork
Kontakt:

Post autor: Dawid2379 » 13 kwie 2013, 13:53

A jak masz podłaczony uC jeżeli chodzi o odfiltrowanie zakłóceń, pewnie to ma duży wpływ i tak w tiny13 niem a za bardzo możliwości odfiltrowania zakłóceń, nie posiada pinów Vfer Avcc

Awatar użytkownika
joon
Użytkownik
Posty: 2076
Rejestracja: 30 cze 2007, 22:56
Lokalizacja: Kraków, Przemyśl, Warszawa
Kontakt:

Post autor: joon » 13 kwie 2013, 14:20

Zasilanie prosto z USB, zmierzone napięcie ~4,82V (w zależności od ilości zapalonych diod nieco "pływa"), Uref wew. Na zasilaniu "typowe" filtrowanie 100u+100n.

Awatar użytkownika
Dawid2379
Użytkownik
Posty: 318
Rejestracja: 17 lis 2010, 19:42
Lokalizacja: Kluczbork
Kontakt:

Post autor: Dawid2379 » 13 kwie 2013, 14:25

No to też bez szału, jak testowalem mege miałem dość dobre filtrowanie a problem wystepował, przy tiny13 tez mam tylko dwa kondensatory, u mnie napięcie równiutkie 5V też z USB no ale mniejsza o to ,uśrednianie wyniku oraz małe opózienie dały porządany efekt:)

Awatar użytkownika
dondu
Użytkownik
Posty: 211
Rejestracja: 24 maja 2005, 9:47
Lokalizacja: Śląskie
Kontakt:

Post autor: dondu » 13 kwie 2013, 14:54

Dawid2379 pisze:... w tiny13 niem a za bardzo możliwości odfiltrowania zakłóceń, nie posiada pinów Vfer Avcc
Ale posiada specjalną funkcjonalność ADC Noise Canceler czyli tryb snu: ADC Noise Reduction
Wykorzystaj ją.

Awatar użytkownika
Dawid2379
Użytkownik
Posty: 318
Rejestracja: 17 lis 2010, 19:42
Lokalizacja: Kluczbork
Kontakt:

Post autor: Dawid2379 » 13 kwie 2013, 15:15

OK nie mam pojęcie o tym ale jak wyczytałem, funkcja ta powoduje zatrzymanie wew. układów i wej/wyj które powodują zakłócenia pomiaru na ADC, aby włączyć tryb o którym mowa nalezy w rejestrze MCUCR włączyć bit SM0, bit ten odpowiada za włączenie wg tabeli ADC Noise Reduction. Nalęzy to zrobic gdzies po włączeniu ADC z tego co wyczytałem.. a jak wzbudzić potem uC do dalszego dzialania aby wykonaf funkcje if itd?

Awatar użytkownika
dondu
Użytkownik
Posty: 211
Rejestracja: 24 maja 2005, 9:47
Lokalizacja: Śląskie
Kontakt:

Post autor: dondu » 14 kwie 2013, 9:58

Możesz to zrobić prościej dołączając nagłówek sleep.h.
Tutaj opis: http://www.nongnu.org/avr-libc/user-manual/modules.html

A procedura wygląda na przykład tak (fragment artykułu, który ukaże się dzisiaj dla ATmega8):

Kod: Zaznacz cały

#include <avr/sleep.h>

volatile unsigned int swiatlo_pomiar;

void dd_swiatlo_adc_ini(void){

	//Funkcja inicjuje przetwornik ADC

	DDRC   &=   ~(1<<PC5); //wejście

	ADMUX  =     (1<<REFS0) //VCC jako napięcie referencyjne
            	|(1<<MUX2) | (1<<MUX0); //kanał ADC5

	ADCSRA =	 (1<<ADEN)	//włącz ADC
	            |(1<<ADIE) 	//włącz przerwania 
	            |(1<<ADPS0) //preskaler 128
	            |(1<<ADPS1)
	            |(1<<ADPS2);    

	sei(); //włącz przerwania globalne
}

//------------------------------------------------------------

void dd_swiatlo_adc_pomiar_start(void){

	//ustaw tryb snu ADC Noise Reduction
	set_sleep_mode(SLEEP_MODE_ADC);	
	sleep_enable();

	//rozpocznij pomiar światła poprzez uśpienie mikrokontrolera
	sleep_cpu();
		
}

//------------------------------------------------------------

ISR(ADC_vect){

	//Przerwanie ADC - pomiar zakończony
	swiatlo_pomiar	=	ADC;

}

Wystarczy wywołać funkcję dd_swiatlo_adc_pomiar_start() i następnie pomiar masz już w zmiennej swiatlo_pomiar. Możesz także nie odczytywać ADC w przerwaniu pozostawiając funkcję pustą (ale musi być), a odczytać tam gdzie wywołałeś wtedy zmienna nie będzie potrzebna.

Datasheet ATmega8:
The ADC features a noise canceler that enables conversion during sleep mode to reduce noise
induced from the CPU core and other I/O peripherals. The noise canceler can be used with ADC
Noise Reduction and Idle mode. To make use of this feature, the following procedure should be
used:
1. Make sure that the ADC is enabled and is not busy converting. Single Conversion
mode must be selected and the ADC conversion complete interrupt must be
enabled.
2. Enter ADC Noise Reduction mode (or Idle mode). The ADC will start a conversion
once the CPU has been halted.
3. If no other interrupts occur before the ADC conversion completes, the ADC interrupt
will wake up the CPU and execute the ADC Conversion Complete interrupt routine. If
another interrupt wakes up the CPU before the ADC conversion is complete, that
interrupt will be executed, and an ADC Conversion Complete interrupt request will be
generated when the ADC conversion completes. The CPU will remain in Active mode
until a new sleep command is executed.
Note that the ADC will not be automatically turned off when entering other sleep modes than Idle
mode and ADC Noise Reduction mode. The user is advised to write zero to ADEN before entering
such sleep modes to avoid excessive power consumption.

Awatar użytkownika
Dawid2379
Użytkownik
Posty: 318
Rejestracja: 17 lis 2010, 19:42
Lokalizacja: Kluczbork
Kontakt:

Post autor: Dawid2379 » 14 kwie 2013, 19:52

No nic poczekam na cały kod aby go przeanalizować, bo nie wiem jak to wszystko posklejać/dodać do mojego kodu:P Nie ma to jak na przykładzie, sam nic nie zwojuje niestety..

Awatar użytkownika
Dawid2379
Użytkownik
Posty: 318
Rejestracja: 17 lis 2010, 19:42
Lokalizacja: Kluczbork
Kontakt:

Post autor: Dawid2379 » 29 kwie 2013, 20:43

Dondu można w moim przypadku wszystko zrealizować w jednym kodzie bez wywoływania kolejnej funkcji? Troche się gubię, bo troche tego tam jest.
Próbuję się wzorować na 'pipdręczycielu' ale to wydaje sie byc inną bajką.Najwiekszy problem sprawia w którym miejscu wstawić;
set_sleep_mode(SLEEP_MODE_ADC);
sleep_enable();
sleep_cpu();

Awatar użytkownika
dondu
Użytkownik
Posty: 211
Rejestracja: 24 maja 2005, 9:47
Lokalizacja: Śląskie
Kontakt:

Post autor: dondu » 06 maja 2013, 17:19

Tak można oczywiście uprościć. Poradziłeś już sobie?
Jeśli nie to pokaż cały program.

Awatar użytkownika
Dawid2379
Użytkownik
Posty: 318
Rejestracja: 17 lis 2010, 19:42
Lokalizacja: Kluczbork
Kontakt:

Post autor: Dawid2379 » 06 maja 2013, 18:01

Ten program to porażka;/, ale pokaże ja kombinowałem...
Wydawało mi się że podstawie kilka linijek kodu związanego z sleep do mojego poprzedniego kodu i będzie ok, szczerze nie ogarniam.
-jak wybudza się procek z trybu Noise reduction, automatycznie?
-w którym momenvie go uspać
-jak podstawic wartość pomierzonego ADC do zmiennej o ile to potrzebne..

duzo pytań się nasuwa..

Kod: Zaznacz cały

#define F_CPU 4800000UL
#include <stdio.h> 
#include <avr/io.h> 
#include <util/delay.h>
#include <avr/interrupt.h> 
#include <avr/sleep.h>
     
#define LED1 PB1
#define LED2 PB2
#define ADCIN PB4  



int main(void)  
{ 
  DDRB  |= (1<<LED1)|(1<<LED2);
  DDRB &=~ (1<<ADCIN); 
  ADCSRA |= (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1) ;   
  ADMUX  |= (1<<MUX1)|(1<<REFS0);
  sei();
     
  
   for(;;) 
    {          
  if(ADC<700)      
    { 
         PORTB  &=~ (1<<LED1); 
        PORTB  &=~ (1<<LED2); 
    } 
    else if(ADC<750)      
    { 
        PORTB  &=~ (1<<LED1); 
        PORTB  |=  (1<<LED2); 
    } 
    else                  
    { 
       PORTB  |=  (1<<LED1);
	   PORTB  |=  (1<<LED2);
    } 
	set_sleep_mode(SLEEP_MODE_ADC);    
      sleep_enable();
     sleep_cpu();          
     }   
} 

ISR(ADC_vect){

} 

ODPOWIEDZ