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

RESET PULSE w 1wire Atmega8 C - brak PRESENCE

dominkaster 04 Mar 2011 16:00 1739 9
REKLAMA
  • #1 9234222
    dominkaster
    Poziom 14  
    Witam.
    Siedzę już nad tym 3-ci dzień, czytam różne przykłady, różne dokumentacje, kupiłem nowy czujnik ds18b20 i nadal ten sam problem - brak odpowiedzi slave na reset pulse. Już pomału zaczynam wariować i tracić chęci skoro nie potrafię poprawnie zaimplementować podstawowej funkcji interfejsu 1wire

    DQ podłączone pod PB0 i opornik 4.7k (opornik do zasilania układu).
    VCC i GND zmostkowane i podłączone pod GND układu.

    PORTD to magistrala do której przyłączone są diody (PD0-PD5) do wyświetlania wartości zmiennych.
    Całość działa na zasilaniu z programatora USBASP.

    Program:
    #define F_CPU 10000000UL
    
    #include <avr/io.h> 
    #include <util/delay.h> 
    #include <avr/interrupt.h> 
    #include <avr/interrupt.h> 
    #include <stdlib.h> 
    #include <inttypes.h>
    
    #define PIN_1WIRE	0
    #define PORT_1WIRE	PORTB
    #define DDR_1WIRE	DDRB
    #define	PIN_READ_1WIRE	PINB
    
    #define DDR_1WIRE_IN	DDR_1WIRE |= _BV(PIN_1WIRE) // Stan niski
    #define DDR_1WIRE_OUT	DDR_1WIRE &= ~_BV(PIN_1WIRE) // Stan wysoki
    #define WIRE_HIGH	PORT_1WIRE |= _BV(PIN_1WIRE)
    #define	WIRE_LOW	PORT_1WIRE &= ~_BV(PIN_1WIRE)
    #define PIN_1WIRE_READ	PIN_READ_1WIRE & 1<<PIN_1WIRE
    
    unsigned char pres1=0, pres2=0;
    
    unsigned char WIRE_RESET()
    {
        unsigned char PRESENCE=0;
        DDR_1WIRE_IN;
        _delay_us(500);
        DDR_1WIRE_OUT;
        _delay_us(50);
        if (bit_is_clear(PORT_1WIRE, PIN_1WIRE))
          pres1 = 1;
        else
          pres1 = 0;
          
        _delay_us(470);
        if (bit_is_set(PORT_1WIRE, PIN_1WIRE))
    	pres2 = 1;
        else
          pres2 = 0;
        return PRESENCE;
    }
    
    int main()
    {
        unsigned char pres;
        DDRD = 0b00011111;
        PORTD = 0x0;
        
        WIRE_RESET();
        PORTD = pres1; // Wyswietlenie na diodach wartosci pres1
        _delay_ms(200);
        
        PORTD = 31;    // Zaswiecenie wszystkich diod przed nastepna wartoscia
        _delay_ms(10);
        
        PORTD = pres2; // Wyswietlenie na diodach wartosci pres2
        _delay_ms(200);
        PORTD=0;
        
        _delay_ms(200);
        return 0;
    }
    


    Po uruchomieniu następuje zapalenie diody (PORTD = pres1;), po 2 sec. zapalenie wszystkich diód na 10ms i zgaszenie diody.
    Czyli pres1=1, pres2=0
    Z tego co wyczytałem obie powinny mieć wartość 1 jeśli ds prawidłowo odpowiada na zapytania.

    Próbowałem używać innych funkcji delayus znalezionych w internecie, jednak efekt ten sam.

    avrdude: safemode: lfuse reads as E1
    avrdude: safemode: hfuse reads as D9
    Czyli pracuje na 1MHz. Kompiluję z opcją -O3

    Bardzo proszę o ukrócenie męk i z góry przepraszam za głupotę.
  • REKLAMA
  • #2 9234344
    janbernat
    Poziom 38  
    Deklarujesz 10MHz a działasz na 1MHz.
    W ogóle ustawienie częstotliwości należy zrobić w opcjach projektu a nie na początku pliku.
    Bo wtedy masz to w make a tk to tylko w tym pliku.
    Poza tym to wykonuje się tylko raz- nie ma pętli.
  • REKLAMA
  • #3 9234406
    dominkaster
    Poziom 14  
    Faktycznie F_CPU źle ustawione... Jednak po zmianie problem pozostaje ten sam.

    Co do projektu to używam zwykłego edytora i własnego makefile. Ale już zmieniłem jak radziłeś.

    EDIT:
    Zmieniłem w fusebitach na 8MHz, w projekcie również bo gdzieś doczytałem że komunikacja powinna się odbywać z prockami >2MHz... Problem pozostal.
  • REKLAMA
  • #4 9234631
    janbernat
    Poziom 38  
    No To ściągnij AVStudio 4.
    Zrobi Ci make i w ogólnych opcjach projektu ustawisz częstotliwość i optymalizację na -Os.
    No i zrób jakąś pętlę w której to się robi.
    A w ogóle to kup książkę:
    http://atnel.pl/wydawnictwo
    Przez trzy dni przeczytasz a przez trzy tygodnie zrozumiesz- poczujesz się genialny.
    Zresztą bez żadnego powodu.
  • #5 9234716
    dominkaster
    Poziom 14  
    Używam linuksa i nie potrzebuję AVStudio. Wszystko co chcę mogę ustawić w pliku makefile - nie mam z tym problemu.

    Jednak mam nierozwiązany problem z obsługą 1WIRE i można się na tym skupić.
  • #6 9235591
    nsvinc
    Poziom 35  
    Reset pulse w 1wire ma trwać conajmniej 480 mikrosekund. Więc może trwać również 5 sekund, i czujnik zachowa się dokładnie tak samo, tj. sciagnie linię DQ do masy. Powiedz mi, czy twoje makro DDR_1WIRE_IN naprawdę ustawia pin portu jako wyjście, jednocześnie ściągając go do masy? Z tego co widzę, chyba nie.
    Z tego co pamiętam z AVRów: wystawiasz 0 na dany pin permanentnie wpisując zero do odpowiedniego bitu w rejestrze PORT. Następnie machasz tylko i wyłącznie bitem w rejestrze DDR, bo wtedy:
    a) gdy bit w DDR jest zero, możesz czytać stan pina z rejestru PIN, a sam pin jest w HiZ...
    b) gdy bit w DDR jest jeden, pin nie jest już w HiZ tylko ściągnięty do masy.
    Nie chce mi się rozszyfrowywać twoich pokrętnych makr...
    Widzę, że 1wire masz pod PORTB0 - czy aby na pewno podciągłeś ten pin do plusa rezystorem 3.3k...4.7k ?

    
    DDRB&=0xFE; PORTB&=0xFE; //pin jest w HiZ
    DDRB|=1; //tu ciagniesz pin do masy...
    _delay_us(600); //dla bezpieczenstwa wiecej czasu
    DDRB&=0xFE; //przywroc pin do HiZ
    _delay_us(100); //CZEKAC NA PRESENCE 15..60us PO PODNIESIENIU PINA!!
    if (!(PINB&1)) 
    {    
    //jak wlezie tutaj to znaczy ze presence [b]zaistniał[/b], i wszystko działa
    };
    


    janbernat napisał:
    Deklarujesz 10MHz a działasz na 1MHz.

    No racja...
    Funkcjom _delay_us nie jest wszystko jedno co zadeklarujesz, bo na tej podstawie obliczają/zgadują (?) ile cykli maszynowych musi minąć aby odmierzyć dany czas. Musisz zadeklarować prawidłową częstotliwość taktowania, aby te funkcje odmierzały podany czas z w miarę rozsądną tolerancją.

    Jesli nadal nie działa, próbuj podać do funkcji odmierzającej stan niski na pinie liczby przesadnie duże, np. 0xFFFF. Czujnikowi to ogólnie wszystko jedno ile maksymalnie będzie trwał reset pulse.

    Pamiętaj o odczekaniu minimum 60us po zwolnieniu stanu niskiego na pinie zanim będziesz czytać pin w poszukiwaniu presence!. U ciebie jest 50us (o ile dobrze zadeklarowałeś zegar procesora). 50us to za mało!
  • #7 9235638
    dominkaster
    Poziom 14  
    Stany mierzyłem na multimetrze. Przy niskim otrzymuje 0.2V przy wysokim 5V więc makra mam ok.

    Najprawdopodobniej znalazłem problem. Próbowałem sprawdzić pin funkcją bit_is_set na który dałem napięcie i zawsze wynik był 0. Gdy zastąpiłem go swoim makrem PIN_1WIRE_READ wtedy zaczął sczytywać ten bit.

    Póki co z tego co widzę reset działa w porządku. Jest mi ktoś jedynie w stanie wytłumaczyć czemu ta funkcja nie działa? Czy coś źle wydedukowałem?
  • REKLAMA
  • #10 9237162
    dominkaster
    Poziom 14  
    Udało mi się w zupełności rozwiązać problem.
    Reset pulse raz działał prawidłowo - raz nie. Winą było użycie pinu PB0 na porcie PORTB (do teraz nie wiem czemu, może dlatego że na tym porcie mam programator, ale gdy próbowałem użyć zew. źródła zasilania problem był ten sam).
    Dzięki za chęci.
REKLAMA