Elektroda.pl
Elektroda.pl
X
Arrow Multisolution Day
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[MEGA8][C] Błędny odczyt temperatury z DS18B20

marwel007 10 Lis 2009 00:07 5905 30
  • #1 10 Lis 2009 00:07
    marwel007
    Poziom 8  

    Cześć!

    Na wyświetlaczu zamiast poprawnej (lub prawie poprawnej) temperatury wyświetla mi się temperatura -0.1 stopnia. Program napisany w bascomie funkcjonuje poprawnie (temperatura nie dokońca się zgadza bo na rtęciowym termometrze mam 23 stopnie a DS pokazuje mi 25). Gdzie popełniłem błąd?

    Code:

    #define WE 2
    #define PORT_1wire PINB
    #define SET_1wire DDRB=~_BV(WE)
    #define CLEAR_1wire DDRB|=_BV(WE)

    char buf[8];


    unsigned char RESET_PULSE(void)
    {
       unsigned char PRESENCE;
       CLEAR_1wire;
       _delay_us(500);
       SET_1wire;
       _delay_us(40);
       if (bit_is_clear(PORT_1wire, WE))
          {
          PRESENCE=1;
          }
       else
          {
          PRESENCE=0;
          }
       return PRESENCE;
    }

    void send(char bit)
    {
       CLEAR_1wire;
       _delay_us(10);
          if(bit==1)
             SET_1wire;
          _delay_us(100);
             SET_1wire;

    }

    unsigned char read(void)
    {
       unsigned char PRESENCE=0;
       CLEAR_1wire;
       _delay_us(4);
       SET_1wire;
       _delay_us(25);
       if(bit_is_set(PORT_1wire, WE)) PRESENCE=1; else PRESENCE=0;

       return(PRESENCE);


    Code:

    unsigned char sprawdz;
    char temp1=0, temp2=0;
       LCD_Start();

    for(;;)
    {
       sprawdz=RESET_PULSE();
       if (sprawdz)
       {
          send_byte(0xCC);
          send_byte(0x44);
          _delay_ms(850);
          sprawdz=RESET_PULSE();
          send_byte(0xCC);
          send_byte(0xBE);

          temp1=read_byte();
          temp2=read_byte();

          sprawdz=RESET_PULSE();
          float temp=0;
          temp=(float)(temp1+(temp2*256))/16;
          dtostrf(temp,1,1,buf);
          LCD_Clear();
          LCD_WriteText(buf);
          _delay_ms(500);

       }
       else
          {
          LCD_Clear();
          LCD_WriteText("brak czujnika");
          }



    PS.
    Dlaczego w cpeie wszystko jest takie trudne, a boscoma można pojąc w 1 weeckend...

    0 29
  • Arrow Multisolution Day
  • #2 10 Lis 2009 20:01
    dawid512
    Poziom 32  

    Znając życie to twój problem polega na złym ustawieniu fuse bitów, nie ustawieniu ich bądź złej deklaracji zegara.

    0
  • #3 12 Lis 2009 23:43
    marwel007
    Poziom 8  

    do programowania uzywam avr-studio bo tylko on mi dziala z moja programatorka. mam ustawiony tam wewnetrzny rezonator 8mhz. cos jeszcze oprocz tego musze ustawic?

    i kolejny problem:

    Code:

    #include <avr\io.h>
    #include <inttypes.h>
    #include <avr\pgmspace.h>
    #include <util\delay.h>
    #include <stdlib.h>
    #include <avr\iom8.h>
    #include <avr\signal.h>
    #include <avr\interrupt.h>


    /*==============================================================================================*/
    #define      SET_BIT(r,x)      r|=_BV(x);
    #define      CLR_BIT(r,x)      r&=~_BV(x);
    #define      TOG_BIT(r,x)      r^=_BV(x);
    /*==============================================================================================*/

    #define   H_WENT            PC5
    #define   H_PORT_WENT         PORTC
    #define   H_PIN_WENT         PINC
    #define   H_DDR_WENT         DDRC
    int z=150;
    int i=0;


    SIGNAL (SIG_OVERFLOW0)
    {
       i=i++;                      // <=================== tu jest problem
       if (i<=z) { SET_BIT(H_PORT_WENT,H_WENT);}
       if (i>z) { CLR_BIT(H_PORT_WENT,H_WENT);}
       if (i>250) { i=0;}

    }

    int main(void)
    {
    i=0;
       CLR_BIT(H_PORT_WENT,H_WENT);
       SET_BIT(H_DDR_WENT,H_WENT);

     TIMSK=1<<TOIE0;
     TCCR0=0;
     sei();

     for (;;)
     {

     }
     return(0);
    }


    To programowy generator PWM, w bascomie taki algorytm działa.
    Tam gdzie jest i=i++; w obsłudze przerwania w kompilatorze wyskakuje mi ostrzeżenie ze wartość nie została zdefiniowana. I przeczuwam ze to jest przyczyną ze ten generator mi nie działa ;/ Co źle zrobiłem?

    0
  • Arrow Multisolution Day
  • #4 13 Lis 2009 00:13
    zdebel
    Poziom 14  

    pisze się i++; tudzież i+=1; tudzież i=i+1

    0
  • #5 13 Lis 2009 00:14
    mirekk36
    Poziom 42  

    po co w ogóle piszesz coś takiego jak:

    i=i++;

    jak już to napisz tylko

    i++;

    albo jeśli wolisz

    i+=1;

    0
  • #6 13 Lis 2009 00:31
    marwel007
    Poziom 8  

    nie zmienia to faktu ze nie działa. to tylko forma zapisu kompilator dalej wskazuje warninga.

    PS środowisko to eclipse z gcc

    0
  • #7 13 Lis 2009 00:39
    zdebel
    Poziom 14  

    ciekawe, na poczatku inicjalizujesz... może magiczne słówko volatile?

    0
  • #8 13 Lis 2009 08:11
    piti___
    Poziom 23  

    Co do DS1820 to strzelam że trzeba rzutować temp1 i temp2 na float
    temp=(float)(temp1+(temp2*256))/16;
    czyli
    temp=(float)((float)temp1+((float)temp2*256))/16;

    0
  • #9 13 Lis 2009 08:51
    flapo213
    Poziom 21  

    Witaj Kolego.

    Ja zrobiłem obsługę one wire w C na mikrokontrolery i działa dobrze. Kilka kwestji jeśli używasz atmega8 to raczej nie używaj zmiennych typu float bo samo użycie tego słowa kluczowego zajmie Ci ponad połowę twojej pamięci flash, niestety tak to już jest. Kilka porad z mojej strony:

    1. Czy przeczytałeś już w manualu od maxima/dallasa jak działa ta magistrala a w szczególności DS18B20 ?

    2. Czy narysowałeś sobie algorytmy jak twoje poszczególne funkcje powinny działać.

    3. Co do Bascoma to jasne że Ci będzie tam działać wszystko bo tam wszystko jest szyte na miare nawet nie musisz nic wiedzieć jak one wire działa ;)

    To tyle na początek.

    Kilka uwag odnośnie one wire a w szczególności DS18B20:

    Zwróć uwagę iż w asortymencie dallasa jest kilka rodzaji układów DS18xxx czujników temperatury głównie różnią się one od siebie rozdzielczością odczytu i oczywiście ceną. Niestety każdy z tych czujników wymaga osobnej procedury konwersji temperatury tzn jeśli masz DS18B20 to funkcji która Ci przetwarza już dane na temperaturę nie nadaje się dla DS1820 - te czujniki mają inną rozdzielczość. Pytanie jakie się może nasunąć to jak robić aby z każdym działało, otóż odpowiedź jest bardzo prosta odczytać numer seryjny układu i już będziesz wiedział z czym masz do czynienia i jak wykonać konwersję. Co do protokołu Dallasa to zazwyczaj masz info co i jak powinieneś do układu wysyłać aby Ci coś odpowiedział, są również manuale do protokołu w których masz np autodetekcję podłączonych układów na magistralę, adresowanie, i praca bezpośrednia z każdym z osobna, itd.

    To co najważniejsze dla Ciebie na początek to spróbuj skomunikować się z ukałdem na najniższym poziomie tzn. spraw aby układ odpowiedział Ci tzw. presence pulse. W one wire panuje taki porządek że to twój układ mikrokontroler i rezystor podciągający daje jedynkę logiczną a układ one wire daje tylko i wyłącznie 0 (ściąga do masy) to najważniejsze !. Językiem C i składnią się narazie nie przejmuj to jest do przebrnięcia bylbyś jakichś rażących błędów nie zrobił typu int tab[10]; tab[12] = 2; to najgorsze co możesz zrobić reszta jakoś przejdzie.

    Fajnie by było jakbyś miał oscyloskop wtedy mógłbyś pomierzyć czasy opóźnień jakie musisz zastosować i które to są bardzo ważne w one wire.

    W razie pytań wal do mnie na priva to coś Ci pomogę i może zamieścimy na forum na potomnych ;)

    Pozdrawiam

    0
  • #10 13 Lis 2009 10:59
    tmf
    Moderator Mikrokontrolery Projektowanie

    Warning dostajesz bo ta zmienna nie jest zainicjowana w procedurze obslugi przerwania tylko w main. Kompilator o tym nic nie wie. Jesli ci ten warning przeszkadza to zadeklaruj ta zmienna jako static co automatycznie ja zainicjalizuje na 0 i usatysfakcjonuje kompilator. W tym wypadku ta zmienna nie musi byc volatile, bo korzystasz z niej wylacznie w procedurze obslugi przerwania.
    Co do bledow odczytu - twoje zmienne temp sa typu char, ktory w wyniku obliczen ulega promocji do typu int, ale nie float. W efekcie uzyskujesz jakies dziwnosci. Jak podzielisz przez 16.0 a nie 16 to moze to pomoze. No i nie zapomnij o zalaczeniu biblioteki libm, bo inaczej bedzie tak jak pisze flapo i zezre ci sporo pamieci.

    0
  • #11 15 Lis 2009 22:32
    marwel007
    Poziom 8  

    zdebel tak znikł ten warning.
    piti___ niestety teraz dostaje inne bzdury... 4095,9 stopnia

    flapo213
    po twoim poście postanowiłem dokładnie przeryć datasheeta i napisać od początku po swojemu procedure obsługi ds18b20. oscyloskopu nie mam i nie bede miec z kilku powodow a najpowazniejszy to $$$.

    oto napisana przezemnie od poczatku procedura obsługi z pomoca datasheeta
    (umiescilem komentarze obok zebyście sprawdzili czy dobrze myśle)

    Code:

    #define   H_1W            PB2
    #define   H_PORT_1W      PORTB
    #define   H_PIN_1W         PINB
    #define   H_DDR_1W         DDRB

    unsigned char RESET_PULSE(void)
    {
       unsigned char PRESENCE;
       PRESENCE=0;
       SET_BIT(H_DDR_1W,H_1W); //ustawiam port na wy
       CLR_BIT(H_PORT_1W,H_1W);//ustawiam stan niski
       _delay_us(480);//czekam 480us
       CLR_BIT(H_DDR_1W,H_1W);//ustawiam port na wejscie
       SET_BIT(H_PORT_1W,H_1W);//podciagam do 1
       _delay_us(80);//czekam
       if (bit_is_clear(H_PIN_1W, H_1W)) {PRESENCE=1;}   else {PRESENCE=0;} //sprawdzam czy na PB2 pojawilo sie 0, jezeli tak to uklad odpowiedzial
       return PRESENCE;
    }

    void send(char bit)
    {
       SET_BIT(H_DDR_1W,H_1W); //ustawiam porta na wyjscie
       CLR_BIT(H_PORT_1W,H_1W);//poziom niski
       _delay_us(15); //port czeka 15us w stanie niskim dla transmisji 1
          if(bit==0) {_delay_us(50);} // jezeli jest wysylane 0 to port czeka jeszcze 50 us
       SET_BIT(H_PORT_1W,H_1W);// podciagam do 1

    }

    unsigned char read(void)
    {
       unsigned char PRESENCE=0; //odczytany bit
       SET_BIT(H_DDR_1W,H_1W);// ustawiam port na wyjscie
       CLR_BIT(H_PORT_1W,H_1W);// sciagam do 0
       _delay_us(1);
       CLR_BIT(H_DDR_1W,H_1W);//ustawiam port na wejscie
       SET_BIT(H_PORT_1W,H_1W);// podciagma do 1
       _delay_us(15);
       if(bit_is_set(H_PIN_1W,H_1W)) PRESENCE=1; else PRESENCE=0;//jezeli na PB2 jest 1 to zczytana zostaje 1

       return(PRESENCE);
    }

    void send_byte(char wartosc)
    {
       unsigned char i;
       unsigned char pom;
       for (i=0;i<8;i++)




       {
          pom=wartosc>>1; //przesuwam w prawo
          pom&= 0x01;//nakladam maske zeruje wszsystkie pozostale bity oprocz ostaniego pozostanie 0 albo 1
          send(pom);
       }
       _delay_us(7);
    }


    unsigned char read_byte(void)
    {
       unsigned char i;
       unsigned char wartosc = 0;
       for(i=0;i<8;i++)
       {
          if(read()) wartosc|=0x01<<i;//???????????
          _delay_us(9);
       }
       return(wartosc);



    int main(void)
    {
       int sprawdz;
           char temp1=0, temp2=0;
       LCD_Initalize();

    for(;;)
    {
       sprawdz=RESET_PULSE();
       if (sprawdz)
       {
       send_byte(0xCC);
       send_byte(0x44);
       _delay_ms(750);
       sprawdz=RESET_PULSE();
       send_byte(0xBE);
       temp1=read_byte();
       temp2=read_byte();
    ......
    ......
    ......
       LCD_Clear();
       LCD_WriteText(temperatura);
       }
       else
       {
       LCD_Clear();
       LCD_WriteText("nie ma czujnika");
       }


    I teraz mam pare pytań:

    W funkcji unsigned char read_byte(void) coś mi się nie podoba (to było robione na podstawie gotowca) a mianowicie. sprawdzam co odczytało. jeżeli odczytało 1 to stosuje maske i ustawiam na ostatnim miejscu 1 po czym przesuwam o i??? chyba powinno tylko raz przesunąć bo pętla jest powtarzana 8 razy. a jeżeli wykryje 0 to powinno przesunąć tylko raz bez stosowania tej maski.

    Gdy już odczytam MSB i LSB muszę je połączyć żeby otrzymać 16 bitową liczbę. Nie za bardzo mam pomysł jak to zrobić. Bo jak je dodam do siebie TEMP1+TEMP2 to wynikiem będzie (chyba) 8bitowa liczba. mając tą liczbę 16 bitową jak ja zamienić na temperaturę?

    załóżmy ze mamy temperaturę 125stopni ( tabelki) 0000 0111 1101 0000. pierwsze 5 zer to znak czyli zajmujemy się tylko 111 1101 0000 jeżeli zamienię tą wartość z binarnego na dziesiętne wychodzi mi 2000...

    tmf to jakie zmienne stosować?

    0
  • #13 16 Lis 2009 00:09
    marwel007
    Poziom 8  

    już chyba wiem jak policzyć temperaturę :)

    temperatura jest na 11 bitach (12 to znak)

    przykład:
    2000 - 125 stopni
    8 - x stopni
    x=(8*125)/2000=0,5 stopnia i to sie zgadza z tabelka :D

    czyli muszę teraz tylko połączyć MSB z LSB w 16bitow przesunąć w lewo o 4bity sprawdzić najstarszy bit znaku, a pozostałe 11 bitów pomnożyć przez 0,0625 i mam temperaturę w Celsjuszach. Dobrze to wymyśliłem?

    0
  • #14 16 Lis 2009 15:13
    flapo213
    Poziom 21  

    Witaj Kolego.

    No dobrze to kombinujesz. Podpowiem Ci jedynie jak możesz sobie to uprościć. Otóż powołaj sobie zmienną 16 bitową zamiast 2 8 bitowych w ARM to short w AVR to int i normalnie odwzoruj całość z czujnika następnie jak chcesz mieć dokładność do 0.5C to przemnóż całość przez 10. Pojawi się zapewne pytanie dlaczego pomnozyc przez 10 odpowiedz jest prosta co w przypadku gdy będziesz miał 0x08Hex jak podzielisz to przez 16 to klops w zmiennej dostaniesz 0 a jak wczesniej pomnozysz to przez 10 otrzymasz 50 co bedzie dla Ciebie znakiem że odczytałeś 0.5C. Następny problem jaki napotkasz to konwersja tejże liczby z hexa na dec bo pewnie byś gdzieś ją chciał wyświetlić. I tu masz dwie metody albo skorzystasz z gotowej funkcji atoi/itoa lub sprintf (bardzo pamięcio żerne) albo skonstruujesz własną funkcyjkę która zamieni Ci liczbę z hex na dec. Ja oczywiście mam taką funkcyjkę ale proponuję abyś ją sam napisał pomocna Ci tu będzie wiedza jak ręcznie przeliczyć hex na dec (takie magiczne dzielenie) ja to miałem w szkole średniej.

    Robisz tak np.

    masz hex 0x2A

    jak to zamienić na dziesiętny

    mnożysz wagi

    2 *16^1 + 0x0A *16^0 = 32 + 10 = 42

    I tyle.

    Pomyśl jak to zrobić w C.

    Jak nie dasz rady podrzucę.

    Pozdrawiam

    PS. Jak widzisz opłaca się czytać dokumentację zawsze coś w głowie zostanie przy Bascomie byś się tego nie nauczył ;)

    Code:
    void send_byte(char wartosc) 
    
    {
       unsigned char i;
       unsigned char pom;
       for (i=0;i<8;i++)
       {
          pom=wartosc>>1; //przesuwam w prawo --*-- (Tak tu powinno być i a nie 1) --*--
          pom&= 0x01;//nakladam maske zeruje wszsystkie pozostale bity oprocz ostaniego pozostanie 0 albo 1
          send(pom);
       }
       _delay_us(7);
    }

    0
  • #15 16 Lis 2009 21:25
    marwel007
    Poziom 8  

    nie za bardzo rozumiem.

    robię tak:

    Code:

    int read_byte(void)
    {
       unsigned char i;
       int wartosc = 0;
       for(i=0;i<16;i++)
       {
          if(read()) wartosc|=0x01<<i;
          _delay_us(9);
       }
       return(wartosc);


    wynikiem tego wg mnie powinna być jedna zmienna wartość 16bitowa która będzie zawierać pomiar temperatury.

    i teraz to mam pomnożyć przez 10?

    wartosc=(wartosc*10)/16;

    i coś tam otrzymam... teraz to muszę zamienić na dziesiętne?

    Code:

    int zamiana(int temp)
    {
       int z;
       int y;
       int q;
       z=temp&=0x0F;
       y=temp&=0xF0>>4
       q=y*16+z;

    return(q);
    }


    coś takiego ma być?

    mam takie wrażenie że jest coś nie tak z pobieraniem danych z czujnika bo ciągle mam tą samą wartość na wyświetlaczu nawet jak ogrzewam ten czujnik w palach...

    0
  • #16 17 Lis 2009 11:38
    flapo213
    Poziom 21  

    Mniej wiecej tak ale to musiałbym sprawdzić. Ale popatrz uważnie zaznaczyłem Ci błąd w funkcji send_byte. Dobrze ją przeanalizuj. W języku C taka składania typu temp = wartosc>>1; zmienia jedynie wartość temp ale zmiennej wartosc nie zmienia

    natomiast konstrukcja typu

    wartosc = wartosc>>1;

    jak najbardziej

    0
  • #17 18 Lis 2009 20:48
    marwel007
    Poziom 8  

    Zdaje mi się że jest coś nie tak z odczytem bo ciągle wyświetla mi się ta sama wartość. Dobrze są timingi ustawione?

    Code:

    unsigned char read(void)
    {
       unsigned char PRESENCE=0;
       SET_BIT(H_DDR_1W,H_1W);
       CLR_BIT(H_PORT_1W,H_1W);
       _delay_us(1);
       CLR_BIT(H_DDR_1W,H_1W);
       SET_BIT(H_PORT_1W,H_1W);
       _delay_us(15);
       if(bit_is_set(H_PIN_1W,H_1W)) PRESENCE=1; else PRESENCE=0;

       return(PRESENCE);
    }

    unsigned char read_byte(void)
    {
       unsigned char i;
       int wartosc = 0;
       for(i=0;i<16;i++)
       {
          if(read()) wartosc|=0x01<<i;
          _delay_us(45);
       }
       return(wartosc);
    }


    [MEGA8][C] Błędny odczyt temperatury z DS18B20

    0
  • #18 18 Lis 2009 21:51
    r-maniac
    Poziom 14  

    Mam pytanie, czy funkcja opóźnienia o wartości dajmy przykładowo 100 us - _delay_us(100) jest w jakiś sposób zależna od prędkości taktowania mikrokontrolera i czy rzeczywiście w przypadku zastosowania różnych prędkości taktowania daje tą samą wartość opóźnienia równą 100 us, czy występują może jakieś odchylenia. Obecnie mam ustawioną prędkość taktowania równą 1 MHz wykorzystując wewnętrzny rezonator mikrokontrolera. Pytam, gdyż również nie nie udaje mi się uruchomić programu obsługującego czujnik DS18B20, mimo, że próbowałem już najróżniejszych kombinacji zmniejszania i zwiększania poszczególnych opóźnień.

    0
  • #19 18 Lis 2009 21:56
    snow
    Poziom 28  

    Zależy od wartości zmiennej F_CPU którą należy mieć zdefiniowaną w kodzie/makefile. Wystarczy zajrzeć do pliku delay.h na jego koniec.

    0
  • #20 18 Lis 2009 22:11
    marwel007
    Poziom 8  

    Hmm... ja nie modyfikuje pliku makefile ale zaraz tam zerknę. U mnie ustawia się wszystko w eclipse'ie.

    PS

    ja nie mam w katalogu w którym jest projekt pliku makefile.... mam tylko cos dziwnego o tej nazwie:

    Code:

    ################################################################################
    # Automatically-generated file. Do not edit!
    ################################################################################

    -include ../makefile.init

    RM := rm -rf

    # All of the sources participating in the build are defined here
    -include sources.mk
    -include subdir.mk
    -include objects.mk

    ifneq ($(MAKECMDGOALS),clean)
    ifneq ($(strip $(C_DEPS)),)
    -include $(C_DEPS)
    endif
    ifneq ($(strip $(ASM_DEPS)),)
    -include $(ASM_DEPS)
    endif
    ifneq ($(strip $(S_DEPS)),)
    -include $(S_DEPS)
    endif
    ifneq ($(strip $(S_UPPER_DEPS)),)
    -include $(S_UPPER_DEPS)
    endif
    endif

    -include ../makefile.defs

    # Add inputs and outputs from these tool invocations to the build variables
    LSS += \
    obslugalcd.lss \

    FLASH_IMAGE += \
    obslugalcd.hex \

    EEPROM_IMAGE += \
    obslugalcd.eep \

    SIZEDUMMY += \
    sizedummy \


    # All Target
    all: obslugalcd.elf secondary-outputs

    # Tool invocations
    obslugalcd.elf: $(OBJS) $(USER_OBJS)
       @echo 'Building target: $@'
       @echo 'Invoking: AVR C Linker'
       avr-gcc -Wl,-Map,obslugalcd.map -mmcu=atmega8 -o"obslugalcd.elf" $(OBJS) $(USER_OBJS) $(LIBS)
       @echo 'Finished building target: $@'
       @echo ' '

    obslugalcd.lss: obslugalcd.elf
       @echo 'Invoking: AVR Create Extended Listing'
       -avr-objdump -h -S obslugalcd.elf  >"obslugalcd.lss"
       @echo 'Finished building: $@'
       @echo ' '

    obslugalcd.hex: obslugalcd.elf
       @echo 'Create Flash image (ihex format)'
       -avr-objcopy -R .eeprom -O ihex obslugalcd.elf  "obslugalcd.hex"
       @echo 'Finished building: $@'
       @echo ' '

    obslugalcd.eep: obslugalcd.elf
       @echo 'Create eeprom image (ihex format)'
       -avr-objcopy -j .eeprom --no-change-warnings --change-section-lma .eeprom=0 -O ihex obslugalcd.elf  "obslugalcd.eep"
       @echo 'Finished building: $@'
       @echo ' '

    sizedummy: obslugalcd.elf
       @echo 'Invoking: Print Size'
       -avr-size --format=avr --mcu=atmega8 obslugalcd.elf
       @echo 'Finished building: $@'
       @echo ' '

    # Other Targets
    clean:
       -$(RM) $(OBJS)$(C_DEPS)$(ASM_DEPS)$(EEPROM_IMAGE)$(FLASH_IMAGE)$(ELFS)$(LSS)$(S_DEPS)$(SIZEDUMMY)$(S_UPPER_DEPS) obslugalcd.elf
       -@echo ' '

    secondary-outputs: $(LSS) $(FLASH_IMAGE) $(EEPROM_IMAGE) $(SIZEDUMMY)

    .PHONY: all clean dependents
    .SECONDARY:

    -include ../makefile.targets

    0
  • #21 18 Lis 2009 23:29
    r-maniac
    Poziom 14  

    Wrzucam listing programu, który od pewnego czasu usiłuję uruchomić...

    Code:
    #define F_CPU 1000000UL // oscylator wewnetrzny AtMega8
    
    #include <avr/io.h>
    #include <stdlib.h>
    #include <util/delay.h>


    #define WE 5
    #define PORT_1WIRE PINC
    #define CLEAR_1WIRE DDRC&=~_BV(WE)
    #define SET_1WIRE DDRC|=_BV(WE)

    char buf[8];

    // reset magistrali
    unsigned char RESET_PULSE(void)
    {
        unsigned char PRESENCE;
        CLEAR_1WIRE;
        _delay_us(500);
        SET_1WIRE;
        _delay_us(30);
        if (bit_is_clear(PORT_1WIRE, WE)) PRESENCE=1; else PRESENCE=0;
        _delay_us(470);
        return PRESENCE;
    }

    void send(char bit)
    {
        CLEAR_1WIRE;
        _delay_us(5);
        if(bit==1)
            SET_1WIRE;
        _delay_us(80);
        SET_1WIRE;
    }

    unsigned char read(void)
    {
        unsigned char PRESENCE=0;
        CLEAR_1WIRE;
        _delay_us(2);
        SET_1WIRE;
        _delay_us(15);
        if (bit_is_set(PORT_1WIRE, WE)) PRESENCE=1; else PRESENCE=0;
        return (PRESENCE);
    }

    unsigned send_byte(char wartosc)
    {
        unsigned char i;
        unsigned char pom;
        for (i=0; i<8; i++)
        {
            pom = wartosc>>i;
            pom &= 0x01;
            send(pom);
        }
        _delay_us(100);
    }

    unsigned char read_byte(void)
    {
        unsigned char i;
        unsigned char wartosc = 0;
        for (i=0; i<8; i++)
        {
            if(read()) wartosc|=0x01<<i;
            _delay_us(15);
        }
        return (wartosc);
    }

    int main (void)
    {
        unsigned char sprawdz;
        char temp1=0, temp2=0;
        lcd_init(LCD_DISP_ON);
        lcd_clrscr();
        lcd_puts("1 Wire\n");       
        _delay_ms(200);
        for(;;) {
            sprawdz=RESET_PULSE();
            if (sprawdz == 1)
            {
                send_byte(0xCC);
                send_byte(0x44);
                _delay_ms(250);
             _delay_ms(250);
             _delay_ms(250);

                sprawdz=RESET_PULSE();
                send_byte(0xCC);
                send_byte(0x44);
                temp1=read_byte();
                temp2=read_byte();

                sprawdz=RESET_PULSE();
                float temp=0;
                temp=(float)(temp1+(temp2*256))/16;
                dtostrf(temp,1,1,buf);
                lcd_clrscr();
                lcd_home();
                lcd_puts(buf);
                _delay_ms(200);
            }
            else
            {
                lcd_clrscr();
                lcd_home();
                lcd_puts("Brak pomiaru");
            }

        }
    }


    i ponawiam pytanie użytkownika marwel007 dotyczące timing'ów. Co poza tym może być źle, na co szczególnie oprócz wspomnianych czasów zwrócić uwagę? Dodam, że mam taki sam objaw jak autor postu, czyli cały czas widzę wartość -0.1

    0
  • #22 19 Lis 2009 08:00
    flapo213
    Poziom 21  

    Witam

    Więc tak odnośnie kodu

    Code:
           sprawdz=RESET_PULSE(); 
    
            if (sprawdz == 1)
            {
                send_byte(0xCC);
                send_byte(0x44);
    /*
                _delay_ms(250);
             _delay_ms(250);
             _delay_ms(250);
    */
    _delay_ms(750);
                //sprawdz=RESET_PULSE();
                //send_byte(0xCC);
                //send_byte(0x44);
    // Czemu taki dziwny odczyt ? Nie można za jednym razem całości odebrać
    // tylko tak dzielić na części
                temp1=read_byte();
                temp2=read_byte();

    // Reset pulse się wykonuje tylko raz przed wykonaniem szeregu czynności
    // Warto go wykonać raz na jakiś czas nie za każdym razem bo się będzie
    // wszystko resetować
                //sprawdz=RESET_PULSE();
                float temp=0;
                temp=(float)(temp1+(temp2*256))/16;
                dtostrf(temp,1,1,buf); // To funkcja konewrsji danej z hex na ASCII do buf ?
                lcd_clrscr();
                lcd_home();
                lcd_puts(buf);
                _delay_ms(200);
            }
            else
            {
                lcd_clrscr();
                lcd_home();
                lcd_puts("Brak pomiaru");
            }


    Wogóle to zacznijcie od czegoś prostszego, odczytajcie numer seryjny czy się zmienia dla różnych układów, szkoda że to Atmega 8 bo byście sobie jtagiem sprawdzili. Macie na 100% pewność że wasz protokół transmisyjny działa na 100% dobre zgodnie z algorytmem dallas/maxim. Szkoda że nie macie oscyloskopu.

    Pozdrawiam

    PS. Podeślijcie mi te źródła na emial to wam timingi sprawdzę na osyloskopie. To przynajmniej to się wyjaśni.

    0
  • #23 19 Lis 2009 08:33
    Balu
    Poziom 38  

    A odnośnie pierwszego postu i zmiennej i którą wszyscy w przerwaniu inkrementują tak skutecznie, to nie będzie ona się zmieniać, ;-) volatile ;]

    0
  • #24 20 Lis 2009 01:17
    r-maniac
    Poziom 14  

    Dzięki za chęć pomocy, oto program który wysłałem na maila:

    Code:
    #define F_CPU 1000000UL // oscylator wewnetrzny AtMega8
    
    #include <avr/io.h>
    #include <stdlib.h>
    #include <util/delay.h>


    #define WE 5 // przypisanie linii 1-Wire dla pinu PC5
    #define PORT_1WIRE PINC
    #define CLEAR_1WIRE DDRC&=~_BV(WE) // stan niski magistrali
    #define SET_1WIRE DDRC|=_BV(WE)    // stan wysoki magistrali

    char buf[8]; // bufor do przechowywania temperatury po konwersji

    // reset magistrali
    unsigned char RESET_PULSE(void)
    {
        unsigned char PRESENCE;
        CLEAR_1WIRE;
        _delay_us(500);
        SET_1WIRE;
        _delay_us(70);
        if (bit_is_clear(PORT_1WIRE, WE)) PRESENCE=1; else PRESENCE=0;
        _delay_us(470);
        return (PRESENCE);
    }

    void send(char bit) // wyslanie pojedynczego bitu
    {
        CLEAR_1WIRE;
        _delay_us(5);
        if(bit==1)
        SET_1WIRE;
        _delay_us(80);
        SET_1WIRE;
    }

    unsigned char read(void)
    {
        unsigned char PRESENCE=0;
        CLEAR_1WIRE;
        _delay_us(2);
        SET_1WIRE;
        _delay_us(15);
        if (bit_is_set(PORT_1WIRE, WE)) PRESENCE=1; else PRESENCE=0;
        return (PRESENCE);
    }

    unsigned send_byte(char wartosc)
    {
        unsigned char i;
        unsigned char pom;
        for (i=0; i<8; i++)
        {
            pom = wartosc>>i; // przesuniecie bitowe w prawo
            pom &= 0x01;         // skopiowanie bitu do pom
            send(pom);
        }
        _delay_us(108);
    }

    unsigned char read_byte(void)
    {
        unsigned char i;
        unsigned char wartosc = 0;
        for (i=0; i<8; i++)
        {
            if(read()) wartosc|=0x01<<i; // zczytywanie bit po bicie
            _delay_us(120);
        }
        return (wartosc);
    }

    int main (void)
    {
        unsigned char sprawdz;
        char temp1=0, temp2=0;
        lcd_init(LCD_DISP_ON);
        lcd_clrscr();
        lcd_puts("1 Wire\n");       
        _delay_ms(200);
        for(;;) {
            sprawdz=RESET_PULSE();
            if (sprawdz == 1)
            {
                send_byte(0xCC);  // skip ROM
                send_byte(0x44);  // convert temp
                _delay_ms(250);
             _delay_ms(250);   // The maximal possible delay is 262.14 ms / F_CPU in MHz - util/delay.h.
             _delay_ms(250);

                sprawdz=RESET_PULSE();
                send_byte(0xCC); // skip ROM
                send_byte(0xBE); // read scratchpad
                temp1=read_byte(); // odczyt LSB
                temp2=read_byte(); // odczyt MSB

                float temp=0; // zmienna do obliczen
                temp=(float)(temp1+(temp2*256))/16;
                dtostrf(temp,1,1,buf);  // konwersja float do stringa
                lcd_clrscr();
                lcd_home();
                lcd_puts(buf);
                _delay_ms(200);
            }
            else
            {
                lcd_clrscr();
                lcd_home();
                lcd_puts("Brak pomiaru");
            }

        }
    }


    Przyznam, że dopiero zaczynam przygodę z mikrokontrolerami i trochę drażni mnie to, że nie mogę podejrzeć co się w nim aktualnie dzieje z programem. Używam VMLAB'a i prostego programatora ISP własnej konstrukcji, co niestety nie daje zbyt dużych możliwości. Większość programów piszę metodą prób i błędów bez możliwości jakiejkolwiek kontroli "od wewnątrz". Stąd moje dodatkowe pytanie o wspomniany JTAG, czy macie jakieś sprawdzone programy do jego obsługi, jakiś schemat sprawdzonej konstrukcji, gdyż nie ukrywam, że chciałby go sobie sam skonstruować, czy to wymusza konieczność programowania w AVRStudio i co tak z grubsza umożliwia? Domyślam się też, że chyba warto "przesiąść" się na AVRStudio, gdyż program ten ma większe możliwości.

    0
  • #25 20 Lis 2009 08:32
    Balu
    Poziom 38  

    AvrStudio:)
    Podgląd rejestrów, PC, SREGa i takich tam:)

    0
  • #27 20 Lis 2009 21:33
    marwel007
    Poziom 8  

    Walcze już z tym dziadostwem n-ty wieczór i nie mam już pomysłów co tu zrobić. Przeczuwam że jest coś nie tak z odbiorem (lub transmisją) ponieważ w zmiennej do której zapisana jest temperatura jest ciągle ta sama wartość w chwili obecnej mam 159, wcześniej miałem b7,dużo różnych krzaczków i na początku -0.1.

    Mógłby ktoś zerknąć w timeingi z datasheeta i timingi w moich funkcjach? może coś źle odczytuje z tych wykresów?

    [MEGA8][C] Błędny odczyt temperatury z DS18B20

    Code:

    void send(char bit)
    {
       SET_BIT(H_DDR_1W,H_1W);
       CLR_BIT(H_PORT_1W,H_1W); // ustawiam port na wyjscie poziom 0
       _delay_us(15); //czekam
          if(bit==0) // jeżeli wysyłam zero to dalej czekam i dopiero wtedy ustawiam 1
          {
             _delay_us(60-15);
             SET_BIT(H_PORT_1W,H_1W);
          }
          else //gdy idzie jedynka to ustawiam 1 i czekam do konca okna transmisyjnego
             {
             SET_BIT(H_PORT_1W,H_1W);
             _delay_us(60-15);
             }
          _delay_us(1); // czekam 1us odstep miedzy oknami transmisyjnymi
    }

    unsigned char read(void)
    {
       unsigned char PRESENCE=0;
       SET_BIT(H_DDR_1W,H_1W);
       CLR_BIT(H_PORT_1W,H_1W); //ustawiam wyjscie stan niski na 1us
       _delay_us(1);
       CLR_BIT(H_DDR_1W,H_1W); // ustawiam wejscie podciagniete do 1
       SET_BIT(H_PORT_1W,H_1W);
       _delay_us(15);// po 15us sprawdzam czy stan na porcie wysylam 1 lub 0
       if(bit_is_set(H_PIN_1W,H_1W)) PRESENCE=1; else PRESENCE=0;
       _delay_us(60-15);// czekam do konca okna transmisyjnego
       _delay_us(1);// przerwa miedzy oknami
       return(PRESENCE);
    }

    0
  • #28 23 Lis 2009 19:36
    marwel007
    Poziom 8  

    Nikt mi nie pomoże?

    0
  • #29 23 Lis 2009 23:45
    Balu
    Poziom 38  

    Nie podajesz, zegarów, czy dobrze wszystko deklarujesz etc, więc, NO, nobody's gonna help ya.
    Sorry(;
    PS w necie są tony działających bibliotek do tych układów, może warto ich użyć do testów?:>

    0
  • #30 23 Lis 2009 23:49
    mirekk36
    Poziom 42  

    Balu napisał:

    PS w necie są tony działających bibliotek do tych układów, może warto ich użyć do testów?:>


    tym bardziej, że podałem link do na prawdę jednej z lepszych dzięki, której można się dodatkowo sporo nauczyć

    mirekk36 napisał:
    przeanalizuj sobie ten kod - to na pewno dużo ci pomoże:

    http://www.siwawi.arubi.uni-kl.de/avr_projects/tempsensor/index.html


    ale cooo tam ;)

    0