STM8S18B20探测温度

一、DS18bB20温度传感器简介      

1.ds18b20基于单线协议(1-wire协议)与主机通信 ,是 美信公司的

2.什么是1-wire协议?

1-wire协议是一个具有单总线主机和一个或多个从机的系统

3.什么是主、从设备?

如本工程项目中, DS18B20是从机设备,STM8为主机设备

4.主从设备的通信引脚?

DS18B20的DQ引脚------------------------------STM8板子上J4模块的2号引脚DS18B20_DQ

5.电路连接图如下所示:

    

注意:

(1).GND接地;

(2). DQ为数字信号输入/输出端;

(3). VDD为外接供电电源输入端(在寄生电源接线方式时接地)

(4)STM8上PD0引脚复用

二、DS18B20温度传感器的存储器

1.DS18B20温度传感器的内部存储器包括一个高速暂存RAM和一个非易失性的可电擦除的E2RAM,如图

2.中间结果暂存存储器包含了8个连续字节

暂存储器的头两个字节为测得温度信息的低位和高位字节; 
第3, 4字节是TH和TL的易失性拷贝, 在每次电复位时都会被刷新;
第5字节是配置寄存器的易失性拷贝, 同样在电复位时被刷新;第6、7、8个字节用于内部计算,保留
第9字节是前面8个字节的CRC检验值(冗余检验字节)

3.配置寄存器的命令内容如下

低五位一直都是1 ,TM是测试模式位,用于设置DS18B20在工作模式还是在测试模式。在DS18B20出厂时该位被设置为0,用户不要去改动。R1和R0用来设置分辨率,如下表所示:(DS18B20出厂时被设置为12位)

MSB                                                                                            LSB

TM R1 R0

温度分辨率设置表:

R1

R0

分辨率

温度最大转换时间 温度分辨率

0

0

9位

93.75ms 0.5℃

0

1

10位

187.5ms 0.25℃

1

0

11位

375ms 0.125℃

1

1

12位

750ms 0.0625℃

4.温度数据的存储格式:

S18B20 通过编程,可以实现最高 12 位的温度存储值,在寄存器中,以补码的格式存储,如图所示。一共 2 个字节,LSB 是低字节,MSB 是高字节,其中 MSb 是字节的高位,LSb 是字节的低位。大家可以看出来,二进制数字,每一位代表的温度的含义,都表示出来了。其中 S表示的是符号位,低 11 位都是 2 的幂,用来表示最终的温度。DS18B20 的温度测量范围是从-55 度到+125 度,而温度数据的表现形式,有正负温度,寄存器中每个数字如同卡尺的刻度一样分布。

(1)当温度是正的时候SSSSS=00000 ,将测到的数值乘以0.0625就可以得到实际温度;

(2)当温度是负的时候,高8位的最高5位(符号位)是1时,数值就大于7(00000111),将测到的数值取反加1再乘以0.0625就可以得到实际温度;

5.一些温度与转换后输出的数字参照如下:

举个例子吧,比如说-55℃的前12位是符号位+整数部分,后4位是小数部分:

整数部分 55原码   0000 0011 0111
-55原码 1000 0011 0111 
55补码 1111 1100 1001
小数部分 0000
两个8bit的RAM存储 1111 1100 1001  0000

三、ds18b20采集数据的过程:

 

TASK1 : 初始化

1. 初始化抽象了解

就是用主机stm8发信号叫醒温度传感器ds18B20,让它起床工作,首先,先看他还在不在床上,如果温度传感器还在床上、被叫醒了就会给一个应答,说,哦,我醒了,可以准备开始工作了!如果不在床上,就返回一个错误报告。这个过程就是初始化。

2.单线总线上的所有操作都是从初始化开始的. 过程如下: 

1)请求: 主机通过拉低单线480us以上, 产生复位脉冲, 然后释放该线, 进入Rx接收模式. 主机释放总线时, 会产生一个上升沿脉冲.
DQ : 1 -> 0(480us+) -> 1  
2)响应: DS18B20检测到该上升沿后, 延时15~60us, 通过拉低总线60~240us来产生应答脉冲. 
DQ: 1(15~60us) -> 0(60~240us)
3)接收响应: 主机接收到从机的应答脉冲后, 说明有单线器件在线. 至此, 初始化完成.
DQ: 0

3.初始化时序图

4.要用的引用文件


/*要用到的头文件*/
 
#include <stdio.h>
#include <string.h>
#include "TES_ds18b20.h"
#include "timing_delay.h"
#include "stm8_board.h"
#include "conf_eeprom.h"
#include "sensor_proc.h"
 
 
/*要用到的定义和调用文件*/
 
 
/*****************stm8board.h*******************/
 
#define MULFUN_PD0                 GPIOD, GPIO_Pin_0   /*PD0: 多功能复用管脚 */
 
#define TES_SENSOR_PIN             MULFUN_PD0         /*PD0: 温度传感器采样管脚 */  
#define SWT_SWITCH_PIN             MULFUN_PD0         /*PD0: 常开门开关量管脚  */
 
 
 
/****************stm8l15x_gpio.c****************/
 
BitStatus GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin)
{
  return ((BitStatus)(GPIOx->IDR & (uint8_t)GPIO_Pin));
}     //设置GPIO引脚为高电平的函数
 
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint8_t GPIO_Pin)
{
  GPIOx->ODR &= (uint8_t)(~GPIO_Pin);
}     //设置GPIO引脚为低电平的函数
 
BitStatus GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin)
{
  return ((BitStatus)(GPIOx->IDR & (uint8_t)GPIO_Pin));
}    //读取指定端口管脚的输入:ReadValue = GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_0);
 
 
 
/*****************THS_ds18b20.h*******************/
 
#define DS18B20_DQ_PIN    TES_SENSOR_PIN               /*定义DQ引脚为温度传感器引脚*/
 
#define DS18B20_IO_OUT()  GPIO_Init(DS18B20_DQ_PIN, GPIO_Mode_Out_PP_High_Fast) /*设置stm8上的DQ引脚为输出模式*/
#define DS18B20_IO_IN()   GPIO_Init(DS18B20_DQ_PIN, GPIO_Mode_In_PU_No_IT)/*设置stm8上的DQ引脚为输入模式*/
 
#define DS18B20_DQ_HIGH   GPIO_SetBits(DS18B20_DQ_PIN)
#define DS18B20_DQ_LOW    GPIO_ResetBits(DS18B20_DQ_PIN);

5.初始化函数

 
 
/* 复位DS18B20并等待复位应答, 返回值:0 成功  1 失败 */
int DS18B20_Rst(void)	   
{        
  u8             retry=0;//重复次数初始化
  
  /*************************
   *       复位DS18B20     *
   *************************/  
  DS18B20_IO_OUT(); //设置stm8上的DQ引脚为输出模式 
  
  /*Master send a reset signal*/
  DS18B20_DQ_LOW;   //单片机把DQ引脚拉低(拉低总线) stm8->0->ds18B20 主机发送复位脉冲(480-960us)
  udelay(700);      //等待700us
  DS18B20_DQ_HIGH;  //把DQ引脚拉高 
  
  /*Slave will wait for 15~60us*/
  udelay(40);  
  
  /*************************
   * 等待DS18B20的复位应答 *
   *************************/  
  DS18B20_IO_IN();  /* 设置DQ管脚为输入模式 */
 
  /* 在200us的时间内等待复位信号低电平的到来 */
  while (DS18B20_DQ_IN&&retry<200)
  {
    retry++;
    udelay(1);
  };	
 
  if(retry>=200)
    return 1; /* 如果在200us内没有低电平输出出来则出错 */
  else 
    retry=0; 
 
  /* 再在240us的时间内等待复位信号拉高,表示复位结束 */
  while (!DS18B20_DQ_IN&&retry<240)
  {
    retry++;
    udelay(1);
  };
  
  /*没有等到复位信号拉高,出错退出 */
  if(retry>=240)
    return 1;	
  
  return 0;     
}

TASK2: ROM操作命令

当主机检测到应答脉冲, 便可发起ROM操作命令. 共有5类ROM操作命令, 如下表

 命令类型  命令字节 功能
Read Rom   读ROM   33H 读取激光ROM中的64位,只能用于总线上单个DS18B20器件情况, 多挂时会发生数据冲突
Match Rom匹配ROM 55H 此命令后跟64位ROM序列号,寻址多挂总线上的对应DS18B20.只有序列号完全匹配的DS18B20才能响应后面的内存操作命令,其他不匹配的将等待复位脉冲.可用于单挂或多挂两种情况.
Skip Rom   跳过ROM CCH 可无须提供64位ROM序列号即可运行内存操作命令, 只能用于单挂.
Search Rom搜索ROM F0H 通过一个排除法过程, 识别出总线上所有器件的ROM序列号
Alarm Search告警搜索 ECH 命令流程与Search Rom相同, 但DS18B20只有最近的一次温度测量时满足了告警触发条件的, 才会响应此命令.

在成功执行ROM操作命令后, 才可使用内存操作命令. 共有6种内存操作命令:

命令类型 命令字节 功能

Write Scratchpad
写暂存器

4EH 写暂存器中地址2~地址4的3个字节(TH,TL和配置寄存器)在发起复位脉冲之前,3个字节都必须要写.

Read Scratchpad
读暂存器

BEH 读取暂存器内容,从字节0~一直到字节8, 共9个字节,主机可随时发起复位脉冲,停止此操作,通常我们只需读前5个字节.

Copy Scratchpad
复制暂存器

48H 将暂存器中的内容复制进EERAM, 以便将温度告警触发字节存入非易失内存. 如果此命令后主机产生读时隙, 那么只要器件还在进行复制都会输出0, 复制完成后输出1.

Convert T 
温度转换

44H 开始温度转换操作. 若在此命令后主机产生时隙, 那么只要器件还在进行温度转换就会输出0, 转换完成后输出1.

Recall E2    
重调E2暂存器

B8H 将存储在EERAM中的温度告警触发值和配置寄存器值重新拷贝到暂存器中,此操作在DS18B20加电时自动产生.

Read Power Supply
读供电方式

B4H 主机发起此命令后每个读数时隙内,DS18B20会发信号通知它的供电方式:0寄生电源, 1外部供电.

TASK4: 1-WIRE信令


1.简介:

DS18B20要求有严格的时序来保证数据的完整性. 在单线DQ上, 有复位脉冲, 应答脉冲, 写0, 写1, 读0, 读1这6种信号类型. 除了应答脉冲外, 其它都由主机产生. 数据位的读和写是通过读、写时隙实现的.

1) 写时隙:

当主机将数据线从高电平拉至低电平时, 产生写时隙.所有写时隙都必须在60us以上, 各写时隙间必须保证1us的恢复时间.
写"1" : 主机将数据线DQ先拉低, 然后释放15us后, 将数据线DQ拉高;
写"0" : 主机将DQ拉低并至少保持60us以上.


2)读时隙:

当主机将数据线DQ从高电平拉至低电平时, 产生读时隙. 所有读时隙最短必须持续60us, 各读时隙间必须保证1us的恢复时间.
读: 主机将DQ拉低至少1us,. 此时主机马上将DQ拉高, 然后就可以延时15us后, 读取DQ即可.

2.代码如下

1)读一个位bit的函数:

/* 从DS18B20读取一个位:  返回值:1/0 */


u8 DS18B20_Read_Bit(void) 
{
  u8 data;   //一位电平
  DS18B20_IO_OUT(); //设置DQ引脚位输出模式
  
  /*Generate read time slot 产生阅读时间段* /*/
  DS18B20_DQ_LOW;   //单片机拉低DQ电平
  udelay(2);       //延时2us  读时隙间必须保证1us的恢复时间.
  DS18B20_DQ_HIGH;  //拉高DQ引脚
  
  /*Master must read data from slave in 15us主线必须在15us内从ds18b20从设备读到一个位*/
  DS18B20_IO_IN(); //设置DQ引脚位输入模式
  udelay(9);       //延时9us
  
  if(DS18B20_DQ_IN)   //如果读到DQ引脚的电平
    data=1;              //高电平
  else 
    data=0;	   //如果没读到DQ引脚的电平,低电平
  
  udelay(50);          //延时50us
  return data;       //返回1或0
}

2)读一个字节dat的函数

/* 从DS18B20读取一个字节 */
u8 DS18B20_Read_Byte(void)   
{        
    u8 i,j,dat;
    dat=0;
    
    for (i=1;i<=8;i++)
    {
      j=DS18B20_Read_Bit();
      dat=(j<<7)|(dat>>1); 
      /*假如第一次读位读到j=1,那么dat=1000 0000 |(0>>1)=1000 0000;
            第二次读位读到j=1,那么dat=1000 0000 |(1000 0000>>1)
                                      =1000 0000 |  0100 0000
                                      =1100 0000
              第三次读位到j=0,那么dat=0000 0000 |0110 0000
                                      =0110 0000
      。。。。
      依次类推。
      最后得到dat=abcd efgh,  h是第一次读位,a是第8次读位*/
    }						    
    return dat;   //返回8个位的值
}

3)写一个字节,通过读的dat值,写1或者写0的函数

/* 写一个字节到DS18B20 */
void DS18B20_Write_Byte(u8 dat)     
 {             
    u8 j;
    u8 testb;
    
    DS18B20_IO_OUT();//SET PA0 OUTPUT; 
    
    for (j=1;j<=8;j++)   //低位在先,读取时低位在前,高位在后    
                         //所以在读取的过程中要移位操作,把低位不断的往右移动
    {
      testb=dat&0x01;     //假如读到的一个字节是1111 0101  那么dat=1111 0101
                            //testb=1111 0101&0000 0001 =(只用算dat最后一位)即1&1=1 此时steb非0 写1
                              
      dat=dat>>1;           //然后数据右移一位,0111 1010 那么dat=0111 1010
                              //testb=0&1=0,此时写0
      
      if (testb) //如果testb为非0,则执行写1
      {
        DS18B20_DQ_LOW;// Write 1
        udelay(2);
        DS18B20_DQ_HIGH;
        udelay(60); 
      }
      else    //如果testb为0,则执行写0
      {
        DS18B20_DQ_LOW;// Write 0
        udelay(60);   
        DS18B20_DQ_HIGH;
        udelay(2);    
      }
    }
}

4).开始温度转换



/* 开始温度转换 */
void DS18B20_Start(void)
{   						               
    DS18B20_Rst();	//复位 
    DS18B20_Write_Byte(0xcc);// skip rom当总线上只有一个器件的时候可以跳过rom,不进行rom检测
    DS18B20_Write_Byte(0x44);// convert当写入0x44命令后开始进行温度的转换
    msleep(750);
    
} 

5)初始化DS18B20的IO口 


/* 初始化DS18B20的IO口 DQ 同时检测DS的存在: 1->不存在  0->存在 */  	 
u8 ds18b20_init(void)
{
  GPIO_Init(DS18B20_DQ_PIN, GPIO_Mode_Out_PP_High_Fast);//使能stm8上的DS18B20_DQ_PIN引脚
  return DS18B20_Rst();
} 

6)采样函数


/* 从ds18b20得到温度值(12位精度转换) 返回值:两个字节存放 */


uint16_t sample_TES_ds18b20(void)
{
    uint8_t          sign;  /* 温度值为正或负 */
    uint8_t          TL,TH; /* DS18B20读出的温度寄存器值,TH存放高8位,TL存放低8位 */
    uint16_t         tmp;    //16位的温度值
    uint16_t         temp = 0xFFFF;  /* 温度值 */
    uint8_t          byte;     //定义一个byte8位
    
 
    GPIO_Init(DS18B20_DQ_PIN, GPIO_Mode_In_PU_No_IT);   //初始化DS18B20的DQ管脚PD0为采样模式

    msleep(5);
     
    if( ds18b20_init() )
    {
      printf("ERROR: DS18B20 temperature sensor initialise failure\n");
      goto OUT;
    }    

    DS18B20_Start (); /* 开始温度转换 */
    msleep(750);
    DS18B20_Rst(); 
    DS18B20_Write_Byte(0xcc);// skip rom跳过线上器件检查(只有ds18b20)
    DS18B20_Write_Byte(0xbe);// Read Scratchpad,读暂存器指令 ,开始转化   
    TL=DS18B20_Read_Byte(); // LSB 
    TH=DS18B20_Read_Byte(); // MSB  
    
    if(TH>7) /* 高5位为1,说明温度为负 */
    {
      tmp = ~(TH<<8|TL) + 1;  //补码
      sign=1;//温度为负        
    }
    else 
    {
      sign=0;//温度为正	  
      tmp = TH<<8 | TL;
    }

   /* 12位精度转换时,TH的低三位和TL的高四位组成温度值的整数部分,
    * 而TL的低四位为小数精度部分,并且精度系数为0.0625 
    *
    * RF将使用2个bytes来传输这个温度值,其定义为:
    * Byte[0]: 温度数据小数点后两位有效值: 0~99
    * Byte[1]: bit[7]符号位 0为正数 1为负数   bit[0:6]:温度数值正数部分:0~127
    */    
    byte = tmp>>4;     /* 温度的整数位 */
    byte |= sign<<7;   /* 温度的符号位 */
    temp = byte << 8;  //整部分移到高位
    
    byte = (tmp&0xF)*625/1000;//数点后两位有效值,tmp&0XF,取最低四位(小数位)
    temp |= byte;   //整数与小数合并

猜你喜欢

转载自blog.csdn.net/luoyir1997/article/details/81290425