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

[C][ATMEGA32] brak komunikacji z DS18B20

simoon87 15 Lis 2010 21:59 2142 7
  • #1 15 Lis 2010 21:59
    simoon87
    Poziom 9  

    Witam, napiąłem program do obsługi termometru cyfrowego DS18B0, program kompiluje się bez błędu a po wgraniu na wyświetlaczu wyświetla się tylko -1.0. Proszę o sprawdzenie kodu bo nie wiem już gdzie jest błąd.


    DS18B20.H

    Code:

    #ifndef ds18b20
    #define ds18b20

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

    void delayms(long t);
    void delayus(long t);
    unsigned char RESET_PULSE(void);
    void send(char bit);
    void send_byte(char wartosc);
    unsigned char read(void);
    unsigned char read_byte(void);

    #endif


    DS18B20.C
    Code:

    #include <avr/io.h>
    #include <util/delay.h>
    #include "ds18b20.h"

    /***************************************      Opoznienia      **********************************/

    void delayms(long t)
    {
       while(t)
       {
          _delay_ms(10);
          t--;
       }
    }
    void delayus(long t)
    {
       while(t)
       {
          _delay_us(1);
          t--;
       }
    }

    /***************************************   Magistrala 1-wire    **********************************/
       
    unsigned char RESET_PULSE(void)      ////reset magistrali i oczekiwanie na impuls PRESENCE
    {
       char PRESENCE;
       CLEAR_1WIRE;               //magistrala - stan niski
       delayus(500);
       SET_1WIRE;                  //magastrala - stan wysoki
       delayus(30);               //oczekiwanie na stan niski od DS
       
       if(bit_is_clear(PORT_1WIRE, WE))//sprawdzamy stan linii (LOW)
       {
          PRESENCE = 1;            //1 - odebrano bit
       }
       else
       {
          PRESENCE = 0;            //0 - stan nieaktywny
       }




       
       delayus(470);               //MASTER na stan wysoki od DS
       
       if(bit_is_set(PORT_1WIRE, WE))   //sprawdza stan linii (HIGH)
       {
          PRESENCE = 1;
       }
       else
       {
          PRESENCE=0;
       }
       return(PRESENCE);            //zwraca wartosc funkcji
    }

    void send(char bit)               ////wysyłanie pojedynczego bitu do DS
    {
       CLEAR_1WIRE;
       delayus(5);

       if(bit == 1)
       {
          SET_1WIRE;               //zwolnienie magistrali - wysylanie 1
          delayus(80);            //przetrzymanie
          CLEAR_1WIRE;            //wysylanie zera
       }
    }

    void send_byte(char wartosc)      ////wysyla caly bajt na magistrale
    {
       unsigned char i=0;            //zmienna licznikowa
       unsigned char pom;            //pomocnicza

       for(i=0; i<8; i++)
       {
          pom = wartosc>>i;         //przesuniecie bitowe
          pom = 0x01;               //skopiowanie bitu do zmiennej pomocniczej
          send(pom);               //wyslanie bitu na magistrale
       }
       delayus(100);
    }

    unsigned char read(void)         ////zczytuje bit z magistralii
    {
       unsigned char PRESENCE = 0;

       CLEAR_1WIRE;               //ustawienie w stan niski DS
       delayus(2);                  //oczekiwanie
       SET_1WIRE;                  //zwolnienie magistrali
       delayus(15);               //oczeliwanie

       if(bit_is_set(PORT_1WIRE, WE))   //odbior 1 lub 0
       {
          PRESENCE = 1;
       }
       else
       {
          PRESENCE = 0;
       }
       return(PRESENCE);            //zwracanie wartosci funkcjii
    }

    unsigned char read_byte(void)      ////zczytuje bajt z magistralii
    {
       unsigned char i = 0;         //zmienna licznikowa
       unsigned char wartosc = 0;      //pomocnicza

       for(i=0; i<8; i++)
       {
          if(read())
          {
             wartosc |= 0x01<<i;      //zczystywanie po jednym bicie
          }
          delayus(15);
       }
       return(wartosc);            //zwrot wartosci funkcjii         
    }


    MAIN.C
    Code:

    #define F_CPU 16000000L
    #include <avr/io.h>
    #include <util/delay.h>
    #include <stdlib.h>
    #include "hd44780.h"
    #include "ds18b20.h"

    /***************************************   Zmienne i prototypy    **********************************/
    void sys_init(void);

    char buf[8];

    /***************************************      Program glowny       **********************************/
    void main(void)
    {
       unsigned char sprawdz;
       char LSB = 0, MSB = 0;

       sys_init();
       for(;;)
       {
          sprawdz = RESET_PULSE();
          if(sprawdz)
          {
             send_byte(0xCC);      //SKIP ROM
             send_byte(0x44);      //CONVERT T
             delayms(75);         //oczekiwanie - czas konwersji
             
             sprawdz = RESET_PULSE();//wysylanie sygnalu reset
             send_byte(0xCC);      //SKIP ROM
             send_byte(0xBE);      //READ SCRATCHPAD

             LSB = read_byte();      //odczyta czesci mlodszej
             MSB = read_byte();      //odczyta czesci starszej

             sprawdz = RESET_PULSE();//zwolnienie magistrali
             
             float temp = 0;
             temp = (float)(LSB | (MSB<<8));
                      
             dtostrf(temp,1,1,buf);   //konswersja FLOAT na STRING
             LCD_LOCATE(0,0);
             lcd_puts(buf);
             delayms(100);
          }
       }
    }

    /***************************************      Funkcje       **********************************/
    void sys_init(void)
    {
       lcd_init();
        LCD_DISPLAY(LCDDISPLAY);
       LCD_CLEAR;
       LCD_LOCATE(0,0);
    }




    inventco.eu - regulamin p.11.1. Poprawiłem.

    0 7
  • #2 15 Lis 2010 22:13
    boogdan
    Poziom 15  

    ja na twoim miejscu nie używałbym jakichś dziwnych wrapperów na wbudowane funkcje opóźnień.
    dla ms zwielokrotniasz czas oczekiwania 10 razy, a dla us to ciężko powiedzieć jak sie funkcja _delay_us zachowa przy opóźnieniu 1us.
    lepiej użyj zamiast swoich funkcji te wbudowane _delay_ms i _delay_us

    0
  • #3 15 Lis 2010 23:22
    hotdog
    Poziom 26  

    Powiedz jakie wartości odczytujesz z czujnika (chodzi mi o wartości binarne zmiennych LSB i MSB).

    temp = (float)(LSB | (MSB<<8)); dziwnie mi to wygląda. jak by tu czegoś brakowało...

    Jeżeli na czujniku rzeczywiście by było -1 to byłby uwalony, ale tutaj ewidentnie masz coś w kodzie skopane.

    Podaj jakie LSB i MSB przyjmuje wartości.

    Pozdrawiam

    0
  • #4 16 Lis 2010 07:52
    simoon87
    Poziom 9  

    boogdan napisał:
    ja na twoim miejscu nie używałbym jakichś dziwnych wrapperów na wbudowane funkcje opóźnień.
    dla ms zwielokrotniasz czas oczekiwania 10 razy, a dla us to ciężko powiedzieć jak sie funkcja _delay_us zachowa przy opóźnieniu 1us.
    lepiej użyj zamiast swoich funkcji te wbudowane _delay_ms i _delay_us


    powodem powstania takich funkcji jest to ze _delay_ms i _delay_us maja swoje ograniczenia wg helpa od AVR-GCC (_delay_ms działa poprawinie do ok.200ms itd)

    hotdog napisał:

    Podaj jakie LSB i MSB przyjmuje wartości.


    no niestety nie wiem jak mam to sprawdzic

    0
  • #5 16 Lis 2010 09:05
    hotdog
    Poziom 26  

    simoon87 napisał:

    no niestety nie wiem jak mam to sprawdzic


    To ja nie wiem jak mam Tobie pomóc ;)

    Wyświetl je na wyświetlaczu albo coś...

    0
  • #6 16 Lis 2010 09:42
    tmf
    Moderator Mikrokontrolery Projektowanie

    simoon87 napisał:
    boogdan napisał:
    ja na twoim miejscu nie używałbym jakichś dziwnych wrapperów na wbudowane funkcje opóźnień.
    dla ms zwielokrotniasz czas oczekiwania 10 razy, a dla us to ciężko powiedzieć jak sie funkcja _delay_us zachowa przy opóźnieniu 1us.
    lepiej użyj zamiast swoich funkcji te wbudowane _delay_ms i _delay_us


    powodem powstania takich funkcji jest to ze _delay_ms i _delay_us maja swoje ograniczenia wg helpa od AVR-GCC (_delay_ms działa poprawinie do ok.200ms itd)

    hotdog napisał:

    Podaj jakie LSB i MSB przyjmuje wartości.


    no niestety nie wiem jak mam to sprawdzic


    Przeczytaj lepiej tego hepla dokładniej, bo powtarzasz bajki.
    Twoja funkcja realizująca opóźnienia us działa tak sobie - organizacja pętli zajmuje porównywalny czas z realizacja 1us opóźnienia. Poza tym jak Scypio Afrykański dodam, że już po raz 1001 widzę ten sam pokręcony kod 1-wire :) Czy robiąc copy/paste analizowałeś co ten kod robi?
    To, że masz -1 znaczy najpewniej, że obsługa OW nie działa i na tym się skup.

    0
  • Pomocny post
    #7 16 Lis 2010 14:46
    a2d2a2m
    Poziom 15  

    Jeżeli kolega może podłączyć kwarc 16MHz, to po powrocie z pracy mogę załączyć sprawdzony program termometru z atmegą 32, wspomnianym kwarcem i obsługą LCD 2x16.
    Układ DS18b20, jak inne układy 1-wire wymagają bardzo dokładnych czasów, żeby się poprawnie skomunikować. Ja też trochę powalczyłem zanim zobaczyłem prawidłową temperaturę.
    Zgodnie z obietnicą:

    Code:

    #<include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/eeprom.h>
    #include <string.h>
    //#include <avr/signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <avr/pgmspace.h>
    #include <inttypes.h>
    //#include <util/delay.h>
    #define f_CPU 16000000UL

    ////////////////////termometr////////////////////////////////
    #define WE 0 //czujnik podłączony do portu D pin 0
    #define PORT_1WIRE PIND   
    #define CLEAR_1WIRE DDRD |= _BV(WE)
    #define SET_1WIRE DDRD &=  ~_BV(WE)
    char buf[8];

    ////////////////////wyswietlacz/////////////////////////
    #define DDR_DB4 DDRA //konfiguracja portów podłączenia wyświetlacza
    #define PORT_DB4 PORTA
    #define DB4 PA3
    #define DDR_DB5 DDRA
    #define PORT_DB5 PORTA
    #define DB5 PA4
    #define DDR_DB6 DDRA
    #define PORT_DB6 PORTA
    #define DB6 PA5
    #define DDR_DB7 DDRA
    #define PORT_DB7 PORTA
    #define DB7 PA6
    #define DDR_RS DDRA
    #define PORT_RS PORTA
    #define RS PA1
    #define DDR_E DDRA
    #define PORT_E PORTA
    #define E PA2 
    #define SET_DB4 PORT_DB4 |= _BV(DB4)
    #define CLR_DB4 PORT_DB4 &= ~_BV(DB4)
    #define SET_DB5 PORT_DB5 |= _BV(DB5)
    #define CLR_DB5 PORT_DB5 &= ~_BV(DB5)
    #define SET_DB6 PORT_DB6 |= _BV(DB6)
    #define CLR_DB6 PORT_DB6 &= ~_BV(DB6)
    #define SET_DB7 PORT_DB7 |= _BV(DB7)
    #define CLR_DB7 PORT_DB7 &= ~_BV(DB7)
    #define SET_E PORT_E |= _BV(E)
    #define CLR_E PORT_E &= ~_BV(E)
    #define SET_RS PORT_RS |= _BV(RS)
    #define CLR_RS PORT_RS &= ~_BV(RS)
    #define tau0 247
    #define LCD_X 16
    #define LCD_Y 2

    void waitms(char x)
    {
    unsigned char a,b;
    for( ; x>0;--x)

       for (b=53;b>0;--b)
       for(a=20;a>0;--a)

          __asm("nop");
          }

    void out_nibble(char x)
    {
    CLR_DB4;
    CLR_DB5;
    CLR_DB6;
    CLR_DB7;
    if(x & _BV(0)) SET_DB4;
    if(x & _BV(1)) SET_DB5;
    if(x & _BV(2)) SET_DB6;
    if(x & _BV(3)) SET_DB7;
    }


    void write_to_lcd(char x)
    {
    SET_E;
    out_nibble(x >> 4);
    CLR_E;
    SET_E;
    out_nibble(x);
    CLR_E;
    waitms(1);
    }

    void write_command(char x)
    {
    CLR_RS;
    write_to_lcd(x);
    }

    void write_char(char x)
    {
    SET_RS;
    write_to_lcd(x);
    }

    void write_text(char * s)
    {
    while(*s)
    {
    write_char(*s);
    s++;
    }
    }

    void lcd_init(void)
    {
    DDR_DB4 |= _BV(DB4);
    DDR_DB5 |= _BV(DB5);
    DDR_DB6 |= _BV(DB6);
    DDR_DB7 |= _BV(DB7);
    DDR_E |= _BV(E);
    DDR_RS |= _BV(RS);
    //waitms(15);
     waitms(1);
    CLR_E;
    CLR_RS;
    char i;
    for(i = 0; i < 3; i++)
    {
    SET_E;
    out_nibble(0x03);
    CLR_E;
     waitms(1);
    }
    SET_E;
    out_nibble(0x02);
    CLR_E;
    waitms(1);
    write_command(0x28); // interfejs 4-bity, 2-linie, znak 5x7
    write_command(0x08); // wy31cz LCD, kursor i miganie
    write_command(0x01); // czyoa LCD
    write_command(0x06); // bez przesuwania w prawo
    write_command(0x0C); // w31cz LCD, bez kursora i mrugania
    }


    void LCD_xy(uint8_t x, uint8_t y)
    {
    switch(y)
    {
    case 1: y=0x40; break;
    case 2: y=0x14; break;
    }
    write_command(0x80+y+x);
    }

    void LCD_clr(void)
    {
    write_command(0x01);
    waitms(1);
    LCD_xy(0,0);
    }

    ///////////////////////////////////////////////////termometr///////////////////////////////////////
    void owire_delay(unsigned int __count)
    {
       __asm__ volatile (
          "1: sbiw %0,1" "\n\t"
          "brne 1b"
          : "=w" (__count)
          : "0" (__count)
       );
    }




    // reset magistrali
    unsigned char RESET_PULSE(void)
    {
    unsigned char PRESENCE;
    CLEAR_1WIRE;
       owire_delay(1920);    
    SET_1WIRE;

     owire_delay(120);    
    if (bit_is_clear(PORT_1WIRE, WE)) {PRESENCE=1;} else {PRESENCE=0;}

    owire_delay(1920);
    if (bit_is_set(PORT_1WIRE, WE)) {PRESENCE=1;} else {PRESENCE=0;}


    return PRESENCE;
    }

    void send(char bit)
    {
    //cli();
    CLEAR_1WIRE;

    owire_delay(20);    
    if(bit==1)
    SET_1WIRE;

    owire_delay(320);
    SET_1WIRE;
    //sei();
    }

    unsigned char read(void)
    {
    unsigned char PRESENCE=0;
    //cli();
    CLEAR_1WIRE;
     owire_delay(8);
    SET_1WIRE;
    owire_delay(60);
    if (bit_is_set(PORT_1WIRE, WE)) PRESENCE=1; else PRESENCE=0;
    return (PRESENCE);
    //sei();
    }

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

     owire_delay(400);
    }




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

    owire_delay(60);    
    }
    return (wartosc);
    }
    char *tp="                  ";


    int main (void)
    {

    unsigned char sprawdz;
    char temp1=0, temp2=0;

    for(;;) {
    sprawdz=RESET_PULSE();
    if (sprawdz == 1)
    {

    send_byte(0xCC);
    send_byte(0x44);
    owire_delay(3000);

    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_clr();
    lcd_init();
    write_text("Temperatura");
       LCD_xy(0,1);
       write_text(buf);
    waitms(254);

    }
    else
    {

    LCD_clr();
       lcd_init();
       write_text("brak pomiaru");
    waitms(190);
    }

    }
    }

    >

    czujnik zasilany normalnie( nie pasożytniczo).
    W załączniku plik skompilowany


    inventco.eu - proszę używać znaczników CODE. Poprawiłem.

    2
  • #8 20 Lis 2010 17:47
    simoon87
    Poziom 9  

    a2d2a2m wielkie dzięki za pomoc! Dzięki tobie odnalazłem błąd w moim kodzie który polegał na braku } w jednym miejscu:P

    Całej reszcie "psełdopomagaczy" dziękuje za posty nie wnoszące nic do tego tematu (oby jak najmniej takich ludzi na elektrodzie)

    0