#include "ds18b20.h"
#include "delay.h"
#include "sys.h"
/*****************************************************************
DS18B20指令
1.温度转换指令:0x44(即44H),启动Ds18b20启动转换温度
2.读暂存器指令:0xBE(即BEH),读取暂存器中的九字节数据
3.写暂存器置零:0x4E(即4EH),把数据写入暂存器的MSB、LSB
4.赋值暂存器:0x48(即48H),把暂存器中的MSB、LSB写入EEPROM中
5.读电源供电方式:0xB4(即B4H):启动Ds18b20,发送电源供电方式
6.重调EEPROM:0xB8(即B8H):把EEPROM中的MSB、LSB读至暂存器
*****************************************************************/
#define Ds18b20_Out PGout(6) /* 输出 */
#define Ds18b20_In PGin(6) /* 输入 */
//CRC = X8 + X5 + X4 + 1
const u8 Crc8Table [256]={
0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,
17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,
175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238,
50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53};
/* 说明
* __Ds18b20_Set_Input
* 参数: 无
* 返回值: 无
* 功能设置DS18B20的GPIO_Pin_6为输入
*/
static void __Ds18b20_Set_Input(void)
{
//定义一个初始化结构体
GPIO_InitTypeDef GPIO_InitDATAuct;
//使能GPIO G组时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
GPIO_InitDATAuct.GPIO_Pin = GPIO_Pin_6; //引脚6
GPIO_InitDATAuct.GPIO_Mode = GPIO_Mode_IN; //输出
GPIO_InitDATAuct.GPIO_OType = GPIO_OType_PP; //开漏
GPIO_InitDATAuct.GPIO_Speed = GPIO_Speed_100MHz; //100MHZ速度
GPIO_InitDATAuct.GPIO_PuPd = GPIO_PuPd_NOPULL; //上拉
GPIO_Init(GPIOG, &GPIO_InitDATAuct);
}
/* 说明
* __Ds18b20_Set_Output
* 参数: 无
* 返回值: 无
* 设置DS18B20的GPIO_Pin_6为输出
*/
static void __Ds18b20_Set_Output(void)
{
//定义一个初始化结构体
GPIO_InitTypeDef GPIO_InitDATAuct;
//使能GPIO G组时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
GPIO_InitDATAuct.GPIO_Pin = GPIO_Pin_6; //引脚6
GPIO_InitDATAuct.GPIO_Mode = GPIO_Mode_OUT; //输出
GPIO_InitDATAuct.GPIO_OType = GPIO_OType_OD; //开漏
GPIO_InitDATAuct.GPIO_Speed = GPIO_Speed_100MHz; //100MHZ速度
GPIO_InitDATAuct.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOG, &GPIO_InitDATAuct);
}
/* 说明
* DS18B20复位
* 参数: 无
* 返回值: 无
* 功能复位DS18B20
*/
static void __Ds18b20_Reset(void)
{
/* MCU:
* 每次读写前对 DS18B20 进行复位初始化
* 复位要求主 CPU 将数据线下拉 500us ,然后释放
*/
__Ds18b20_Set_Output(); //设置引脚为输出
Ds18b20_Out = 0; //输出低电平
delay_us(480); //延时500us
Ds18b20_Out=1; //输出高电平
delay_us(15); //延时15us
}
/* 说明
* DS18B20应答
* 参数: 无
* 返回值: (0为DS18B20响应)、(1为错误响应或不响应)
* 功能判断DS18B20是否应答
*/
static u8 __Ds18b20_Answer(void)
{
/*
* DS18B20 收到信号后等待 16us~60us 左右,然后发出60us~240us 的存在低脉冲,
* 主 CPU 收到此信号后表示复位成功
*/
int waitingTime=0;
__Ds18b20_Set_Input(); //设置引脚为输入
//第三步
for(;waitingTime<45;waitingTime++)
{
if(Ds18b20_In == 0)
break;
delay_us(1);
}
if(waitingTime>45)
return 1;
//printf("waitingTime = %d\n",waitingTime); //用于调试
waitingTime = 0; //等待时间清零
//第四步
for(;waitingTime<250;waitingTime++)
{
if(Ds18b20_In == 1)
break;
delay_us(1);
}
if(waitingTime>240||waitingTime<60)
return 1;
//printf("waitingTime = %d\n",waitingTime); //用于调试
return 0;
}
/* 说明
* DS18B20初始化
* 参数: 无
* 返回值: (0为DS18B20响应)、(1为错误响应或不响应)
* 功能初始化DS18B20并检测DS18B20是否响应
*/
u8 Ds18b20_Init(void)
{
/* MCU:
* 主机首先发出一个480-960微秒的低电平脉冲,然后释放总线变为高电平,
* 并在随后的480微秒时间内对总线进行检测,如果有低电平出现说明总线上有器件已做出应答。
* 若无低电平出现一直都是高电平说明总线上无器件应答。
* 器件:
* 做为从器件的DS18B20在一上电后就一直在检测总线上是否有480-960微秒的低电平出现
* 如果有,在总线转为高电平后等待15-60微秒后将总线电平拉低60-240微秒做出响应存在脉冲
* 告诉主机本器件已做好准备。若没有检测到就一直在检测等待
*/
__Ds18b20_Set_Output(); //设置为输出
__Ds18b20_Reset(); //进行复位
return __Ds18b20_Answer(); //判断应答
}
/* 说明
* __Ds18b20_Write_Bit
* 参数: 0或1
* 返回值: 无
* 功能,向DS18B20写一个位
*/
static void __Ds18b20_Write_Bit(u8 bit)
{
/* MCU:
* 写周期最少为60微秒,最长不超过120微秒
* 写周期一开始做为主机先把总线拉低1微秒表示写周期开始
* 随后若主机想写0,则继续拉低电平最少60微秒直至写周期结束,然后释放总线为高电平
* 器件
* 若主机想写1,在一开始拉低总线电平1微秒后就释放总线为高电平,一直到写周期结束
* 器件:
* 而做为从机的DS18B20则在检测到总线被拉底后等待15微秒然后从15us到45us开始对总线采样
* 在采样期内总线为高电平则为1,若采样期内总线为低电平则为0
*/
__Ds18b20_Set_Output(); //设置为输出
Ds18b20_Out = 0; //输出低电平
delay_us(1); //延时1us
if(bit)
Ds18b20_Out = 1; //输出高电平
delay_us(60); //延时60us
Ds18b20_Out=1;
delay_us(5);
}
/* 说明
* __Ds18b20_Read_Bit
* 参数: 无
* 返回值: 0或1、(2为错误数据)
* 功能,从DS18B20读一个位
*/
static u8 __Ds18b20_Read_Bit(void)
{
/* MCU:
* 对于读数据操作时序也分为读0时序和读1时序两个过程。
* 读时隙是从主机把单总线拉低之后,在1微秒之后就得释放单总线为高电平,
* 以让DS18B20把数据传输到单总线上。
* DS18B20在检测到总线被拉低1微秒后,便开始送出数据,
* 若是要送出0就把总线拉为低电平直到读周期结束。
* 若要送出1则释放总线为高电平。
* 主机在一开始拉低总线1微秒后释放总线,
* 然后在包括前面的拉低总线电平1微秒在内的15微秒时间内完成对总线进行采样检测,
* 采样期内总线为低电平则确认为0。
* 采样期内总线为高电平则确认为1。
* 完成一个读时序过程,至少需要60us才能完成
*/
u8 sampling[14];
u8 sampling_flag = 0;
__Ds18b20_Set_Output(); //设置为输出
Ds18b20_Out=0; //输出低电平
delay_us(1); //延时1us
Ds18b20_Out=1; //输出高电平
__Ds18b20_Set_Input(); //设置成输入模式
for(int i=0;i<14;i++)
{
if(Ds18b20_In)
sampling[i] = 1;
else sampling[i] = 0;
delay_us(1); //延时1us
}
for(int i=0;i<14;i++) //根据检测判断数据是否有误
if(1 == sampling[i])
sampling_flag++;
delay_us(50); //延时50us
if(0==sampling_flag)
return 0;
else if(14 == sampling_flag)
return 1;
else return 2;
}
/* 说明
* Ds18b20_Write_Byte
* 参数: data:数据
* 返回值: 无
* 功能,向DS18B20写一个字节
*/
void Ds18b20_Write_Byte(u8 data)
{
for(;data!=0;data>>=1)
__Ds18b20_Write_Bit(data&0x01);
}
/* 说明
* Ds18b20_Read_Byte
* 参数: 无
* 返回值: 读取的字节
* 功能,从DS18B20读一个字节
*/
u8 Ds18b20_Read_Byte(void)
{
u8 data = 0;
for(u8 i=1;i<=8;i++)
{
data>>=1;
data+=(__Ds18b20_Read_Bit()<<7);
}
return dat