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.

[PIC][Hi-TechC] DS1307 na sprzętowym I2C

utak3r 02 Cze 2010 22:15 2393 9
  • #1 02 Cze 2010 22:15
    utak3r
    Poziom 25  

    Pierwszy raz przyszło mi, prawdę mówiąc, obsługiwać sprzętową magistralę I2C (na 16F88). No i pojawił się dość dziwny problem z kostką DS1307.
    - Inicjalizacja zegara danymi
    - wyczyszczony bit CH, zegar rusza
    - pod SQWE mam podpiętego LEDa, więc widzę, że RTC ruszył - nadawany jest sygnał 1Hz. Jak zmienię w procedurze inicjalizacji, żeby bit CH był ustawiony, LED nie miga: ergo inicjalizacja przebiega pomyślnie.
    - Odczyt: albo same zera, albo znaki zapytania.

    I teraz... jeśli odczyt danych dam natychmiast po inicjalizacji, to okazuje się, że w ciągu pierwszej sekundy odczytane dane zgodne są z tym, co podałem podczas inicjalizacji, natomiast już od następnej sekundy jest echo - najczęściej znaki zapytania. Wygląda to tak, jakby sam zapis i odczyt działały ok w takim razie, więc nie wiem o co chodzi - RTC gubi dane??...

    Bateria nie podpięta, w związku z tym, zgodnie ze specyfikacją, Vbat wpięte do masy.

    Dodano po 2 [minuty]:

    Acha, kawałki kodu (napisałem już chyba ze 20 wersji tego... :| )

    Code:

    void ds1307_init()
    {
       i2c_Start();
       i2c_WriteTo(0xD0);
       i2c_PutByte(0x00);
       __delay_us(50);
       //i2c_PutByte(0x80); // CH ustawiony - zegar zatrzymany!!
       i2c_PutByte(0x00); // CH wyczyszczony - zegar chodzi!!
       i2c_PutByte(0x10);
       i2c_PutByte(0x05);
       i2c_PutByte(0x02);
       i2c_PutByte(0x28);
       i2c_PutByte(0x02);
       i2c_PutByte(0x10);
        i2c_PutByte(0x10); // SQWE 1 Hz
       i2c_Stop();
    }

    unsigned char ds1307_get(unsigned char addr)
    {
       unsigned char ret;   
       
       //i2c_Start();
       i2c_WriteTo(0xD0);
       i2c_PutByte(addr);
       i2c_Stop();
       
       //i2c_Restart();
       i2c_ReadFrom(0xD1);
       ret = i2c_GetByte(I2C_LAST);
       i2c_Stop();
       
       return ret;         
    }


    Reszta kodu mniej istotna raczej...

    0 9
  • #2 02 Cze 2010 22:44
    alien_audio
    Poziom 21  

    Witam.
    Układy DS1307 u mnie bez baterii głupiały całkowicie. Więc dla testy podepnij baterie. Rezystory na szynie I2C oczywiście zastosowałeś.

    0
  • #3 02 Cze 2010 23:21
    utak3r
    Poziom 25  

    hmmm... mówisz? Zaraz sprawdzę.
    A pullupy oczywiście są :) Zresztą wygląda na to, że sama komunikacja przebiega ok.

    Dodano po 21 [minuty]:

    No niestety to nie to :( Z baterią tak samo się zachowuje :|

    0
  • #4 02 Cze 2010 23:28
    tadzik85
    Poziom 38  

    Cytat:
    Code:
    unsigned char ds1307_get(unsigned char addr)
    
    {
       unsigned char ret;   
       
       //i2c_Start();
       i2c_WriteTo(0xD0);
       i2c_PutByte(addr);
       i2c_Stop();
       
       //i2c_Restart();
       i2c_ReadFrom(0xD1);
       ret = i2c_GetByte(I2C_LAST);
       i2c_Stop();
       
       return ret;         
    }
    najpierw start po adresie zapisu znów start i potem odczytywanie

    Dodano po 1 [minuty]:

    I po co ci funkcje read i write skoro są one identyczne?

    0
  • #5 02 Cze 2010 23:38
    utak3r
    Poziom 25  

    tadzik85 napisał:

    najpierw start po adresie zapisu znów start i potem odczytywanie


    Tak też było i mam teraz (jak mówię - przetestowałęm już dziesiątki kombinacji...)

    Code:

    unsigned char ds1307_get(unsigned char addr)
    {
       unsigned char ret;   
       
       i2c_Start();
       i2c_WriteTo(0xD0);
       i2c_PutByte(addr);
       i2c_Start();
       i2c_ReadFrom(0xD1);
       ret = i2c_GetByte(I2C_LAST);
       i2c_Stop();
       
       return ret;         
    }



    tadzik85 napisał:

    I po co ci funkcje read i write skoro są one identyczne?


    ... nie rozumiem, o czym mówisz?...

    Może zapodam aktualny stan kodu:

    Code:

    void ds1307_init()
    {
       i2c_Start();
       i2c_WriteTo(0xD0);
       i2c_PutByte(0x00);
       __delay_us(50);
       i2c_PutByte(0x80); // CH ustawiony - zegar zatrzymany!!
       //i2c_PutByte(0x00); // CH wyczyszczony - zegar chodzi!!
       i2c_PutByte(0x10);
       i2c_PutByte(0x05);
       i2c_PutByte(0x04);
       i2c_PutByte(0x02);
       i2c_PutByte(0x06);
       i2c_PutByte(0x10);
        i2c_PutByte(0x10); // SQWE 1 Hz
       i2c_Stop();
    }

    void ds1307_write(unsigned char addr, unsigned char val)
    {
       i2c_Start();
       i2c_WriteTo(0xD0);
       i2c_PutByte(addr);
       __delay_us(50);
       i2c_PutByte(val);
       i2c_Stop();
    }

    unsigned char ds1307_get(unsigned char addr)
    {
       unsigned char ret;   
       
       i2c_Start();
       i2c_WriteTo(0xD0);
       i2c_PutByte(addr);
       i2c_Start();
       i2c_ReadFrom(0xD1);
       ret = i2c_GetByte(I2C_LAST);
       i2c_Stop();
       
       return ret;         
    }

    void ds1307_start()
    {
        int seconds=0;
       seconds = ds1307_get(0);




       seconds = seconds & 0x7F; // czyścimy bit CH
       ds1307_write(0, seconds);
    }

    void ds1307_stop()
    {
        int seconds = 0;
       seconds = ds1307_get(0);
       seconds = seconds | 0x80; // ustawiamy bit CH
       ds1307_write(0, seconds);
    }

    void ds1307_settime(unsigned char hh, unsigned char mm, unsigned char ss)
    {
       i2c_Start();
       i2c_WriteTo(0xD0);
       i2c_PutByte(0x00);
       __delay_us(50);
       i2c_PutByte(ss);
       i2c_PutByte(mm);
       i2c_PutByte(hh);
       i2c_Stop();
    }

    void ds1307_setdate(unsigned char dd, unsigned char mm, unsigned char yy)
    {
       i2c_Start();
       i2c_WriteTo(0xD0);
       i2c_PutByte(0x04);
       __delay_us(50);
       i2c_PutByte(dd);
       i2c_PutByte(mm);
       i2c_PutByte(yy);
       i2c_Stop();
    }


    I potem w mainie:

    Code:

       ds1307_init();
       ds1307_start();
       ds1307_settime(0x22, 0x25, 0x00);
       ds1307_setdate(0x02, 0x06, 0x10);

       for(;;)
       {
          sekunda = ds1307_get(0);
          minuta = ds1307_get(1);
          godzina = ds1307_get(2);
    .........................


    Zwracam kolejny raz uwagę na cholernie dziwny fakt:
    Pierwszy odczyt, który następuje jeszcze przed pierwszym tickiem zegara - jest poprawny, natomiast po pierwszym mrugnięciu LEDem na SQWE, odczyt jest już zrąbany.

    0
  • #6 03 Cze 2010 09:12
    adamwesola
    Poziom 24  

    Znam tylko asembler i odczyt u mnie wygląda tak :

    Code:
    ;=========================================
    
    odczyt   call   iic_start
          movlw   0A0         ; adres urzadzenia+zapis
          call   iic_write
          movfw   mem_loc         ; pozycja w pamieci
          call   iic_write            
    ;--------------------------------------
              call   iic_start      ; restart do odczytu       
              movlw   0A1      ; adres urzadzenia+odczyt
              call   iic_write                         
              call   iic_read   ; mem_data - odczytany bajt               
          call   iic_stop
          return

    Nie wiem co robi w C "i2c_ReadFrom(0xD1)",może również ustawia port na wejście, ja po restarcie dalej używam zapisu by podać bajt 0D1, a przęłączenie portu na wejście realizuje dopiero w "iic_read".
    Poza tym co z konfiguracja pinu sda ? i co z bitem ACK ?

    0
  • #7 03 Cze 2010 10:22
    utak3r
    Poziom 25  

    adamwesola napisał:

    Nie wiem co robi w C "i2c_ReadFrom(0xD1)",może również ustawia port na wejście


    Tak, to jest taki inny zapis, chodzi tylko o czytelność kodu.

    adamwesola napisał:

    ja po restarcie dalej używam zapisu by podać bajt 0D1, a przęłączenie portu na wejście realizuje dopiero w "iic_read".


    Robiłem już na 100 różnych sposobów... i wszystkie działają tak samo - pierwszy odczyt dobry, następne zkaszanione.
    Po południu dzisiaj, jak wrócę z wyjazdu, narysuję jeszcze schemat, no ale tu nie ma chyba co skopać...

    adamwesola napisał:

    Poza tym co z konfiguracja pinu sda ? i co z bitem ACK ?


    Konfiguracja prawidłowa, funkcje odpowiednio przełączają kierunek pinu. ACK/NAK teoretycznie obsługiwany... funkcje odczytu i zapisu wywołują takie dwie funkcje pomocnicze:

    Code:

    signed char
    i2c_ReadAcknowledge(void)
    {
       unsigned char ack;

       SCL_LOW();                  /* make clock is low */
       SDA_DIR = I2C_INPUT;         /* disable data line - listen for ack */
       __delay_us(I2C_TM_SCL_TO_DATA);   /* SCL low to data out valid */
       SCL_DIR = I2C_INPUT;         /* float clock high */
       __delay_us(I2C_TM_DATA_SU);
       ack = SDA;                  /* read the acknowledge */

       /* wait for slave to release clock line after processing byte */
       if(i2c_WaitForSCL())
          return I2C_ERROR;
       return ack;
    }

    void
    i2c_SendAcknowledge(unsigned char status)
    {
       SCL_LOW();
       if ( status & 0x01) {
          SDA_LOW();            /* drive line low -> more to come */
       }else {
          SDA_HIGH();
       }
       __delay_us(I2C_TM_DATA_SU);
       SCL_DIR = I2C_INPUT;      /* float clock high */
       __delay_us(I2C_TM_SCL_HIGH);
       return;
    }



    Poza tym.... chyba by w ogóle nie działało, gdyby coś tutaj było źle?... Gdybym ani razu nie dostał prawidłowego odczytu, to rozumiem, ale to tutaj dziwnie wygląda :|

    0
  • #8 03 Cze 2010 11:10
    janbernat
    Poziom 38  

    Sprawdź napięcie na baterii w czasie pracy.
    Nie może być większe niż 3.5V przy zasilaniu 5V.
    I gdy Vcc spadnie poniżej 1.25xVbat zegar przestaje odpowiadać i przechodzi w tryb podtrzymania z baterii.

    0
  • #9 03 Cze 2010 18:55
    utak3r
    Poziom 25  

    No właśnie, tak wyglądają te objawy... niestety, to też nie to :( na baterii 2,95V, Vcc ma 5,03V. Zresztą, po odpięciu baterii i wpięciu Vbat do GND, jest to samo.

    Już normalnie z sił opadam... 3 wieczory jak w piach... prosta rzecz a nie mogę tego przejść. To musi być coś błahego, jak zwykle...

    0
  • #10 07 Cze 2010 23:28
    utak3r
    Poziom 25  

    W którymś wątku jakiś czas temu Freddie Chopin napisał, że dla PICów z rodziny 10/12/16 mamy przecież darmowy kompilator C - Hi-Tech C. O ile Microchipowy PIC18 jest świetny, to ten do maluchów... ujmę to tak: żenada, porażka i wstyd takie narzędzie wypuszczać!

    Okazało się, że zwyczajnie musiałem usiąść i od nowa, samemu napisać procedury do obsługi I2C. Efekt? Wszystko pięknie śmiga.

    Żenada!!

    Wcześniej swoje projekty robiłem na mikroC, ale tutaj pracuję na procku, który jest objęty ograniczeniami darmowej wersji mikroC, stąd przesiadłem się na na PicC.

    PS. Dzięki wszystkim za próby pomocy :)

    0