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ę
Strona 2 z 18
Bit
rzeczywisty
Bit
uzupełniony
Interpretacja
0
0
Na pozycji bitu znajdują się „0” i „1”; to jest sprzeczność
0
1
Na pozycji bitu znajduje się „0”
1
0
Na pozycji bitu znajduje się „1”
1
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).
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
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
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.
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
0
0
0
adres układu
Szukaj następnego
nie zmieniać
nie zmieniać
nie zmieniać
adres układu
Weryfikacja
0x40
bez znaczenia
0
należy wpisać adres
poszukiwanego układu a następnie
sprawdzić rezultat
Szukaj układów z
danej rodziny
0x40
0
0
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
0
0
nie zmieniać
Tabela 3. Podsumowanie opisu funkcji wyszukujących 1-Wire.
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
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.
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();
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();
}
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;
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)
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;
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
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
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
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--)
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.