diff --git a/gpio/dht_sensor/dht.c b/gpio/dht_sensor/dht.c index c9ce8748c..00683c50e 100644 --- a/gpio/dht_sensor/dht.c +++ b/gpio/dht_sensor/dht.c @@ -13,80 +13,199 @@ #define LED_PIN PICO_DEFAULT_LED_PIN #endif -const uint DHT_PIN = 15; -const uint MAX_TIMINGS = 85; - -typedef struct { +// Data memory +struct DHT_Data { float humidity; float temp_celsius; -} dht_reading; +}; + +// forward declarations +int8_t await_state(uint8_t state); +int8_t read_sensor_data(uint8_t *buffer, uint8_t size); +int8_t read_from_dht(struct DHT_Data *result); +void print_byte_as_bit(char value); -void read_from_dht(dht_reading *result); +// define constants +const int8_t SENSOR_READ_OK = 0; +const int8_t SENSOR_ERROR_CHECKSUM = -1; +const int8_t SENSOR_ERROR_TIMEOUT = -2; +const uint8_t READ_TIMEOUT = 100U; + +// DHT Pin +const uint DHT_PIN = 15; int main() { stdio_init_all(); gpio_init(DHT_PIN); + gpio_pull_up(DHT_PIN); #ifdef LED_PIN gpio_init(LED_PIN); gpio_set_dir(LED_PIN, GPIO_OUT); #endif + printf("\n\n === Pi Pico Example - Read DHTxx-Sensor === \n\n"); + // wait min. 2 s to power up the sensor (see darasheet) + sleep_ms(2000); + while (1) { - dht_reading reading; - read_from_dht(&reading); - float fahrenheit = (reading.temp_celsius * 9 / 5) + 32; - printf("Humidity = %.1f%%, Temperature = %.1fC (%.1fF)\n", - reading.humidity, reading.temp_celsius, fahrenheit); - sleep_ms(2000); +#ifdef LED_PIN + gpio_put(LED_PIN, 1); +#endif + struct DHT_Data dht_data; + int8_t status = read_from_dht(&dht_data); + +#ifdef LED_PIN + gpio_put(LED_PIN, 0); +#endif + + printf("Sensor-status: %d\n", status); + + if (status == SENSOR_READ_OK) { + float fahrenheit = (dht_data.temp_celsius * 9 / 5) + 32; + printf("Humidity = %.1f %%\tTemperature = %.1f degC (%.1f F)\n", + dht_data.humidity, dht_data.temp_celsius, fahrenheit); + } + else { + if (status == SENSOR_ERROR_CHECKSUM) { + printf("ERROR: Checksum not valid\n"); + } + else if (status == SENSOR_ERROR_TIMEOUT) { + printf("ERROR: Timeout overflow\n"); + } + } + printf("\n\n"); + sleep_ms(5000); } } -void read_from_dht(dht_reading *result) { - int data[5] = {0, 0, 0, 0, 0}; - uint last = 1; - uint j = 0; - +int8_t read_from_dht(struct DHT_Data *result) { gpio_set_dir(DHT_PIN, GPIO_OUT); + // start sequence min. 1 ms low then high gpio_put(DHT_PIN, 0); - sleep_ms(20); + sleep_us(1200U); + gpio_put(DHT_PIN, 1); gpio_set_dir(DHT_PIN, GPIO_IN); -#ifdef LED_PIN - gpio_put(LED_PIN, 1); -#endif - for (uint i = 0; i < MAX_TIMINGS; i++) { - uint count = 0; - while (gpio_get(DHT_PIN) == last) { - count++; - sleep_us(1); - if (count == 255) break; - } - last = gpio_get(DHT_PIN); - if (count == 255) break; + // await for the Acknowledge sequence + // wait for 80 µs lOW + await_state(0); + // wait for 80 µs HIGH + await_state(1); - if ((i >= 4) && (i % 2 == 0)) { - data[j / 8] <<= 1; - if (count > 16) data[j / 8] |= 1; - j++; + // Now read Sensor data + // start of time critical code + // create buffer + uint8_t data[5U] = {0}; + if (read_sensor_data(data, 5U) == SENSOR_ERROR_TIMEOUT) { + return SENSOR_ERROR_TIMEOUT; + } + // ==> END of time critical code <== + // check checksum + int8_t _checksum_ok = (data[4] == ( (data[0] + data[1] + data[2] + data[3]) & 0xFF) ); + //printf("Checksum_ok: %d\n", _checksum_ok); + + /* + // Code part to check the checksum + // Due to older sensors have an bug an deliver wrong data + int8_t d4 = data[4]; + int8_t cs = ( (data[0] + data[1] + data[2] + data[3]) & 0xFF); + printf("delivered Checksum: %d - ", d4); + print_byte_as_bit(d4); + printf("calculated Checksum: %d - ", cs); + print_byte_as_bit(cs); + */ + + if (_checksum_ok) { + uint16_t hum = (uint16_t)((data[0] << 8) | data[1]); + // check now if temperature is smaller than zero + int16_t temp = 0; + if (data[2] & 0x80) { + // found negative Temperature + data[2] &= 0x7f; + temp = -(int16_t)((data[2] << 8) | data[3]); + } + else { + temp = (int16_t)((data[2] << 8) | data[3]); } + result->humidity = hum * 0.1F; + result->temp_celsius = temp * 0.1F; + return SENSOR_READ_OK; } -#ifdef LED_PIN - gpio_put(LED_PIN, 0); -#endif + else { + return SENSOR_ERROR_CHECKSUM; + } +} - if ((j >= 40) && (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF))) { - result->humidity = (float) ((data[0] << 8) + data[1]) / 10; - if (result->humidity > 100) { - result->humidity = data[0]; +/** + * @brief wait for given state + * + * @param state + * @return int8_t state to wait for + */ +int8_t await_state(uint8_t state) { + uint8_t wait_counter = 0, state_counter = 0; + // count wait for state time + while ( (gpio_get(DHT_PIN) != state) ) { + ++wait_counter; + sleep_us(1U); + if (wait_counter >= READ_TIMEOUT) { + return SENSOR_ERROR_TIMEOUT; } - result->temp_celsius = (float) (((data[2] & 0x7F) << 8) + data[3]) / 10; - if (result->temp_celsius > 125) { - result->temp_celsius = data[2]; + } + // count state time + while ( (gpio_get(DHT_PIN) == state) ) { + ++state_counter; + sleep_us(1U); + if (state_counter >= READ_TIMEOUT) { + return SENSOR_ERROR_TIMEOUT; } - if (data[2] & 0x80) { - result->temp_celsius = -result->temp_celsius; + } + return (state_counter > wait_counter); +} + +/** + * @brief read sensor data + * + * @param buffer data buffer of 40 bit + * @param size of buffer => 5 Byte + * @return int8_t + */ +int8_t read_sensor_data(uint8_t *buffer, uint8_t size) { + for (uint8_t i = 0; i < size; ++i) { + for (uint8_t bit = 0; bit < 8; ++bit) { + uint8_t wait_counter = 0, state_counter = 0; + // count wait for state time + while ( !gpio_get(DHT_PIN) ) { + ++wait_counter; + sleep_us(1U); + if (wait_counter >= READ_TIMEOUT) { + return SENSOR_ERROR_TIMEOUT; + } + } + // count state time + while ( gpio_get(DHT_PIN) ) { + ++state_counter; + sleep_us(1U); + if (state_counter >= READ_TIMEOUT) { + return SENSOR_ERROR_TIMEOUT; + } + } + buffer[i] <<= 1; + buffer[i] |= (state_counter > wait_counter); } - } else { - printf("Bad data\n"); } + return SENSOR_READ_OK; +} + +/** + * @brief helper function to print byte as bit + * + * @param value byte with 8 bits + */ +void print_byte_as_bit(char value) { + for (int i = 7; i >= 0; --i) { + char c = (value & (1 << i)) ? '1' : '0'; + printf("%c", c); + } + printf("\n"); }