Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[AtMega8][Bascom] wykrywanie adresów I2C

maximus22_kr 15 Aug 2011 01:18 4097 9
  • #1
    maximus22_kr
    Level 18  
    Witam
    W oparciu o kod znaleziony na forum Elektroda mam programik wyświetlający adresy układów w magistrali I2C ( TWI ).
    Kod jest taki:

    Code:

    $regfile = "m8def.dat"                                      'definicja procesora
    $crystal = 4000000                                          'taktowanie procesora
    $hwstack = 32                                               ' rozmiar stosu sprzętowego
    $swstack = 10                                               ' rozmiar stosu
    $framesize = 40                                             ' rozmiar ramki

    Config Debounce = 30

    '********************* Konfiguracja wyświetlacza
    Config Lcdbus = 4
    Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , Db7 = Portd.7 , E = Portc.3 , Rs = Portc.1
    Config Lcd = 24 * 2

    '********************* Konfiguracja znaku specjalnego LCD

    Deflcdchar 0 , 8 , 20 , 8 , 32 , 32 , 32 , 32 , 32          ' znak stopnia celcjusza

    '********************* Konfiguracja magistrali I2C

    Config I2cdelay = 10                                        ' domyślnie tryb Slow
    Config Sda = Portc.4
    Config Scl = Portc.5

    '********************* Konfiguracja podświetlania

    Config Portb.0 = Output                                     'Podswietlanie Niebieskie
    Reset Portb.0

    Config Portb.1 = Output                                     'Podswietlanie Czerwone
    Reset Portb.1

    Config Portb.2 = Output                                     'Podswietlanie Zielone
    Reset Portb.2

    Config Portd.2 = Input                                      'wejście - przycisk do GND
    Set Portd.2

    '********************* Konfiguracja magistrali 1-Wire

    Config 1wire = Portc.0

    '********************* Konfiguracja Timer2

    Config Timer1 = Timer , Prescale = 64                       'dla kwarc = 4000000 Hz Prescale = 64 przepełnienie co 16us
    Enable Timer1

    Enable Interrupts

    On Timer1 Czas
    Timer1 = 34286                                              '31250 x 16us = 0,5 s , 65536 - 31250 = 34286

    '********************* Deklaracje zmiennych

    Dim Odczyt As Byte
    Dim Odczyt1 As Byte
    Dim Temp As Byte
    Dim Twi1 As Bit
    Dim Twi2 As Bit
    Dim Twi3 As Bit
    Dim Twi4 As Bit
    Dim Twi5 As Bit
    Dim Twi6 As Bit
    Dim A As Byte
    Dim B As Byte
    Dim C As Byte
    Dim D As Byte
    Dim E As Byte
    Dim F As Byte
    Dim N As Byte


    '********************* Deklaracja podprogramów

    Declare Sub Przeszukaj_i2c
    Declare Sub Wyswietla_adres

    '********************* Przypisanie przyjaznych nazw do poszczególnych portów - Aliasów

    Niebieski Alias Portb.0
    Czerwony Alias Portb.1
    Zielony Alias Portb.2
    Szukaj Alias Pind.2



    '********************* Wartości początkowe
    Niebieski = 1
    Twi1 = 0
    Twi2 = 0
    Twi3 = 0
    Twi4 = 0
    Twi5 = 0
    Twi6 = 0


    Cursor Off

    Cls
    '**************** Program główny

    Do

    Locate 1 , 1
    Lcd A

    Locate 1 , 5
    Lcd B

    Locate 1 , 9
    Lcd C

    Locate 2 , 1
    Lcd D

    Locate 2 , 5
    Lcd E

    Locate 2 , 9
    Lcd F


    'If Szukaj = 0 Then
     Call Przeszukaj_i2c
    'End If



    Loop
    End



    '*********************** Podprogram szukania adresu układu I2C
    Przeszukaj_i2c:
       For Temp = 100 To 255                                    'Zakres szukania 100 - 255
          I2cstart                                              'Warunek startu
          Waitms 20
          I2cwbyte Temp
          Waitms 20
          I2cstop                                               'Warunek stopu
          If Err = 0 Then                                       'Jeśli nie ma błędów to
             'Locate 2 , 13                                      'wyświetlaj wartość zmiennej Temp
             'Lcd Temp
             'Flaga_twi = 1
             Gosub Wyswietl_adres


    End If
    Waitms 200
    Next Temp

    Return



    Wyswietl_adres:
    If Temp <> 0 And Twi1 = 0 Then
       A = Temp
       Locate 1 , 1
       Lcd A
       Twi1 = 1

    Elseif Temp <> A And Twi1 = 1 And A > B Then
       B = Temp
       Locate 1 , 5
       Lcd B
       Twi2 = 1


    Elseif Temp <> B And Twi1 = 1 And Twi2 = 1 And B > C Then
       C = Temp
       Locate 1 , 9
       Lcd C
       Twi3 = 1


    Elseif Temp <> C And Twi1 = 1 And Twi2 = 1 And Twi3 = 1 And C > D Then
       D = Temp
       Locate 2 , 1
       Lcd D
       Twi4 = 1

    Elseif Temp <> D And Twi1 = 1 And Twi2 = 1 And Twi3 = 1 And Twi4 = 1 And D > E Then
       E = Temp
       Locate 2 , 5
       Lcd E
       Twi5 = 1

    Else
    If Temp <> D And Twi1 = 1 And Twi2 = 1 And Twi3 = 1 And Twi4 = 1 And Twi5 = 1 And E > F Then
       F = Temp
       Locate 2 , 9
       Lcd F
       Twi6 = 1

     End If
    End If
    Return


    W sumie spora kobyła i może pokazać tylko 6 adresów. Zastanawiam się, czy da się to napisać, żeby było "lżejsze" ( na Atmega8 zajmuje 26% ), poza tym problem będzie w przypadku, jak będzie więcej układów.

    Drugie pytanie jest takie, czy da się "wyciągnąć" więcej informacji na temat układu. Czyli, żeby uzyskać coś takiego:
    24L32 adres 162
    24L32 adres 163
    PCF8591 adres 144
  • #2
    piotrva
    VIP Meritorious for electroda.pl
    Da się to odchudzić, oczywiście
    To samo z większą ilością układów, albo dane można wysyłać po rs232 do pc, albo dać po 6 układach przycisk next wyswietlajjący kolejne 6 układów i tak dalej...
    Co do nazw to nie da się, chyba że przepiszesz setki danych z kart i obsłużysz jakoś rozpoznawanie układów o takich samych adresach, np at24cxx i pcf8583 lub 8563
  • #3
    maximus22_kr
    Level 18  
    szkoda, myślałem, że może firma Philips coś "zaszyła"> Ale skoro nie to pewnie nie ma znaczenia co się podłączy ( byle poprawnie ) tylko jak to się "obsłuży", czyli adres układu i odpowiednia składnia.

    Co do kodu to spory, bo nie za bardzo mi to na początku wychodziło, tzn. np. program cały czas "biegł" pokazując wszystkie adresy po kolei w jednej pozycji albo pokazywał tylko pierwszy w pierwszej pozycji, a na drugiej pozycji adresy "biegły".

    Dopiero dodanie warunku A > B, B > C , itd spowodowało, że w odpowiednie pozycje weszły po kolei wszystkie adresy i po prostu wskakują ( nie widać samego wyszukiwania )

    Jakby go Kolega uprościł ?
    Może użyć FOR NEXT i wykorzystać zmienna np TWI typu Byte - może tę pętlę wstawić w pętle wyszukiwania i po każdym Err = 0 i zapisywać do tablicy
  • #4
    tmf
    Moderator of Microcontroller designs
    Coś tam Philips zaszył - na podstawie najstarszych bitów adresu urządzenia można ogólnie się zorientować co to za urządzenie (RTC, pamięć, ekspander, itd). Potem można zrobić specyficzne testy określające np. wielkość pamięci, czy konkretny typ układu. Ale jest to pracochłonne i nie wiem czy ma sens, chyba, że robisz detektor typu scalaka I2C z zatartym oznaczeniem :)
    Taki kod enumerujący urządzenia to w C kilkaset bajtów max. Ogólna zasada jest prosta - skanujesz kolejne adresy - na I2C nie ma ich dużo (mówię oczywiście o trybie podstawowym).
  • #5
    maximus22_kr
    Level 18  
    Sam rodzaj układu by wystarczył. Nie potrzebne są szczegóły.

    Wiem, że w C można to zrobić krócej i szybciej - ja na razie poznaję podstawy funkcjonowania - mam książkę Kolegi oraz Kolegi Mirka. Przyjdzie na nie czas, bo nie zwykłem kupować czegoś, żeby leżało.
  • #6
    piotrva
    VIP Meritorious for electroda.pl
    Hmm, ale typ układu? Jak to się ma np. do PCF8583 (zegar) i pamięci At24Cxx (eeprom) - adresy bazwoe takie same...
  • #7
    maximus22_kr
    Level 18  
    U mnie to jest tak:
    144, 145 PCF8591
    162, 163 PCF8563
    160, 161 EEPROM 24LC32A
  • #9
    maximus22_kr
    Level 18  
    Udało mi się trochę odchudzić program.
    Wykorzystałem tablice + inkrementacja numeru komórki w tablicy.
    Chciałem wykorzystać FOR - NEXT, ale coś nie działa jak trzeba

    Code:

    Do

    Locate 1 , 1
    Lcd A

    Locate 1 , 7
    Lcd B

    Locate 2 , 1
    Lcd C

    Locate 2 , 7
    Lcd D

    Locate 1 , 13
    Lcd E

    Locate 1 , 19
    Lcd F

    'If Szukaj = 0 Then
     Call Przeszukaj_i2c
    'End If

    Loop
    End

    '*********************** Podprogram szukania adresu układu I2C
    Przeszukaj_i2c:
       For Temp = 100 To 255                                    'Zakres szukania 100 - 255
       I2cstart                                                 'Warunek startu
       Waitms 20
       I2cwbyte Temp
       Waitms 20
       I2cstop                                                  'Warunek stopu
         If Err = 0 Then                                        'Jeśli nie ma błędów to
           Twi_tab(twi) = Temp                                  'wpisz do tablicy w pozycji określonej przez zmienna TWI - wartość zmiennej Temp
           Incr Twi                                             'zwiększ wartość zmiennej Twi
          If Twi = 15 Then                                      'gdy zmienna Twi osiągnie wartość 15
          Locate 2 , 13
          Lcd "Koniec"
          Exit For                                              'wyjdź z pętli
        End If
    End If
    Waitms 200
    Gosub Wyswietl_adres
    Next Temp

    Return

    Wyswietl_adres:
    A = Twi_tab(1)
    B = Twi_tab(2)
    C = Twi_tab(3)
    D = Twi_tab(4)
    E = Twi_tab(5)
    F = Twi_tab(6)

    Return


    Dodano po 1 [godziny]:

    Kontynuując temat komunikacji I2C.
    Chciałbym zapisać zawartość tablicy składającej się z ośmiu elementów ( numer seryjny DS18B20 ), na razie pomijam kwestie zapisu identyfikatora tego DS, żebym wiedział, że np DS18B20 o identyfikatorze 111 to jest na zewnątrz. Pamięć EEPROM 24LC32

    Zakładając, że wcześniej odczytałem ID DS18B20 i umieściłem w tablicy to kod zapisu powinien wyglądać tak:

    Code:

    Const Adres_read = 161                                      'adres odczytu EEPROM I2C
    Const Adres_save = 160                                      'adres zapisu EEPROM I2C

    A = Twi_tab(1)
    B = Twi_tab(2)
    C = Twi_tab(3)
    D = Twi_tab(4)
    E = Twi_tab(5)
    F = Twi_tab(6)
    G = Twi_tab(7)
    H = Twi_tab(8)

    Sub Zapis_eeprom:

    I2cstart                                                    'warunek startu
    I2cwbyte Adres_save                                         'wyślij adres układu
    I2cwbyte M                                                  'wyślij adres w pamięci EEPROM

    I2cwbyte A                                                  'wyślij daną
    I2cwbyte B                                                  'wyślij daną
    I2cwbyte C                                                  'wyślij daną
    I2cwbyte D                                                  'wyślij daną
    I2cwbyte E                                                  'wyślij daną
    I2cwbyte F                                                  'wyślij daną
    I2cwbyte G                                                  'wyślij daną
    I2cwbyte H                                                  'wyślij daną

    I2cstop                                                     'warunek stopu

    Waitms 70                                                   'czekamy 70mS ponieważ EEPROM potrzebuje czasu na  zapisanie danych w pamięci

    End Sub


    Gdzie zmienna M to adres zapisu w pamięci, równy np. 10 ( dla drugiego może być 20 dla trzeciego 30 itp. )

    Czy można to zrobić prościej przy pomocy pętli FOR NEXT ?
    np. tak:
    Code:


    Dim M as Byte                              'Adres początkowy komórki dla pierwszego układu DS

    Dim N as Byte                              'Adres końcowy komórki dla pierwszego układu DS

    Const Adres_read = 161                                      'adres odczytu EEPROM I2C
    Const Adres_save = 160                                      'adres zapisu EEPROM I2C

    A = Twi_tab(1)
    B = Twi_tab(2)
    C = Twi_tab(3)
    D = Twi_tab(4)
    E = Twi_tab(5)
    F = Twi_tab(6)
    G = Twi_tab(7)
    H = Twi_tab(8)

    Sub Zapis_eeprom:
    For Adres = M To N
    I2cstart                                                    'warunek startu
    I2cwbyte Adres_save                                   'wyślij adres układu
    I2cwbyte M                                                'wyślij adres w pamięci EEPROM

    I2cwbyte A                                                 'wyślij daną

    I2cstop                                                     'warunek stopu

    Waitms 70                                                   'czekamy 70mS ponieważ EEPROM potrzebuje czasu na  zapisanie danych w pamięci
    Next M

    End Sub


    Proszę poprawić, bo pewnie się mylę
    Czyli pętla FOR NEXT powinna zmieniać adres komórki od M do N. Tylko jeszcze podstawienie danych z komórki tablicy z numeru ID do zmiennej A.

    Może któryś z Kolegów pomoże.

    Chyba, żeby to zrobić przez
    A = Twi_tab(Adres)

    Niestety coś z tymi pętlami nie mogę sobie poradzić.
  • #10
    piotrva
    VIP Meritorious for electroda.pl
    maximus22_kr wrote:
    (...)Niestety coś z tymi pętlami nie mogę sobie poradzić.

    No to od ich zrozumienia czas zacząć ;-)