/********************************************************************** * Copyright: (C)2023 LingYun IoT System Studio * Author: GuoWenxue QQ: 281143292 * Description: ISKBoard DS18B20 temperature sensor Hardware Abstract Layer driver * * ChangeLog: * Version Date Author Description * V1.0.0 2023.04.3 GuoWenxue Release initial version ***********************************************************************/ #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<= 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; }