天天看點

1-Wire搜尋算法詳解(3)

原文連接配接:http://blog.sina.com.cn/s/blog_57ad1bd20102uxxw.html

1-Wire搜尋算法詳解(3)

#include
 #include sbitDQ=P0^7;  //1-wire總線
 sbitK1=P0^6;  //标志變量,用于觀察進出某段代碼所用時間
 sbit P_Read=P0^5; //
 sbit P_Write=P0^4; //// definitions
 #define FALSE 0
 #define TRUE //幾個延時函數,供一線低級操作時調用
 //如果改用不同的MPU,如12T,則必須修改這幾個函數,確定時間符合協定要求
 voidDelay480us();  //@12.000MHz
 voidDelay410us();  //@12.000MHz
 void Delay3_88us(unsigned char i);//一線低級操作函數
 bit  OWReset();      //複位
 void OWWriteBit(bitbit_value);  //寫一位
 bit OWReadBit();     //讀一位
 void OWWriteByte(unsigned charbyte_value); //寫一個位元組
 ////搜尋函數
 bit OWSearch();  //算法核心函數,完成一次ROM搜尋過程
 bit OWFirst();   //調用OWSearch完成第一次搜尋
 bit OWNext();   //調用OWSearch完成下一次搜尋
 unsigned char docrc8(unsigned charvalue); //執行CRC校驗//全局搜尋變量
 unsigned char ROM_NO[8]; //數組,存放本次搜尋到的ROM碼(8個位元組)
 charLastDiscrepancy;  //每輪搜尋後指向最後一個走0的差異位
 charLastFamilyDiscrepancy; //指向家族碼(前8位)中最後一個走0的差異位
 bitLastDeviceFlag;   //搜到最後一個ROM後,程式通過判别将該變量置1,下輪搜尋時即會結束退出
 unsigned char crc8;   //CRC校驗變量
   //--------------------------------------------------------------------------
 //   在單總線上搜尋第一個器件
 // 傳回TRUE: 找到, 存入ROM_NO緩沖;FALSE:無裝置
 // 先将初始化3個變量,然後調用OWSearch算法進行搜尋
 //--------------------------------------------------------------------------
 bit OWFirst()
 {
    LastDiscrepancy = 0;
    LastDeviceFlag = FALSE;
    LastFamilyDiscrepancy =0;
    return OWSearch();
 }//--------------------------------------------------------------------------
 //   在單總線上搜尋下一個器件
 // 傳回TRUE: 找到, 存入ROM_NO緩沖;FALSE:無裝置,結束搜尋
 // 在前一輪搜尋的基礎上(3個變量均在前一輪搜尋中有明确的值),再執行一輪搜尋
 //--------------------------------------------------------------------------
 bit OWNext()
 {
    return OWSearch();
 }      
//--------------------------------------------------------------------------
 //    單總線搜尋算法,利用了一些狀态變量,這是算法的核心程式,代碼也較長
 //    傳回TRUE: 找到, 存入ROM_NO緩沖;FALSE:無裝置,結束搜尋
 //--------------------------------------------------------------------------bit OWSearch()
 {
    charid_bit_number;    //訓示目前搜尋ROM位(取值範圍為1-64)
     //下面三個狀态變量含義:
   //last_zero:  指針,記錄一次搜尋(ROM1-64位)最後一位往0走的混碼點編号
   //search_direction:搜尋某一位時選擇的搜尋方向(0或1),也是“一寫”的bit位值
   //rom_byte_number: ROM位元組序号,作為ROM_no[]數組的下标,取值為1—8
     bit id_bit,cmp_id_bit,search_direction; //二讀(正碼、反碼)、及一寫(決定二叉搜尋方向)
    unsigned char rom_byte_mask; //ROM位元組掩碼,  //初始化本次搜尋變量
    id_bit_number = 1;
    last_zero = 0;
    rom_byte_number = 0;
    rom_byte_mask = 1;
    search_result = 0;
   //------------------------------------------------------------------
 //1。是否搜尋完成(已到最後一個裝置)?
 //-------------------------------------------------------------------
    if(!LastDeviceFlag)  //LastDeviceFlag由上輪搜尋确定是否為最後器件,當然首次進入前必須置False
    {
      if(OWReset())    //複位總線
      {
         LastDiscrepancy =0;  //複位幾個搜尋變量
         LastDeviceFlag = FALSE;
         LastFamilyDiscrepancy = 0;
         returnFALSE;    //如果無應答,傳回F,退出本輪搜尋程式
      }    OWWriteByte(0xF0);   //發送ROM搜尋指令F0H
   //=====================================================================
 // 開始循環處理1-64位ROM,每位必須進行“二讀”後進行判斷,确定搜尋路徑
 // 然後按標明的路徑進行“一寫”,直至完成全部位的搜尋,這樣一次循環
 // 可以完成一輪搜尋,找到其中一個ROM碼。
 //=====================================================================
      do        //逐位讀寫搜尋,1-64位循環
      {
         id_bit =OWReadBit();   //二讀:先讀正碼、再讀反碼
         cmp_id_bit = OWReadBit();       if (id_bit  &&cmp_id_bit)  //二讀11,則無器件退出程式
            break;
         else       //二讀不為11,則需分二種情況
         {
            //*********************************************
    //第一種情況:01或10,直接可明确搜尋方向
            if (id_bit != cmp_id_bit)
               search_direction = id_bit;   //*********************************************
            else
            {
               // 否則就是第二種情況:遇到了混碼點,需分三種可能分析:
               // 1。目前位未到達上輪搜尋的“最末走0混碼點”(由LastDiscrepancy存儲)
      //   說明目前經曆的是一個老的混碼點,判别特征為目前位在(小于)LastDiscrepancy前
      //   不管上次走的是0還是1,隻需按上次走的路即可,該值需從ROM_NO中的目前位擷取
               if (id_bit_number < LastDiscrepancy)
                  search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask)> 0);
      // 從
               
      else
               // 2。目前位正好為上輪标記的最末的混碼點,這個混碼點也就是上次走0的點
      //   那麼這次就需要走1
      // 3。除去上二種可能,那就是第3種可能: 這是一個新的混碼點,
      //   id_bit_number>LastDiscrepancy
      //。。然而下一條語句巧妙地将上二種可能合在一起處理,看不懂我也沒辦法了
                  search_direction = (id_bit_number == LastDiscrepancy);
    
    //************************************************          // 确定了混碼點的路徑方向還沒完事,還需要更新一個指針:last_zero
    //這個指針每搜尋完一位後(注意是一bit不是一輪)總是指向新的混碼點
    //凡遇到新的混碼點,我們按算法都是先走0,是以凡遇走0的混碼點必須更新此指針
               if (search_direction == 0)
               {
                  last_zero = id_bit_number;                // 下面二條是程式的進階功能了:64位ROM中的前8位是器件的家族代碼,
      // 用LastFamilyDiscrepancy這個指針來記錄前8位ROM中的最末一個混碼點
      // 可用于在多類型器件的單線網絡中對家族分組進行操作
                  if (last_zero < 9)
                     LastFamilyDiscrepancy = last_zero;
               }
            }          // 确定了要搜尋的方向search_direction,該值即ROM中目前位的值,需要寫入ROM
            // 然而64位ROM需分8個位元組存入ROM_NO[],程式使用了一個掩碼位元組rom_byte_mask
    //以最低位為例:該位元組值為00000001,如記錄1則二位元組或,寫0則與反掩碼
            if (search_direction == 1)
               ROM_NO[rom_byte_number] |= rom_byte_mask;
            else
               ROM_NO[rom_byte_number] &=~rom_byte_mask;          // 關鍵的一步操作終于到來了:一寫
            OWWriteBit(search_direction);          // 一個位的操作終于完成,但還需做些工作,以準備下一位的操作:
            // 包括:位變量id_bit_number指向下一位;位元組掩碼左移一位
            id_bit_number++;
            rom_byte_mask <<= 1;          // 如果夠8位一位元組了,則對該位元組計算CRC處理、更新位元組号變量、重設掩碼
            if (rom_byte_mask == 0)
            {
                docrc8(ROM_NO[rom_byte_number]);  //CRC計算原理參考其他文章
                rom_byte_number++;
                rom_byte_mask = 1;
            }
         }
      }
      while(rom_byte_number < 8);  // ROM bytes編号為0-7
   //流程圖中描述從1到64的位循環,本代碼中是利用rom_byte_number<8來判斷的
   //=================================================================================
  
      // 一輪搜尋成功,找到的一個ROM碼也校驗OK,則還要處理二個變量
      if (!((id_bit_number < 65) || (crc8 != 0)))
      {
         // 一輪搜尋結束後,變量last_zero指向了本輪中最後一個走0的混碼位
    //然後再把此變量儲存在LastDiscrepancy中,用于下一輪的判斷
    //當然,last_zero在下輪初始為0,搜尋是該變量是不斷變動的
        LastDiscrepancy = last_zero;       // 如果這個指針為0,說明全部搜尋結束,再也沒有新ROM号器件了
         if (LastDiscrepancy == 0)
            LastDeviceFlag = TRUE;  //設定結束标志
         
         search_result =TRUE;  //傳回搜尋成功
      }
   //------------------------------------------------------------------
 //搜尋完成,如果搜尋不成功包括搜尋到了但CRC錯誤,複位狀态變量到首次搜尋的狀态。
 //-------------------------------------------------------------------
    if (!search_result ||!ROM_NO[0])
    {
      LastDiscrepancy = 0;
      LastDeviceFlag = FALSE;
      LastFamilyDiscrepancy = 0;
      search_result = FALSE;
    }
    return search_result;
 }//=====================================================================
   至此,OWSearch函數結束。函數實作的是一輪搜尋,如成功,可得到一個ROM碼
 //=======================================================================
 //=====================================================================
 // 1-Wire函數調用所需的延時函數,注意不同MCU下須重調參數
 //=====================================================================voidDelay480us()  //@12.000MHz
 {
  unsigned char i, j;
  i = 2;
  j = 90;
  do
  {
   while (--j);
  } while (--i);
 }voidDelay410us()  //@12.000MHz
 {
  unsigned char i, j;
  i = 2;
  j = 40;
  do
  {
   while (--j);
  } while (--i);
 } void Delay3_88us(unsigned chari)  //@12.000MHz 隻能3-80us
 {
  //i*=3;
  i-=1;
  while (--i);
 }
    //=====================================================================
 //  一線函數:複位、讀一位、寫一位、寫一位元組
 //=====================================================================
 bit OWReset()
 {
        bit result;
   unsigned char i;
        DQ=0;    //拉低總線啟動複位信号
        Delay480us();  
        DQ=1;    //Releases the bus
   i=53;   //延時70us
   while(--i);
        result = DQ;  // 采樣總線上從機存在信号
        Delay410us();  //
        return result;  //
 }//-----------------------------------------------------------------------------
 void OWWriteBit(bitdat)  //寫一位函數
  //
 {
   unsigned char i;
   P_Write=1;    //寫函數執行的标志變量,用于調試
        if(dat)    //寫1
        {
                DQ=0;    //Drives DQ low
                i=4;    //延時6us
 u
     while(--i);
                DQ=1;    //釋放總線
                i=38;    //延時54us,不要看i的值,實測為54us
     while(--i);  //
        }
        else     //寫0
        {
                DQ=0;   //
     i=35;    // 延時60
     while(--i);
                DQ=1;    //釋放總線
     i=7;   //延時10
     while(--i);
        }
   P_Write=0;
 }//-----------------------------------------------------------------------------
 bitOWReadBit()     //讀一位
 {
        bit result;
   unsigned char i;
     P_Read=1;    //時間隙6+9+55
        DQ=0;     //Drives DQ low
        i=8;   //6
   while(--i);
        DQ=1;     //釋放
        i=6;   //9
   while(--i);
        result = DQ;   // 取樣總線
        i=32;   //45
   while(--i);    //
    P_Read=0;
        return result;
 }//-----------------------------------------------------------------------------
 void OWWriteByte(unsigned char dat) //寫一位元組
 {
        char loop;
        for (loop = 0; loop < 8; loop++) //低位先傳
        {
                OWWriteBit(dat & 0x01);
                dat >>= 1;    //右移
         }
 }//-----------------------------------------------------------------------------
 charOWReadByte(void)  //讀一位元組,本例中并未用到
 {
        char loop, result=0;
        for (loop = 0; loop < 8; loop++)
        {
          result >>= 1;
            if (OWReadBit())
             result |= 0x80;
        }
        return result;
 }//  CRC計算用表
 static unsigned char 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};
   //--------------------------------------------------------------------------
 //疊代計算CRC,傳回目前CRC值
 unsigned char docrc8(unsigned char value)
 {
    // 詳見應用筆記AN27
    crc8 = dscrc_table[crc8 ^value];   //^表示按位異或
    return crc8;
 }//主函數,
 void main()
 {
    bit rslt;
   K1=0;   //這三個位用于觀察“二讀一寫”
    P_Read=0;
     rslt =OWFirst();  //搜尋第一個ROM
    while(rslt)   //如果搜尋成功,繼續搜尋下一個
    {
      rslt = OWNext();
    }
    while(1);
 }