基于FS4412的DS18B20温度采集编程实现(1-时序分析)

作者:秦老师,华清远见教育科技集团讲师。

一、DS18B20简介

DS18B20是常用的数字温度计。DS18B20数字温度计提供9至12位(可配置)温度读数,表明该设备的温度。

信息通过单总线接口被发送到DS18B20或从DS18B20发出,因此从中央微处理器到DS18B20只有需要一个线(和地线)。

读,写和进行温度转换所需要的电源,可以由数据线本身来提供,无需外部电源。 由于每个DS18B20含有唯一的序列号,多个DS18B20可以挂载在一条单总线上。这允许在许多不同的地方,放置温度传感器。

这个功能是非常有用的,可以应用在包括HVAC环境控制,建筑物内部的温度感应, 设备或机械,过程监测和控制等领域。

二、DS18B20硬件连接

  
DS18B20引脚图                                                           DS18B20 原理图

DS18B20 有三个引脚。根据原理图可知,DS18B20采用了外部供电的连接方式,而DQ引脚上拉10k电阻。DQ引脚连接在4412芯片的GPK1_1 引脚上面。

GND
DQ 数据线
VDD 电源(可选)

三、DS18B20时序分析

DS18B20是一个单总线,输入和输出都是通过DQ引脚,我们需要根据时序图,不断的操作DQ这个引脚,实现具体的功能。

(一)ds18b20复位时序和函数实现

通过复位信号,可以检测DS18B20是否工作正常,并通知DS18B20准备通信。

(1)4412拉低DQ引脚,复位周期开始。

(2)DQ引脚上的低电平保持480us—960us 的时间,然后释放总线。

(3)4412延时16us—60us等待DS18B20应答。

(4)DS18B20拉低DQ引脚60us—240us,表示应答。

4412读取DQ引脚电平,如果是低电平,表示初始化完成。

(5)DS18B20应答信号结束后,释放总线,DQ引脚被上拉电阻拉高,复位周期结束。

实现ds18b20的复位代码:
        void DS18_Reset()
        {
                  GPK1.PUD = 0;                                       //GPK1_1 禁止上下拉
                  GPK1.CON = (GPK1.CON & ~(0xF << 4)) | 0x1 << 4;   //设置GPK1_1为输出引脚
                  GPK1.DAT &= ~(0x1 << 1);                                 //设置GPK1_1 输出‘0’,拉低DQ引脚
                  delay_us(700);                                                                //延时 600us
                  GPK1.DAT |= 0x1 << 1;                                                      //GPK1_1释放总线
                  GPK1.CON &= ~(0xF << 4);                                             //设置GPK1_1为输入引脚
                  while(GPK1.DAT & (0x1 << 1));                     //等待DS18B20应答信号 (DQ引脚低电平)
                  while(!(GPK1.DAT & (0x1 << 1)));
                                    //等待DS18B20应答信号结束(DQ引脚高电平)
         }

(二)ds18b20写时序和函数实现

当我们需要从DS18B20写数据的时候,必须严格DS18B20的写时序,进行操作。

向DS18B20写逻辑0操作:

(1)4412拉低DQ引脚,写周期开始。

(2)DQ引脚保持低电平15us左右。

(3)DQ引脚继续保持低电平20us--45us。

(4)释放总线。

向DS18B20写逻辑1操作:

(1)4412拉低DQ引脚,写周期开始。

(2)DQ引脚上的低电平保持大于1us后,拉高DQ引脚 ,总共15us。

(3)DQ引脚继续保持高电平20us—45us

(4)释放总线。

实现向DS18B20写入一个字节代码:

void DS18_Write(unsigned char data)
         {
                  unsigned char i;
                  GPK1.CON = (GPK1.CON & ~(0xF << 4)) | 0x1 << 4;     //设置GPK1_1为输出引脚
        
                  for(i = 0; i < 8; i++)
                  {
                            GPK1.DAT |= 0x1 << 1;                                          //设置GPK1_1 输出1
                            delay_us(1);                                  //延时1us
                            GPK1.DAT &= ~(0x1 << 1);                                                //设置GPK1_1 输出0形成下降沿
                            delay_us(12);                                 //延时12us,大于1us小于15us
                            if(data & 0x1)                                                                //如果数据低位为1
                            GPK1.DAT |= 0x1 << 1;                                     //设置GPK1_1 输出1
                            delay_us(40);                                                               //延时40us
                            data = data >> 2;                               //数据右移1位
                  }
         }

(三)ds18b20写时序和函数实现

当我们需要从DS18B20读数据的时候,必须严格DS18B20的读时序,进行操作。

(1)通过4412拉低DQ引脚,读周期开始。

(2)DQ引脚上的低电平至少保持1us 的时间,然后释放引脚。

(3)4412延时几us(留物理电平反应时间),读取DQ引脚的数据。

注意:根据图中MASTER SAMPLES指示,从拉低电平转换开始,留给物理电平转换时间,到后4412的对DQ引脚读取操作应给在15us之内完成。

(4)15us后读时隙结束时,DQ引脚将通过外部上拉电阻拉回高电平。

4412延时45us等待读周期结束。

实现向DS18B20读入一个字节数据代码:

unsigned char DS18_Read()
         {
                  unsigned char i, Temp = 0;                                                       //初始化接受变量Temp为0
                  for(i = 0; i < 8; i++)
                  {
                            GPK1.CON = (GPK1.CON & ~(0xF << 4)) | 0x1 << 4;  //设置GPK1_1为输出引脚
                            GPK1.DAT |= 0x1 << 1;                                                 //设置GPK1_1 输出1
                            GPK1.DAT &= ~(0x1 << 1);                                                        //设置GPK1_1 输出0,形成下降沿
                            GPK1.DAT |= 0x1 << 1;                                                      //GPK1_1释放总线
                            GPK1.CON &= ~(0xF << 4);                                           //设置GPK1_1为输出引脚
                            Temp >>= 1;                                    //接受变量右移1位
                            if(GPK1.DAT & (0x1 << 1))                                                        //读取DQ引脚,如果DQ为1
                            Temp |= 0x80;                              //接受变量Temp,高位置1
                            delay_us(30);                                   //延时30us
                  }
                  return Temp;
                                          //返回接受变量
         }