- uint8_t OWSearch(void)
- {
- uint8_t id_bit_number; //指示当前搜索ROM位(取值范围为1-64)
- /*下面三个状态变量含义:last_zero:指针,记录一次搜索(ROM1-64位)最后一位往0走的混码点编号
- search_direction:搜索某一位时选择的搜索方向(0或1),也是“一写”的bit位值
- rom_byte_number:ROM字节序号,作为ROM_no[]数组的下标,取值为1—8
- */
- uint8_t last_zero, rom_byte_number, search_result;
- uint8_t id_bit, cmp_id_bit,search_direction; //二读(正码、反码)、及一写(决定二叉搜索方向)
- uint8_t rom_byte_mask ; //ROM字节掩码
- //初始化本次搜索变量
- id_bit_number = 1;
- last_zero = 0;
- rom_byte_number = 0;
- rom_byte_mask = 1;
- search_result = 0;
- crc8 = 0;
- /*
- 是否搜索完成(已到最后一个设备)?
- */
- if(!LastDeviceFlag) //LastDeviceFlag由上轮搜索确定是否为最后器件,当然首次进入前必须置FALSE
- {
- DS18B20_Rst();
- //if(OWReset()) //复位总线
- if(DS18B20_Check())
- {
- LastDiscrepancy = 0; //复位几个搜索变量
- LastDeviceFlag = FALSE;
- LastFamilyDiscrepancy = 0;
- return FALSE; //如果无应答,返回FALSE,退出本轮搜索程序
- }
- DS18B20_Write_Byte(0xF0); //发送ROM搜索命令F0H
- __delay_us(60);
- /*
- 开始循环处理1-64位ROM,每位必须进行“二读”后进行判断,确定搜索路径
- 然后按选定的路径进行“一写”,直至完成全部位的搜索,这样一次循环
- 可以完成一轮搜索,找到其中一个ROM码
- */
- do //逐位读写搜索,1-64位循环
- {
- id_bit = DS18B20_Read_Bit(); //二读:先读正码、再读反码
- cmp_id_bit = DS18B20_Read_Bit();
- if(id_bit && cmp_id_bit) //二读11,则无器件退出程序
- break;
- else //二读不为11,则需分二种情况
- {
- /*
- 第一种情况:01或10,直接可明确搜索方向
- */
- if(id_bit != cmp_id_bit)
- search_direction = id_bit; //记下搜索方向search_direction的值待“一写”
- 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;
- //关键的一步操作终于到来了:一写
- DS18B20_Write_Bit(search_direction);
- /*
- 一个位的操作终于完成,但还需做些工作,以准备下一位的操作:
- 包括:位变量id_bit_number指向下一位,字节掩码左移一位
- */
- id_bit_number++;
- rom_byte_mask <<= 1;
- //如果够8位一字节了,则对该字节计算CRC处理,更新字节号变量,重设掩码
- if(rom_byte_mask == 0)
- {
- GenerateCRC8(ROM_NO[rom_byte_number]); //CRC计算
- rom_byte_number++;
- rom_byte_mask = 1;
- }
- }
- }
- while(rom_byte_number < 8); //ROM bytes编号为 0-7
- //代码中是利用rom_byte_number<8来判断的,至此,完成8个字节共64位的循环处理
-
- //一轮搜索成功,找到的一个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;
- }
④、实现效果:
测试代码: