background image

 
 
 
 
 

 

Strona 1 z 18 

 

Algorytm poszukiwania układów  

w sieci 1-Wire. 

 

Każdy z układów z interfejsem 1-Wire posiada unikatowy 64-bitowy kod identyfikacyjny. 
Kod ten nosi nazwę „kod ROM” i może być utożsamiany z unikatowym adresem układu z 
interfejsem 1-Wire. Kod ten używany jest przez układ Master do wyboru układu w sieci. 
W związku z tym, że jest to kod unikatowy, to jeśli nie jest znana liczba układów Slave w 
sieci,  może  ona  zostać  określona  przy  jego  użyciu  przez  zastosowanie  funkcji 
przeszukiwania sieci. Algorytm jej działania oparty jest o zasadę przeszukiwania drzewa 
binarnego. Gałęzie przeszukiwane są do momentu aż zostanie odnaleziony koniec gałęzi 
lub  pamięć  ROM  układu  1-Wire.  Funkcja  przeszukuje  drzewo  do  momentu  aż  wszystkie 
numery ROM i wszystkie zakończenia zostaną odkryte. 
Algorytm  rozpoczyna  się  od  wysłania  rozkazu  reset.  Jeśli  jego  przesłanie  zakończy  się 
powodzeniem, to znaczy odpowiednio zareagują na niego układy dołączone do magistrali, 
wysyłana jest 1-bajtowa komenda zwana „search” o kodzie 0xF0 lub 0xFC. Komenda ta 
przygotowuje układy podłączone do magistrali do przeszukiwania. 
Firma  Dallas  zaimplementowała  dwa  rodzaje  komend  przeszukujących.  Najczęściej 
używane  jest  przeszukiwanie  tzw.  normalne  (0xF0)  sprawdzające  wszystkie  układy 
podłączone do linii. Innym rodzajem przeszukiwania jest tzw. warunkowe, które znajduje 
układy  będące  w  stanie  alarmowym,  np.  załączone  termostaty  czy  timery,  które 
sygnalizują  zakończenie  odmierzania  czasu.  Redukowany  jest  w  ten  sposób  obszar 
przeszukiwania  do  tylko  tych  układów,  które  muszą  zostać  z  jakiś  powodów  odczytane 
czy ustawione. 
Po  wysłaniu  przez  układ  Master  komendy  przeszukiwania,  układy  Slave  podłączone  do 
magistrali  1-Wire  (wszystkie,  których  dotyczy  komenda)  odpowiadają  wysyłając 
jednocześnie  mniej  znaczący  bit  własnego  adresu.  Według  standardu  1-Wire,  układ 
Master inicjuje przesłanie każdego bitu zapisywanego czy odczytywanego z układu Slave. 
W związku ze specyfiką interfejsu, gdzie wszystkie układy podłączone są do wspólnej linii 
przesyłowej  i  na  odebraną  komendę  przeszukiwania  odpowiadają  w  tym  samym  czasie 
(jednocześnie  i  synchronicznie  z  sygnałem  zegarowym  wysyłanym  przez  układ  Master), 
rezultat  odczytu  docierający  do  układu  Master  jest  iloczynem  logicznym  stanów  wyjść 
układów Slave (wired and). 
Po  tym  jak  układy  Slave  prześlą  1-szy  bit  swojego  adresu,  układ  Master  inicjuje  odbiór 
następnego bitu, na który układy Slave odpowiadają wysyłając ponownie 1-szy bit adresu 
lecz  tym  razem  jest  to  jego  bit  komplementarny.  Następnie  układ  Master  wysyła  bit 
adresu do układów Slave. Jeśli urządzenie Slave odbiera bit, który zgadza się z bitem na 
pozycji  adresu,  pozostaje  załączone  i  aktywne.  Jeśli  natomiast  odebrany  bit  nie 
odpowiada  temu  z  adresu,  urządzenie  Slave  przechodzi  do  stanu  oczekiwania  i  nie 
przesyła już żadnych danych. Stan ten trwa aż do odebrania następnego sygnału reset. 
Opisywana wyżej procedura tzn. odbiór przez układ Master jednego bitu jako „normalny” 
i  komplementarny  a  następnie  przesłanie  tego  bitu  adresu  do  układu  Slave  (jako 
„normalny”),  powtarzana  jest  dla  wszystkich  63  pozostałych  bitów  adresu.  W  takiej 
sytuacji  urządzenie  Slave  wywołuje  wszystkie  układy  dołączone  do  magistrali,  lecz  w 
danym  momencie,  po  odbiorze  bitu  adresu,  tylko  jeden  z  nich  przejdzie  do  stanu 
oczekiwania.  Na  końcu  procedury  znany  jest  adres  ostatniego  układu  dołączonego  do 
magistrali.  W  następnych  przejściach  procedury  uwzględniana  jest  inna  ścieżka,  dotąd 
nie przeszukiwana. 
Wyjaśnienia wymaga jeszcze jedna drobna nieścisłość opisu. Proszę zauważyć, że w tym 
opisie bitem 1-szym nazywam najmniej znaczący bit adresu układu, czyli bit na pozycji 0, 
natomiast bit 64 to bit na pozycji 63. 
Jest oczywiste, że wszystkie uczestniczące w przeszukiwaniu układy mają bit o tej samej 
wartości na danej jego pozycji (tabela 1). Jeśli na przeszukiwanej gałęzi nie znajduje się 

background image

 
 
 
 
 

 

Strona 2 z 18 

 

Bit 

rzeczywisty 

Bit 

uzupełniony 

Interpretacja 

Na pozycji bitu znajdują się „0” i „1”; to jest sprzeczność 

Na pozycji bitu znajduje się „0” 

Na pozycji bitu znajduje się „1” 

Brak urządzeń na przeszukiwanej gałęzi 

Tabela 1. Interpretacja bitów odebranych przez układ Master w czasie przeszukiwania 
 
żaden układ, przeszukiwanie jest zatrzymywane i rozpoczynane jest nowe, od wysyłania 
sygnału „1-Wire reset”. Sytuacja, gdy na pozycji bitu umieszczone jest zarówno „0” jak i 
„1”,  nazywana  jest  sprzecznością  i  jest  kluczem  do  określania  kierunku  i  gałęzi 
przeszukiwania.  
Opisywany  algorytm  wykrywa  warunek  sprzeczności  w  pierwszym  przebiegu 
(bit/uzupełnienie = 0/0) i na jego podstawie wybiera gałąź „0” do kontynuacji pracy. To 
jest metoda przyjęta dla tego algorytmu. Możliwe jest stworzenie własnego, w którym do 
kontynuacji wybrana będzie gałąź „1”. Pozycja bitu, dla której ostatnio określony został 
warunek sprzeczności jest zapamiętywana dla następnych operacji wyszukiwania. 
 

Wynik porównania pozycji przeszukiwanego 

bitu z pozycją ostatnio odnalezionej 

sprzeczności 

Obierana gałąź przeszukiwania 

Wybierz gałąź „1” 

Obierz tę samą gałąź co ostatnio (od ostatnio 
znalezionego adresu) 

Wybierz gałąź „0” 

Tabela 2. Określanie kierunku przeszukiwań 
 
Algorytm  zapamiętuje  także  ścieżkę  ostatnich  sprzeczności,  które  wystąpiły  w  obrębie 
pierwszych  8  bitów  adresu  układu.  Jest  to  kod  rodziny  układów.  Jako  rezultat  takiego 
działania,  układy  odkryte  podczas  przeszukiwania  grupowane  są  w  rodziny.  Ostatnio 
odkryty  warunek  sprzeczności  w  obrębie  rodziny,  może  zostać  użyty  do  przeszukiwania 
selektywnego danej rodziny układów (np. czujników temperatury czy pamięci). 

background image

 
 
 
 
 

 

Strona 3 z 18 

 

 
 
 
 

                1-Wire Reset 

 

 

 

 

 

 

                    Wykryto             Nie 

                   obecność 

                   układów? 

 

 
 

                             Tak 

 
 

 

 

                      Czy                 Tak 

              LastDeviceFlag 

                      =1? 

 

 

 

                              Nie 

 

        id_bit_number = 1 

        last_zero = 0 

 

 

 

 

       Wyślij komendę 

       „search” (0xF0 lub 0xEC) 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Opisy zmiennych: 

 

cmp_id_bit – uzupełnienie jedynkowe bitu (w 

tym przypadku to negacja); należy pamiętać o 

fakcie, że do układu Master dociera iloczyn 

logiczny wszystkich bitów wysyłanych przez 

układy dołączone do magistrali 1-Wire 

 

id_bit – pierwszy bit odczytany podczas 

sekwencji odczytu; uwaga jak powyżej 

 

id_bit_number – pozycja bitu w adresie 

(numerze ROM) układu; zmienna zmienia się od 

1 do 64, podczas gdy faktyczna pozycja (waga) 
bitu jest o 1 mniejsza (0..63) 

 

LastDeviceFlag – zmienna wskazująca, że 

poprzednio odszukany układ był ostatnim w 

danej gałęzi 

 

LastDiscrepancy – indeks wskazujący na bit,  

od którego bitu powinno się rozpocząć następne 

poszukiwanie sprzeczności (określanie gałęzi 

przeszukiwań) 

 

LastFamilyDiscrepancy – indeks wskazujący 

na bit identyfikujący ostatnią sprzeczność 

wykrytą w obrębie 8-bitowego kodu rodziny 

układów 

 

last_zero – pozycja bitu ostatnio zapisanego 0, 

dla której nie wykryto sprzeczności 

 

ROM_NO – bufor o rozmiarze 8 bajtów, który 

zawiera numer ROM (adres) ostatnio wykrytego 

układu 

 

search_direction – zmienna o rozmiarze 1 bitu 

wskazująca kierunek przeszukiwania drzewa; 

wszystkie układy znajdujące się na kierunku 

przeszukiwania są aktywne, reszta znajduje się w 

stanie oczekiwania na następne przeszukiwanie 

background image

 
 
 
 
 

 

Strona 4 z 18 

 

 

 

 

 

 
 

    Pobierz id_bit i bit 
    komplementarny cmp_id_bit 

 
 
 
 
 

                 id_bit                TAK 
            =cmp_id_bit 
                  =1? 

 
 
                          NIE 
 

                 id_bit               TAK                                                      

NIE                                                   

NIE 

            =cmp_id_bit                           

id_bit_number=                               

     id_bit_number> 

                   =0?                                  

LastDiscrepancy?                            

     LastDiscrepancy? 

 
                          NIE                                               

  TAK                                                  

    TAK 

 
      

search_direction =                     

search_direction = 1                      

search_direction = 0 

      

id_bit 

 
 
 
 
 

 

 

 

 

 

 

 

 

 

       

search_direction= 

 

 

 

 

 

 

 

 

 

 

       

id_bit_number 

                                                   NIE                   search_            TAK         last_zero = 

                                                            Direction 

               id_bit_number 

 

 

 

 

 

             =0? 

 

     id_bit_number = 
     search_direction
 
     i wyślij przez interfejs 

 

NIE 

 

 

     Czy 

      TAK           LastFamilDiscr.= 

     1-Wire                                                       

 

 

last_zero   

         last_zero 

 

 

 

 

 

 

 

 

     <9? 

 

    Zwiększ 
    id_bit_number o 1 

 
 
 
 

NIE 

 id_bit_           TAK  

LastDiscrepancy =   

          LastDiscr. 

TAK            Ustaw flagę 

 

    

number   

    

last_zero   

 

               =0? 

 

  LastDeviceFlag 

 

      

>64? 

 
 
 

 

 

 

 

 

 

 

 

 

NIE 

 
 

background image

 
 
 
 
 

 

Strona 5 z 18 

 
 
 
 
 
 
 
 
 

       CRC8  

 

NIE 

                 Ustal warunki początkowe: 

 

       poprawny? 

 

 

 

LastDiscrepancy=0             

 

Ustaw wartość funkcji 

 

 

 

 

 

 

LastFamilyDiscrep.=0 

           

na FAŁSZ 

 

 

 

 

 

 

LastDeviceFlag=0 

 

 

TAK 

 
           Ustaw wartość funkcji 
           na PRAWDA 
 
 
 
 

      KONIEC 

 
 

 

Rysunek 1. Algorytm działania funkcji wyszukiwania układów 1-Wire 
 

 
 

Wyszukiwanie proste. 

 

Poprzez  manipulację  wartościami  zmiennych  LastDiscrepancy,  LastFamilyDiscrepancy, 
LastDeviceFlag  i  wartością  rejestru  ROM_NO  możliwe  są  do  przeprowadzenia  dwa 
podstawowe warianty wyszukiwania układów. 
 
Szukanie pierwszego. 
Pierwszy  z  nich  to  wyszukanie  pierwszego  adresu  urządzenia.  Jest  to  możliwe  po 
ustawieniu  LastDiscrepancy,  LastFamilyDiscrepancy  i  LastDeviceFlag  na  wartość  0  i  po 
tym  wywołanie  funkcji  poszukiwania.  Rezultat  może  zostać  odczytany  z  rejestru 
ROM_NO.  Jeśli  żadne  urządzenie  nie  jest  podłączone  do  magistrali  1-Wire,  wówczas 
przeszukiwanie  jest  przerywane.  Jeśli  znaleziono  jakiś  układ,  jego  adres  można  pobrać 
właśnie z tejże tabeli. Implementację tej funkcji można znaleźć na listingu 2 pod nazwą 
int one_wire_FIRST()
 
Szukanie następnego. 
Drugi  wariant  to  wyszukanie  następnego  układu,  po  pierwszym  lub  po  kolejnym. 
Wykorzystywany jest po wywołaniu funkcji „szukaj pierwszego” układu lub jako kolejne w 
ciągu  poleceń  wyszukiwania  następnych  urządzeń.  Rezultat  działania  zwracany  jest  w 
buforze  ROM_NO.  Jeśli  poprzednio  odszukano  ostatnie  urządzenie,  zostanie  ustawiona 
zmienna  informująca  o  zakończeniu  przeszukiwania  a  funkcja  zwróci  wartość  FALSE. 
Implementację tej funkcji można znaleźć na listingu 2 pod nazwą int one_wire_NEXT()
 
 
Zaawansowane funkcje wyszukiwania. 
 
Inne  możliwości  stwarza  tzw.  przeszukiwanie zaawansowane,  dzięki któremu  można  się 
odwołać  do  konkretnego  układu  lub  grupy  układów.  Podobnie  jak  poprzednio,  funkcje 
wywołuje się po uprzedniej manipulacji zawartością zmiennych. 
 

background image

 
 
 
 
 

 

Strona 6 z 18 

Weryfikacja. 
Weryfikacja przeprowadza sprawdzenie, czy układ o znanym adresie  podłączony jest do 
magistrali  1-Wire.  Można  ją  przeprowadzić  podając  adres  układu  w  rejestrze  ROM_NO 
oraz  ustawiając  wartość  zmiennych:  LastDiscrepency  na  0x40  (64  dziesiętnie)  i 
LastDeviceFlag na 0. Po opisanych nastawach należy wywołać funkcję wyszukiwania a po 
jej zakończeniu należy sprawdzić zawartość ROM_NO. Jeśli bufor zawiera adres, który był 
poszukiwany  oznacza  to,  że  urządzenie  jest  podłączone  do  magistrali  1-Wire. 
Implementację tej funkcji można znaleźć na listingu 2 pod nazwą int one_wire_VERIFY()
 
Wyszukiwanie w obrębie rodziny układów. 
Innym  rodzajem  operacji  jest  przeszukiwanie  konkretnej  rodziny  układów.  Jak  zapewne 
pamiętamy  z  wcześniejszej  lektury,  każdy  układ  z  interfejsem  1-Wire  posiada  własny 
unikatowy 64-bitowy kod, z czego pierwsze 8 bitów określa kod rodziny układów. Kod ten 
pozwala  oprogramowaniu  funkcjonującemu  w  układzie  Master  na  orientację,  czy  pewne 
funkcje,  związane  z  daną  rodziną  układów,  są  dostępne  czy  też  nie.  Jeśli  dana  sieć 
zawiera wiele różnych układów, to dobrą praktyką jest komunikacja z daną ich grupą, np. 
czujnikami temperatury.  
Aby  odwołać  się  do  konkretnej  grupy  układów,  należy  pierwszy  bajt  bufora  ROM_NO 
ustawić  na  wartość  równą  kodowi  grupy  a  resztę  bufora  wypełnić  wartością  0.  Należy 
również  ustawić  wartość  zmiennej  LastDiscrepancy  ustawić  na  0x40  (64  dziesiętnie)  a 
LastDeviceFlag i LastFamilyDiscrepancy na wartość 0. Jeśli funkcja poszukiwania znajdzie 
układ z rodziny podanym kodzie, wówczas jego adres zostanie umieszczony w ROM_NO. 
Jeśli  natomiast  brak  jest  układu  z  pożądanej  grupy,  to  ROM_NO  będzie  zawierać  adres 
pierwszego  znalezionego  układu.  W  związku  z  tym  konieczne  jest  sprawdzenie  wartości 
1-go  bajtu  ROM_NO  po  zakończeniu  pracy  funkcji.  Implementację  tej  funkcji  można 
znaleźć na listingu 2 pod nazwą void one_wire_TSETUP(byte family_code)
 
Pomijanie grupy układów. 
Inną  dostępną  operacją  jest  –  można  by  powiedzieć  odwrotna  do  powyżej  opisanej  – 
funkcja pomijania danej rodziny układów. Polega ona na pomijaniu rodziny układów, do 
której  należy  poprzednio  odszukany  układ.  Można  w  ten  sposób  znacznie  przyspieszyć 
wyszukiwanie,  ograniczając  się  do  konkretnej  grupy  układów,  na  której  w  danym 
momencie  nam  zależy,  pomijając  wszystkie  pozostałe.  Funkcja  może  być  wywołana 
wyłącznie  po  przeprowadzonym  poprzednio  szukaniu,  np.  pierwszego  układu.  Aby  ją 
uruchomić należy wartość LastFamilyDiscrepancy skopiować do zmiennej LastDiscrepancy 
i  wywołać  wyszukiwanie.  Następne  szukanie  odnajdzie  pierwszy  z  układów  po  podanym 
kodzie  rodziny.  Jeśli  dana  rodzina  należała  do  ostatniej  grupy  układów,  to  wówczas 
zmienna  LastDeviceFlag  przyjmie  wartość  „prawda”.  Implementację  tej  funkcji  można 
znaleźć na listingu 2 pod nazwą void one_wire_FAMILYSKIP().  
 
 

Zmienna 

 

Opis funkcji 

Last-

Discrepancy 

LastFamily 

Discrepancy 

LastDeviceFlag 

ROM_NO 

Szukaj pierwszego 

adres układu 

Szukaj następnego 

nie zmieniać 

nie zmieniać 

nie zmieniać 

adres układu 

Weryfikacja 

0x40 

bez znaczenia 

należy wpisać adres 
poszukiwanego układu a następnie 

sprawdzić rezultat 

Szukaj układów z 

danej rodziny 

0x40 

należy ustawić 1-szy bajt na kod 

rodziny układów a następnie sprawdzić 

rezultat 

Omiń układy z 

danej rodziny 

pobierz z 

ostatniego 

wyszukiwania 

nie zmieniać 

Tabela 3. Podsumowanie opisu funkcji wyszukujących 1-Wire. 
 

background image

 
 
 
 
 

 

Strona 7 z 18 

Jako  ciekawostkę  warto  wspomnieć,  że  układ  DS2480B  posiada  zaimplementowany 
sprzętowo  niemal  identyczny  algorytm.  Zwalnia  to  użytkownika  od  konieczności 
powtórnej  jego  implementacji  i  oszczędza  czas  konieczny  na  zbudowanie  urządzenia  i 
oczywiście  –  co  w  dzisiejszych  czasach  nie  ma  już  tak  wielkiego  znaczenia  –  pamięć 
programu mikrokontrolera. 
 

Jacek Bogusz 

 

 
 

 

 

 

 

Szukaj pierwszego: 

 

LastDiscrepancy = LastDeviceFlag = 0 

 

sygnalizacja 1-Wire reset 

 

czekaj na odpowiedź układów, jeśli brak odpowiedzi to koniec pracy 

 

id_bit_number = 1, last_zero = 0 

 

wyślij komendę przeszukiwania układów (0xF0) 

 

odczytaj pierwszy bit id_bit  

[urządzenie (A = 1)] and [urządzenie (B = 0)] and [urządzenie (C = 1)] = 0 

 

odczytaj bit komplementarny cmp_id_bit 

[urządzenie (A = 0)] and [urządzenie (B = 1)] and [urządzenie (C = 0)] = 0 

 

jeśli id_bit_number>LastDescrepancy to search_direction=0, last_zero=1 

 

wyślij na magistralę 1-Wire bit search_direction równy 0 (urządzenia A i C przejdą w stan 

oczekiwania na sygnał reset) 

 

zwiększ id_bit_number (zmienna przyjmie on wartość 2) 

 

odczytaj drugi bit id_bit (będzie on miał wartość 0, bo odpowie urządzenie B) 

 

czytaj drugi bit komplementarny cmp_id_bit (będzie on miał wartość 1 z powodu jak wyżej) 

 

bit i bit komplementarny mają różną wartość: search_direction = id_bit 

 

wyślij na magistralę 1-Wire search_direction równy 0, urządzenie B jest określane przez 

zawartość ROM_NO i jest wybrane (aktywne) 

 

LastDescrepancy = last_zero 

 

Szukaj następnego: 

 

sygnalizacja 1-Wire reset 

 

czekaj na odpowiedź układów, jeśli brak odpowiedzi to koniec pracy 

 

id_bit_number = 1, last_zero = 0 

 

wyślij komendę przeszukiwania układów (0xF0) 

 

odczytaj pierwszy bit id_bit  

[urządzenie (A = 1)] and [urządzenie (B = 0)] and [urządzenie (C = 1)] = 0 

 

odczytaj bit komplementarny cmp_id_bit 

[urządzenie (A = 0)] and [urządzenie (B = 1)] and [urządzenie (C = 0)] = 0 

 

ponieważ id_bit_number = LastDescrepancy to zmiennej search_direction nadaj wartość 1 

 

wyślij na magistralę 1-Wire bit search_direction równy 1 (urządzenie B przejdzie w stan 

spoczynkowy) 

 

zwiększ id_bit_number (przyjmie on wartość 2) 

 

odczytaj drugi bit id_bit (będzie on miał wartość 0, bo [urządzenie (A = 0) and [urządzenie (C = 

1)] = 0) 

szukaj 

pierwszego

 

szukaj 

następnego

 

szukaj 

następnego

 

background image

 
 
 
 
 

 

Strona 8 z 18 

 

czytaj drugi bit komplementarny cmp_id_bit (będzie on miał wartość 0, bo [urządzenie (A = 1) 

and [urządzenie (C = 0)] = 0) 

 

ponieważ id_bit_number > LastDescrepancy, to search_direction = 0 i last_zero = 2 

 

wyślij na magistralę 1-Wire search_direction równy 0, urządzenie A jest określane przez 

zawartość ROM_NO i jest wybrane (aktywne), urządzenie C przejdzie w stan spoczynkowy 

 

LastDescrepancy = last_zero 

 

Szukaj następnego: 

 

sygnalizacja 1-Wire reset 

 

czekaj na odpowiedź układów, jeśli brak odpowiedzi to koniec pracy 

 

id_bit_number = 1, last_zero = 0 

 

wyślij komendę przeszukiwania układów (0xF0) 

 

odczytaj pierwszy bit id_bit  
[urządzenie (A = 1)] and [urządzenie (B = 0)] and [urządzenie (C = 1)] = 0 

 

odczytaj bit komplementarny cmp_id_bit 

[urządzenie (A = 0)] and [urządzenie (B = 1)] and [urządzenie (C = 0)] = 0 

 

ponieważ id_bit_number < LastDescrepancy to search_direction = ROM_NO = 1 

 

wyślij na magistralę 1-Wire bit search_direction równy 1 (urządzenie B przejdzie w stan 

spoczynkowy) 

 

zwiększ id_bit_number (przyjmie on wartość 2) 

 

odczytaj drugi bit id_bit (będzie on miał wartość 0, bo [urządzenie (A = 0) and [urządzenie (C = 

1)] = 0) 

 

czytaj drugi bit komplementarny cmp_id_bit (będzie on miał wartość 0, bo [urządzenie (A = 1) 

and [urządzenie (C = 0)] = 0) 

 

ponieważ id_bit_number = LastDescrepancy, to search_direction = 1 

 

wyślij na magistralę 1-Wire search_direction równy 1, urządzenie C jest określane przez 

zawartość ROM_NO i jest wybrane (aktywne), urządzenie A przejdzie w stan spoczynkowy 

 

LastDescrepancy = last_zero, które jest równe 0 tak więc LastDeviceFlag = prawda 

 

Szukaj następnego: 

 

zmienna LastDeviceFlag ma wartość „prawda”, więc koniec pracy 

 

LastDiscrepancy = LastDeviceFlag = 0 

 

 

Rysunek 2. Schemat i pseudokod funkcjonowania opisywanego algorytmu dla adresu 2-
bitowego.

background image

 
 
 
 
 

 

Strona 9 z 18 

/************************************************* 
 Na podstawie AN187 firmy MAXIM-DALLAS 
 2004/04 Jacek Bogusz 
  
 kompilator RC-51 
 *************************************************/ 

 
#pragma SMALL  
#include <reg51.h> 
#include <stdio.h> 
 

//************* definicje stałych dla preprocesora ******************** 

#define FALSE 0 
#define TRUE 1 
#define byte unsigned char 
 
#define 

XTAL  110592 

 

//definicja rezonatora (8..25MHz!) 

#define 

nop()  ACC++  

 

//opóźnienie, 1 cykl maszynowy 

 
sbit one_wire_IO = P1^0;   

//definicja podłączenia linii portu 1W 

 

//****************** deklaracje metod i funkcji *********************** 

 

//wyszukanie pierwszego układu na magistrali 1-Wire 

int one_wire_FIRST(); 

//wyszukanie następnego układu 

int one_wire_NEXT(); 

//weryfikacja,czy układ jest dołączony do magistrali 

int one_wire_VERIFY(); 

//wyszukiwanie układów w konkretnej grupie 

void one_wire_TSETUP(byte family_code); 

//omijanie grupy układów 

void one_wire_FAMILYSKIP(); 

//wysłanie sygnału reset na magistralę 1-Wire 

int one_wire_RESET(); 

//wysłanie bajtu na magistralę 1-Wire 

void one_wire_WRBYTE(byte byte_value); 

//wysłanie bitu na magistralę 1-Wire 

void one_wire_WRBIT(bit bit_value); 

//odczyt bitu z magistrali 1-Wire 

byte one_wire_RDBIT(); 

background image

 
 
 
 
 

 

Strona 10 z 18 

//ogólna funkcja wyszukiwania 

int one_wire_SEARCH(); 

//wyliczenie sumy kontrolnej odebranych bajtów 

byte docrc8(byte value); 
 

//************************ zmienne globalne *************************** 
//adres odnalezionego układu 

byte ROM_NO[8]; 

//ostatnio odnaleziona sprzeczność 

int LastDiscrepancy; 

//ostatnio odnaleziona sprzeczność w obrębie 8-bitów rodziny układów 

int LastFamilyDiscrepancy; 

//flaga sygnalizująca, że układ jest ostatnim z danej grupy lub dołączonych układów 

int LastDeviceFlag; 

//suma kontrolna CRC8 

byte crc8; 
 
 

//-------------------------------------------------------------------------- 
// Odnajduje "pierwszy" układ na magistrali 1-Wire 
// Zwraca TRUE, jeśli odnaleziono układ (adres zawarty w ROM_NO) 
// Zwraca FALSE, jeśli nie ma układu 

int one_wire_FIRST() 

//ustalenie warunków początkowych 

 

LastDiscrepancy = LastFamilyDiscrepancy = 0; 

 

LastDeviceFlag = FALSE; 

 

return (one_wire_SEARCH()); 


 
 

//-------------------------------------------------------------------------- 
// Odnajduje "następny" układ na magistrali 1-Wire 
// Zwraca TRUE, jeśli odnaleziono układ (adres zawarty w ROM_NO) 
// Zwraca FALSE, jeśli nie ma układu 

int one_wire_NEXT() 

//ustalenie war.początkowych polega na nie zmienianiu poprzedniego stanu 

 

return one_wire_SEARCH(); 


 

background image

 
 
 
 
 

 

Strona 11 z 18 

 

//-------------------------------------------------------------------------- 
//Ogólna funkcja wyszukiwania; podstawowa implementacja algorytmu 
// Zwraca TRUE, jeśli odnaleziono układ (adres zawarty w ROM_NO) 
// Zwraca FALSE, jeśli nie ma układu; koniec przeszukiwania 

int one_wire_SEARCH() 

 

int id_bit_number; 

 

int last_zero, rom_byte_number, search_result; 

 

int id_bit, cmp_id_bit; 

 

byte rom_byte_mask, search_direction; 

//inicjalizacja zmiennych 

 

id_bit_number = 1; 

 

last_zero = 0; 

 

rom_byte_number = 0; 

 

rom_byte_mask = 1; 

 

search_result = 0; 

 

crc8 = 0; 

//jeśli poprzednie wywołania nie odszukało ostatniego układu 

 

if (!LastDeviceFlag) 

 

//1-Wire reset 

 

 

if (!one_wire_RESET()) 

 

 

//inicjalizacja zmiennych 

 

 

 

LastDiscrepancy = LastFamilyDiscrepancy = 0; 

 

 

 

LastDeviceFlag = FALSE; 

 

 

 

return FALSE; 

 

 

//wysłanie komendy "szukaj" 

 

 

one_wire_WRBYTE(0xF0); 

//pętla, w której przeprowadzane jest szukanie 

 

 

do { 

//odczytaj bit i bit komplementarny 

 

 

 

id_bit = one_wire_RDBIT(); 

 

 

 

cmp_id_bit = one_wire_RDBIT(); 

//sprawdź warunek różnych wartości bitu i bitu komplementarnego 

 

 

 

if ((id_bit == 1) && (cmp_id_bit == 1)) break; else 

 

 

 

//bit adresu 0 lub 1 dla wszystkich dołączonych układów 

 

 

 

 

if (id_bit != cmp_id_bit) search_direction = id_bit;  

background image

 
 
 
 
 

 

Strona 12 z 18 

 

 

 

 

else 

 

 

 

 

 

 

 

 

 

if (id_bit_number < LastDiscrepancy)  

 

 

 

 

 

search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0); 

 

 

 

 

 

else search_direction = (id_bit_number == LastDiscrepancy); 

 

 

 

 

 

if (search_direction == 0) 

 

 

 

 

 

 

 

 

 

 

 

last_zero = id_bit_number; 

//sprawdź, czy to ostatni warunek sprzeczny w obrębie rodziny układów 

 

 

 

 

 

 

if (last_zero < 9) 

 

 

 

 

 

 

LastFamilyDiscrepancy = last_zero; 

 

 

 

 

 

 

 

 

 

//ustaw lub wyzeruj bit w zmiennej rom_byte_number 
//za pomocą maski rom_byte_mask 

 

 

 

 

if (search_direction == 1)  

 

 

 

 

 

ROM_NO[rom_byte_number] |= rom_byte_mask; else ROM_NO[rom_byte_number] &= ~rom_byte_mask; 

//wyślij bit kierunku poszukiwania 

 

 

 

 

one_wire_WRBIT(search_direction & 0x01); 

//zwiększ licznik id_bit_number i przesuń w lewo maskę rom_byte_mask 

 

 

 

 

id_bit_number++; 

 

 

 

 

rom_byte_mask <<= 1; 

//jeśli maska jest 0, to weź nowy adres rom_byte_number kasuj maskę 

 

 

 

 

if (rom_byte_mask == 0) 

 

 

 

 

//wylicz CRC8 

 

 

 

 

 

docrc8(ROM_NO[rom_byte_number]); 

 

 

 

 

 

rom_byte_number++; 

 

 

 

 

 

rom_byte_mask = 1; 

 

 

 

 

 

 

 

//wykonaj dla wszystkich bajtów adresu 

 

 

}while(rom_byte_number < 8); 

 

//jeśli poszukiwanie zakończyło się sukcesem 

 

 

if (!((id_bit_number < 65) || (crc8 != 0))) 

 

 

//ustaw zmienne LastDiscrepancy, LastDeviceFlag, search_result 

 

 

 

LastDiscrepancy = last_zero; 

//sprawdź, czy to ostatni układ 

 

 

 

if (LastDiscrepancy == 0) 

background image

 
 
 
 
 

 

Strona 13 z 18 

 

 

 

LastDeviceFlag = TRUE; 

 

 

 

search_result = TRUE; 

 

 

 

//jeśli nie znaleziono żadnego układu 

 

if (!search_result || !ROM_NO[0]) 

 

 

 

LastDiscrepancy = 0; 

 

 

LastDeviceFlag = FALSE; 

 

 

LastFamilyDiscrepancy = 0; 

 

 

search_result = FALSE; 

 

 

return search_result; 


 
 

//-------------------------------------------------------------------------- 
// Weryfikuje,czy urządzenie od podanym adresie jest dołączone do 1-Wire 
// Zwraca TRUE, jeśli tak 

int one_wire_VERIFY() 

 

byte rom_backup[8]; 

 

int i,rslt,ld_backup,ldf_backup,lfd_backup; 

//przechowaj kopię stanu aktualnego 

 

for (i = 0; i < 8; i++) rom_backup[i] = ROM_NO[i]; 

 

ld_backup = LastDiscrepancy; 

 

ldf_backup = LastDeviceFlag; 

 

lfd_backup = LastFamilyDiscrepancy; 

//ustaw procedurę wyszukiwania 

 

LastDiscrepancy = 64; 

 

LastDeviceFlag = FALSE; 

 

if (one_wire_SEARCH()) 

 

//sprawdź czy znaleziono ten sam układ 

 

 

rslt = TRUE; 

 

 

for (i = 0; i < 8; i++) 

 

 

 

 

 

if (rom_backup[i] != ROM_NO[i]) 

 

 

 

 

 

 

 

rslt = FALSE; 

 

 

 

 

break; 

background image

 
 
 
 
 

 

Strona 14 z 18 

 

 

 

 

 

 

} else rslt = FALSE; 

//odtworzenie stanu początkowego 

 

for (i = 0; i < 8; i++) ROM_NO[i] = rom_backup[i]; 

 

LastDiscrepancy = ld_backup; 

 

LastDeviceFlag = ldf_backup; 

 

LastFamilyDiscrepancy = lfd_backup; 

//zwróć rezultat weryfikacji 

 

return rslt; 


 
 

//-------------------------------------------------------------------------- 
// Ustawienie warunków dla wyszukiwania układów w rodzinie, po tym można 
// uruchomić funkcję "szukaj następnego" (one_wire_NEXT) 

void one_wire_TSETUP(byte family_code) 

 

int i; 

 

ROM_NO[0] = family_code; 

 

for (i = 1; i < 8; i++) ROM_NO[i] = 0; 

 

LastDiscrepancy = 64; 

 

LastFamilyDiscrepancy = 0; 

 

LastDeviceFlag = FALSE; 


 
 

//-------------------------------------------------------------------------- 
// Ustawienie warunków do pomijania przy wyszukiwaniu danej rodziny układów 
// dla funkcji one_wire_NEXT(). 

void one_wire_FAMILYSKIP() 

 

LastDiscrepancy = LastFamilyDiscrepancy; 

 

LastFamilyDiscrepancy = 0; 

 

if (LastDiscrepancy == 0) LastDeviceFlag = TRUE; 


 
 

//-------------------------------------------------------------------------- 
// Wysłanie sygnału reset i sprawdzenie obecności układów na magistrali; 
// zwracane jest TRUE, jeśli układy są obecne 

background image

 
 
 
 
 

 

Strona 15 z 18 

int one_wire_RESET() 

 

byte delay; 

 

bit err; 

//pętla opóźnienia 480 < t < 960 cykli 

 

delay = (byte)(XTAL/12e6*480/4); 

//pętle opóźniające służą do wytworzenia tzw. time slots, których dokładny opis 
//można znaleźć w opisie standardu 1-Wire 

 

do 

 

 

 

 

 

 

 

 

 

 

 

 

 

one_wire_IO = 0;  

 

 

 

nop(); 

 

} while(--delay); 

//pętla opóźnienia 60 < t < 75 cm. 

 

delay = (byte)( XTAL / 12e6 * 66 / 2 ); 

 

do  

 

 

 

one_wire_IO = 1; 

 

}while(--delay); 

//stan niski oznacza, że urządzenie(a) 1W jest(są) podłączone 

 

err = one_wire_IO; 

 

 

 

//opóźnienie 480 < t 

 

delay = (byte)(XTAL/12e6*(480-66)/4); 

 

do 

 

 

 

 

 

 

 

 

 

 

 

 

 

nop();  

 

 

nop(); 

 

}while(--delay); 

 
 

err = one_wire_IO; 

//stan niski linii portu 1W oznacza błąd  

 

return (!err); 


 
 

//-------------------------------------------------------------------------- 
// Przesłanie lub odczyt bitu przez linię 1W 

bit one_wire_bit_io(bit b) 

 

byte delay; 

 
 

delay = (byte)(XTAL/12e6*15/2-2);   

 

//15 > t 

background image

 
 
 
 
 

 

Strona 16 z 18 

 

one_wire_IO = 0;  

 

 

 

 

//1 

 

one_wire_IO = b;  

 

 

 

 

//3 

 

while(--delay);   

 

 

 

 

//3 + delay * 2 

 

b = one_wire_IO; 

 

delay = (byte)(XTAL/12e6*45/2); 

 

 

//60 < t 

 

while(--delay); 

 

one_wire_IO = 1; 

 

return b; 


 
 

//-------------------------------------------------------------------------- 
// Przesłanie bajtu przez magistralę 1-Wire 

void one_wire_WRBYTE(byte byte_value) 

 

byte bit_counter = 8; 

 

do  

 

 

 

byte_value = byte_value >> 1 | (one_wire_bit_io(byte_value & 0x01) ? 0x80 : 0); 

 

}while(--bit_counter); 


 
 

//-------------------------------------------------------------------------- 
// Przesłanie pojedynczego bitu przez magistralę 1-Wire 

void one_wire_WRBIT(bit bit_value) 

 

one_wire_bit_io(bit_value); 


 
 

//-------------------------------------------------------------------------- 
// Odczyt pojedynczego bitu z magistrali 1-Wire 

byte one_wire_RDBIT() 

 

return (one_wire_bit_io(1)); 


 
 

//-------------------------------------------------------------------------- 
// Tablica wartości do wyznaczenia sumy kontrolnej CRC8 

background image

 
 
 
 
 

 

Strona 17 z 18 

code byte dscrc_table[] = { 
0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65, 
157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220, 
35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98, 
190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255, 
70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7, 
219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154, 
101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36, 
248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185, 
140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205, 
17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80, 
175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238, 
50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115, 
202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139, 
87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22, 
233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168, 
116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53}; 
 
 

//-------------------------------------------------------------------------- 
// Wyliczenie sumy kontrolnej CRC8 

byte docrc8(byte value) 

 

crc8 = dscrc_table[crc8 ^ value]; 

 

return crc8; 


 
 

//-------------------------------------------------------------------------- 
// Program główny, demonstracja sposobu użycia funkcji 

void main() 

 

int rslt,i,cnt; 

//wyszukiwanie wszystkich układów 1-Wire 

 

printf("\nSZUKAM WSZYSTKICH\n"); 

 

cnt = 0; 

 

rslt = one_wire_FIRST(); 

 

while (rslt) 

 

//wypisanie odnalezionego adresu układu 

 

 

for (i = 7; i >= 0; i--) 

background image

 
 
 
 
 

 

Strona 18 z 18 

 

 

printf("%02X", ROM_NO[i]); 

 

 

printf(" %d\n",++cnt); 

 

 

rslt = one_wire_NEXT(); 

 

//odnalezienie układów wyłącznie z rodziny 0x1A 

 

printf("\nSZUKAM RODZINY '0x1A'\n"); 

 

cnt = 0; 

 

one_wire_TSETUP(0x1A); 

 

while (one_wire_NEXT()) 

 

//weryfikacja odnalezionych układów 

 

 

if (ROM_NO[0] != 0x1A) 

 

 

break; 

//wypisanie odnalezionych adresów układów 

 

 

for (i = 7; i >= 0; i--) 

 

 

printf("%02X", ROM_NO[i]); 

 

 

printf(" %d\n",++cnt); 

 

//odnalezienie wszystkich za wyjątkiem rodzin o kodach 0x04, 0x1A, 0x23, and 0x01 

 

printf("\nSZUKAM WSZYSTKICH Z WYJATKIEM: 0x10, 0x04, 0x0A, 0x1A, 0x23, 0x01\n"); 

 

cnt = 0; 

 

rslt = one_wire_FIRST(); 

 

while (rslt) 

 

//weryfikacja 

 

 

if ((ROM_NO[0] == 0x04) || (ROM_NO[0] == 0x1A) || 

 

 

(ROM_NO[0] == 0x01) || (ROM_NO[0] == 0x23) || 

 

 

(ROM_NO[0] == 0x0A) || (ROM_NO[0] == 0x10)) 

 

 

one_wire_FAMILYSKIP(); 

 

 

else 

 

 

//wypisanie 

 

 

 

for (i = 7; i >= 0; i--) 

 

 

 

printf("%02X", ROM_NO[i]); 

 

 

 

printf(" %d\n",++cnt); 

 

 

 

 

rslt = one_wire_NEXT(); 

 

Listing 2. Implementacja funkcji wyszukiwania układów podłączonych do magistrali 1-Wire w języku C.