轉自:http://blog.sina.com.cn/s/blog_57ad1bd20102uxxw.html
1-WIRE搜索算法詳解(1)
0前言
美信公司(http://www.maximintegrated.com/cn)生產了許多1-Wire®器件產品,硬件電路極致簡單,而相應軟件就顯得複雜。美信網站的《應用筆記187》介紹了單線ROM搜索算法,並提供了TMEX API測試程序的源代碼,該算法較爲複雜,而且是通用於多平臺(windows\JAVA等)的API,無法直接在KeilC上調試並寫入單片機。本人在學習理解其算法後,適當修改源代碼,並作上了詳細的註釋和圖解,代碼在KeilC環境下調試通過,並在一個掛接4個DS18B20的小型1-Wire環境中測試成功,順利獲取4個ROM碼。現把算法分析及測試過程成文如下,其中算法部分保留了大部分AN187的內容,但作了許多修改和補充,原文可參見http://www.maximintegrated.com/cn/app-notes/index.mvp/id/187。本文介紹的搜索算法及源代碼,對任何現有的或將要推出的1-Wire器件都是有效的。
1測試環境及圖示
硬件連接:4個DS18B20並接,MCU爲笙泉MG82G516仿真芯片(其他普通51系列都可,仿真芯片可以方便調試),軟件爲Keil 3。
1.
2.笙泉THO65B+仿真器(可仿真51芯片)
3.Saleae Logic分析儀
4.全家福(開發板僅安裝芯片及供電用)
圖1中,4個DS18B20並接,紅黃黑三線爲電源、信號、地,綠色線通黃色線,接邏輯分析儀。原來邏輯分析儀從單片機端採集1-Wire信號,但實測中主機拉高電平(從機低電平)時,邏輯分析儀採集到一個尖刺脈衝,造成分析儀識別1-Wire協議失誤;後將採集線接到從機端,信號正常。
圖2是笙泉THO65B+仿真器,USB接口,可仿真51系列,方便程序調試。該仿真器芯片型號爲MPC82G516,類似於STC15F2K60S2,爲1T單片機,片上64KB Flash, 60KB程序存儲器, 3KB IAP存儲器, 1KB ISP 引導程序空間,以及1KRAM。
圖3爲邏輯分析儀,十分小巧,支持8路信號輸入,最高採樣速率24M,實際一般使用16M。USB接口,附送軟件。圖4爲開發板,本例中主要功能僅爲提供CPU插座及供電,1-Wire器件連接是相當簡單的。
2
Maxim的1-Wire®器件都帶有一個64位的唯一註冊碼,生產時通過激光刻蝕在內部只讀存儲器內(ROM),用於在1-Wire網絡中通過1-Wire主機對其尋址。如果1-Wire網絡中從機器件數量不定且ROM碼未知,則可採用搜索算法查找這些碼。下表是64Bit
ROM碼的組成示意:
(MSB表示Most
Significant Bit最高有效位,LSB表示Least
Significant Bit最低有效位)
MSB |
||
8位CRC |
48位序列號
MSB |
8位家庭碼
MSB |
搜索順序是從低位到高位的,如下: 第64位←——————————————————————第1位 |
圖5. 64位唯一的ROM註冊碼
圖6、通過邏輯分述儀採集到的1-Wire信號
圖片說明:
1. 上圖是邏輯分析儀在ROM搜索到1個ROM時1-Wire總線上採集到的信號,可見搜索耗時15ms;
2. 因低位先傳送,邏輯分析儀上顯示低位在左邊;
3. 信號自左到右分別爲:復位R、存在脈衝、主機發搜索命令8位、從機回覆64位ROM碼(包括家族碼0x28、48位ROM、8位CRC碼)
4. 分析軟件識別出了1-Wire協議,在信號頂部標示了內容和數位,閱讀時相當直觀。
5. 將圖6中家族碼的部分放大如圖7。
圖7. 搜索過程中採集的家族碼部分放大圖
圖片說明
1.
2.
3.
3
搜索算法採用的是二叉樹型結構,搜索過程沿各分節點進行,直到找到器件的ROM碼即葉子爲止;後續的搜索操作沿着節點上的其它路徑進行,按照同樣的方式直到找到總線上的所有器件代碼。本文後面提供了一個簡單示例:4個ROM,每個僅取4位,構造了一棵二叉樹,並在此示例上推導出搜索算法的許多細節及實現。
搜索算法首先通過復位(reset)和在線應答脈衝(presence pulse)時隙將1-Wire總線上的所有器件復位;成功地執行該操作後,發送1 個字節的搜索命令;搜索命令使1-Wire器件準備就緒、開始進行搜索操作。
搜索命令分爲兩類:標準搜索命令(F0 hex)用來搜索連接到網絡中所有器件;報警或有條件搜索命令(EC hex)只用來搜索那些處於報警狀態下的器件,這種方式縮小了搜索範圍,可以快速查找到所需要注意的器件。本文附帶代碼僅使用了標準搜索命令。
搜索命令發出之後,開始實際的搜索過程。首先總線上的所有從機器件同時發送ROM碼(也叫註冊碼)中的第一位(最低有效位) (參見圖1)。與所有的1-Wire通信一樣,無論是讀取數據還是向從機器件寫數據,都由1-Wire主機啓動每一位操作。按照1-Wire協議設置特性,當所有從機器件同時應答主機時,結果相當於全部發送數據位的邏輯AND;從機發送其ROM碼的第一位後,主機啓動下一位操作、接着從機發送第一位數據的補碼;從兩次讀到的數據位可以對ROM碼的第一位做出幾種判斷(參見下表)。上述二次讀取1-Wire總線上當前位ROM碼的正碼和反碼的操作,本文簡述爲“二讀”。
表1. 檢索信息位
主機讀一位 從機提供當前位正碼 |
主機再讀一位 從機提供該位反碼 |
二讀後可以判斷獲得的信息 注意:主線讀到的是各個響應從機的“線與”邏輯 |
0 |
0 |
連接器件的該位有0有1,這是一個差異位(混碼位) |
0 |
1 |
連接器件的該位均爲0 |
1 |
0 |
連接器件的該位均爲1 |
1 |
1 |
沒有器件與總線相連 |
按照搜索算法的要求,“二讀”後1-Wire主機必須向總線上的從機發回一個指定位,稱爲“一寫”;如果從機器件中ROM碼的當前位的值與該數據位匹配,則繼續參與搜索過程;若從機器件的當前位與之不匹配,則該器件轉換到休眠狀態,直到下一個1-Wire復位信號到來被再次喚醒。其餘63位ROM碼的搜索依然按照這種‘讀兩位’、‘寫一位’的模式進行重複操作。
按照這種搜索算法進行下去,最終除了一個從機器件外所有從機將進入等待狀態,經過一輪檢測,就可得到最後保留(未進入等待狀態)器件的ROM碼。在後續搜索過程中,選用不同的路徑(或分支)來查找其它器件的ROM碼。需要注意的是本文ROM碼的數據位用第1位(最低有效位)到第64 位(最高有效位)表示,而不是第0位到第63位的模式;這樣設置允許將差異位置計數器初始值置爲0,爲以後的比較提供了方便。
上述過程可簡述爲“二讀一寫”,“二讀”結果爲“00”,主機就判定這一位是“差異位”,也可稱爲“衝突位”“混碼位”。舉例來說,“二讀”就相當於“老師問名”,設想學生的名字就是64位ROM碼,老師第1問時學生反應爲:“1的不吭聲,0就高喊到”;第2問時學生反過來:“0的不吭聲,1的高喊到”,老師通過二次答覆就可分辨:“不吭聲+不吭聲”表示一個學生也沒有;“不吭聲+到”表示大家都是1,“到+不吭聲”表示大家都是0;而“到+到”收表示有0有1。試想,如果有0有1,只要有1個喊到,老師就能聽到,這種合成效果就是所謂的“線與”,當然這裏應稱爲“聲與”。
搜索到“差異位”時,主機如何確定搜索方向(0還是1),這是本算法的核心問題,這也是典型的“二叉樹遍歷”算法。或許有人會提出一種“笨”算法,就是窮舉64位組合,從000…000到111…111遍歷,有應答的從機就會被一個一個找出來,這確實是一種簡單的“笨”算法,在許多地方很有用,但對於64位ROM來說,假設一位的訪問需要100us,64位則需要6.4ms,窮舉全部ROM碼有264=1844億億,極端的遍歷時間爲37億年,這確實是一種無法實現的笨辦法。
下表列出了1-Wire主機和從機的搜索過程:
Master |
Slave |
發送“復位”信號 |
產生“存在”脈衝 |
發送“搜索”命令 |
全體器件進入“應付搜索”狀態,不斷地根據主機信號作出反應 |
從總線讀取1位“線與” |
全體器件發送64位ROM碼的第1位 |
從總線讀取1位“線與” |
全體器件發送64位ROM碼的第1位的反碼 |
向總線寫1位(按算法) |
器件們接收此位後,凡與ROM碼的第1位不符的器件進入休眠狀態 |
讀64位ROM碼後續位 |
器件發後續位ROM碼 |
讀64位ROM碼後續位的反碼 |
器件發後續位ROM碼的反碼 |
寫後續各位 |
器件們接收此位後,凡與ROM碼的當前位不符的器件進入休眠狀態. |
從上表可以看出:如果所有總線上的器件在當前位具有相同值,那麼只有一條分支路徑可選;總線上沒有器件響應的情況是一種異常狀態,可能是要查找的器件在搜尋過程中與1-Wire總線脫離。如果出現這種情況,應中止搜索,併發出1-Wire復位信號起始新的搜索過程。如果當前位既有0也有1,這種情況稱爲位值差異,它對在後續搜索過程中查找器件起關鍵作用。搜索算法指定在第一輪查詢中若出現差異(數據位/補碼 = 0/0),則選用‘0’路徑。注意:這一點是由本文檔中介紹的特定算法決定的,其它算法中或許首先選用‘1’路徑。算法需要記錄最後一次值差異的位置以供下一次搜索使用。
本文介紹的搜索算法是一個通用的程序,Maxim工程師極巧妙地設計了一些變量,只要在搜索前設置這些變量的初始值,程序就能完成不同的搜索功能,下文中會列出這些變量,但理解其奧祕需要花點時間。比如程序對最初8位ROM中出現的最後一次位差異設置了一個專門的變量保持跟蹤,因爲64位註冊碼的前8位是家族碼,利用此變量可以在器件的搜索過程中可以按照其家族碼進行分類。運用該變量可以有選擇性地跳過1-Wire器件的整個分組。如需進行選擇性的搜索,可參考關於高級變量搜索的詳細解釋。
64位ROM碼中還包含8位循環冗餘校驗碼(CRC);CRC值用於驗證是否搜索到正確的ROM碼。ROM碼的排列如圖1所示。關於CRC校驗的原理,內容豐富到需要專文論述,這裏不詳述,可參見Maxim網站相關筆記。
(未完待續)
1-Wire搜索算法詳解(2)
4 實例及算法分析
要理解算法,或制定算法,我們需要通過一個實例來解釋:
ROM編號 |
1234…… |
ROM1 |
0011…… |
ROM2 |
1010…… |
ROM3 |
1111…… |
ROM4 |
0001…… |
假設1-Wire掛有4個ROM如上表, 這裏ROM碼僅設4位,編號從1到4,而實際器件ROM位序號從1到64。右圖則是按“先0後1”遍歷順序所構造的二叉樹,可見第一次遍歷得到ROM4:0001,第二次遍歷得到ROM1:0011,依次類推。圖中打有⊕的位置就是分叉點,即差異位(或稱爲混碼位)。
現在根據上例觀察各次遍歷,提煉出算法及實現細節:
1.第一次遍歷時,第1位Bit1時遇到第一個差異位,按左序遍歷即先0後1的順序,我們選擇0(稱爲方向0);Bit2不是差異位,算法根據“二讀”後方便地選0;Bit3又是差異位,再選擇方向0,Bit4也不是差異位。遍歷結果得到ROM4。這裏可得出結論1:凡遇到新的差異位,選擇0。
2.第二次遍歷,按實例分析,Bit1處再選擇方向0;Bit2取0;Bit3不能再選0了,改選1;Bit4取1;得到ROM1。問題隨即產生:問題1、Bit1爲何走0?此處確爲差異位,但已不是首次經過,不能套用結論1。問題2、Bit3處爲何改走1?簡單分析問題2可得出結論2:凡上次遍歷時最後一個走0的差異位本次應走1。很明顯,“上次遍歷時最後一個差異位”下的左分支已經走過,這次應該往右走了。再回答問題1可以得到結論3:凡上次遍歷時最後一個走0的差異位之前的差異位仍按上次遍歷的老路走。這個結論比較拗口,觀察實例來解釋:Bit3是差異位,右分支還沒走過,現在我要走Bit3下邊的右分支,Bit3之前當然是按上次路線來走了。
3.然後是否就可以進行第三次遍歷了呢?且慢,有一個重要的問題還沒處理。第二次遍歷前,那個“上次遍歷時最後一個走0的差異位”應該Bit3,我們先設置一個變量LastDiscripancy來記住這個值,即LastDiscripancy=3;從前面的分析我們知道,這個變量的值是決定本次遍歷時算法在哪個位置改道的依據,而且這個變量在本次遍歷全過程中應該保持不變的,如果在該節點前或後有任意多少的差異位,均按結論1(新差異位)和結論3(老差異位)來處理。也可以理解成結論2在一次遍歷中必須適用且僅適用一次,這也就是每次遍歷都能找出一個新的ROM的核心所在。那麼第二次遍歷後,變量LastDiscripancy應該指向哪個節點呢?直接觀察就可發現應該指向Bit1。
4.那麼算法中如何實現每次遍歷後變量LastDiscripancy的更新呢?要知道這個指針隨着每次遍歷在或上或下地移動,如第一次遍歷後指向Bit3,第二次後指向Bit1,第三次後指向Bit2。還有,第一次開始遍歷前、第四次遍歷後該變量又指向哪裏呢?由於實際ROM多達64位,從機如果數據多的話,差異位也會隨之增加,所以算法再引入一個變量Last_Zero,在每次遍歷前設爲0,即指向起始位置前,然後遍歷ROM碼的1-64位時,該變量始終指向最後一個走0的差異位,等到遍歷完成後,將該變量的值賦給LastDiscripancy即可。這樣我們再觀察實例的第二次遍歷,Last_Zero遍歷前爲0,Bit1時,符合“走0的差異位”,於是Last_Zero=1,後續Bit3儘管是差異位,但不走0,所以遍歷完成後,該值還是1,最後交給LastDiscripancy,自己又指向0,爲第三次遍歷作好準備。
5.第三次遍歷就變得順理成章:LastDiscripancy=1,Bit1處需運用結論2,算法改走1。而且第三次遍歷讓Bit2成爲了“最後一個走0的差異位”,第四次遍歷就在此處改走1了。第四次遍歷搜索到最後一個rom,但還得告訴程序結束信號,從而退出搜索。結束信號用什麼判定?4個ROM循環4次?當然不是,上述表圖只是舉例,實際總路線上掛接多少從機是未知的。答案還是利用變量LastDiscripancy來判定,開始搜索前自然有LastDiscripancy=0,但一旦進入搜索程式,每次遍歷後該變量總是指向ROM碼中間可能的某一位(1-64),直至遍歷到最後一個從機,這時必定是所有差異位均走1,如果Last_Zero保持爲初始值0,遍歷過程中未作修改,遍歷完成後LastDiscripancy=Last_Zero=0。以此爲條件可判定搜索全部完成。
6.綜上,當算法執行到一個差異位時,需判斷區分爲三種情況:首次遇到型、上次最後走0型、上次非最後走0型。可以通過二個變量的比較來表徵這三種情況,即比較當前搜索的位id_bit_number和上次最後走0的位LastDiscrepancy 的大小來判別,如下表:
表3. 搜索路徑方向的確定
三種情況 |
當前搜索位 vs 最後走0差異位 |
路徑(變量:search_direction) |
結論2:上輪最後差異位 |
Id_bit_number=LastDiscripancy |
選1 |
結論3:非最後差異位 |
Id_bit_number < LastDiscripancy |
同上次 (來自存儲的最近ROM碼) |
結論1:新遇差異位 |
Id_bit_number > LastDiscripancy |
選0 |
其中變量Id_bit_number表示當前搜索位,每一次遍歷時從1至64步進;
變量search_direction表示當前節點經過二讀及判斷後確定的搜索方向,是0還是1;
其他變量說明請參見流程圖中附文。
5
圖9列出了對一個從器件進行搜索的流程圖;注意:流程圖附文中列出了涉及到的一些關鍵變量,並進行了說明,在本文描述內容、流程圖及源代碼中也將用到這些名稱的變量。
其他說明:
1、 該流程最終被代碼表達成一個函數,可以執行對一個器件的搜索;
2、 當主機復位後未收到從機的存在脈衝、最後設備變量LastDeviceFlat=1、二讀後均爲1這三種情況,函數執行初始化變量後返回False;
3、 紅色虛線框中流程,是針對差異位的處理,分3種情況走不同分支,該部分是本算法的精華;
4、 紅色虛線框中最下面的二個綠色背景框,是對家族碼的處理,適用於多類型器件混合網絡的指定處理,如單類器件組網,可以跳過此部分;
5、 圖中各指令框邊上列出了部分變量、變量比較、變量賦值表達式,以方便後續理解代碼;
程序每步搜索確定的ROM碼將存入數組變量ROM_no[]中,流程圖中“同上次”框中將調用此數組變量的值,獲取上輪遍歷時該位值。 |
6 實現
上述流程圖算法實際上是一個通用的函數,可實現一次從機ROM碼的搜索,在附錄代碼中即爲OWSearch()函數,執行一次該函數,可以有以下幾種結果:
1.復位信號發出後,未收到任何應答信號,表明無器件掛接或硬件電路故障,函數返回False退出;
2.上輪搜索中程序判斷爲最後一個器件,本次執行函數也是返回False退出;
3.在某位“二讀”時出現“11”的信號,這是執行中出現的異常,函數也是返回False退出;
4.首次或再次進入此函數,信號也正常,函數將搜索到總線上的第一個器件ROM碼;
在上述4種結果中,第1和第3是異常後退出,第2是器件搜索完畢後結束退出。第4是首次執行搜索和再次執行搜索這二種情況,可以表述後下面二個函數:First和Next,二個函數通過對LastDiscrepancy、LastFamilyDiscrepancy、LastDeviceFlag和ROM_NO值的處理,利用同一流程實現了兩個不同類型的搜索操作;這兩個操作是搜索1-Wire器件ROM碼的基礎,本文附後列出了全部代碼,可供測試。
First
‘FIRST’操作是搜索1-Wire總線上的第一個從機器件。該操作是通過將LastDiscrepancy、LastFamilyDiscrepancy和LastDeviceFlag置零,然後進行搜索完成的。最後ROM碼從ROM_NO寄存器中讀出。若1-Wire總線上沒有器件,復位序列就檢測不到應答脈衝,搜索過程中止。
Next
‘NEXT’操作是搜索1-Wire總線上的下一個從機器件;一般情況下,此搜索操作是在‘FIRST’操作之後或上一次‘NEXT’操作之後進行;保持上次搜索後這些值的狀態不變、執行又一次搜索即可實現‘NEXT’操作。之後從ROM_NO寄存器中來讀出新一個ROM碼。若前一次搜索到的是1-Wire上的最後一個器件,則返回一個無效標記FALSE,並且把狀態設置成下一次調用搜索算法時將是‘FIRST’操作的狀態。
7 高級變量搜索
有3種利用同一組狀態變量LastDiscrepancy、LastFamilyDiscrepancy、LastDeviceFlag、ROM_NO實現的高級變量搜索算法,這幾種高級搜索算法允許來指定作爲搜索目標或需要跳過搜索的器件的類型(家族碼)以及驗證某類型的器件是否在線(參見表4)。
如果理解了算法原理及各個變量的作用,不難理解“高級變量搜索”的三種功能。本文附帶代碼爲簡便起見,刪除了這些內容,讀者如感興趣可直接訪問AN187應用筆記。
Verify
‘VERIFY’操作用來檢驗已知ROM碼的器件是否連接在1-Wire總線上,通過提供ROM碼並對該碼進行目標搜索就可確定此器件是否在線。首先,將ROM_NO寄存器值設置爲已知的ROM碼值,然後將LastDiscrepancy和LastDeviceFlag標誌位分別設置爲64 (40h)和0; 進行搜索操作,然後讀ROM_NO的輸出結果;如果搜索成功並且ROM_NO中存儲的仍是要搜索器件的ROM碼值,那麼此器件就在1-Wire總線上。
Target Setup
‘TARGET SETUP’操作就是用預置搜索狀態的方式首先查找一個特殊的家族類型,每個1-Wire器件都有一個字節的家族碼內嵌在ROM碼中(參見圖1),主機可以通過家族碼來識別器件所具有的特性和功能。若1-Wire總線上有多片器件時,通常是將搜索目標首先定位在需注意的器件類型上。爲了將一個特殊的家族作爲搜索目標,需要將所希望的家族碼字節放到ROM_NO寄存器的第一個字節中,並且將ROM_NO寄存器的復位狀態置零,然後將LastDiscrepancy設置爲64 (40h);把LastDeviceFlag和LastFamilyDiscrepancy設置爲0。在執行下一次搜索算法時就能找出所期望的產品類型的第一個器件;並將此值存入ROM_NO寄存器。需要注意的是如果1-Wire總線上沒有掛接所期望的產品類型的器件,就會找出另一類型的器件,所以每次搜索完成後,都要對ROM_NO寄存器中存儲的結果進行校驗。
Family Skip Setup
‘FAMILY SKIP SETUP’操作用來設置搜索狀態以便跳過搜索到的指定家族中的所有器件,此操作只有在一個搜索過程結束後才能使用。通過把LastFamilyDiscrepancy複製到LastDiscrepancy,並清除LastDeviceFlag即可實現該操作;在下一搜索過程就會找到指定家族中的下一個器件。如果當前家族碼分組是搜索過程中的最後一組,那麼搜索過程結束並將LastDeviceFlag置位。
要注意的是,FamilySkipSetup和TargetSetup函數實際上並沒有進行搜索操作,它們只不過是用來設置搜索寄存器,以便在下一次執行‘NEXT’操作時能跳過或找到所期望的類型。
表4. 搜索變量狀態的設置
功能函數 |
LastDiscrepancy |
LastFamily- Discrepancy |
LastDeviceFlag |
ROM_NO |
FIRST |
0 |
0 |
0 |
搜索結果 |
NEXT |
保持原值 |
保持原值 |
保持原值 |
保持搜索結果 |
VERIFY |
64 |
0 |
0 |
驗證與預設相同 |
TARGET SETUP |
64 |
0 |
0 |
僅設家族碼,其他爲0 |
FAMILY SKIP SETUP |
複製於LastFamilyDiscrepancy |
0 |
0 |
保持原值 |
8 結論
本文提供的搜索算法可以找出任意給定的1-Wire器件組中獨一無二的ROM碼,這是保證多點1-Wire總線應用的關鍵,已知ROM碼後就可以對逐一選定的某個1-Wire器件來進行操作。本文還對一些變量搜索算法做了詳細論述,這些變量搜索算法能夠查找或跳過特定類型的1-Wire器件。
或許Maxim覺得1-Wire
器件的軟件開銷讓人望而生畏,因此設計了專用芯片DS2480B系列,可以實現串口到1-Wire線路的驅動,包括與本文檔中相同的搜索算法,詳細資料請參閱DS2480B數據資料和應用筆記192;以及DS2490 芯片,實現USB口到1-Wire橋接,也可實現了整個搜索過程;還有一款I2C橋接1-Wire的芯片。使用這些芯片,無須編寫複雜算法,只需向芯片發送命令即可實現多種控制,其最大優點是芯片中集成了1-Wire操作控制的硬件,省卻了1-Wire複雜的時序控制,因而其他編程可使用高級語言來編寫,甚至直接使用Maxim提供的平臺軟件在PC上開發1-Wire應用系統。
9 附錄
《詳解3》中將給出了實現搜索過程的例程,並給出了‘C’程序代碼,需要注意的是,Maxim並沒有給出“復位、讀寫總線”等低級1-Wire函數的C代碼,而是提示我們可以調用TMEX API實現,考慮到本程序在51系列平臺上獨立調試,代碼中提供了這些函數。關於TMEX API和其它一些1-Wire API的詳細資料請參考應用筆記155。
另須注意:低級1-Wire函數對時序控制有極高要求,其延時代碼必須確保符合讀寫時序,本文程序在1T單片機MPC82G516調試通過,如改用其他1T單片機或12T單片機,必須對延時函數重新調試參數,以獲得1-Wire規定時序。另:代碼在實測中也適用於“寄生供電”,即不給從機連接VCC電源,代碼也可正常工作。關於“寄生供電”的詳細信息,請參見Maxim其他應用筆記。
(介紹完,代碼待續)
1-Wire搜索算法詳解(3)
C代碼:
#include
#include
sbit DQ=P0^7;
sbit K1=P0^6;
sbit P_Read=P0^5;
sbit P_Write=P0^4;
// definitions
#define FALSE 0
#define TRUE
//幾個延時函數,供一線低級操作時調用
//如果改用不同的MPU,如12T,則必須修改這幾個函數,確保時間符合協議要求
void Delay480us();
void Delay410us();
void Delay3_88us(unsigned char i);
//一線低級操作函數
bit
void OWWriteBit(bit bit_value);
bit
void OWWriteByte(unsigned char byte_value);
//////
//搜索函數
bit
bit
bit
unsigned char docrc8(unsigned char value);
//全局搜索變量
unsigned char ROM_NO[8];
char LastDiscrepancy;
char LastFamilyDiscrepancy;
bit LastDeviceFlag;
unsigned char crc8;
//--------------------------------------------------------------------------
//
// 返回TRUE: 找到, 存入ROM_NO緩衝;FALSE:無設備
// 先將初始化3個變量,然後調用OWSearch算法進行搜索
//--------------------------------------------------------------------------
bit OWFirst()
{
}
//--------------------------------------------------------------------------
//
// 返回TRUE: 找到, 存入ROM_NO緩衝;FALSE:無設備,結束搜索
// 在前一輪搜索的基礎上(3個變量均在前一輪搜索中有明確的值),再執行一輪搜索
//--------------------------------------------------------------------------
bit OWNext()
{
}
//--------------------------------------------------------------------------
//
//
//--------------------------------------------------------------------------
{
// ------------------------------------------------------------------
//1。是否搜索完成(已到最後一個設備)?
//-------------------------------------------------------------------
//=====================================================================
// 開始循環處理1-64位ROM,每位必須進行“二讀”後進行判斷,確定搜索路徑
// 然後按選定的路徑進行“一寫”,直至完成全部位的搜索,這樣一次循環
// 可以完成一輪搜索,找到其中一個ROM碼。
//=====================================================================
// ------------------------------------------------------------------
//搜索完成,如果搜索不成功包括搜索到了但CRC錯誤,復位狀態變量到首次搜索的狀態。
//-------------------------------------------------------------------
}
//=====================================================================
//=======================================================================
//=====================================================================
// 1-Wire函數調用所需的延時函數,注意不同MCU下須重調參數
//=====================================================================
void Delay480us()
{
}
void Delay410us()
{
}
void Delay3_88us(unsigned char i)
{
}
//=====================================================================
//
//=====================================================================
bit OWReset()
{
}
//-----------------------------------------------------------------------------
void OWWriteBit(bit dat)
{
u
}
//-----------------------------------------------------------------------------
bit OWReadBit()
{
}
//-----------------------------------------------------------------------------
void OWWriteByte(unsigned char dat)
{
}
//-----------------------------------------------------------------------------
char OWReadByte(void)
{
}
//
static unsigned char dscrc_table[] = {
//--------------------------------------------------------------------------
//迭代計算CRC,返回當前CRC值
unsigned char docrc8(unsigned char value)
{
}
//主函數,
void main()
{
}