新建工程,DS18B20 ROM搜索部分代码使用http://blog.sina.com.cn/s/blog_57ad1bd20102uxxw.html
ds18b20.c代码如下:
//CRC计算用表static uint8_t 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 }; uint8_t ROM_NO[8]; //数组,存放本次搜索到的ROM码(8个字节) uint8_t LastDiscrepancy; //每轮搜索后指向最后一个走0的差异位 uint8_t LastFamilyDiscrepancy; //指向家族码(前8位)中最后一个走0的差异位 uint8_t LastDeviceFlag; //搜到最后一个ROM后,程序通过判别将该变量置1,下轮搜索时即会结束退出 uint8_t crc8; //CRC校验变量 uint8_t ID_Buff[DS18B20_NUM][8]; //将搜索到的ROM存放在二维数组 /* DS18B20 APIs */ //复位DS18B20 void DS18B20_Rst(void) { rt_pin_mode(DS18B20_DQ, PIN_MODE_OUTPUT); //输出模式 rt_pin_write(DS18B20_DQ, PIN_LOW); //拉低DQ rt_hw_us_delay(380); //拉低750us(480~960us) rt_pin_write(DS18B20_DQ, PIN_HIGH); //拉高DQ } //等待DS18B20应答,有应答返回0,无应答返回1 uint8_t DS18B20_Check(void) { uint8_t retry = 0; //进入接收模式,等待应答信号 //等待时间 rt_pin_mode(DS18B20_DQ, PIN_MODE_INPUT); //输入模式 rt_hw_us_delay(15); //等待15~60us while(rt_pin_read(DS18B20_DQ) && retry<30) //最多再等待120us { retry++; rt_hw_us_delay(1); }; if(retry >= 30) return 1; //120us未响应,则判断未检测到 else retry = 0; //DS18B20开始拉低DQ while(!rt_pin_read(DS18B20_DQ) && retry<38) //最长拉低240us { retry++; rt_hw_us_delay(1); }; if(retry >= 38) return 1; return 0; } //写位到DS18B20 void DS18B20_Write_Bit(uint8_t dat) { rt_pin_mode(DS18B20_DQ, PIN_MODE_OUTPUT); //输出模式 if (dat) //输出高 { rt_pin_write(DS18B20_DQ, PIN_LOW); //拉低DQ rt_hw_us_delay(1); //延时2us rt_pin_write(DS18B20_DQ, PIN_HIGH); //拉高DQ rt_hw_us_delay(29); //延时60us } else //输出低 { rt_pin_write(DS18B20_DQ, PIN_LOW); //拉低DQ rt_hw_us_delay(29); //延时60us rt_pin_write(DS18B20_DQ, PIN_HIGH); //拉高DQ rt_hw_us_delay(1); //延时2us } rt_pin_mode(DS18B20_DQ, PIN_MODE_INPUT); //输入模式 } //写字节到DS18B20 void DS18B20_Write_Byte(uint8_t dat) { uint8_t j; uint8_t temp; rt_pin_mode(DS18B20_DQ, PIN_MODE_OUTPUT); //输出模式 for(j=1; j<=8; j++) { temp = dat & 0x01; dat = dat >> 1; if (temp) //输出高 { rt_pin_write(DS18B20_DQ, PIN_LOW); //拉低DQ rt_hw_us_delay(1); //延时2us rt_pin_write(DS18B20_DQ, PIN_HIGH); //拉高DQ rt_hw_us_delay(29); //延时60us } else //输出低 { rt_pin_write(DS18B20_DQ, PIN_LOW); //拉低DQ rt_hw_us_delay(29); //延时60us rt_pin_write(DS18B20_DQ, PIN_HIGH); //拉高DQ rt_hw_us_delay(1); //延时2us } } rt_pin_mode(DS18B20_DQ, PIN_MODE_INPUT); //输入模式 } //从DS18B20读位 uint8_t DS18B20_Read_Bit(void) { uint8_t data; rt_pin_mode(DS18B20_DQ, PIN_MODE_OUTPUT); //输出模式 rt_pin_write(DS18B20_DQ, PIN_LOW); //拉低DQ rt_hw_us_delay(1); //延时2us rt_pin_write(DS18B20_DQ, PIN_HIGH); //拉高DQ rt_pin_mode(DS18B20_DQ, PIN_MODE_INPUT); //输入模式 rt_hw_us_delay(2); //延时12us if(rt_pin_read(DS18B20_DQ)) //读DQ数据 data = 1; else data = 0; rt_hw_us_delay(25); //延时50us return data; } //从DS18B20读字节 uint8_t DS18B20_Read_Byte(void) { uint8_t i, j, dat = 0; for(i=1; i<=8; i++) { j = DS18B20_Read_Bit(); dat = (j << 7) | (dat >> 1); } return dat; } //开始温度转换 void DS18B20_Start(void) { DS18B20_Rst(); DS18B20_Check(); DS18B20_Write_Byte(0xcc); DS18B20_Write_Byte(0x44); } //读取温度值 /*搜索到的DS18B20 ROM码存放在DS18B20_NUM*8的二维数组,每行存放一个ROM码,分8字节存放,获取每个DS18B20温度值时,发送二维数组每行字节,进行序列号匹配*/ float DS18B20_Get_Temp(uint8_t pID[8]) { uint8_t i; uint8_t sign; //温度符号,0为-,1为+ uint8_t TL, TH; uint16_t temp; float temp1; DS18B20_Start (); rt_thread_mdelay(800); //等待转换完成 DS18B20_Rst(); DS18B20_Check(); DS18B20_Write_Byte(0x55); //发送序列号匹配命令 for(i=0; i<8; i++) //发送8byte的序列号 { DS18B20_Write_Byte(pID[i]); } rt_hw_us_delay(10); DS18B20_Write_Byte(0xbe); TL = DS18B20_Read_Byte(); TH = DS18B20_Read_Byte(); if(TH > 7) { TH = ~TH; TL = ~TL; sign = 0; //温度为负 } else sign = 1; //温度为正 temp = TH; //高八位 temp <<= 8; temp += TL; //低八位 temp1 = (float)temp * 0.0625; //转换实际温度 if(sign) return temp1; //返回温度值 else return -temp1; } /* * 初始化 */ uint8_t DS18B20_Init(void) { DS18B20_Rst(); return DS18B20_Check(); } /* 生成CRC8校验码 */ uint8_t GenerateCRC8(uint8_t value) { crc8 = dscrc_table[crc8 ^ value]; //^表示按位异或 return crc8; } /* 单总线搜索算法,返回TRUE:找到,存入ROM_NO缓冲;FALSE:无设备,结束搜索 */ 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 rt_hw_us_delay(45); /* 开始循环处理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; } /* 在单总线上搜索第一个器件 返回TRUE:找到,存入ROM_NO缓冲;FALSE:无设备 先将初始化3个变量,然后调用OWSearch算法进行搜索 */ uint8_t OWFirst(void) { LastDiscrepancy = 0; LastDeviceFlag = FALSE; LastFamilyDiscrepancy = 0; return OWSearch(); } /* 在单总线上搜索下一个器件 返回TRUE:找到,存入ROM_NO缓冲;FALSE:无设备,结束搜索 在前一轮搜索的基础上(3个变量均在前一轮搜索中有明确的值),再执行一轮搜索 */ uint8_t OWNext(void) { return OWSearch(); } /* 搜索并返回ROM */ uint8_t DS18B20_SearchROM(void) { uint8_t num = 0, result = 0, i; result = OWFirst(); //搜索第一个ROM if(result) { for(i=0; i<8; i++) ID_Buff[num][i] = ROM_NO[i]; num++; } while(result) //搜索成功,继续搜索下一个 { result = OWNext(); if(result) { for(i=0; i<8; i++) ID_Buff[num][i] = ROM_NO[i]; num++; } } return num; }
复制代码