#include "stm32f10x.h" // Device header
#include "Delay.h"
#define DS_DQ_PORT GPIOB //数据线
#define DS_DQ_PIN GPIO_Pin_0
#define ROM_READ 0x33
#define ROM_MATCH 0x55
#define ROM_SEARCH 0xF0
#define ROM_SKIP 0xCC
#define ALARM_SEARCH 0xEC
#define TEMPER_CONVERT 0x44
#define RAM_READ 0xBE
#define RAM_WRITE 0x4E
#define RAM_TO_EE 0x48
#define EE_TO_RAM 0xB8
#define POWER_READ 0xB4
/*定义结构体用来存储温度*/
typedef struct
{
u32 Temperature;
u8 Temper_plus_minus;
}DS18B20_MEASURE;
/**
* @brief DS18B20端口输入初始化
* @param 无
* @retval 无
*/
void DS18B20_In_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//开启RCC时钟
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//这里设置的是上拉输入模式
GPIO_InitStructure.GPIO_Pin=DS_DQ_PIN;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(DS_DQ_PORT,&GPIO_InitStructure);
}
/**
* @brief DS18B20端口输出初始化
* @param 无
* @retval 无
*/
void DS18B20_OUT_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = DS_DQ_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //这里选择的是开漏输出,推挽 输出也可以
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DS_DQ_PORT, &GPIO_InitStructure);
}
/**
* @brief 写入数据0
* @param 无
* @retval 无
*/
void DS18B20_WR_0(void)
{
GPIO_ResetBits(DS_DQ_PORT, DS_DQ_PIN);//端口数据清0 ,拉为低电平
Delay_us(70);; //延时最低60 60~120
GPIO_SetBits(DS_DQ_PORT, DS_DQ_PIN); //端口数据拉高 ,拉位高电平
Delay_us(2); //延时2us,要大于1us
}
/**
* @brief 写入数据1
* @param 无
* @retval 无
*/
void DS18B20_WR_1(void)
{
GPIO_ResetBits(DS_DQ_PORT, DS_DQ_PIN);//端口数据清0 拉为低电平
Delay_us(15); //延时15秒,最低1us,发送数据起始位
GPIO_SetBits(DS_DQ_PORT, DS_DQ_PIN); //端口数据拉高 延时2us(大于1us) 拉为高电平
Delay_us(30); //延时30us,建议在15--60之间
}
/*这个要根据手册中写1或0的时序来写*/
/**
* @brief 写入一个字节
* @param 要写入的数据
* @retval 无
*/
void DS18B20_Write_Byte(u8 data)
{
u8 i,temp;
DS18B20_OUT_Init();//数据线配置为输出模式
for(i = 0; i < 8; i++)
{
temp = (data>>i)&0x01;//一共8位,从低位开始,然后向右移,每次取data的最后一位
if(temp)
DS18B20_WR_1(); //temp为真写1
else
DS18B20_WR_0(); //temp为假写0
}
}
/**
* @brief 读取指定端口的一位数据(状态)
* @param 无
* @retval 返回端口状态,高电平返回1,低电平返回0
*/
u8 DS18B20_RD_Bit(void)
{
u8 val;
DS18B20_OUT_Init();//数据线配置为输出模式 ,为什么
GPIO_ResetBits(DS_DQ_PORT, DS_DQ_PIN);//端口数据清0 ,把电平拉低
Delay_us(2); //延时2us,要求大于1us
GPIO_SetBits(DS_DQ_PORT, DS_DQ_PIN); //拉高,把电平拉高
DS18B20_In_Init(); //数据配置为输入,为什么?
Delay_us(15); //延时10个us开始采样总线数据,根据读0和读1时序之间的不同来确定的
val = 0;
if(GPIO_ReadInputDataBit(DS_DQ_PORT, DS_DQ_PIN))//读取端口的一位数据,判断状态
val = 1; //如果高电平
Delay_us(60); //所有读时序必须间隔60us以上
return val;
}
/*这个判断到底是读0还是读1时,根据读0和读1的时序图的区别来判断,并设置相应的标志量*/
/**
* @brief 读取端口的字节
* @param 无
* @retval 返回该字节
*/
u8 DS18B20_RD_Byte(void)
{
u8 i,dat; //
dat = 0;
for(i = 0; i < 8; i++)
{
dat |= DS18B20_RD_Bit() << i; //先读低位,并把每位赋值给dat
}
return dat;
}
/*这个要根据读时序来配置*/
/**
* @brief 复位并初始化函数
* @param
* @retval 为0电表成功,非0代表失败
*/ uint8_t DS18B20_Reset(void)
{
uint8_t timeout;
DS18B20_OUT_Init();//设置为端口输出模式 ?
GPIO_ResetBits(DS_DQ_PORT, DS_DQ_PIN);//端口数据清0 设为低电平
Delay_us(600);//时间在480--960之间
GPIO_SetBits(DS_DQ_PORT, DS_DQ_PIN);//端口设置1 设为高电平
Delay_us(50); //最低延时15us 15us-60us
DS18B20_In_Init(); //端口输入初始化?
//等待DS18B20应答
while(GPIO_ReadInputDataBit(DS_DQ_PORT, DS_DQ_PIN)) //如果端口状态为高电平 //等待拉低
{
Delay_us(1);
if(++timeout > 240) //时间超时
goto Exit;
}
timeout = 0;
while(!GPIO_ReadInputDataBit(DS_DQ_PORT, DS_DQ_PIN)) //如果端口状态为低电平 //等待拉高
{
Delay_us(1);
if(++timeout > 240) //超时
goto Exit;
}
return 0; //成功
Exit:
return 0xFF; //超时
}
1.单片机拉低总线至少480us,产生复位脉冲,然后释放总线(拉高电平)。 2.这时DS8B20检测到请求之后,会拉低信号,大约60~240us表示应答。 3.DS8B20拉低电平的60~240us之间,单片机读取总线的电平,如果是低电平,那么表示初始化成功 4.DS18B20拉低电平60~240us之后,会释放总线。
/**
* @brief 读取DS18B20的转换温度
* @param 无
* @retval 无
*/
void DS18B20_ReadTemper(void)
{
u8 TH,TL; //温度高8位 低8位
u16 temper; //温度
DS18B20_Reset(); //复位DS18B20总线
DS18B20_Write_Byte(ROM_SKIP); //写一个字节,先写低位(跳过ROM(只读存储器)(0xcc)),只有一个温度传感器时,可以跳过
DS18B20_Write_Byte(TEMPER_CONVERT); //读一个字节,(启动温度转换(0x44))
DS18B20_Reset(); //复位DS18B20
DS18B20_Write_Byte(ROM_SKIP); //跳过ROM 0xcc
DS18B20_Write_Byte(RAM_READ); //读RAM中9字节数据(0xbe)
TL = DS18B20_RD_Byte(); //先读低字节
TH = DS18B20_RD_Byte(); //读高字节
temper = (TH << 8) + TL;//把单独的高低位整合到一起
if(TH > 7) //负温度,前八位表示正负,0表式正
{
DS18B20_Measure.Temper_plus_minus = 1; //标记负温度
temper = (~temper) + 1; //求补码
}
else //正温度
{
DS18B20_Measure.Temper_plus_minus = 0; //标记正温度
}
DS18B20_Measure.Temperature = temper * 6250 / 10000; //温度计算 精度为0.625;
}
*************上述为DS18B20.C文件*******************
/*以下为DS18B20.H文件*/
#ifndef __DS18B20_H__
#define __DS18B20_H__
void DS18B20_In_Init(void);
void DS18B20_OUT_Init(void);
u8 DS18B20_Reset(void);
void DS18B20_ReadTemper(void);
typedef struct
{
u32 Temperature;
u8 Temper_plus_minus;
}DS18B20_MEASURE;
DS18B20_MEASURE DS18B20_Measure;
#endif
/*main.c*/
#include "Delay.h"
#include "OLED.H"
#include "DS18B20.H"
extern DS18B20_MEASURE DS18B20_Measure;
int main(void)
{
OLED_Init();
OLED_ShowString(1,1,"Zqz");
while(1)
{
DS18B20_ReadTemper();//读取温度
OLED_ShowChar(2,4,'.');
if(DS18B20_Measure.Temper_plus_minus==1) OLED_ShowChar(2,1,'-');//负的显示负号
else OLED_ShowChar(2,1,'+');
OLED_ShowNum(2,2,DS18B20_Measure.Temperature/10,2);//显示前两位
OLED_ShowNum(2,5,DS18B20_Measure.Temperature%10,1);//显示小数部分
}
}