DS18B20调试总结

news/2024/10/17 22:12:28/

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

1.复位

时序图

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.主机发送一个字节

时序图

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.主机读一字节

时序图

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校验。

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校验不通过。

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


http://www.ppmy.cn/news/478927.html

相关文章

群晖服务器216j增加硬盘,群晖DS216j影视库搭建方法 | 群晖DS216j存储服务器怎么样_什么值得买...

打造私人影视库:Synology 群晖 DS216j NAS 网络存储 2016-04-29 16:14:50 215点赞 1909收藏 283评论 前言 作为一个影视爱好者,整天在张大妈原创区看大家各种白群/黑群的晒幸福,不可谓不中毒,故心中暗下决心要弄台Nas回来,自己也是小白,一切遵循少折腾的原则,入手了群晖…

mojave时间机器文件服务器,年轻人的第一台NAS——群晖DS218j 篇二:配置 Time Machine 时间机器为macOS备份...

年轻人的第一台NAS——群晖DS218j 篇二:配置 Time Machine 时间机器为macOS备份 2019-12-15 16:52:16 9点赞 105收藏 34评论 创作立场声明:参考了群晖知识数据库的文章,并针对Bonjour播送和SMB协议部分进行了修改,本文仅适合于Mojave及更新的系统,其他系统版本没有做相关测…

群晖218J安装mysql_ds216(群晖218j可以换内存吗)

关键在CPU和内存上,群晖DS216se是入门最基础的一款,群晖DS216play含4K视频转码、支持转档,相比群晖DS216se的配置要高。 群晖DS216play拥有超大容量,2盘位,常规使用配2T硬盘。4TB的存储空间也可以够你存储将近6000多集美剧。产品类型: 企业级网络存储接口: USB 3.0端口*…

群晖Synology-DS218j-从开箱到安装

文章目录 外观展示使用感受 总结 外观展示 京东送到的时候就是这样&#xff0c;没套袋子&#xff0c;有点脏 主机用泡沫纸包裹 两侧都有镂空的logo 上全家福&#xff0c;主机、电源、电源线、网线、3包螺丝、硬盘架、保修和说明书 拆开主机&#xff0c;异常简洁&#xff0c;板…

群晖 NAS DS218j的优秀与缺憾

在去年的时候入手了群晖的个人家庭版 NAS DS218j&#xff0c;使用一年有余了&#xff0c;现在我来分享一下我个人使用过程中的体会&#xff0c;分享它给我带来的便捷&#xff0c;同时吐槽一下遇到的一堆问题。 当时我是在天猫买的这一款&#xff0c;因为好像京东的好像是贵一…

python pyqt5 参数保存与加载(简单)

1、创建系统变量与参数 app文件 sys_app.py from app.param_single import ParamSingleclass SysApp(object):_instance = Noneparam = ParamSingle()param.load()def __new__

19n20c的参数_供应IC芯片 745653-3 329056 品牌、价格、PDF参数 - 电子产品资料

请致电 021-51875986 5-103673-131811TPS2211AIDBRLTC4001EUF#PBFIPI60R099CPXKSA1 534206-9P22-8R-MTUSB2077APTRLTC4089EDJC-5#PBFIRF6717MTR1PBF 929842-01-37-30P10-8R-DTUSB2077APTRLTC4069EDC#TRPBFBSZ019N03LSATMA1 55959103034143PCA9500BS,118LTC4089EDJC-5#PBFSTW9NK…

js逆向-百度登陆参数

声明 本文仅供学习参考&#xff0c;禁止用于其他途径&#xff0c;违者后果自负 前言 网站&#xff1a;aHR0cHM6Ly93d3cuYmFpZHUuY29tLw 接口&#xff1a;aHR0cHM6Ly9wYXNzcG9ydC5iYWlkdS5jb20vdjIvYXBpLz9sb2dpbg 逆向分析 抓包后会发现post请求会提交很多的参数&#xff…