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

[C / Atmega8] Działający LED sensor

oskar777 22 Maj 2010 22:13 3079 15
  • #1 8106930
    oskar777

    Poziom 26  
    Witam Was.
    Mam taki problemik i nie mogę sobie z nim poradzić.

    Chciałem zrobić czujnik ruchu wykorzystując diodę led, ale niestety nie chce zaskoczyć :/.

    Kod opierałem o teorię z

    http://blog.makezine.com/archive/2006/06/led_touch_sensor.html
    oraz trochę na kodzie z strony


    http://www.thebox.myzen.co.uk/Workshop/LED_Sensing_files/Sensor_LEDs.pde

    Co może być nie tak ?
    Do pinu 0 DDRD jest podpięta dioda pokazująca czy czujnik działa.
    Pod pin 2 jest podpięta katoda czujnika wraz z rezystorem 220R
    Pod pin 1 jest podpięta anoda bezpośrednio połączona z led.

    Kod może nie jest idealny ale dopiero się uczę.

    Pozdrawiam serdecznie.



    
    #include <avr/io.h>
    #include <delay_x.h>    
    #include <inttypes.h>
    
                              
    
    #define Led1on PORTD = 0x0E;                   
    #define ledsw1 PORTD = 0x03;                   
    #define ledsw2 PORTD = 0x05;
    
    #define output_all DDRD  |= _BV(0)	 | _BV(1) | _BV(2); // ustaw jako wyjscia
    #define input DDRD &= ~_BV(2); // ustaw jedno wejscie
    
    
    #define pullupled_1 PORTD &= ~_BV(2);
    #define pullupled_of PORTD |= _BV(2);
    #define led_gnd  PORTD &= ~_BV(1);
    // Function prototypes
    
    int main(void);
    void setup();
    
    uint8_t stan;
    uint8_t czas;
    
    void setup() {
    
    }
    
    
    int main( void )                        // program główny
    {
    
    czas = 60;
    output_all;
    
      while(1)                                
      {
     
    	
    	
    	ledsw1; // zapal diode
    	_delay_ms(1);
    	ledsw2; // zamien bieguny
    	_delay_ms(1);
    	
    	
    	input; // ustaw katode jako odczyt
    	pullupled_1; // wylacz podciaganie do plusa
    	led_gnd; // masa na anodzie
    	
    	
    	
    	
    	
    	
    	if(bit_is_clear(PIND, 2)){
    	Led1on;
    	
    	}
    	_delay_ms(czas);
    	pullupled_of;
    	output_all;
    	
    	
    		
        
      }
    }
    
  • #2 8107446
    GSM
    Poziom 25  
    Witam,

    przeczytaj kod z tej strony do której linka wkleiłeś, są całkiem ładne komentarze tam.
    Musisz mierzyć poziom napięcia na wyłączonej diodzie przy pomocy ADC.

    Pozdrawiam,
    GSM
  • #3 8107520
    AVRowiec
    Poziom 18  
    Jak zbudujesz układ i Ci to ruszy to daj znać i wrzuć wszystkie materiały :) Ludzkość będzie Ci wdzięczna.

    Bardzo ciekawy projekt. Aż sie nie chce wierzyć że z matrycy led można zrobić panel dotykowy. film: http://cs.nyu.edu/~jhan/ledtouch/ledtouch.mpg
  • #4 8107697
    oskar777

    Poziom 26  
    Muszę poczytać o ADC :/ i wtedy pozadaje pytania by ludzi nie denerwować :).
    Jeszcze tu wrócę :)
  • #5 8130810
    oskar777

    Poziom 26  
    Witam.
    Nowe zmiany. Niestety nie działa jeszcze ale może ktoś będzie miał pomysł co jest nie tak.
    Kod jest taki
    
    // Opis
    
    #include <avr/io.h>
    #include <delay_x.h>    
    #include <inttypes.h>
    #include <avr/interrupt.h>
    
    // zmienne
    volatile uint16_t wynik_adc;
    volatile uint8_t licznik;
    // ustawienie Portu D jako wyjscia
    #define ddrd_output DDRD = 0xFF;
    
    
    // prototypy
    int main(void);
    void led_on();
    void sw_led();
    void setup_adc();
    void adc_off();
    
    // zapalenie diody
    void led_on() {
    DDRC  |= _BV(0) | _BV(1); // PC0, PC1 jako wyscia
    PORTC |= _BV(0); // 1 dla PC0
    PORTC &= ~_BV(1); // 0 dla PC1
    }
    
    // przelaczenie biegunow
    void sw_led() {
    PORTC &= ~_BV(0); // 0 dla PC0
    PORTC |= _BV(1); // 1 dla PC1
    }
    
    // ustawienia ADC
    void setup_adc() {
    
    // ADFR - staly pomiar
    // ADPSx - ustawienia preskalera ADPS0 =1, ADPS1 =1, ADPS2 = 1 >> podzial przez 128 dla 12MHz =  12 Mhz / 128 = 90kHz
    // ADIE - aktywowanie przerwania
    // ADSC - start pomiaru
    ADCSR |= _BV(ADEN) |_BV(ADIE)|_BV(ADFR)|_BV(ADSC)|_BV(ADPS0)|_BV(ADPS1) |_BV(ADPS2);
    
    // REFS1 = 1, REFS0 = 1 >> wewnetrzne napiecie odniesienia 2.65V z kondensatorem na wyprowadzeniu AHREF atmegi
    // MUX1 = 1, wybranie pierwszego kanalu do pomiaru
    ADMUX |= _BV(REFS1) | _BV(REFS0) | _BV(MUX1) ; 
    }
    
    // wylaczenie ADC
    void adc_off(){
    ADCSR &= ~_BV(ADEN);
    }
    void adc_on(){
    // ADEN - aktywacja ADC
    ADCSR |= _BV(ADEN);
    }
    
    
    // przerwanie z przetwornika ADC
    SIGNAL(SIG_ADC)                        
    {
    wynik_adc = ADCW;                        // czytaj wartość z przetwornika ADC
    PORTD = ~(wynik_adc>>2);                 // wyślij przetworzoną wartość na LED
      }
    
    // program główny
    int main( void )                        
    {
    ddrd_output;
    
    setup_adc();
    sei();
    
    DDRC &= ~_BV(1);
      PORTC &= ~_BV(1);
    
      while(1)                                
      {
      
      // === Zapalenie diody ===
      led_on();
      _delay_ms(1);
      // === przelaczenie biegunow ===
      sw_led;
      
      setup_adc();
      _delay_ms(50);
      
      
     // adc_on();
      
     // adc_off();
      _delay_ms(20);
      //adc_off();
      
    
    
      
      }
    
    
    }
    


    Dorzucę jeszcze raz obrazek działania.

    [C / Atmega8] Działający LED sensor



    Sytuacja jest taka, że jak dotknę led anody to diody mrugają inaczej.
    Ale to wiele jeszcze nie mówi.

    Może da się jakoś zrobić ja nie wiem jak by z tej wartość bin zrobić taki miernik napięcia na led. Czyli jak większa jest wartość to więcej diod się zapali.

    Być może coś z czasami jest skopane

    Będę bardzo wdzięczny za wskazówki.

    Pozdrawiam
  • #6 8131397
    GSM
    Poziom 25  
    1. Nie potrzebujesz adc_off(), ADEN sam się zeruje po ukończeniu konwersji.
    2. setup_adc() wystarczy raz wywołać, wyrzuć je z pętli głównej.
    3. po adc_on() program dalej się wykonuje, nie czekając na ukończenie pracy przez ADC, gorzej twoje adc_off zatrzymuje konwersję jeszcze zanim się rozpoczęła! musisz po adc_on() wstawić oczekiwanie na ukończenie konwersji, czyli na wyzerowanie się ADEN, np while(ADCSR&_BV(ADEN));

    To takie najważniejsze grzechy jakie rzuciły mi się w oczy.

    Pozdrawiam,
    GSM
  • #7 8131459
    oskar777

    Poziom 26  
    Dzieki za informację.
    Czyli mam dać while(ADCSR&_BV(ADEN)); przed ponownym zapaleniu diody, czy ten zapis jest równoważny while(!(ADCSRA & (1<<ADIF))); ?

    I jak z wynikiem, LCD jeszcze nie opanowałem, tak więc zastanawiam się czy da się taką linijke led zrobić
  • #8 8131515
    GSM
    Poziom 25  
    Możesz w ogóle w takim układzie pozbyć się tego przerwania ADC, i odczytywać jego wartość po tym jak ADSC zostanie wyzerowany przez przetwornik po zakończeniu konwersji.

    Poza tym moja pomyłka miałem na myśli ADSC a nie ADEN.

    Nie musisz zerować ADEN (wyłączać ADC) gdy jest w single conversion mode, a free running nie jest ci potrzebny.

    Twoja "linijka" aktualnie pokazuję "surową" liczbę binarnie, na upartego idzie to odczytać, opanować LCD nie jest trudno, szczególnie, że istnieją gotowe biblioteki do ich obsługi, a wygoda wzrasta bardzo.
    Jeszcze co do tej linijki, możesz zrobić bargraf, wszystkie zgaszone dla wyniku konwersji 0 połowa dla 127, i wszystkie zapalone dla 255.
  • #9 8131648
    oskar777

    Poziom 26  
    Chciałem dać przerwanie, ponieważ jest to kawałem programu w sumie tak naprawdę (nie wiem czy się da) ale ten cały kod dałbym w przerwaniu. Docelowo w pętli będą instrukcje które nie powinny mieć takich opóźnień jakie mam teraz. Co do baragrafu znalazłem takie coś
    http://www.mbeckler.org/microcontrollers/led_bargraph/

    Pozdrawiam
  • #10 8141116
    oskar777

    Poziom 26  
    Witam.
    Sensor działa nie jest idealnie ale działa :>.

    Filmik tu




    Problem jest taki że czasem dioda kilka razy zamruga zanim się ustabilizuje, może jakieś mądre głowy wymyślą jak to przystopować tak by działało stabilniej
    
    #include <inttypes.h>
    #include <avr/interrupt.h>
    #include <avr/io.h>
    #include <stdlib.h>
    #include <delay_x.h>    
    #include "lcd.h"
    
    #define ddrd_output DDRD = 0xFF;
    
    
    volatile uint8_t i;
    char buffer_n[5];  
    signed long int wartosc;
    volatile uint16_t wynik_adc;
    volatile uint8_t licznik;
    
    
    int main(void);
    void led_on();
    void sw_led();
    void setup_adc();
    void adc_off();
    void adc_on();
    
    
    // zapalenie testowej diody
    void tmp_led_on() {
    DDRB  |= _BV(0);
    PORTB &= ~_BV(0); 
    }
    void tmp_led_off() {
    PORTB |= _BV(0); 
    }
    
    
    // zapalenie diody
    void led_on() {
    DDRC  |= _BV(0) | _BV(1); // PC0, PC1 jako wyscia
    PORTC |= _BV(0); // 1 dla PC0
    PORTC &= ~_BV(1); // 0 dla PC1
    }
    
    // przelaczenie biegunow
    void sw_led() {
    PORTC &= ~_BV(0); // 0 dla PC0
    PORTC |= _BV(1); // 1 dla PC1
    }
    
    void setup_adc() {
    
    // ADFR - staly pomiar
    // ADPSx - ustawienia preskalera ADPS0 =1, ADPS1 =1, ADPS2 = 1 >> podzial przez 128 dla 12MHz =  12 Mhz / 128 = 90kHz
    // ADIE - aktywowanie przerwania
    // ADSC - start pomiaru
    ADCSR |= _BV(ADEN) |_BV(ADIE)|_BV(ADFR)|_BV(ADSC)|_BV(ADPS0)|_BV(ADPS1) |_BV(ADPS2);
    
    // REFS1 = 1, REFS0 = 1 >> wewnetrzne napiecie odniesienia 2.65V z kondensatorem na wyprowadzeniu AHREF atmegi
    // MUX1 = 1, wybranie pierwszego kanalu do pomiaru
    ADMUX |= _BV(REFS1) | _BV(REFS0) | _BV(MUX1); 
    }
    
    // wylaczenie ADC
    void adc_off(){
    ADCSR &= ~_BV(ADEN);
    }
    void adc_on(){
    // ADEN - aktywacja ADC
    ADCSR |= _BV(ADEN);
    }
    
    
    SIGNAL(SIG_ADC)                        
    {
    licznik++;
    if(licznik == 5) {
    
    i =9;
    while(i) {
    wynik_adc = ADCW;              
    wartosc = wartosc + wynik_adc;
    i--;
    }
    wartosc = wartosc / 9;
    
    
    
    utoa(wartosc, buffer_n, 10);
    
    if(wartosc > 135) {
    tmp_led_on();
    } else {
    tmp_led_off();
    }
    
    
    
    LCD_putstr(buffer_n);
    
    _delay_ms(300); // czas dla podglądu na LCD normalnie 0-1 ms
    LCD_clear();
    }
    }
    
    
    int main(void)
    {
    ddrd_output;
    
    setup_adc();
    adc_on();
    sei();
    
    LCD_init();
    //LCD_clear();
    while(1) {
    
     // === Zapalenie diody ===
      led_on();
      _delay_ms(1);
      // === przelaczenie biegunow ===
      sw_led();
       
      _delay_ms(1);
      DDRC &= ~_BV(1);
      PORTC &= ~_BV(1);
      adc_on();
      while(ADCSR&_BV(ADEN));
    
    
      _delay_ms(20);
    
    
    
    
    
    
    
    
    
    }
    
    }
    
    


    Dołączam pliki co ważniejsze
  • #11 8144631
    oskar777

    Poziom 26  
    Za bardzo się cieszyłem :/.
    Układ działa ale w dzień. Gdy dodam kod oczekujący na zakończenie konwersji czyli while(ADCSR&_BV(ADEN)); to potem nie mogę zapalić diody przez funkcję led_on();
    Będę wdzięczny za pomoc bo nie wiem co z tym fantem zrobić.
  • #12 8145229
    poczitamagoczi
    Poziom 14  
    Na jednej diodzie nie zrobisz sensora led który by działał w nocy ... zainstaluj obok diodę która świeci cały czas i emitowane z niej fotony odbijały by się od jakiegoś zbliżającego się obiektu. Jeśli chcesz żeby światło było niewidoczne użyj diody podczerwieni.
  • #13 8208672
    nethero
    Poziom 10  
    Z tego co wiem to w rejestrze ADCSR bitem określającym czy konwersja jeszcze trwa jest ADSC, a nie ADEN. ADEN będzie 1 tak długo, jak będziesz miał aktywny ADC, więc nie bardzo widzę w nim sensu. Poza tym działasz na przerwaniach, które same w sobie załatwiają kwestię oczekiwania na wynik - dostajesz przerwanie po zakończeniu konwersji.
  • #14 8219845
    carkar
    Poziom 15  
    Ludzie cała filozofia w tym:
    
    DDRA = 0xFF;
    PORTA = 0x01;
    _delay_ms(1);
    PORTA = 0x02;
    _delay_ms(1);
    DDRA = 0xFD.
    

    podłączenie:
    post a.0 pin 1 leda
    port a.1 pin 2 leda....
  • #15 8220694
    poczitamagoczi
    Poziom 14  
    Cytat:
    Ludzie cała filozofia w tym:...

    No jeśli po prostu ustawisz dany pin jako wyjście na katodę diody i dasz tam stan wysoki a późnij będziesz czekał na rozładowanie potencjału na tym pinie to będzie oczywiście najprostsze rozwiązanie. Ale układy mierzący stan napięcia tak jak robi to oskar777 jest moim zdaniem o wiele ciekawszym rozwiązaniem. Kiedyś zrobiłem podobny układ i zrobiłem rysunek do cyklu pomiarowego który zamieszczam niżej.
    [C / Atmega8] Działający LED sensor
  • #16 8222414
    carkar
    Poziom 15  
    No to kondensatorek mały wystarczy i już....

    EDIT i jeszcze moje 1 pytanko jak to wyregulować by nie reagował na światło słoneczne??
REKLAMA