本應(yīng)用向用戶介紹簡單的1-Wire軟件,用于將微控制器連接至DS18B20、DS18S20和DS1822 1-Wire溫度傳感器。本文舉例使用DS5000(兼容8051)微控制器。給出了軟件示例,說明了延遲、復(fù)位、讀位、寫位、讀字節(jié)、寫字節(jié)、ROM搜索、CRC、讀溫度和讀暫存本例程的實(shí)現(xiàn)。
介紹
DS1B18、DS20S18或DS20等1822-Wire器件與微控制器的接口有多種方法可供選擇。這些方法包括簡單的軟件解決方案,使用串行接口芯片(如DS2480B),以及將Maxim的VHDL 1-Wire主控制器集成到定制ASIC中。本文向用戶介紹最簡單的軟件方案,用于微控制器與任意數(shù)量的DS1x18或DS20溫度傳感器之間的基本1822-Wire通信。
DS18B20、DS18S20和DS1822的詳細(xì)時(shí)序和工作原理信息可在各自的數(shù)據(jù)資料中找到,可從Maxim網(wǎng)站獲取。
硬件配置
圖1中的框圖說明了使用多個(gè)1-Wire溫度傳感器時(shí)硬件配置的簡單性。單線總線為所有設(shè)備提供通信訪問和電源??偩€電源通過 4.7kΩ 上拉電阻從 3V 至 5.5V 電源軌提供??偩€上可以連接幾乎無限數(shù)量的1-Wire器件,因?yàn)槊總€(gè)器件都有一個(gè)唯一的64位ROM碼標(biāo)識符。
圖1.主機(jī)微控制器接口。
接口時(shí)序
與DS18x20/DS1822的通信通過使用“時(shí)隙”實(shí)現(xiàn),允許數(shù)據(jù)通過1-Wire總線傳輸。每個(gè)通信周期從微控制器的復(fù)位脈沖開始,然后是來自DS18x20/DS1822的存在脈沖,如圖2所示。
當(dāng)總線主控將1-Wire總線從邏輯高電平(非活動)拉至邏輯低電平時(shí),將啟動寫入時(shí)隙。所有寫入時(shí)隙的持續(xù)時(shí)間必須為60μs至120μs,周期之間的最小恢復(fù)時(shí)間為1μs。寫“0”和寫“1”時(shí)隙如圖3所示。在寫入“0”時(shí)隙期間,主機(jī)微控制器在該時(shí)隙的持續(xù)時(shí)間內(nèi)將線路拉低。但是,在寫入“1”時(shí)隙期間,微控制器將線路拉低,然后在時(shí)隙開始后15μs內(nèi)釋放線路。
當(dāng)微控制器將總線拉低1μs,然后釋放時(shí)隙時(shí)啟動,DS18x20/DS1822可以控制線路并提供有效數(shù)據(jù)(高電平或低電平)。所有讀取時(shí)隙的持續(xù)時(shí)間必須為60μs至120μs,周期之間的恢復(fù)時(shí)間至少為1μs(見圖3)。
圖2.復(fù)位脈沖和存在脈沖。
圖3.寫入和讀取時(shí)間段。
軟件控制
為了精確控制1-Wire接口的特殊定時(shí)要求,必須首先建立某些關(guān)鍵功能。創(chuàng)建的第一個(gè)函數(shù)必須是“延遲”函數(shù),它是所有讀寫控制的組成部分。此功能完全取決于微控制器的速度。本文使用DS5000(兼容8051)微控制器,其工作頻率為11.059MHz。右邊的示例說明了用于創(chuàng)建時(shí)序延遲的“C”原型函數(shù)。
延遲示例
// 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由于每個(gè)通信周期都必須從微控制器的復(fù)位開始,因此“復(fù)位”功能是要實(shí)現(xiàn)的下一個(gè)最重要的功能。復(fù)位時(shí)隙為 480μs。通過將延遲設(shè)置為“3”,后跟“25”(見下面的示例),復(fù)位脈沖將持續(xù)所需的持續(xù)時(shí)間。復(fù)位后,微控制器必須松開,以便DS18x20/DS1822能夠通過拉低線路來指示其“存在”。請注意,如果總線上有多個(gè)溫度傳感器,它們將同時(shí)響應(yīng)存在脈沖。
重置示例
////////////////////////////////////////////////////////////////////////////// // 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以下四個(gè)示例中顯示的讀寫函數(shù)代碼段提供了所有數(shù)據(jù)位和數(shù)據(jù)字節(jié)讀寫操作所需的基本結(jié)構(gòu)。
讀取位示例
////////////////////////////////////////////////////////////////////////////// // 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讀取字節(jié)示例
////////////////////////////////////////////////////////////////////////////// // 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<寫入字節(jié)示例
////////////////////////////////////////////////////////////////////////////// // 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網(wǎng)絡(luò)概念,微控制器必須能夠與連接到網(wǎng)絡(luò)的任意數(shù)量的器件進(jìn)行通信。為此,微控制器必須使用圖64所示的“Search ROM”算法學(xué)習(xí)總線上每個(gè)器件的唯一4位ROM識別碼。圖 4 以下示例解釋了具有四個(gè)從設(shè)備的總線的搜索 ROM 例程。還顯示了搜索 ROM 例程的示例代碼。一旦識別出所有ROM代碼,“匹配ROM”命令可用于與網(wǎng)絡(luò)上的任何特定設(shè)備進(jìn)行通信。
圖4.搜索 ROM 算法。
ROM 搜索示例
在ROM搜索過程中,總線主站必須重復(fù)一個(gè)簡單的三步例程:1)從從設(shè)備讀取ROM碼位,2)讀取位的補(bǔ)碼,3)寫入該位的選定值??偩€主機(jī)必須執(zhí)行此三步例程 64 次,每個(gè) ROM 代碼位執(zhí)行一次。完成一次通過后,總線主站將知道總線上一個(gè)從設(shè)備的ROM代碼。其余設(shè)備及其ROM代碼可以通過額外的通道來識別。
以下示例說明了ROM搜索過程,該示例假設(shè)四個(gè)不同的器件連接到同一1-Wire總線。四個(gè)設(shè)備的ROM代碼如下所示:
ROM1 00110101...
ROM2 10101010...
ROM3 11110101...
ROM4 00010001...搜索過程如下:
總線主站通過發(fā)出復(fù)位脈沖來開始初始化序列。從設(shè)備響應(yīng)方式 同時(shí)發(fā)出存在脈沖。
然后,總線主控器在1-Wire總線上發(fā)出搜索ROM命令。
每個(gè)器件將響應(yīng)搜索ROM命令,將各自ROM碼的第一位值放到1-Wire總線上。然后,主站將讀取總線值。在這種情況下,ROM1和ROM4將在0-Wire總線上放置一個(gè)1,即它們將其拉低。ROM2和ROM3將在1-Wire總線上放置一個(gè)1,允許線路保持高電平。結(jié)果是線路上所有設(shè)備的邏輯 AND;因此,總線主站將讀取 0。1-Wire總線上的所有器件都將響應(yīng)此讀取,方法是將其ROM碼的第一位補(bǔ)碼放到1-Wire總線上:ROM1和ROM4在1-Wire總線上放置一個(gè)1,使線路保持高電平,ROM2和ROM3將在總線上放置一個(gè)0。 把它拉低??偩€主控服務(wù)器現(xiàn)在將再次讀取總線,并將再次讀取 0。
根據(jù)從設(shè)備ROM代碼,總線主站可以從兩次讀取中獲得四種可能的數(shù)據(jù)組合。這些組合可以解釋如下:
00 有些連接到總線的設(shè)備在當(dāng)前ROM代碼位位置具有沖突位。 01 連接到總線的所有設(shè)備在此位位置都有一個(gè) 0。 10 連接到總線的所有設(shè)備在此位位置都有一個(gè) 1。 11 沒有器件連接到1-Wire總線。
在本例中,總線主控器在每次讀取時(shí)都讀取0,這告訴它1-Wire總線上有一些器件在第一個(gè)ROM代碼位置為0,而其他器件則為1。
為了響應(yīng)前面的數(shù)據(jù),總線主控服務(wù)器將 0 寫入總線。這將取消選擇此搜索通道其余部分的ROM2和ROM3,僅保留ROM1和ROM4“連接”到1-Wire總線。
總線主站再執(zhí)行兩次讀取,并收到 0,后跟 1。這表示仍連接到總線的所有設(shè)備都將 0 作為其第二個(gè) ROM 數(shù)據(jù)位。
然后,總線主站寫入 0 以保持 ROM1 和 ROM4 連接到總線。
總線主站再次執(zhí)行兩次讀取并接收兩個(gè) 0。這向主機(jī)表明,1-Wire總線上的一個(gè)器件在第三個(gè)ROM碼位置為0,另一個(gè)器件為1。
總線主站將 0 寫入總線,總線取消選擇 ROM1,并將 ROM4 保留為唯一仍連接的設(shè)備。
總線主站從 ROM4 讀取 ROM 位的其余部分,并根據(jù)需要繼續(xù)訪問 ROM4 設(shè)備。這樣就完成了第一個(gè) ROM 搜索傳遞;總線主站現(xiàn)在通過學(xué)習(xí)4-Wire總線上的ROM碼,唯一地識別了1-Wire總線上的一個(gè)從機(jī)(ROM<>)。
總線主站通過重復(fù)步驟 1 到 7 來啟動新的 ROM 搜索序列。
總線主站現(xiàn)在將 1 寫入總線(而不是步驟 0 中所做的 8)。這會解耦 ROM4,只留下 ROM1 仍處于連接狀態(tài)。
總線主站現(xiàn)在從ROM1讀取ROM位的其余部分,并可以根據(jù)需要與ROM1設(shè)備通信。這樣就完成了第二個(gè)ROM搜索過程,主設(shè)備現(xiàn)在已經(jīng)識別了另一個(gè)從設(shè)備(ROM1)。
總線主站通過重復(fù)步驟 1 到 3 開始新的 ROM 搜索。
總線主控服務(wù)器現(xiàn)在將 1 寫入總線(而不是步驟 0 中所做的 4)。這將取消選擇此搜索傳遞的其余部分的 ROM1 和 ROM4,只留下耦合到總線的 ROM2 和 ROM3。
總線主站執(zhí)行兩次讀取并接收兩個(gè) 0。
總線主站將 0 寫入總線,使 ROM3 去耦,只留下 ROM2 連接到總線。
總線主站從 ROM2 讀取 ROM 位的其余部分,并在需要時(shí)與 ROM2 設(shè)備通信。這樣就完成了第三次ROM搜索,主設(shè)備現(xiàn)在已經(jīng)識別了ROM2從設(shè)備。
總線主站通過重復(fù)步驟 13 到 15 開始第四次也是最后一次 ROM 搜索。
總線主站將 1 寫入總線(而不是步驟 0 中所做的 16),這會解耦 ROM2,只留下 ROM3 連接到總線。
總線主站從 ROM3 讀取 ROM 位的其余部分,并在需要時(shí)與 ROM3 設(shè)備通信。這樣就完成了第四次ROM搜索傳遞,在此期間,主設(shè)備識別了ROM3設(shè)備。此時(shí),主站已經(jīng)識別了總線上的所有從設(shè)備,從這一點(diǎn)開始,總線主站可以使用其ROM代碼單獨(dú)尋址任何設(shè)備。
注意:總線主控在每次ROM搜索過程中學(xué)習(xí)一個(gè)1-Wire器件的唯一ROM代碼。學(xué)習(xí)一個(gè)ROM代碼所需的時(shí)間是:
960μs + (8 + 3 × 64) 61μs = 13.16m
因此,總線主站每秒能夠識別75個(gè)不同的1-Wire從器件。
搜索 ROM 代碼示例
如下面的原型功能所示,“查找器件”功能以1-Wire復(fù)位開始,以確定網(wǎng)絡(luò)上是否有任何器件,如果有,則喚醒它們。然后調(diào)用“First”函數(shù),以跟蹤差異位并返回“Next”,該函數(shù)在網(wǎng)絡(luò)上找到每個(gè)唯一的設(shè)備。
“Next”功能非常廣泛,并且大部分工作都是為網(wǎng)絡(luò)上的每個(gè)設(shè)備查找每個(gè)唯一的64位ROM代碼標(biāo)識符。
// 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; } 執(zhí)行循環(huán)冗余校驗(yàn)
循環(huán)冗余校驗(yàn)(CRC)可以使用下面顯示的功能完成,在執(zhí)行搜索ROM功能時(shí)應(yīng)包括循環(huán)冗余校驗(yàn)。
////////////////////////////////////////////////////////////////////////////// // 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};讀取設(shè)備溫度
如果網(wǎng)絡(luò)上只有一個(gè)設(shè)備,則可以直接使用“讀取溫度”功能,如下所示。但是,如果網(wǎng)絡(luò)上有多個(gè)設(shè)備,為了避免數(shù)據(jù)沖突,必須使用“匹配ROM”功能來選擇特定的設(shè)備。
下面的代碼示例是專門為DS18S20溫度傳感器編寫的。當(dāng)此代碼與DS18B20或DS1822配合使用時(shí),由于溫度寄存器格式的差異,必須稍作修改。有關(guān)溫度寄存器格式信息,請參閱相應(yīng)的數(shù)據(jù)表。
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 }讀取暫存器內(nèi)存
暫存盤存儲器為用戶提供所有必要的設(shè)備數(shù)據(jù),包括溫度、TH 和 TL 可編程溫度計(jì)設(shè)置,以及分?jǐn)?shù)溫度測量中使用的計(jì)數(shù)剩余和每 C 計(jì)數(shù)數(shù)據(jù)。CRC字節(jié)也包含在暫存器存儲器中。
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”命令用于在網(wǎng)絡(luò)上只有一個(gè)設(shè)備時(shí)查找64位ROM代碼。多個(gè)設(shè)備需要使用“搜索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才能選擇網(wǎng)絡(luò)上的單個(gè)設(shè)備。
// 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; }審核編輯:郭婷
-
微控制器
+關(guān)注
關(guān)注
48文章
7552瀏覽量
151423 -
溫度傳感器
+關(guān)注
關(guān)注
48文章
2940瀏覽量
156074 -
asic
+關(guān)注
關(guān)注
34文章
1200瀏覽量
120504
發(fā)布評論請先 登錄
相關(guān)推薦
評論