新建工程,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;
- }