DS18B20调试总结

时间:2024-04-06 17:34:20

DS18B20是单总线的温度传感器,在使用MCU对其进行操作的时候,往往使用模拟单总线时序来进行读写,下面是驱动。

1.复位

时序图

DS18B20调试总结

static HRINT8U DS18B20_Reset(void)
{
    HRINT8U  status;    
    DS18B20_SetDataOut();//数据线配成输出
    DS18B20_DATA_HIGH(); //拉高总线   
    DS18B20_Delayus(2);//延时2us
    DS18B20_DATA_LOW();//拉低总线
    DS18B20_Delayus(500);//延时500us,时序图规定最小480us
    DS18B20_SetDataIn();//总线配置成输入
    DS18B20_Delayus(70);//延时70us,时序图上规定等待时间15-60us
    if(DS18B20_ReadDataBit() == 0)//读总线上电平,判断DS18B20是否有回复
    {
        status = 1;//有回复
    }
    else
    {
        status = 0;//无回复
    }
    DS18B20_Delayus(410);//延时410us
    return(status);//返回复位的状态
}

2.主机发送一个字节

时序图

DS18B20调试总结

DS18B20调试总结

static void DS18B20_WriteDataByte(HRINT8U pWrite)
{
    HRINT8U i,WriteData;
    WriteData = pWrite;
    DS18B20_SetDataOut();//配置成输出
    for(i=0;i<8;i++)//循环发送8位
    {
        DS18B20_DATA_HIGH();//拉高总线
        DS18B20_Delayus(2);    
        DS18B20_DATA_LOW();//拉低总线
        DS18B20_Delayus(2);        
        if(WriteData&0x01)//先发低位,为1
        {
            DS18B20_DATA_HIGH();//拉高总线
        }
        else//为0
        {        
            DS18B20_DATA_LOW();//拉低总线
        }
        DS18B20_Delayus(62);//延时62us,数据稳定时间设定为62us
        WriteData >>= 1;//字节左移一位
    }
    DS18B20_SetDataIn();//配置成输入
}

3.主机读一字节

时序图

DS18B20调试总结

DS18B20调试总结

static HRINT8U DS18B20_ReadDataByte(void)
{
    HRINT8U i,ReadData = 0;
    for(i=0;i<8;i++)//循环读取8位
    {
        ReadData = ReadData >> 1;  //左移一位      
        DS18B20_SetDataOut();//配成输出
        DS18B20_DATA_HIGH();//先置高总线
        DS18B20_Delayus(2); //延时           
        DS18B20_DATA_LOW();//置低总线,告诉DS18B20主机要操作总线了
        DS18B20_Delayus(2);//延时2us    
        DS18B20_SetDataIn();//配置成输入
        DS18B20_Delayus(8);//延时8us,加上之前的2us大概10us开始采集,数据手册要求在15us前采集
        if(DS18B20_ReadDataBit())//读总线电平,为高
        {
            ReadData = ReadData | 0x80;//置1
        }
        else//为0,ReadData 原本就初始化为0,不用动作
        {
            
        }
        DS18B20_Delayus(45);//延时45us,芯片手册规定1个为60us
    }
    return(ReadData);//返回数据
}

4.DS18B20采集模式配置

DS18B20的操作顺序是:

第一:复位指令    第二:ROM指令    第三:DS18B20功能指令

下面是DS18B20的暂存器,总共9字节。0字节为温度低8位,1字节为温度高8位,2字节是高报警阈值,3字节是低报警阈值,4字节是配置寄存器(用于配置精度),5-7字节保留,8是CRC校验。

DS18B20调试总结

static void DS18B20_ModeConfiguration(void)
{
    HRINT8U i;
    DS18B20_Reset();//复位指令
    DS18B20_WriteDataByte(0xCC);//忽略ROM操作,总线只挂一个传感器时用(ROM指令)
    DS18B20_WriteDataByte(0x4E);//写暂存器操作(DS18B20功能指令)
    DS18B20_WriteDataByte(0x25);//高报警
    DS18B20_WriteDataByte(0x21);//低报警
#if     (DS18B20_RESOLUTION_MODE == DS18B20_RESOLUTION_9BIT)//根据不用的转换精度配置,编译不同的代码,条件编译
    DS18B20_WriteDataByte(DS18B20_RESOLUTION_9BIT);//精度9位,这是一个宏定义,值是0x1F
#elif    (DS18B20_RESOLUTION_MODE == DS18B20_RESOLUTION_10BIT)
    DS18B20_WriteDataByte(DS18B20_RESOLUTION_10BIT);//精度10位,这是一个宏定义,值是0x3F
#elif    (DS18B20_RESOLUTION_MODE == DS18B20_RESOLUTION_11BIT)
    DS18B20_WriteDataByte(DS18B20_RESOLUTION_11BIT);//精度11位,这是一个宏定义,值是0x5F
#else
    DS18B20_WriteDataByte(DS18B20_RESOLUTION_12BIT);//精度12位,这是一个宏定义,值是0x7F
#endif    
    DS18B20_Reset();//复位
    DS18B20_WriteDataByte(0xCC);//忽略ROM
    DS18B20_WriteDataByte(0xBE);//读暂存其指令,可将刚才写入的值读取出来,看看是否正确写入
    for(i=0;i<9;i++)
    {
        DS18B20_RevBuff[i] = DS18B20_ReadDataByte();
    }
    DS18B20_Reset();//复位
    DS18B20_WriteDataByte(0xCC);//忽略ROM
    DS18B20_WriteDataByte(0x48); //将刚才写入的3字节暂存器的值搬到E2ROM,防止掉电丢失。
    DS18B20_Delayms(15);//延时15ms
    DS18B20_Reset();//复位
}

5.采集函数

HRFLOAT DS18B20_Sample(void)
{
    HRINT8U i;
    static HRFLOAT Temp;
    OS_ERR      err;

    HRDisableInterrupts();  //禁止全局中断,这里关中断时为了在循环时频率有中断,导致延时不准确而通讯失败
    DS18B20_Reset();//复位
    DS18B20_WriteDataByte(0xCC);   //忽略ROM指令
    DS18B20_WriteDataByte(0x44);//开始转换
    HREnableInterrupts();   //开全局中断
#if     (DS18B20_RESOLUTION_MODE == DS18B20_RESOLUTION_9BIT)//根据精度不同,延时时间不一样
//    DS18B20_Delayms(100);//for延时100ms
    OSTimeDly ( 100, OS_OPT_TIME_DLY, & err );//ucosIII延时100ms
#elif    (DS18B20_RESOLUTION_MODE == DS18B20_RESOLUTION_10BIT)
    //DS18B20_Delayms(200);
    OSTimeDly ( 200, OS_OPT_TIME_DLY, & err );
#elif    (DS18B20_RESOLUTION_MODE == DS18B20_RESOLUTION_11BIT)
    //DS18B20_Delayms(400);
    OSTimeDly ( 400, OS_OPT_TIME_DLY, & err );
#else
    OSTimeDly ( 800, OS_OPT_TIME_DLY, & err );//由于转换时间较长,有操作系统时建议采用操作系统来延时,提高程序效率
//    DS18B20_Delayms(800);//
#endif    
    HRDisableInterrupts();    //禁止全局中断
    DS18B20_Reset();   //复位 
    DS18B20_WriteDataByte(0xCC);    //忽略ROM
    DS18B20_WriteDataByte(0xBE);//读暂存器指令
    for(i=0;i<9;i++)
    {
        DS18B20_RevBuff[i] = DS18B20_ReadDataByte();//读回9个字节
    }
    HREnableInterrupts();    //开启中断
    if(DS18B20_CRC8(DS18B20_RevBuff,8) == DS18B20_RevBuff[8])//判断CRC是否正确
    {
            Temp = DS18B20_16sToFloat((HRINT16S)((DS18B20_RevBuff[1]<<8) | DS18B20_RevBuff[0]));//将温度转换成小数
    }
    else
    {
            Temp = Temp;//the last time
    }
    OS_TaskSemPost ((OS_TCB  *)&AppTaskBuzzerTCB,
                  (OS_OPT   )0,
                  (CPU_TS   )0,
                  (OS_ERR  *)&err);    //uscosIII操作系统函数,用于通知其他任务温度采集完毕,可去掉
    return(Temp);//返回温度值
}

下面是CRC校验和温度转换成小数的代码

static HRINT8U DS18B20_CRC8(HRINT8U *RomCode,HRINT8U Length) 

    HRINT8U i,x,crc,crcbuff;
    crc=0;
    for(x = 0; x < Length; x++)
    {
        crcbuff=RomCode[x];
        for(i = 0; i < 8; i++) 
        { 
            if(((crc ^ crcbuff)&0x01)==0) 
            {
                crc >>= 1; 
            }
            else 
            { 
                crc ^= 0x18;   //CRC=X8+X5+X4+1
                crc >>= 1; 
                crc |= 0x80; 
            }         
            crcbuff >>= 1;       
        }
    }
    return crc;    
}

static HRFLOAT DS18B20_16sToFloat(HRINT16S pSource)
{
    HRFLOAT pDest;
    pDest = (HRFLOAT)(pSource * 0.0625);
    return(pDest);
}

6.调试过程中遇到的问题

6.1.调试遇到for语句延时的问题,for代码如下,示波器卡好DS18B20_Delayus(1)延时1.04us,调用DS18B20_Delayus
(480)时,延时时间不够480。
static void DS18B20_Delayus(HRINT32U nTime)
{    
    HRINT32U i,j;
    for(j=0;j< nTime;j++)
    {
    for(i=0;i<9;i++);
    }
}
原因:调用DS18B20_Delayus(1)进出函数一次,DS18B20_Delayus(480)也是进入函数一次,在DS18B20_Delayus(1)的时候进出函数的时间使得DS18B20_Delayus(1)里面的for时间不到1us,所以调用480时时间不够。正确做法是DS18B20_Delayus(1000)卡一个1ms时间,然后再推出1us的时间,尽量让总的延时时间能够忽略掉进出函数的时间。

6.2.调试遇到向DS18B20写入数据,DS18B20无回复现象。查看发送波形是正常的。
原因:写完一个字节以后,没有释放总线,写完后将设置成输入即可。

6.3采集温度时偶尔出现CRC校验不通过。

原因:在读数据时没有关掉系统的中断,导致中断打乱了延时,造成数据读取失败。