本應用向用戶介紹簡單的1-Wire軟件,用于將微控制器連接至DS18B20、DS18S20和DS1822 1-Wire溫度傳感器。本文舉例使用DS5000(兼容8051)微控制器。給出了軟件示例,說明了延遲、復位、讀位、寫位、讀字節、寫字節、ROM搜索、CRC、讀溫度和讀暫存本例程的實現。
介紹
DS1B18、DS20S18或DS20等1822-Wire器件與微控制器的接口有多種方法可供選擇。這些方法包括簡單的軟件解決方案,使用串行接口芯片(如DS2480B),以及將Maxim的VHDL 1-Wire主控制器集成到定制ASIC中。本文向用戶介紹最簡單的軟件方案,用于微控制器與任意數量的DS1x18或DS20溫度傳感器之間的基本1822-Wire通信。
DS18B20、DS18S20和DS1822的詳細時序和工作原理信息可在各自的數據資料中找到,可從Maxim網站獲取。
硬件配置
圖1中的框圖說明了使用多個1-Wire溫度傳感器時硬件配置的簡單性。單線總線為所有設備提供通信訪問和電源。總線電源通過 4.7kΩ 上拉電阻從 3V 至 5.5V 電源軌提供。總線上可以連接幾乎無限數量的1-Wire器件,因為每個器件都有一個唯一的64位ROM碼標識符。
圖1.主機微控制器接口。
接口時序
與DS18x20/DS1822的通信通過使用“時隙”實現,允許數據通過1-Wire總線傳輸。每個通信周期從微控制器的復位脈沖開始,然后是來自DS18x20/DS1822的存在脈沖,如圖2所示。
當總線主控將1-Wire總線從邏輯高電平(非活動)拉至邏輯低電平時,將啟動寫入時隙。所有寫入時隙的持續時間必須為60μs至120μs,周期之間的最小恢復時間為1μs。寫“0”和寫“1”時隙如圖3所示。在寫入“0”時隙期間,主機微控制器在該時隙的持續時間內將線路拉低。但是,在寫入“1”時隙期間,微控制器將線路拉低,然后在時隙開始后15μs內釋放線路。
當微控制器將總線拉低1μs,然后釋放時隙時啟動,DS18x20/DS1822可以控制線路并提供有效數據(高電平或低電平)。所有讀取時隙的持續時間必須為60μs至120μs,周期之間的恢復時間至少為1μs(見圖3)。
圖2.復位脈沖和存在脈沖。
圖3.寫入和讀取時間段。
軟件控制
為了精確控制1-Wire接口的特殊定時要求,必須首先建立某些關鍵功能。創建的第一個函數必須是“延遲”函數,它是所有讀寫控制的組成部分。此功能完全取決于微控制器的速度。本文使用DS5000(兼容8051)微控制器,其工作頻率為11.059MHz。右邊的示例說明了用于創建時序延遲的“C”原型函數。
延遲示例
// DELAY - with an 11.059MHz crystal. // Calling the routine takes about 24us, and then // each count takes another 16us. // void delay(int useconds) { int s; for (s=0; s由于每個通信周期都必須從微控制器的復位開始,因此“復位”功能是要實現的下一個最重要的功能。復位時隙為 480μs。通過將延遲設置為“3”,后跟“25”(見下面的示例),復位脈沖將持續所需的持續時間。復位后,微控制器必須松開,以便DS18x20/DS1822能夠通過拉低線路來指示其“存在”。請注意,如果總線上有多個溫度傳感器,它們將同時響應存在脈沖。
重置示例
////////////////////////////////////////////////////////////////////////////// // OW_RESET - performs a reset on the one-wire bus and // returns the presence detect. Reset is 480us, so delay // value is (480-24)/16 = 28.5 - we use 29. Presence checked // another 70us later, so delay is (70-24)/16 = 2.875 - we use 3. // unsigned char ow_reset(void) { unsigned char presence; DQ = 0; //pull DQ line low delay(29); // leave it low for 480us DQ = 1; // allow line to return high delay(3); // wait for presence presence = DQ; // get presence signal delay(25); // wait for end of timeslot return(presence); // presence signal returned } // 0=presence, 1 = no part以下四個示例中顯示的讀寫函數代碼段提供了所有數據位和數據字節讀寫操作所需的基本結構。
讀取位示例
////////////////////////////////////////////////////////////////////////////// // READ_BIT - reads a bit from the one-wire bus. The delay // required for a read is 15us, so the DELAY routine won't work. // We put our own delay function in this routine in the form of a // for() loop. // unsigned char read_bit(void) { unsigned char i; DQ = 0; // pull DQ low to start timeslot DQ = 1; // then return high for (i=0; i<3; i++); // delay 15us from start of timeslot return(DQ); // return value of DQ line }寫入位示例
////////////////////////////////////////////////////////////////////////////// // WRITE_BIT - writes a bit to the one-wire bus, passed in bitval. // void write_bit(char bitval) { DQ = 0; // pull DQ low to start timeslot if(bitval==1) DQ =1; // return DQ high if write 1 delay(5); // hold value for remainder of timeslot DQ = 1; }// Delay provides 16us per loop, plus 24us. Therefore delay(5) = 104us讀取字節示例
////////////////////////////////////////////////////////////////////////////// // READ_BYTE - reads a byte from the one-wire bus. // unsigned char read_byte(void) { unsigned char i; unsigned char value = 0; for (i=0;i<8;i++) { if(read_bit()) value|=0x01<寫入字節示例
////////////////////////////////////////////////////////////////////////////// // WRITE_BYTE - writes a byte to the one-wire bus. // void write_byte(char val) { unsigned char i; unsigned char temp; for (i=0; i<8; i++) // writes byte, one bit at a time { temp = val>>i; // shifts val right 'i' spaces temp &= 0x01; // copy that bit to temp write_bit(temp); // write bit in temp into } delay(5); }搜索 ROM 算法
為了充分利用1-Wire網絡概念,微控制器必須能夠與連接到網絡的任意數量的器件進行通信。為此,微控制器必須使用圖64所示的“Search ROM”算法學習總線上每個器件的唯一4位ROM識別碼。圖 4 以下示例解釋了具有四個從設備的總線的搜索 ROM 例程。還顯示了搜索 ROM 例程的示例代碼。一旦識別出所有ROM代碼,“匹配ROM”命令可用于與網絡上的任何特定設備進行通信。
圖4.搜索 ROM 算法。
ROM 搜索示例
在ROM搜索過程中,總線主站必須重復一個簡單的三步例程:1)從從設備讀取ROM碼位,2)讀取位的補碼,3)寫入該位的選定值。總線主機必須執行此三步例程 64 次,每個 ROM 代碼位執行一次。完成一次通過后,總線主站將知道總線上一個從設備的ROM代碼。其余設備及其ROM代碼可以通過額外的通道來識別。
以下示例說明了ROM搜索過程,該示例假設四個不同的器件連接到同一1-Wire總線。四個設備的ROM代碼如下所示:
ROM1 00110101...
ROM2 10101010...
ROM3 11110101...
ROM4 00010001...搜索過程如下:
總線主站通過發出復位脈沖來開始初始化序列。從設備響應方式 同時發出存在脈沖。
然后,總線主控器在1-Wire總線上發出搜索ROM命令。
每個器件將響應搜索ROM命令,將各自ROM碼的第一位值放到1-Wire總線上。然后,主站將讀取總線值。在這種情況下,ROM1和ROM4將在0-Wire總線上放置一個1,即它們將其拉低。ROM2和ROM3將在1-Wire總線上放置一個1,允許線路保持高電平。結果是線路上所有設備的邏輯 AND;因此,總線主站將讀取 0。1-Wire總線上的所有器件都將響應此讀取,方法是將其ROM碼的第一位補碼放到1-Wire總線上:ROM1和ROM4在1-Wire總線上放置一個1,使線路保持高電平,ROM2和ROM3將在總線上放置一個0。 把它拉低。總線主控服務器現在將再次讀取總線,并將再次讀取 0。
根據從設備ROM代碼,總線主站可以從兩次讀取中獲得四種可能的數據組合。這些組合可以解釋如下:
00 有些連接到總線的設備在當前ROM代碼位位置具有沖突位。 01 連接到總線的所有設備在此位位置都有一個 0。 10 連接到總線的所有設備在此位位置都有一個 1。 11 沒有器件連接到1-Wire總線。
在本例中,總線主控器在每次讀取時都讀取0,這告訴它1-Wire總線上有一些器件在第一個ROM代碼位置為0,而其他器件則為1。
為了響應前面的數據,總線主控服務器將 0 寫入總線。這將取消選擇此搜索通道其余部分的ROM2和ROM3,僅保留ROM1和ROM4“連接”到1-Wire總線。
總線主站再執行兩次讀取,并收到 0,后跟 1。這表示仍連接到總線的所有設備都將 0 作為其第二個 ROM 數據位。
然后,總線主站寫入 0 以保持 ROM1 和 ROM4 連接到總線。
總線主站再次執行兩次讀取并接收兩個 0。這向主機表明,1-Wire總線上的一個器件在第三個ROM碼位置為0,另一個器件為1。
總線主站將 0 寫入總線,總線取消選擇 ROM1,并將 ROM4 保留為唯一仍連接的設備。
總線主站從 ROM4 讀取 ROM 位的其余部分,并根據需要繼續訪問 ROM4 設備。這樣就完成了第一個 ROM 搜索傳遞;總線主站現在通過學習4-Wire總線上的ROM碼,唯一地識別了1-Wire總線上的一個從機(ROM<>)。
總線主站通過重復步驟 1 到 7 來啟動新的 ROM 搜索序列。
總線主站現在將 1 寫入總線(而不是步驟 0 中所做的 8)。這會解耦 ROM4,只留下 ROM1 仍處于連接狀態。
總線主站現在從ROM1讀取ROM位的其余部分,并可以根據需要與ROM1設備通信。這樣就完成了第二個ROM搜索過程,主設備現在已經識別了另一個從設備(ROM1)。
總線主站通過重復步驟 1 到 3 開始新的 ROM 搜索。
總線主控服務器現在將 1 寫入總線(而不是步驟 0 中所做的 4)。這將取消選擇此搜索傳遞的其余部分的 ROM1 和 ROM4,只留下耦合到總線的 ROM2 和 ROM3。
總線主站執行兩次讀取并接收兩個 0。
總線主站將 0 寫入總線,使 ROM3 去耦,只留下 ROM2 連接到總線。
總線主站從 ROM2 讀取 ROM 位的其余部分,并在需要時與 ROM2 設備通信。這樣就完成了第三次ROM搜索,主設備現在已經識別了ROM2從設備。
總線主站通過重復步驟 13 到 15 開始第四次也是最后一次 ROM 搜索。
總線主站將 1 寫入總線(而不是步驟 0 中所做的 16),這會解耦 ROM2,只留下 ROM3 連接到總線。
總線主站從 ROM3 讀取 ROM 位的其余部分,并在需要時與 ROM3 設備通信。這樣就完成了第四次ROM搜索傳遞,在此期間,主設備識別了ROM3設備。此時,主站已經識別了總線上的所有從設備,從這一點開始,總線主站可以使用其ROM代碼單獨尋址任何設備。
注意:總線主控在每次ROM搜索過程中學習一個1-Wire器件的唯一ROM代碼。學習一個ROM代碼所需的時間是:
960μs + (8 + 3 × 64) 61μs = 13.16m
因此,總線主站每秒能夠識別75個不同的1-Wire從器件。
搜索 ROM 代碼示例
如下面的原型功能所示,“查找器件”功能以1-Wire復位開始,以確定網絡上是否有任何器件,如果有,則喚醒它們。然后調用“First”函數,以跟蹤差異位并返回“Next”,該函數在網絡上找到每個唯一的設備。
“Next”功能非常廣泛,并且大部分工作都是為網絡上的每個設備查找每個唯一的64位ROM代碼標識符。
// FIND DEVICES void FindDevices(void) { unsigned char m; if(!ow_reset()) //Begins when a presence is detected { if(First()) //Begins when at least one part is found { numROMs=0; do { numROMs++; for(m=0;m<8;m++) { FoundROM[numROMs][m]=ROM[m]; //Identifies ROM \\number on found device } printf("\nROM CODE =%02X%02X%02X%02X\n", FoundROM[5][7],FoundROM[5][6],FoundROM[5][5],FoundROM[5][4], FoundROM[5][3],FoundROM[5][2],FoundROM[5][1],FoundROM[5][0]); }while (Next()&&(numROMs<10)); //Continues until no additional devices are found } } }// FIRST // The First function resets the current state of a ROM search and calls // Next to find the first device on the 1-Wire bus. // unsigned char First(void) { lastDiscrep = 0; // reset the rom search last discrepancy global doneFlag = FALSE; return Next(); // call Next and return its return value }// NEXT // The Next function searches for the next device on the 1-Wire bus. If // there are no more devices on the 1-Wire then false is returned. // unsigned char Next(void) { unsigned char m = 1; // ROM Bit index unsigned char n = 0; // ROM Byte index unsigned char k = 1; // bit mask unsigned char x = 0; unsigned char discrepMarker = 0; // discrepancy marker unsigned char g; // Output bit unsigned char nxt; // return value int flag; nxt = FALSE; // set the next flag to false dowcrc = 0; // reset the dowcrc flag = ow_reset(); // reset the 1-Wire if(flag||doneFlag) // no parts -> return false { lastDiscrep = 0; // reset the search return FALSE; } write_byte(0xF0); // send SearchROM command do // for all eight bytes { x = 0; if(read_bit()==1) x = 2; delay(6); if(read_bit()==1) x |= 1; // and its complement if(x ==3) // there are no devices on the 1-Wire break; else { if(x>0) // all devices coupled have 0 or 1 g = x>>1; // bit write value for search else { // if this discrepancy is before the last // discrepancy on a previous Next then pick // the same as last time if(m0); else // if equal to last pick 1 g = (m==lastDiscrep); // if not then pick 0 // if 0 was picked then record // position with mask k if (g==0) discrepMarker = m; } if(g==1) // isolate bit in ROM[n] with mask k ROM[n] |= k; else ROM[n] &= ~k; write_bit(g); // ROM search write m++; // increment bit counter m k = k<<1; // and shift the bit mask k if(k==0) // if the mask is 0 then go to new ROM { // byte n and reset mask ow_crc(ROM[n]); // accumulate the CRC n++; k++; } } }while(n<8); //loop until through all ROM bytes 0-7 if(m<65||dowcrc) // if search was unsuccessful then lastDiscrep=0; // reset the last discrepancy to 0 else { // search was successful, so set lastDiscrep, // lastOne, nxt lastDiscrep = discrepMarker; doneFlag = (lastDiscrep==0); nxt = TRUE; // indicates search is not complete yet, more // parts remain } return nxt; } 執行循環冗余校驗
循環冗余校驗(CRC)可以使用下面顯示的功能完成,在執行搜索ROM功能時應包括循環冗余校驗。
////////////////////////////////////////////////////////////////////////////// // ONE WIRE CRC // unsigned char ow_crc( unsigned char x) { dowcrc = dscrc_table[dowcrc^x]; return dowcrc; }#define FALSE 0 #define TRUE 1 //////////////////////////////////////////////////////////////////////////// // GLOBAL VARIABLES // unsigned char ROM[8]; // ROM Bit unsigned char lastDiscrep = 0; // last discrepancy unsigned char doneFlag = 0; // Done flag unsigned char FoundROM[5][8]; // table of found ROM codes unsigned char numROMs; unsigned char dowcrc; unsigned char code 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};讀取設備溫度
如果網絡上只有一個設備,則可以直接使用“讀取溫度”功能,如下所示。但是,如果網絡上有多個設備,為了避免數據沖突,必須使用“匹配ROM”功能來選擇特定的設備。
下面的代碼示例是專門為DS18S20溫度傳感器編寫的。當此代碼與DS18B20或DS1822配合使用時,由于溫度寄存器格式的差異,必須稍作修改。有關溫度寄存器格式信息,請參閱相應的數據表。
void Read_Temperature(void) { char get[10]; char temp_lsb,temp_msb; int k; char temp_f,temp_c; ow_reset(); write_byte(0xCC); //Skip ROM write_byte(0x44); // Start Conversion delay(5); ow_reset(); write_byte(0xCC); // Skip ROM write_byte(0xBE); // Read Scratch Pad for (k=0;k<9;k++){get[k]=read_byte();} printf("\n ScratchPAD DATA = %X%X%X%X%X\n",get[8],get[7],get[6],get[5],get[4],get[3],get[2],get[1],get[0]); temp_msb = get[1]; // Sign byte + lsbit temp_lsb = get[0]; // Temp data plus lsb if (temp_msb <= 0x80){temp_lsb = (temp_lsb/2);} // shift to get whole degree temp_msb = temp_msb & 0x80; // mask all but the sign bit if (temp_msb >= 0x80) {temp_lsb = (~temp_lsb)+1;} // twos complement if (temp_msb >= 0x80) {temp_lsb = (temp_lsb/2);}// shift to get whole degree if (temp_msb >= 0x80) {temp_lsb = ((-1)*temp_lsb);} // add sign bit printf( "\nTempC= %d degrees C\n", (int)temp_lsb ); // print temp. C temp_c = temp_lsb; // ready for conversion to Fahrenheit temp_f = (((int)temp_c)* 9)/5 + 32; printf( "\nTempF= %d degrees F\n", (int)temp_f ); // print temp. F }讀取暫存器內存
暫存盤存儲器為用戶提供所有必要的設備數據,包括溫度、TH 和 TL 可編程溫度計設置,以及分數溫度測量中使用的計數剩余和每 C 計數數據。CRC字節也包含在暫存器存儲器中。
void Read_ScratchPad(void) { int j; char pad[10]; printf("\nReading ScratchPad Data\n"); write_byte(0xBE); for (j=0;j<9;j++){pad[j]=read_byte();} printf("\n ScratchPAD DATA = %X%X%X%X%X%X\n",pad[8],pad[7],pad[6],pad[5],pad[4],pad[3],pad[2],pad[1],pad[0]); }“讀取ROM”命令用于在網絡上只有一個設備時查找64位ROM代碼。多個設備需要使用“搜索ROM”功能。
void Read_ROMCode(void) { int n; char dat[9]; printf("\nReading ROM Code\n"); ow_reset(); write_byte(0x33); for (n=0;n<8;n++){dat[n]=read_byte();} printf("\n ROM Code = %X%X%X%X\n",dat[7],dat[6],dat[5],dat[4],dat[3],dat[2],dat[1],dat[0]); }“匹配ROM”功能必須提供64位ROM-ID才能選擇網絡上的單個設備。
// Perform Match ROM // unsigned char Send_MatchRom(void) { unsigned char i; if(ow_reset()) return false; write_byte(0x55); // match ROM for(i=0;i<8;i++) { write_byte(FoundROM[numROMs][i]); //send ROM code } return true; }審核編輯:郭婷
-
微控制器
+關注
關注
48文章
7645瀏覽量
151857 -
溫度傳感器
+關注
關注
48文章
2972瀏覽量
156284 -
asic
+關注
關注
34文章
1206瀏覽量
120644
發布評論請先 登錄
相關推薦
評論