c20160526 发表于 2026-4-27 11:09:43

读取多路18b20

请问那位有读取多路18b20 id程序,自己查资料弄了,读出不出来,也不知那不对


sbit DQ = P7^3;                   //DS18B20的数据口
u8 MinusFlag;       //负数标志,0:正数,1:负数


unsigned char DS18B20_ID;      // 存检测到的传感器DS18B20_ID的数组,前面的维数代表单根线传感器数量上限
unsigned char DS18B20_SensorNum;                        // 检测到的传感器数量(从1开始,例如显示1代表1个,8代表8个)

/**************************************
复位DS18B20,并检测设备是否存在
**************************************/
void DS18B20_Reset()
{
   
      DQ = 0;                     //送出低电平复位信号
      delay_us(480);            //延时至少480us

      DQ = 1;                     //释放数据线

      delay_us(15);

}

/**************************************
从DS18B20读1字节数据
**************************************/
u8 DS18B20_ReadByte()
{
    u8 i;
    u8 dat = 0;

    for (i=0; i<8; i++)             //8位计数器
    {
      dat >>= 1;
      DQ = 0;                     //开始时间片
      delay_us(1);                //延时等待
      DQ = 1;                     //准备接收
      delay_us(1);                //接收延时
      if (DQ) dat |= 0x80;      //读取数据
      delay_us(60);               //等待时间片结束
    }

    return dat;
}

/**************************************
向DS18B20写1字节数据
**************************************/
void DS18B20_WriteByte(u8 dat)
{

      u8 j;
      u8 testb;
      for (j = 1; j <= 8; j++)
      {
                testb = dat & 0x01;
                dat = dat >> 1;
                if (testb)
                {
                        DQ=0;// 写1
                        delay_us(10);
                        DQ=1;
                        delay_us(50);
                }
                else
                {
                        DQ=0;// 写0
                        delay_us(60);
                        DQ=1;// 释放总线
                        delay_us(2);
                }
      }
}

// 检测从机给主机返回的应答脉冲。从机接收到主机的复位信号后,会在15~60us后给主机发一个应答脉冲
u8 DS18B20_Answer_Check(void)
{
      u8 delay=0;

      // 等待应答脉冲(一个60~240us的低电平信号 )的到来
      // 如果100us内,没有应答脉冲,退出函数,注意:从机接收到主机的复位信号后,会在15~60us后给主机发一个存在脉冲
      while (DQ&&delay <100)
      {
                delay++;
                delay_us(1);
      }
      // 经过100us后如果没有应答脉冲;退出函数
      if (delay>=100)//Hu200
                return 1;
      else
                delay=0;
      // 有应答脉冲且存在时间不超过240us
      while (!DQ&&delay<240)
      {
                delay++;
                delay_us(1);
      }
      if (delay>=240)
                return 1;
      return 0;
}

u8 DS18B20_INit()
{
   DS18B20_Reset();
      return DS18B20_Answer_Check();
}
/*void ds18b20_rom()
{
      int j;
         DS18B20_Reset();                //设备复位
    DS18B20_WriteByte(0x33);      //发送读序列号命令      
      
      for(j=0;j<8;j++)
      FAC_DATA_Table.ds18b20_rom_buf=DS18B20_ReadByte();
}*/

// 从DS18B20读取2个位
u8 DS18B20_Read_2Bit(void)//读二位 子程序
{
      u8 i;
      u8 dat = 0;
      for (i = 2; i > 0; i--)
      {
                dat = dat << 1;
                DQ=0;
                delay_us(2);
                DQ=1;
                delay_us(12);
                if (DQ)      dat |= 0x01;
                delay_us(50);
      }
      return dat;
}

// 写1位到DS18B20
void DS18B20_Write_Bit(u8 dat)
{
      DQ=0;
      delay_us(1);
      if(dat & 0x01)DQ=1;
      else DQ=0;
      delay_us(60);
      DQ=1;
      delay_us(1);
}
// 自动搜索ROM
u8 DS18B20_Search_Rom()
{
      u8 k, l, chongtuwei, m, n, num;
      u8 zhan;
      u8 ss;
      u8 tempp;
      l = 0;
      num = 0;
      do
      {
                DS18B20_Reset(); //注意:复位的延时不够
               
                delay_us(480); //480、720
                DS18B20_WriteByte(0xf0);
                for (m = 0; m < 8; m++)
                {
                        u8 s = 0;
                        for (n = 0; n < 8; n++)
                        {
                              k = DS18B20_Read_2Bit();//读两位数据

                              k = k & 0x03;
                              s >>= 1;
                              if (k == 0x01)//01读到的数据为0 写0 此位为0的器件响应
                              {
                                        DS18B20_Write_Bit(0);
                                        ss[(m * 8 + n)] = 0;
                              }
                              else if (k == 0x02)//读到的数据为1 写1 此位为1的器件响应
                              {
                                        s = s | 0x80;
                                        DS18B20_Write_Bit(1);
                                        ss[(m * 8 + n)] = 1;
                              }
                              else if (k == 0x00)//读到的数据为00 有冲突位 判断冲突位
                              {
                                        //如果冲突位大于栈顶写0 小于栈顶写以前数据 等于栈顶写1
                                        chongtuwei = m * 8 + n + 1;
                                        if (chongtuwei > zhan)
                                        {
                                                DS18B20_Write_Bit(0);
                                                ss[(m * 8 + n)] = 0;
                                                zhan[++l] = chongtuwei;
                                        }
                                        else if (chongtuwei < zhan)
                                        {
                                                s = s | ((ss[(m * 8 + n)] & 0x01) << 7);
                                                DS18B20_Write_Bit(ss[(m * 8 + n)]);
                                        }
                                        else if (chongtuwei == zhan)
                                        {
                                                s = s | 0x80;
                                                DS18B20_Write_Bit(1);
                                                ss[(m * 8 + n)] = 1;
                                                l = l - 1;
                                        }
                              }
                              else
                              {
                                        return 5;//没有搜索到
                              }
                        }

                        tempp = s;
                        DS18B20_ID = tempp; // 保存搜索到的ID
                }
                num = num + 1;// 保存搜索到的个数
      } while (zhan != 0 && (num < MaxSensorNum));
      DS18B20_SensorNum=num;
      return num;
}
//========================================================================
// 函数: u16 ReadTemperature()
// 描述: 读取温度函数。
// 参数: none..
// 返回: 温度值.
// 版本: VER1.0
// 日期: 2020-7-30
// 备注:
//========================================================================
float ReadTemperature(u8 chi)
{   u8 i;
    u16 TempH, TempL, Temperature;
    DS18B20_Reset();                //设备复位
      DS18B20_Answer_Check();
    DS18B20_WriteByte(0xcc);      //跳过ROM命令
    DS18B20_WriteByte(0x44);      //开始转换命令
    //while (!DQ);                  //等待转换完成

    DS18B20_Reset();                //设备复位
      DS18B20_Answer_Check();
      
    //DS18B20_WriteByte(0xCC);      //跳过ROM命令
      DS18B20_WriteByte(0x55);      //pi
      for(i=0;i<8;i++)
      DS18B20_WriteByte(FAC_DATA_Table.ds18b20_rom_buf);      //读暂存存储器命令
      
    DS18B20_WriteByte(0xBE);      //读暂存存储器命令
      
    TempL = DS18B20_ReadByte();   //读温度低字节
    TempH = DS18B20_ReadByte();   //读温度高字节
      
    if(TempH & 0xf8)    //判断是否位负数
    {
      MinusFlag = 1;//设置负数标志
      Temperature = (TempH<<8) | TempL;
      Temperature = ~Temperature + 1;
      Temperature *= 0.625 / 100.0f * (float)FAC_DATA_Table.Adjust_s.Temp;       //0.0625 * 10,保留1位小数点
    }
    else
    {
      MinusFlag = 0;//清除负数标志
      Temperature = (((TempH<<8) | TempL) * 0.625); //0.0625 * 10,保留1位小数点
    }
      

    return Temperature;
}



void        main(void)
{   
        u8 i,j;
        IO_INIT();

        EG1163S_OFF=0;
        OFFON=0;
        IRON = 0;//T12控制
        //P5n_push_pull(0x04);        //P5.2 设置为推挽输出
        I2C_INIT();
       
        ADC_config();
        DMA_ADC_Config();
        EA = 1;   //打开总中断
       
        LCM_Config();        //LCM初始化
        DMA_Config();        //LCM_DMA初始化, 使用DMA方式显示下面的字符串.
        ST7735_init();

    LCD_Display_Dir(2);                               //屏幕方向
        display();
        UartInit();
       
        PID_nitialization();
        PWMA_config();
        PWMB_config();
       
        BEEP=0;
        UpdatePwm_CC(min2);
        MCP4725_Write_VCC(0);
        user_menu_init();
        while(DS18B20_INit())
        {
          printf("DS18B20 cheak failed!\r\n");
        }
       
           printf("DS18B20 read!\r\n");

       DS18B20_Search_Rom();
                printf("DS18B20_SensorNum:%d\r\n",DS18B20_SensorNum);
          for(i=0;i<DS18B20_SensorNum;i++)
                {
                          for(j=0;j<8;j++)
                      printf("0x%02x,",DS18B20_ID);   //串口打印
                        printf("\r\n");
                }   
               
        // RSTFLAG |= 0x04;   //设置看门狗复位需要检测P3.2的状态,否则看门狗复位后进入USB下载模式
        while (1)
        {
         if( EG1163S_OFF==1)
                CV_DAC=PID_Compute((float)min1,(float)OUT_VCC*100);
                else
                {
                     CV_DAC=0;
                       MCP4725_Write_VCC(0);

                }
                //UpdatePwm_CV(min1);
                MCP4725_Write_VCC(CV_DAC);
               
          UpdatePwm_CC(min2);
                UpdatePwm_PID(1500);
      }
}
这个程序,挂载了3个18b20,有时候能正确读出来1个id,有时候一个都不行,要么就是读出来的id是错误的,自己用0x33一个一个读出id后,可以正确读出各路的温度,就一次型读取多路id不行,求大佬帮忙看看,多谢了

c20160526 发表于 2026-4-27 11:11:28

读取多路,始终串口打印发现0个18b20

wulin 发表于 2026-4-27 17:12:53

c20160526 发表于 2026-4-27 11:11
读取多路,始终串口打印发现0个18b20


c20160526 发表于 2026-4-29 09:54:19

wulin 发表于 2026-4-27 17:12


还是读不出来,要么读出来全是0x00或者不是28开头的数据,用0x33一个一个可以读取出来,单路读取后的id,可以读出正确的温度

wulin 发表于 2026-4-29 15:40:05

c20160526 发表于 2026-4-29 09:54
还是读不出来,要么读出来全是0x00或者不是28开头的数据,用0x33一个一个可以读取出来,单路读取后的id, ...

这个程序中的自动搜索总线上多个DS18B20序列号代码是实际用于某医用检测仪器的。单总线5路温度检测。有可能是你的硬件不匹配,也有可能是你修改软件出错。
页: [1]
查看完整版本: 读取多路18b20