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

DS18B20 nie odpowiada - atmega8 + LCD (Rozwiązane)

hektor190 07 Gru 2009 15:34 3187 8
  • #1 7357036
    hektor190
    Poziom 11  
    Witam serdecznie - jestem początkujący i próbuję uruchomić termometr na atmedze8

    Atmega ma podłączony wyświetlacz alfanumeryczny 2x16 znaków

    DS podłączony normalnie - nie pasożytniczo
    pisząc program opierałem się na:
    http://ds5.agh.edu.pl/~czaro/naukowo/avr_1wire.htm
    oraz chwilkę później ponieważ pierwsze rozwiązanie nie działało:
    http://www.elportal.pl/forum/viewtopic.php?p=58414
    to bardzo podobne rozwiązanie - które podobnie nie działa:
    Próbowałem wiele konfiguracji i metod - nigdy nie uzyskałem odpowiedzi z DS
    (Proszę się nie śmiać z mojego programu to mój czwarty pod uC)




    Cytat:
    //-------------------------------------------------------------------------------------------------
    // Wyświetlacz alfanumeryczny ze sterownikiem HD44780 oraz termometrem DS18B20
    // Sterowanie w trybie 4-bitowym bez odczytu flagi zajętości
    //-------------------------------------------------------------------------------------------------

    #include "HD44780.h"
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/eeprom.h>
    #include <string.h>

    #include <stdio.h>
    #include <stdlib.h>
    #include <avr/pgmspace.h>
    #include <inttypes.h>
    //#include "daley.c"
    #define f_CPU 1000000
    int x = 0;
    int y = 0;

    #include <util/delay.h>
    //-------------------------------------------------------------------------------------------------
    //
    // Funkcja wystawiająca półbajt na magistralę danych
    //
    //-------------------------------------------------------------------------------------------------
    void _LCD_OutNibble(unsigned char nibbleToWrite)
    {
    if(nibbleToWrite & 0x01)
    LCD_DB4_PORT |= LCD_DB4;
    else
    LCD_DB4_PORT &= ~LCD_DB4;

    if(nibbleToWrite & 0x02)
    LCD_DB5_PORT |= LCD_DB5;
    else
    LCD_DB5_PORT &= ~LCD_DB5;

    if(nibbleToWrite & 0x04)
    LCD_DB6_PORT |= LCD_DB6;
    else
    LCD_DB6_PORT &= ~LCD_DB6;

    if(nibbleToWrite & 0x08)
    LCD_DB7_PORT |= LCD_DB7;
    else
    LCD_DB7_PORT &= ~LCD_DB7;
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Funkcja zapisu bajtu do wyświetacza (bez rozróżnienia instrukcja/dane).
    //
    //-------------------------------------------------------------------------------------------------
    void _LCD_Write(unsigned char dataToWrite)
    {
    LCD_E_PORT |= LCD_E;
    _LCD_OutNibble(dataToWrite >> 4);
    LCD_E_PORT &= ~LCD_E;
    LCD_E_PORT |= LCD_E;
    _LCD_OutNibble(dataToWrite);
    LCD_E_PORT &= ~LCD_E;
    _delay_us(50);
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Funkcja zapisu rozkazu do wyświetlacza
    //
    //-------------------------------------------------------------------------------------------------
    void LCD_WriteCommand(unsigned char commandToWrite)
    {
    LCD_RS_PORT &= ~LCD_RS;
    _LCD_Write(commandToWrite);
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Funkcja zapisu danych do pamięci wyświetlacza
    //
    //-------------------------------------------------------------------------------------------------
    void LCD_WriteData(unsigned char dataToWrite)
    {
    LCD_RS_PORT |= LCD_RS;
    _LCD_Write(dataToWrite);
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Funkcja wyświetlenia napisu na wyswietlaczu.
    //
    //-------------------------------------------------------------------------------------------------
    void LCD_WriteText(char * text)
    {
    while(*text)
    LCD_WriteData(*text++);
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Funkcja ustawienia współrzędnych ekranowych
    //
    //-------------------------------------------------------------------------------------------------
    void LCD_GoTo(unsigned char x, unsigned char y)
    {
    LCD_WriteCommand(HD44780_DDRAM_SET | (x + (0x40 * y)));
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Funkcja czyszczenia ekranu wyświetlacza.
    //
    //-------------------------------------------------------------------------------------------------
    void LCD_Clear(void)
    {
    LCD_WriteCommand(HD44780_CLEAR);
    _delay_ms(2);
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Funkcja przywrócenia początkowych współrzędnych wyświetlacza.
    //
    //-------------------------------------------------------------------------------------------------
    void LCD_Home(void)
    {
    LCD_WriteCommand(HD44780_HOME);
    _delay_ms(2);
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Procedura inicjalizacji kontrolera HD44780.
    //
    //-------------------------------------------------------------------------------------------------
    void LCD_Initalize(void)
    {
    unsigned char i;
    LCD_DB4_DIR |= LCD_DB4; // Konfiguracja kierunku pracy wyprowadzeń
    LCD_DB5_DIR |= LCD_DB5; //
    LCD_DB6_DIR |= LCD_DB6; //
    LCD_DB7_DIR |= LCD_DB7; //
    LCD_E_DIR |= LCD_E; //
    LCD_RS_DIR |= LCD_RS; //
    _delay_ms(15); //15 oczekiwanie na ustalibizowanie się napiecia zasilajacego
    LCD_RS_PORT &= ~LCD_RS; // wyzerowanie linii RS
    LCD_E_PORT &= ~LCD_E; // wyzerowanie linii E

    for(i = 0; i < 3; i++) // trzykrotne powtórzenie bloku instrukcji
    {
    LCD_E_PORT |= LCD_E; // E = 1
    _LCD_OutNibble(0x03); // tryb 8-bitowy
    LCD_E_PORT &= ~LCD_E; // E = 0
    _delay_ms(5); // czekaj 5ms
    }

    LCD_E_PORT |= LCD_E; // E = 1
    _LCD_OutNibble(0x02); // tryb 4-bitowy
    LCD_E_PORT &= ~LCD_E; // E = 0

    _delay_ms(1); // czekaj 1ms
    LCD_WriteCommand(HD44780_FUNCTION_SET | HD44780_FONT5x7 | HD44780_TWO_LINE | HD44780_4_BIT); // interfejs 4-bity, 2-linie, znak 5x7
    LCD_WriteCommand(HD44780_DISPLAY_ONOFF | HD44780_DISPLAY_OFF); // wyłączenie wyswietlacza
    LCD_WriteCommand(HD44780_CLEAR); // czyszczenie zawartosći pamieci DDRAM
    _delay_ms(2);
    LCD_WriteCommand(HD44780_ENTRY_MODE | HD44780_EM_SHIFT_CURSOR | HD44780_EM_INCREMENT);// inkrementaja adresu i przesuwanie kursora
    LCD_WriteCommand(HD44780_DISPLAY_ONOFF | HD44780_DISPLAY_ON | HD44780_CURSOR_OFF | HD44780_CURSOR_NOBLINK); // włącz LCD, bez kursora i mrugania
    }

    //-------------------------------------------------------------------------------------------------
    //
    // Koniec pliku HD44780.c
    //
    //-------------------------------------------------------------------------------------------------



    //////////////POCZĄTEK TERMOMETRU //////////////////////////////////////////////////



    #define WE 1
    #define PORT_1WIRE PIND
    #define CLEAR_1WIRE DDRD&=~_BV(WE)
    #define SET_1WIRE DDRD|=_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);
    if (bit_is_set(PORT_1WIRE, WE)) PRESENCE=1; else PRESENCE=0;
    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;

    //inicjalizacja wyświetlacza
    LCD_Initalize();
    LCD_Clear();
    LCD_Home();
    _delay_ms(100);
    LCD_WriteText("Init LCD- ok");
    _delay_ms(400);
    LCD_Clear();
    for(;;) {
    sprawdz=RESET_PULSE();
    if (sprawdz == 1)
    {
    send_byte(0xCC);
    send_byte(0x44);
    _delay_ms(750);

    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_Clear();
    LCD_WriteText(buf);
    _delay_ms(200);
    }
    else
    {
    LCD_Clear();


    LCD_WriteText("Brak pomiaru");
    _delay_ms(300);
    }

    }
    }


    */


    Próbowałem zmieniać fusy - taktować zewnętrznym kwarcem 8MHz 2MHz wewnętrznym 1MHz nie mam koncepcji co mogę robić nie tak - na co powinienem zwócić uwagę.
    Wiem że _delay_ms(); nie powinno przekraczać 262,14ms/MHz ale wszyscy tak robią i im działa (może się mylę ale tak widzę przeglądając choćby elektrode)
    Będę wdzięczny za każdą pomoc
  • #3 7357265
    hektor190
    Poziom 11  
    Rzeczywiście tutaj był błąd:
    przy clear miernik pokazywał 5,10V przy set 44mV
    Po poprawieniu dzieje się dziwne zjawisko: pokazuje temperaturę 0,0 A jak wyciągnę termometr to -0,1

    Działo mi się tak już wcześniej że mimo że w układzie nie było termometru funkcja zwracała mi że jest i że odpowiada.

    Co ciekawe włożenie innego DSa powoduje że wyświetla -2,0
  • #4 7359029
    ksarim
    Poziom 15  
    Patrząc na Twój kod zauważyłem że wykorzystujesz funkcję z biblioteki "delay.h". Tymi funkcjami nie uzyskasz dokładnych czasów potrzebnych do obsługi interfejsu 1-Wire po którym komunikuje się czujnik DS18B20. Udostępnię Ci swoją sprawdzoną w 100% bibliotekę do komunikacji po 1-Wire.

    W tej bibliotece wystarczy dobrać czasy opóźnień dla Twojego kwarcu i wszystko na pewno będzie śmigało. Sam z niej korzystam. Czasy są poustawiane dla kwarcu 16MHz więc jeżeli wykorzystujesz powiedzmy kwarc 8MHz to wystarczy parametry we wszystkich wywołaniach funkcji owire_delay(...) w pliku 1-Wire.c mniejszyć o połowę. Analogicznie w przypadku innych kwarców. Mam nadzieję, że z tym sobie poradzisz.

    Teraz jeżeli chodzi o sam odczyt temperatury też udostępnię Ci sprawdzony w 100% kod:
    void odczytaj_temperature()
    {
    	unsigned char w_temperatura[8];
    	unsigned char lsb = 0;			// młodsze bity odczytane z czujnika temperatury		
    	unsigned char msb = 0;			// starsze bity odczytane z czujnika temperatury
    	unsigned char znak_temperatury;
    	unsigned char zp99;
    	owire_reset();					// sekwencja inicjalizująca
    	owire_write_byte(0xCC);			// rozkaz pomiń ROM
    	owire_write_byte(0x44);			// rozkaz konwertuj temperaturę
    	owire_reset();
    	owire_write_byte(0xCC);			// rozkaz pomiń ROM
    	owire_write_byte(0xBE);			// rozkaz umożliwiający odczytanie temperatury 
    	lsb = owire_read_byte();		// odczytanie młodszych bitów temperatury 
    	msb = owire_read_byte();		// odczytanie starszych bitów temperatury 
    	znak_temperatury = 1;			// do określenia znaku temperatury
    	// konwersja odczytanych z czujnika danych na temperaturę
    	if(msb & 0x80)					// sprawdzenie znaku temperatury	
    	{
    		lsb ^= lsb;					// konwersja ujemnej temperatury
    		msb ^= lsb;
    		if(lsb == 0xFF)
    			msb = msb + 1;
    		else
    			lsb = lsb + 1;	
    		znak_temperatury = 0;		// określa ujemny znak temperatury
    	}
    	zp1 = lsb & 0x0F;				// pozbycie się 4 najstarszych bitów(pozostała liczba wskazuje na wartości dzięsiętne temperatury)
    	lsb  = lsb >> 4;				// pozbycie się 4 najmłodszych bitów
    	msb  = msb << 4;				// pozbycie się 4 najstarszych bitów
    	if(znak_temperatury == 0 && (lsb + msb) > 0)// ujemna temperatura
    	{
    		w_temperatura[0] = '-';
    		zp99 = dBCD(lsb+msb) >> 4;;	// konwersja temperatury do kodu BCD i pozbycie się 4 najmodszych bitów
    		if(zp99 != 0)				// temperatura <= -10
    		{
    			w_temperatura[1] = 48 + zp99;
    			zp99 = dBCD(lsb+msb) & 0x0F;;// maska pozostawiająca 4 najmłodsze bity
    			w_temperatura[2] = 48 + zp99;
    			w_temperatura[3] = ',';
    			zp1 = (zp1*625)/1000;	// wartości po ,
    			w_temperatura[4] = 48 + zp1;
    			w_temperatura[5] = 0xFF;// stopień
    			w_temperatura[6] = 'C';	
    			w_temperatura[7] = 251;	// koniec danych		
    		}
    		else						// temperatura > -10, < 0 
    		{
    			zp99 = dBCD(lsb+msb) & 0x0F;
    			w_temperatura[1] = 48 + zp99;
    			w_temperatura[2] = ',';
    			zp1 = (zp1*625)/1000;	// wartość po ,
    			w_temperatura[3] = 48 + zp1;
    			w_temperatura[4] = 0xFF;// stopień
    			w_temperatura[5] = 'C';
    			w_temperatura[6] = 251;	// koniec danych
    		}
    	}
    	else							// dodatnia temperatura
    	{
    		zp99 = dBCD(lsb+msb) >> 4;
    		if(zp99 != 0)				// temperatura >= 10
    		{
    			w_temperatura[0] = 48 + zp99;
    			zp99 = dBCD(lsb+msb) & 0x0F;// maska pozostawiająca 4 najmłodsze bity
    			w_temperatura[1] = 48 + zp99;
    			w_temperatura[2] = ',';
    			zp1 = (zp1*625)/1000;	// wartość po ,
    			w_temperatura[3] = 48 + zp1;
    			w_temperatura[4] = 0xFF;// stopień
    			w_temperatura[5] = 'C';
    			w_temperatura[6] = 251;	// koniec danych
    		}
    		else						// temperatura >= 0, < 10
    		{
    			zp99 = dBCD(lsb+msb) & 0x0F;
    			w_temperatura[0] = 48 + zp99;
    			w_temperatura[1] = ',';
    			zp1 = (zp1*625)/1000;	// wartosć po ,
    			w_temperatura[2] = 48 + zp1;
    			w_temperatura[3] = 0xFF;
    			w_temperatura[4] = 'C';
    			w_temperatura[5] = 251;
    		}
    	}
    }

    Ja wynik pomiaru zapisywałem w tablicy w_temperatura w kodzie ASCII. Możesz to sobie przerobić i od razu wyrzucać otrzymaną wartość temperatury na wyświetlacz.
  • #5 7361657
    hektor190
    Poziom 11  
    Witam ponownie:
    Trochę nad tym przesiedziałem.
    Na początek spróbowałem porównać Twój i kod z tym który ja mam.
    Linijka po linijce (pomijając funkcję main - z twoim odczytem - są inaczej zupełnie skontrowane)

    różnice jakie znalazłem to trochę inne czasy - poprawiłem na Twoje,
    Wykorzystujesz swoją funkcję do opóźnień - wkleiłem ją do siebie i użyłem.
    Poprawnie podzieliłem czasy - kwarc zewnętrzny 8MHz

    Ostatecznie wkleiłem Twój kod (nie bardzo chciał się kompilować - wywalał że nie ma zmiennej zp1 oraz w linijkach w których używasz konwersji
     zp99 = dBCD(lsb+msb) >> 4;;   // konwersja temperatury do kodu BCD i pozbycie się 4 najmłodszych bitów 


    Przyznam się szczerze że funkcja odczytu i transformacji jest dla mnie nie zrozumiała.
    Ale wracając - mamy te same czasy, a termometru nie widać. wyświetla teraz rózne wartosci (0,9 ; -0,1; 0,0) w zależności od użytego termometru (sprawdzałem na trzech różnych)

    Nie rozumiem jeszcze jednej różnicy w kodzie używasz
     PINB & _BV(DQ) 
    zamiast mojej
     (bit_is_set(PORT_1WIRE, WE)) 
    w funkcji read

    Ma ktoś może pomysł co robię nie tak?
  • Pomocny post
    #6 7369040
    ksarim
    Poziom 15  
    Witam

    Przejrzałem Twój kod obsługi magistrali 1-Wire i zauważyłem, że nasze kody mają dość sporo różnic. Ja bym Ci radził nie przerabiać Twojego kodu bo na pewno będą pomyłki tylko po prostu podpiąć moją bibliotekę która jest sprawdzona. Później jak wszystko już będzie działać możesz sam dla siebie spróbować przerobić to co teraz masz. Tak w ogóle to sam to napisałeś ? zaczerpnąłeś z jakiegoś źródła ? sprawdzone to jest ? Mi się wydaje, że lepiej postawić na coś sprawdzonego.

    Kolejna sprawa to samo podłączenie czujnika. Czy na linii z danymi DQ masz podłączony rezystor pociągający?
  • #7 7370062
    hektor190
    Poziom 11  
    Sprawa wygląda tak - działa - błąd pomiaru względem (bazarowego) termometra cyfr wynosi ok 0,3*C -0,5*C wiec jest dobrze : )
    Dzięki za pomoc i wsparcie:

    Teraz dla wszystkich napisze co było źle:

    -nasze funkcje różnią się nieznacznie i mój kod był względnie dobry ale funkcja odczytu temperatury (u mnie main) była błędna:

     float temp = 0;
    	
    		   sprawdz = RESET_PULSE();               // sekwencja inicjalizująca
    		   send_byte(0xCC);         // rozkaz pomiń ROM
    		   send_byte(0x44);         // rozkaz konwertuj temperaturę
    		   sprawdz = RESET_PULSE();   //  <<<<<  TEGO MI BRAKOWAŁO
    		   send_byte(0xCC);         // rozkaz pomiń ROM
    		   send_byte(0xBE);         // rozkaz umożliwiający odczytanie temperatury
    		   temp1 = read_byte();      // odczytanie młodszych bitów temperatury
    		   temp2 = read_byte();      // odczytanie starszych bitów temperatury
    		  
    		   temp=(float)(temp1+(temp2*256))/16;
    		   temp = -temp;     //bo temp wychodziła ujemna
    					dtostrf(temp,1,1,buf);
    					LCD_Clear();
    					LCD_WriteText(buf);
    					_delay_ms(500);


    zobacz: "TEGO MI BRAKOWAŁO" w kodzie:
    Strasznie niezrozumiała u Ciebie jest konwersja temperatury do wersji jadalnej przez LCD wiec pozostawiłem swoją.
    Nie wiem jak delay działa bo korzystam z Twojego ale spróbuję zwykłe opóźnienia dać i sprawdzę.
    W każdym razie wielkie dzięki - jest to mój pierwszy projekt na którym chciałbym się nauczyć programować.

    Poza tematem: Planuję zrobić stację pogody która będzie z czasem rosnąć o kolejne elementy.
    Na następny klocek pójdzie czas.

    Mógłbyś jeszcze wyjaśnić różnice między dwoma linijkami które podałem w wpisie wcześniej? Chciałbym to jakoś zrozumieć : )
  • #8 7370240
    ksarim
    Poziom 15  
    Ciesze się, że w końcu Ci się udało.

    Co do różnic to Ty do sprawdzenia stanu na określonym pinie używasz funkcji:
    (bit_is_set(PORT_1WIRE, WE)) 

    Ja wczytuję wartość rejestru PINB (czyli stany na poszczególnych pinach portu B) i wykorzystuję maskę & _BV(DQ) dzięki czemu otrzymuję od razu stan na interesującym mnie pinie.
    PINB & _BV(DQ) 

    Efekt jest oczywiście ten sam chociaż Twój zapis może wydawać się czytelniejszy.

    Też jednym z moich pierwszych projektów była stacja pogodowa. Powodzenia i nigdy się nie poddawaj bo prace projektowo/programowe nigdy nie są łatwe i zawsze będą problemy ale problemy są po to żeby je rozwiązywać :)
  • #9 7371515
    hektor190
    Poziom 11  
    Dzięki - : ) Właśnie zaczynam pracę (listę zakupów) odnośnie zegara PCF 8583p


    //Temat można chyba zamknąć : )
REKLAMA