注:原理图
18b20.c
#include "18b20.h"
#include "stm32f10x.h" // Device header
void DS18B20_IO_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_8;//PORTA0 推挽输出
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
void DS18B20_IO_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
//复位DS18B20
void DS18B20_Rst(void)
{
DS18B20_IO_OUT(); //设置为输出模式
DS18B20_DQ_OUT=0; //拉低DQ
Delay_us(750); //拉低750us(至少480us)
DS18B20_DQ_OUT=1; //DQ=1拉高释放总线
Delay_us(15); //15US
}
//返回1:未检测到DS18B20的存在
//返回0:存在
/*
主机首先发出一个480-960微秒的低电平脉冲,然后释放总线变为高电平,
并在随后的480微秒时间内对总线进行检测,如果有低电平出现说明总线上有器件已做出应答。
若无低电平出现一直都是高电平说明总线上无器件应答。
作为从器件的DS18B20在一上电后就一直在检测总线上是否有480-960微秒的低电平出现,
如果有,在总线转为高电平后等待15-60微秒后将总线电平拉低60-240微秒做出响应存在脉冲,
告诉主机本器件已做好准备。若没有检测到就一直在检测等待。
*/
u8 DS18B20_Check(void)
{
u8 retry=0;
DS18B20_IO_IN();//SET PA0INPUT
while(DS18B20_DQ_IN&&retry<200)// DS18B20_DQ_IN的作用为读引脚,观察其是否为低电平
{
retry++;//如果为高电平,则retry++
Delay_us(1);
}
if(retry>=200)//未检测到18B20
{
return 1;
}
else
{
retry=0;
}
while(!DS18B20_DQ_IN&&retry<240)
{
retry++;//低电平时retry++
Delay_us(1);
}
if(retry>=240)return 1;//由于拉低总线的时间在60~240us,大于240则没检测到18B20
return 0;
}
//初始化DS18B20的IO口DQ 同时检测DS的存在
//返回1:不存在
//返回0:存在
u8 DS18B20_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能PORTA时钟
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_8;//PORTA0 推挽输出
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_8); //输出1
DS18B20_Rst();
return DS18B20_Check();//未检测到DS18B20则返回1
}
//写一个字节到DS18B20
//dat:要写入的字节
void DS18B20_Write_Byte(u8 dat)
{
u8 j;
u8 testb;
DS18B20_IO_OUT();//设置IO口为输出
for (j=1;j<=8;j++) //八位数据,一位一位写
{
testb=dat&0x01;//取第一位数据
dat=dat>>1;//移位
if (testb) //输出高
{
DS18B20_DQ_OUT=0;//主机输出低电平
Delay_us(2);//延时2us
DS18B20_DQ_OUT=1;
Delay_us(60); //延时60us
}
else//输出低
{
DS18B20_DQ_OUT=0;//主机输出低电平
Delay_us(60);
DS18B20_DQ_OUT=1;//释放总线
Delay_us(2);
}
}
}
//从DS18B20读取一个位
//返回值:1/0
u8 DS18B20_Read_Bit(void)
{
u8 data;
DS18B20_IO_OUT();//设置IO口为输出
DS18B20_DQ_OUT=0; //输出低电平2us
Delay_us(2);
DS18B20_DQ_OUT=1; //拉高释放总线
DS18B20_IO_IN();//设置IO口为输入
Delay_us(12);//延时12us
if(DS18B20_DQ_IN)data=1;//读取总线数据(当前电平)
else data=0;
Delay_us(50);//延时50us
return data;
}
//从DS18B20读取一个字节
//返回值:读到的数据
u8 DS18B20_Read_Byte(void)
{
u8 i,j,dat=0;
for (i=1;i<=8;i++)
{
j=DS18B20_Read_Bit();
dat=(j<<7)|(dat>>1);
}
return dat;
}
void DS18B20_Start(void)// ds1820 start convert
{
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);// skip rom
DS18B20_Write_Byte(0x44);// convert
}
//从ds18b20得到温度值
//精度:0.1C
//返回值:温度值(-550~1250)
short DS18B20_Get_Temp(void)
{
u8 temp;
u8 TL,TH;
short tem;
DS18B20_Start (); // ds1820 start convert
DS18B20_Rst();//复位
DS18B20_Check();
DS18B20_Write_Byte(0xcc);// skip rom
DS18B20_Write_Byte(0xbe);//convert
TL=DS18B20_Read_Byte();// LSB
TH=DS18B20_Read_Byte();// MSB
if(TH>7)//(TH>xxxxx111)温度为负
{
TH=~TH;TL=~TL;
temp=0;
}
else temp=1;//温度为正
tem=TH;//获得高八位
tem<<=8;
tem+=TL;//获得底八位
tem=(float)tem*0.625;//转换
if(temp) return tem; //返回温度值
else return -tem;
}
18b20.h
#ifndef __18B20_H
#define __18B20_H
#include "sys.h"
#include "stm32f10x.h"
#include "delay.h" //#include "SysTick.h"
#define DS18B20_DQ_OUT PAout(8)
#define DS18B20_DQ_IN PAin(8)
short DS18B20_Get_Temp(void);
u8 DS18B20_Init(void);
#endif