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

[attiny2313][C][winavr] ds18b20 program

seba.et 08 Sie 2008 14:09 5991 16
  • #1 5420409
    seba.et
    Poziom 17  
    Witam.
    Proszę nie mówcie żebym nie szukał na forum bo tego jest miliony i tu się zgodzę bo jest pełno ale dla kogoś kto średnio się zna to jest mało przydatne.

    Mam układ ds18b20 podłączony do portu D pin 0 avr'ka tiny2313 rezystor podciągający 4,7k. Cały port B wykorzystany do sterowani podwójnym wyświetlaczem siedmio segmentowym przy pomocy CD4511. Część sprzętowa jest sprawna, wyświetlacz działa tak jak działać powinien. Nie mam zewnętrznego kwarcu. Poniżej zamieszczę program do obsługi tego ds'a który oczywiście nie działa tzn ciągle wyświetla 70 albo 07 w zależności od zmiennych w1 i w2.

    Pozdrawiam i mam nadzieje że mój problem nie odejdzie w cień i ktoś pomoże.
    
    #include <avr/io.h>
    #include <stdlib.h>
    #include <util/delay.h>
    
    #define WE 0
    #define PORT_1wire PIND
    #define SET_1wire DDRD&=~_BV(WE)
    #define CLEAR_1wire DDRD|=_BV(WE)
    
    int d1,d2,w1,w2;
    
    
    //reset magistrali oczekiwanie na impuls
    unsigned char RESET_PULSE(void)
    {
    unsigned char PRESENCE;
    CLEAR_1wire; // ustawienie na poziom niski
    _delay_us(500);
    SET_1wire; //ustawienie na poziom wysoki
    _delay_us(30); //oczekiwanie na ustaweinie linii w poziom niski przez ds'a
    
    //sprawdzenie poziomu na linii ds'a czy w stanie niskim
    if (bit_is_clear(PORT_1wire, WE)) {PRESENCE=1;} else {PRESENCE=0;}
    //1-odebrano bit presence, 0 stan nieaktywnosci
    _delay_us(470);// oczekiwanie przez mastera ok 470 mikro sekund i spr czy ds podciagnal magistrale
    //sprawdzamy czy poziom linni ustawiony
    if (bit_is_set(PORT_1wire, WE)) {PRESENCE=1;} else {PRESENCE=0;}
    return PRESENCE; // zwracamy wartosc do funkcji
    }
    
    
    //wysyla do ukladu pojedynczy bit
    void send(char bit)
    {
    CLEAR_1wire;// ustawienie w stan niski magistrali
    _delay_us(5);
    if(bit==1)
    SET_1wire; //zwolnienie magistrali - wyslanie jedynki
    _delay_us(80);//przetrzymanie - wyslanie zera
    SET_1wire;
    }
    
    
    //odczytuje bit z magistrali
    unsigned char read(void)
    {
    unsigned char PRESENCE=0;
    
    CLEAR_1wire; //ustawienie w stan niski
    _delay_us(2);
    SET_1wire;
    _delay_us(15);
    
    if (bit_is_set(PORT_1wire, WE)) PRESENCE=1; else PRESENCE=0;
    
    return(PRESENCE);
    }
    
    //wysyla caly bajt do ukladu
    
    void send_byte(char wartosc)
    {
    unsigned char i;//zmienna licznikowa
    unsigned char pom; //zmienna pomocnicza
    
    for(i=0;i<8;i++)
    {
    pom = wartosc>>i;//przesuniecie bitowe w prawo
    pom &=0x01; //skopiowanie bitu do zmiennej pomocniczej
    send(pom); //wyslanie bitu na magistrale
    }
    _delay_us(100);
    }
    
    //zczytuje caly bajt z ukladu
    unsigned char read_byte(void)
    {
    unsigned char i;// zmienna licznikowa
    unsigned char wartosc=0; //zczytywana wartosc
    
    for (i=0;i<8;i++)
    {
    if (read()) wartosc|=0x01<<i; //zczytywanie po jednym bicie
    _delay_us(15);
    }
    
    return(wartosc);
    }
    
    
    
    int main (void)
    {
    //deklaracja zmiennych lokalnych
    
    DDRB = 0xFF; // Ustawiamy port B jako wyjścia
    unsigned char sprawdz;
    char temp1=0, temp2=0;
    //
    
    for(;;)
    {
    if(sprawdz==1)
    {
    send_byte(0xCC); //skip rom
    send_byte(0x44);//convert t
    _delay_ms(750);
    
    sprawdz=RESET_PULSE();
    send_byte(0xCC);
    send_byte(0xBE);
    
    temp1=read_byte();//odczytanie lsb
    temp2=read_byte();//odczytanie msb
    
    sprawdz=RESET_PULSE(); //zowlnienie magistrali
    
    
    w2 = temp1/10;
    w1 = temp2%10;
    
    
    switch(w2){
    case 0:
    d2=(0x00);
    break;
    case 1:
    d2=(0x01);
    break;
    case 2:
    d2=(0x08);
    break;
    case 3:
    d2=(0x09);
    break;
    case 4:
    d2=(0x04);
    break;
    case 5:
    d2=(0x05);
    break;
    case 6:
    d2=(0x0C);
    break;
    case 7:
    d2=(0x0D);
    break;
    case 8:
    d2=(0x02);
    break;
    case 9:
    d2=(0x03);
    break;
    default:
    d2=(0x00);
    break;
    }
    
    
    switch(w1){
    case 0:
    d1=(0x00);
    break;
    case 1:
    d1=(0x01);
    break;
    case 2:
    d1=(0x08);
    break;
    case 3:
    d1=(0x09);
    break;
    case 4:
    d1=(0x04);
    break;
    case 5:
    d1=(0x05);
    break;
    case 6:
    d1=(0x0C);
    break;
    case 7:
    d1=(0x0D);
    break;
    case 8:
    d1=(0x02);
    break;
    case 9:
    d1=(0x03);
    break;
    default:
    d1=(0x00);
    break;
    }
    
    
    PORTB=(d1 <<4 | d2);
    
    _delay_ms(200);
    
    }
    }
    }
    
    
    
  • #2 5421213
    Dr.Vee
    VIP Zasłużony dla elektroda
    Witam,

    1. Sformatuj kod, wcięcia...
    2. Mimo wszystko - poszukaj na forum i w googlach :)
    3. Czy każdy musi pisać własną obsługę 1wire? Może szybciej będzie skorzystać z gotowych rozwiązań??
    4. Takie rzeczy jak Twój kod "case" powinno się robić tablicami.

    Pozdrawiam,
    Dr.Vee
  • #4 5421955
    zumek
    Poziom 39  
    
    //...
    temp1=read_byte();//odczytanie lsb
    temp2=read_byte();//odczytanie msb
    
    sprawdz=RESET_PULSE(); //zowlnienie magistrali
    
    
    w2 = temp1/10;        // ???
    w1 = temp2%10;      // ???
    //... 


    Wytłumacz nam proszę , skąd Ty wytrzasnąłeś takie wyliczenia i dlaczego zastosowałeś int(temp1) , a wczytujesz tylko (unsigned) char :?:

    Piotrek
  • #5 5422230
    demeus
    Poziom 18  
    Tak wygląda najprostsza obsługa DS'a razem z LCD:

    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/eeprom.h>
    #include <string.h>
    
    #include "delay.h"
    #include "lcd.h"
    #include "ds18x20.h"
    
    
    int main( void )
    {
    	uint16_t decicelsius;
    	uint8_t diff, i, subzero, cel, cel_frac_bits;
    	LCD_init();
    
    	while(1)
    	{
    		DS18X20_start_meas( DS18X20_POWER_PARASITE, NULL );
    		delayms(DS18B20_TCONV_12BIT);
    		DS18X20_read_meas_single(0x10, &subzero, &cel, &cel_frac_bits);
    		decicelsius = DS18X20_temp_to_decicel(subzero, cel, cel_frac_bits);
    
    		LCD_xy(0,0);
    		LCD_putchar((subzero)?'-':'+');
     		LCD_putint( (decicelsius/10) ,10);
    		LCD_putchar(',');
    		LCD_putchar( (decicelsius%10) + '0');
    	}
    }
    


    Jest to przykład wzięty z bilbiotek rklibavr.
    Biblioteki rklibavr znajdziesz tu: http://avr.elektroda.eu/?q=node/4


    Jeśli obsługujesz DS18B20 to odczyt wygląda tak:
    
    DS18X20_read_meas_single(0x28, &subzero, &cel, &cel_frac_bits);
    

    natomiast jak obsługujesz DS18S20 to odczyt wygląda tak:
    
    DS18X20_read_meas_single(0x10, &subzero, &cel, &cel_frac_bits);
    


    Opisane jest to w pliku ds18x20.h w bibliotekach rklibavr.

    Mam nadzieje, że poraz pierwszy komuś pomogłem na elektrodzie :D

    --
    pozdrawiam
    demeus
  • #6 5422375
    seba.et
    Poziom 17  
    Jestem miło zaskoczony tak sporym zainteresowanie za co dziękuje.
    Demeus a nie miałeś problemu z tą biblioteką, napisałem ten program co proponujesz dodałem biblioteki ale ciągle wywala mi błędy typu:

    undefined reference to 'DS18X20_start_meas'
    undefined reference to 'delayloop32'
    undefined reference to 'DS18X20_read_meas_single'
    undefined reference to 'DS18X20_temp_to_decicel'

    już nawet skopiowałem wszystkie te biblioteki które są potrzebne do katalogu z projektem ale nadal nic.
  • #7 5422416
    Dr.Vee
    VIP Zasłużony dla elektroda
    Witam,

    Musisz dodać do linkera flagi:

    
    -Lkatalog_z_biblioteka -lnazwa_biblioteki
    


    W dobrze napisanym Makefile dodajesz te opcje do zmiennej LDFLAGS.

    Pozdrawiam,
    Dr.Vee
  • #8 5422460
    demeus
    Poziom 18  
    W bibliotekach rklibavr sa gotowe przyklady wraz z plikami makefile, w których wystatrzy zmienić ścieżki do bilbiotek w przypadku ich przenoszenia, ew. możesz skompliować to w katalogu gdzie jest przykład wtedy bez problemu kompiler/linker powinien Ci wszystko znaleźć.

    --
    pozdrawiam
    demeus
  • #9 5422466
    seba.et
    Poziom 17  
    Witam.

    Mój make file tworze przy pomocy narzędzia w pakiecie winavr

    oto fragment w którym znajdują się te flagi i biblioteki które dodałem:

    
    #---------------- Linker Options ----------------
    #  -Wl,...:     tell GCC to pass this to linker.
    #    -Map:      create map file
    #    --cref:    add cross reference to  map file
    LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
    LDFLAGS += $(EXTMEMOPTS)
    LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
    LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
    #LDFLAGS += -T linker_script.x
    LDFLAGS -LC:\avr\lib -lds18x20.h
    LDFLAGS -LC:\avr\lib -ldelay.h
    LDFLAGS -LC:\avr\lib -lonwire.h


    o takie coś chodzi?

    Dodano po 4 [minuty]:

    skompilowałem tak jak autor zalecał czyli z wiersza poleceń przykład full ale to nie pomogło
  • #10 5422516
    demeus
    Poziom 18  
    Otwórz gotowy przykład z bilbiotek rklibavr w WinAVR i uruchom kompilacje.
    U mnie działa bez problemu
  • #11 5422536
    Dr.Vee
    VIP Zasłużony dla elektroda
    Witam,

    seba.et napisał:
    
    #LDFLAGS += -T linker_script.x
    LDFLAGS -LC:\avr\lib -lds18x20.h
    LDFLAGS -LC:\avr\lib -ldelay.h
    LDFLAGS -LC:\avr\lib -lonwire.h


    o takie coś chodzi?


    Nie. Plik nagłówkowy to nie biblioteka.

    Raczej o coś takiego:
    
    LDFLAGS += -LC:\avr\lib -lnazwa
    


    Ale wcześniej musisz jeszcze skompilować bibliotekę, tj. uzyskać plik w katalogu C:\avr\lib który będzie się nazywał libnazwa.a

    Zrób tak, jak mówi demeus - spróbuj najpierw skompilować przykłady, które są rozprowadzane razem z rklibavr. Później użyj tamtego makefile (z katalogu przykładu) do swojego projektu, zmień tylko MCU i USRLIB na prawidłowe.

    Daj znać, co Ci się uda zrobić.

    Pozdrawiam,
    Dr.Vee
  • #14 5425241
    seba.et
    Poziom 17  
    Witam ponownie, coś udało się ruszyć.
    Wszystko ładnie pięknie się kompiluje, poniżej zamieszczam kod programu czy mógłby ktoś sprawdzić czy ma prawo działać bo narazie wyświetla mi 38 albo 83 i nie reaguje na podgrzanie.

    Dla osób które w przyszłości będą mieć podobny problem, ja rozwiązałem to w ten sposób, że najpierw zainstalowałem najnowszą wersję winavr następnie biblioteki avr umieściłem na dysku C w katalogu rklibavr czyli tak jak się wypakowały z archiwum. Następnie odpaliłem tak jak koledzy podpowiadali jakiś przykład w winavr i nic więcej nie musiałem robić. Kolejna rzecz to tylko zapisanie swojego projektu w katalogu z przykładem i kompilacja śmiga bez errorów :)
    Pozdrawiam


    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/eeprom.h>
    #include <string.h>
    
    #include "delay.h"
    #include "ds18x20.h"
    
    uint8_t gSensorIDs[OW_ROMCODE_SIZE];
    unsigned char w1,w2,d1,d2;
    
    
    int main( void )
    {
    	DDRB = 0xFF; // Ustawiamy port B jako wyjścia
    	DDRD = 0x00;
    
    	uint16_t decicelsius;
    	uint8_t diff, i, subzero, cel, cel_frac_bits;
    
    
    	
    	while(1)
    	{
    
    		DS18X20_start_meas( DS18X20_POWER_PARASITE, NULL );
    		delayms(DS18B20_TCONV_12BIT);
    		DS18X20_read_meas_single(0x28, &subzero, &cel, &cel_frac_bits);
    		decicelsius = DS18X20_temp_to_decicel(subzero, cel, cel_frac_bits);
    		
    		
    		
    				w2 = decicelsius/10;
    				w1 = decicelsius%10;
    		
    
    		switch(w2){
    											case 0:
    													d2=(0x00);
    											break;
    											case 1:
    													d2=(0x01);
    											break;
    											case 2:
    													d2=(0x08);
    											break;
    											case 3:
    													d2=(0x09);
    											break;
    											case 4:
    													d2=(0x04);
    											break;
    											case 5:
    													d2=(0x05);
    											break;
    											case 6:
    													d2=(0x0C);
    											break;
    											case 7:
    													d2=(0x0D);
    											break;
    											case 8:
    													d2=(0x02);
    											break;
    											case 9:
    													d2=(0x03);
    											break;	
    											default:
    													d2=(0x00);
    											break;
    									  }
    							
    								
    							switch(w1){
    											case 0:
    													d1=(0x00);
    											break;
    											case 1:
    													d1=(0x01);
    											break;
    											case 2:
    													d1=(0x08);
    											break;
    											case 3:
    													d1=(0x09);
    											break;
    											case 4:
    													d1=(0x04);
    											break;
    											case 5:
    													d1=(0x05);
    											break;
    											case 6:
    													d1=(0x0C);
    											break;
    											case 7:
    													d1=(0x0D);
    											break;
    											case 8:
    													d1=(0x02);
    											break;
    											case 9:
    													d1=(0x03);
    											break;	
    											default:
    													d1=(0x00);
    											break;
    										}
    										
    								
    						PORTB=(d1 <<4 | d2);
    					
    	}
    		
    }


    Przed chwilą zauważyłem, że w pliku make w katalogu z przykładem jest wybór procka i na tej liście nie ma mojego attiny2313, trzeba samemu dopisać czy bibliotek przystosowana jest do tych wymienionych??
  • #15 5425346
    demeus
    Poziom 18  
    Witam

    Ta linia w programie jest zbędna:
    uint8_t gSensorIDs[OW_ROMCODE_SIZE];


    W pliku makefile w definicji możesz dopisać własnego procka,
    tak jak i to robiłeś we wcześniejszym pliku makefile.

    Biegły w C nie jestem, dopiero się uczę, ale:
    -) dodaj definicję pliku #include "config.h" plik powinien znajdować się w katalogu razem z przykładem na którym pracujesz,
    -) w pliku config.h ustaw port na którym pracuje czujnik DS poprzez:
    #define OW_PORT		PORTB
    #define OW_BIT		0

    oczywiście wpisz swój port i pin
    -) sprawdź czy czujnik jest podłączony poprawnie wg. tego schematu:
    http://radzio.dxp.pl/ds18b20/ds18b20_podstawy.htm

    Sprawdź czy definicji
    #include "config.h"
    nie masz przypadkiem w pliku: ds18x20.h, jeśli tak to nie musisz jej dodawać do głównego pliku z programem.

    P.S. Wypada podziękować czasem ludziom za pomoc :)

    --
    pozdrawiam
    demeus
  • #16 5427652
    seba.et
    Poziom 17  
    witam.

    config.h dołączony, port i pin ds'a również, zasilanie z osobnego przewodu. Tak się zastanawiam czy nie trzeba przypadkiem ustawić zegaru procka tak jak jest w pliku config na 8MHz przez fuse bity?

    Słuszna uwaga demeus, zapomniałem jakże prostego i zarazem ważnego słowa DZIĘKUJĘ. Więc dzięki wielkie za swój wkład jaki poświęcacie.

    Dodano po 2 [godziny] 16 [minuty]:

    No w końcu coś mierzy i wygląda na to że całkiem poprawnie:) (sprawdzone z lodem i zapalniczką) wystarczyło dzielić nie decicelsius a cel i wszystko działa. Jeszcze raz wielkie dzięki dla wszystkich w szczególności za pomoc w uruchomieniu gotowych bibliotek. Pozdro demeus:)
  • Pomocny post
    #17 5430795
    demeus
    Poziom 18  
    seba.et napisał:
    witam.

    config.h dołączony, port i pin ds'a również, zasilanie z osobnego przewodu. Tak się zastanawiam czy nie trzeba przypadkiem ustawić zegaru procka tak jak jest w pliku config na 8MHz przez fuse bity?

    Słuszna uwaga demeus, zapomniałem jakże prostego i zarazem ważnego słowa DZIĘKUJĘ. Więc dzięki wielkie za swój wkład jaki poświęcacie.

    Dodano po 2 [godziny] 16 [minuty]:

    No w końcu coś mierzy i wygląda na to że całkiem poprawnie:) (sprawdzone z lodem i zapalniczką) wystarczyło dzielić nie decicelsius a cel i wszystko działa. Jeszcze raz wielkie dzięki dla wszystkich w szczególności za pomoc w uruchomieniu gotowych bibliotek. Pozdro demeus:)


    W pliku config.h podajesz swoje taktowanie procka! takie z jakim działa Twój procek
    Wg. mnie wartością wyjściową do obrówki jest decicelsius i dzielisz to najpierw przez 10 by otrzymać część całkowitą a potem robisz %10 (modulo) by otrzymać resztę z dzielenia - część po przecinku.

    Nie mam za dużego doświadczenia i w zasadzie nie wiem czemu Ci działa inny sposób, ale skoro działa to ok :)

    P.S. Dziękuję sie wyraża poprzez kliknięcie na przycisk [Pomógł] ;)

    --
    pozdrawiam
    demeus
REKLAMA