#include "ds18b20.h"
#include "common.h"




void DS18B20_IO_IN(void)
{
    DQ_IN();  // 设置为上拉输入模式
}


void  DS18B20_IO_OUT(void)
{
    GPIOD->CRH &= ~(0xF << 16);  // 清除配置位
    GPIOD->CRH |= (0x3 << 16);   // 设置为推挽输出模式
}

void DS18B20_Rst(void)
{
    DS18B20_IO_OUT();
    DS18B20_DQ_OUT_LOW; // 拉低DQ
    delay_us(750);  // 延时750微秒
    DS18B20_DQ_OUT_HIGH; // 释放DQ
    delay_us(15);   // 延时15微秒
}

uint8_t DS18B20_Check(void)
{
    uint8_t retry = 0;
    DS18B20_IO_IN();
    while (DS18B20_DQ_IN && retry < 200) // 等待DS18B20拉低电平
    {
        retry++;
        delay_us(1);
    }
    if (retry >= 200)
        return 1;
    else
        retry = 0;

    while (!DS18B20_DQ_IN && retry < 240)
    {
        retry++;
        delay_us(1);
    }
    if (retry >= 240)
        return 1;

    return 0;
}

uint8_t DS18B20_Read_Bit(void)
{
    uint8_t data;
    DS18B20_IO_OUT();
    DS18B20_DQ_OUT_LOW;
    delay_us(2);

    DS18B20_DQ_OUT_HIGH;
    DS18B20_IO_IN();
    delay_us(12);

    if (DS18B20_DQ_IN)
        data = 1;
    else
        data = 0;

    delay_us(50);
    return data;
}


uint8_t DS18B20_Read_Byte(void)
{
    uint8_t i, j, data;
    data = 0;
    for (i = 1; i <= 8; i++)
    {
        j = DS18B20_Read_Bit();
        data = (j << 7) | (data >> 1);
    }
    return data;
}




void DS18B20_Write_Byte(uint8_t data)
{
    uint8_t j;
    uint8_t testb;
    DS18B20_IO_OUT(); // 输出模式
    for (j = 1; j <= 8; j++)
    {
        testb = data & 0x01;
        data = data >> 1;
        if (testb)
        {
            DS18B20_DQ_OUT_LOW; // 拉低至少1微秒
            delay_us(2);

            DS18B20_DQ_OUT_HIGH;
            delay_us(60);

        }
        else
        {
            DS18B20_DQ_OUT_LOW; // 写0 至少拉低60微秒
            delay_us(60);

            DS18B20_DQ_OUT_HIGH; // 释放总线 至少1微秒
            delay_us(2);

        }
    }
}


void DS18B20_Start(void)
{
    DS18B20_Rst();
    DS18B20_Check();
    DS18B20_Write_Byte(0xCC);
    DS18B20_Write_Byte(0x44);
}


uint8_t DS18B20_Init(void)
{

    DS18B20_Rst();
    return DS18B20_Check();
}


short DS18B20_Get_Temperature(void)
{
    uint8_t TL, TH;
    short temperature;

    DS18B20_Start();
    DS18B20_Rst();
    DS18B20_Check();
    DS18B20_Write_Byte(0xCC);
    DS18B20_Write_Byte(0xBE);
    TL = DS18B20_Read_Byte();
    TH = DS18B20_Read_Byte();

    if (TH > 7)
    {
        TH = ~TH;
        TL = ~TL;
        temperature = -1;
    }
    else
        temperature = 1;

    temperature = (TH << 8) | TL;
    temperature = (float)temperature * 0.625;

    return temperature;
}
