精度较高的DS18B20温度传感器,只需要用一个IO模拟单总线的通信
特点:
1、电压3V—5V
2、多个DS18B20可以挂接在唯一的三线上面
3、温度范围-55°~125°
4、这里用的分辨率是12位,0.0625°的精度
5、VCC和GND接反也不一定烧毁
DQ就是用来传输信息的单总线
当给DS18B20发送温度转换命令44H后,他会将转换之后的温度值以二字节的补码形式,放在两个存储的寄存器里。单片机读取数据是低位在前,高位在后;
前5位S表示温度的正负;如果都为零,温度为正,后面的数值×0.0625=温度;都为1,温度为负,后面温度取反+1再×0.0625=温度;举例:
关于模拟单总线的协议
初始化的时序图
主机=0,保持480us;释放总线=拉高1,延时15~60us;等待DS18B20的响应,如果接收到DS18B20的拉低=0,持续60~240us就是应答;后半段总的时间最少要480us
写时序
写0时序:主机=0,延时60us,然后拉高=1,2us;
写1时序:主机=0,延时2us,拉高60us;
两个之间间隔1us
读时序
主机拉低=0,延时2us,然后主机输入模式延时12us,主机拉高释放,读取当前的电平延时50us;
常见的读取过程:
开发板上DQ接在了PG11上面,本身存在一个上拉的电阻,空闲时间总线被拉高
代码部分学习
#include "ds18b20.h"
#include "SysTick.h"
/*******************************************************************************
* 函 数 名 : DS18B20_IO_IN
* 函数功能 : DS18B20_IO输入配置
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void DS18B20_IO_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=DS18B20_PIN;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//DQ=PG11的输入模式
GPIO_Init(DS18B20_PORT,&GPIO_InitStructure);
}
/*******************************************************************************
* 函 数 名 : DS18B20_IO_OUT
* 函数功能 : DS18B20_IO输出配置
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void DS18B20_IO_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=DS18B20_PIN;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//DQ=PG11的输出模式
GPIO_Init(DS18B20_PORT,&GPIO_InitStructure);
}
/*******************************************************************************
* 函 数 名 : DS18B20_Reset
* 函数功能 : 复位DS18B20
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void DS18B20_Reset(void)
{
DS18B20_IO_OUT(); //SET PG11 输出模式
DS18B20_DQ_OUT=0; //拉低DQ
delay_us(750); //拉低750us 这里最少480us
DS18B20_DQ_OUT=1; //DQ=1
delay_us(15); //15US
}
/*******************************************************************************
* 函 数 名 : DS18B20_Check
* 函数功能 : 检测DS18B20是否存在
* 输 入 : 无
* 输 出 : 1:未检测到DS18B20的存在,0:存在
*******************************************************************************/
u8 DS18B20_Check(void) //等待DS18B20是否拉低响应
{
u8 retry=0;//用来记录时间的变量
DS18B20_IO_IN();//SET PG11 INPUT 输入模式
while (DS18B20_DQ_IN&&retry<200)
{
retry++;
delay_us(1);
};
if(retry>=200)return 1;//如果200us还没有检测到拉低,说明不存在
else retry=0;//可能存在,将计数器置零,还要再判断一下是不是拉低大概240us
while (!DS18B20_DQ_IN&&retry<240)
{
retry++;
delay_us(1);
};//当DS18B20置高会跳出来
if(retry>=240)return 1;//如果一直被拉低超过240us说明可能不是由DS18b20产生的拉低
return 0;
}
/*******************************************************************************
* 函 数 名 : DS18B20_Read_Bit
* 函数功能 : 从DS18B20读取一个位
* 输 入 : 无
* 输 出 : 1/0
*******************************************************************************/
u8 DS18B20_Read_Bit(void) // 读一位
{
u8 data;
DS18B20_IO_OUT();//SET PG11 OUTPUT
DS18B20_DQ_OUT=0; //主机拉低
delay_us(2);
DS18B20_DQ_OUT=1;
DS18B20_IO_IN();//SET PG11 INPUT
delay_us(12);
if(DS18B20_DQ_IN)data=1;
else data=0;
delay_us(50);
return data;
}
/*******************************************************************************
* 函 数 名 : DS18B20_Read_Byte
* 函数功能 : 从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);
}
return dat;
}
/*******************************************************************************
* 函 数 名 : DS18B20_Write_Byte
* 函数功能 : 写一个字节到DS18B20
* 输 入 : dat:要写入的字节
* 输 出 : 无
*******************************************************************************/
void DS18B20_Write_Byte(u8 dat)
{
u8 j;
u8 testb;//用来记录所取出来的每一位,低位在前
DS18B20_IO_OUT();//SET PG11 OUTPUT;
for (j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;//向右移动一位
if (testb)
{
DS18B20_DQ_OUT=0;// Write 1
delay_us(2);
DS18B20_DQ_OUT=1;
delay_us(60);
}
else
{
DS18B20_DQ_OUT=0;// Write 0
delay_us(60);
DS18B20_DQ_OUT=1;
delay_us(2);
}
}
}
/*******************************************************************************
* 函 数 名 : DS18B20_Start
* 函数功能 : 开始温度转换
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void DS18B20_Start(void)// ds1820 start convert
{
DS18B20_Reset();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);// skip rom
DS18B20_Write_Byte(0x44);// convert
}
/*******************************************************************************
* 函 数 名 : DS18B20_Init
* 函数功能 : 初始化DS18B20的IO口 DQ 同时检测DS的存在
* 输 入 : 无
* 输 出 : 1:不存在,0:存在
*******************************************************************************/
u8 DS18B20_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(DS18B20_PORT_RCC,ENABLE);
GPIO_InitStructure.GPIO_Pin=DS18B20_PIN;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(DS18B20_PORT,&GPIO_InitStructure);
DS18B20_Reset();//复位一下
return DS18B20_Check();//检查看有没有响应
}
/*******************************************************************************
* 函 数 名 : DS18B20_GetTemperture
* 函数功能 : 从ds18b20得到温度值
* 输 入 : 无
* 输 出 : 温度数据
*******************************************************************************/
float DS18B20_GetTemperture(void)
{
u16 temp;
u8 a,b;
float value;
DS18B20_Start(); // ds1820 start convert
DS18B20_Reset();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);// skip rom
DS18B20_Write_Byte(0xbe);// convert
a=DS18B20_Read_Byte(); // LSB
b=DS18B20_Read_Byte(); // MSB
temp=b;
temp=(temp<<8)+a;
if((temp&0xf800)==0xf800)//如果读出来为-;前5位全部为1
{
temp=(~temp)+1;
value=temp*(-0.0625);
}
else
{
value=temp*0.0625;//为正,前5位为0直接转换
}
return value;
}
main函数
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"
#include "ds18b20.h"
int main()
{
u8 i=0;
float temper;
SysTick_Init(72);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组
LED_Init();
USART1_Init(115200);
while(DS18B20_Init())
{
printf("DS18B20检测失败,请插好!\r\n");
delay_ms(500);
}
printf("DS18B20检测成功!\r\n");
while(1)
{
i++;
if(i%20==0)
{
LED1=!LED1;
}
if(i%50==0)
{
temper=DS18B20_GetTemperture();
if(temper<0)
{
printf("检测的温度为:-");
}
else
{
printf("检测的温度为: ");
}
printf("%.2f°C\r\n",temper);
}
delay_ms(10);
}
}