/*
|
* ds18b20.c
|
*
|
* Created on: 2021年8月17日
|
* Author: Think
|
*/
|
#include "main.h"
|
#include "miscdev.h"
|
|
typedef struct w1_gpio_s
|
{
|
GPIO_TypeDef *group;
|
uint16_t pin;
|
} w1_gpio_t;
|
|
static w1_gpio_t W1Dat = /* IO pin connected to PA12 */
|
{
|
.group = GPIOA,
|
.pin = GPIO_PIN_12,
|
};
|
|
#define W1DQ_Input() \
|
{ \
|
GPIO_InitTypeDef GPIO_InitStruct = {0}; \
|
GPIO_InitStruct.Pin = W1Dat.pin; \
|
GPIO_InitStruct.Mode = GPIO_MODE_INPUT; \
|
GPIO_InitStruct.Pull = GPIO_PULLUP; \
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; \
|
HAL_GPIO_Init(W1Dat.group, &GPIO_InitStruct); \
|
}
|
|
#define W1DQ_Output() \
|
{ \
|
GPIO_InitTypeDef GPIO_InitStruct = {0}; \
|
GPIO_InitStruct.Pin = W1Dat.pin; \
|
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; \
|
GPIO_InitStruct.Pull = GPIO_NOPULL; \
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; \
|
HAL_GPIO_Init(W1Dat.group, &GPIO_InitStruct); \
|
}
|
|
#define W1DQ_Write(x) HAL_GPIO_WritePin(W1Dat.group, W1Dat.pin, \
|
(x==1)?GPIO_PIN_SET:GPIO_PIN_RESET)
|
|
#define W1DQ_Read() HAL_GPIO_ReadPin(W1Dat.group, W1Dat.pin)
|
|
|
/* Master issues reset pulse and DS18B20s respond with presence pulse */
|
uint8_t ds18b20_reset(void)
|
{
|
uint8_t rv = 0;
|
uint8_t retry;
|
|
/* Setup W1 DQ pin as output and high level*/
|
W1DQ_Output();
|
W1DQ_Write(1);
|
delay_us(2);
|
|
/* Reset pulse by pulling the DQ pin low >=480us */
|
W1DQ_Write(0);
|
delay_us(480);
|
|
/* Master releases bus to high. When DS18B20 detects this rising edge, it waits 15µs to 60µs */
|
W1DQ_Write(1);
|
delay_us(60);
|
|
/* Then DS18B20 transmits a presence pulse by pulling the W1 bus low for 60µs to 240µs */
|
while( W1DQ_Read() && retry <240)
|
{
|
retry++;
|
delay_us(1);
|
}
|
|
if(retry >= 240)
|
rv = 1;
|
|
delay_us(240);
|
|
/* Master Rx time must >= 480us */
|
W1DQ_Output();
|
W1DQ_Write(1);
|
delay_us(240);
|
|
return rv;
|
}
|
|
void ds18b20_write(uint8_t byte)
|
{
|
uint8_t i = 0;
|
|
W1DQ_Output();
|
|
for(i=0; i<8; i++)
|
{
|
/* Write 1: pull low <= 15us, Write 0: pull low 15~60us*/
|
W1DQ_Write(0);
|
delay_us(10);
|
|
/* DS18B20 bit sent by LSB (lower bit first) */
|
if( byte & 0x1 )
|
W1DQ_Write(1);
|
else
|
W1DQ_Write(0);
|
|
/* Write 1/0 slot both >= 60us, hold the level for 60us */
|
delay_us(60);
|
|
/* Release W1 bus to high */
|
W1DQ_Write(1);
|
delay_us(2);
|
|
/* Prepare for next bit */
|
byte >>= 1;
|
}
|
}
|
|
|
uint8_t ds18b20_read(void)
|
{
|
uint8_t i = 0;
|
uint8_t byte = 0;
|
|
for(i=0; i<8; i++)
|
{
|
/* Read time slot is initiated by master pulling the W1 bus
|
* low for minimum of 1µs and then releasing the bus */
|
W1DQ_Output();
|
W1DQ_Write(0);
|
delay_us(2);
|
W1DQ_Write(1);
|
delay_us(2);
|
|
/* After master initiates read time slot, DS18B20 will begin
|
* transmitting a 1 or 0 on bus */
|
W1DQ_Input();
|
|
/* DS18B20 bit sent by LSB (lower bit first) */
|
if( W1DQ_Read() )
|
{
|
byte |= 1<<i;
|
}
|
|
/* Read slot for >= 60us */
|
delay_us(60);
|
|
/* Release W1 bus to high */
|
W1DQ_Output();
|
W1DQ_Write(1);
|
delay_us(2);
|
}
|
|
return byte;
|
}
|
|
static inline int ds18b20_start_convert(void)
|
{
|
/* Master issues reset pulse and DS18B20s respond with presence pulse */
|
if( 0 != ds18b20_reset() )
|
return -1;
|
|
/* Master issues Skip ROM command */
|
ds18b20_write(0xCC);
|
|
/* Master issues Convert T command. */
|
ds18b20_write(0x44);
|
|
return 0;
|
}
|
|
static inline int ds18b20_start_read(uint8_t *buf, int bytes)
|
{
|
/* Master issues reset pulse and DS18B20s respond with presence pulse */
|
if( 0 != ds18b20_reset() )
|
return -1;
|
|
/* Master issues Skip ROM command */
|
ds18b20_write(0xCC);
|
|
/* Master issues Read Scratchpad command. */
|
ds18b20_write(0xBE);
|
|
buf[0] = ds18b20_read(); /* Temperature LSB */
|
buf[1] = ds18b20_read(); /* Temperature MSB */
|
|
/*Don't care followed 7 bytes data */
|
|
return 0;
|
}
|
|
int ds18b20_sample(float *temperature)
|
{
|
uint8_t byte[2];
|
uint8_t sign;
|
uint16_t temp;
|
static uint8_t firstin = 1;
|
|
if( !temperature )
|
return -1;
|
|
if( 0 != ds18b20_start_convert() )
|
return -2;
|
|
/* First sample need 750ms delay */
|
if( firstin )
|
{
|
HAL_Delay(750);
|
firstin = 0;
|
}
|
|
if( 0 != ds18b20_start_read(byte, 2) )
|
return -3;
|
|
/* Temperature byte[0] is LSB, byte[1] is MSB, total 16 bit:
|
* Byte[0]: bit[3:0]: decimal bits, bit[7:4]: integer bits
|
* bYTE[1]: bit[2:0]: integer bits, bit[7:3]: sign bits
|
*/
|
if( byte[1]> 0x7 ) /* bit[7:3] is 1 */
|
{
|
temp = ~(byte[1]<<8|byte[0]) + 1; //补码
|
sign=0; //温度为负
|
}
|
else
|
{
|
sign=1;//温度为正
|
temp = byte[1]<<8 | byte[0];
|
}
|
|
/* byte[1]的低三位和byte[0]的高四位组成温度值的整数部分,
|
* 而byte[0]的低四位为小数精度部分,且精度系数为0.0625 */
|
*temperature = (temp>>4) + (temp&0xF)*0.0625 ;
|
if( !sign )
|
{
|
*temperature = -*temperature;
|
}
|
|
return 0;
|
}
|