· 

16.温度センサープロジェクト(6)DHT-22ーRaspberry Pi Pico WindowsC言語入門

13.6.DHT-22による温度、湿度計測

プロジェクト名:TempDHT22

プロジェクトの概要

DHT-22温度センサーによる温度計測プロジェクトです。Picoとの通信は専用の1線のシリアル通信です。通信距離は5.1kΩプルアップ時、最大30mです。仕様は以下です。

電源電圧:5V(3.5V~5.5V)

内部ADコンバータ:各16bit

湿度センサ測定範囲:0~99.9%RH・精度:±2% RH(@25℃)

温度センサ測定範囲:-40~+80℃・精度:±0.5℃

出力データ:湿度16bit(分解能:0.1%RH)、温度16bit(分解能:0.1℃)

DHT-22との接続は以下で、電源、ロジックは3.3Vで使用しています。

       DHT-22                               Pico

DAT                                     GPIO10

       VCC                                     3.3V

        GND                                   GND

DHT-22側にプルアップ抵抗4.7KDATラインに入れています。長距離接続の場合、ノイズに強くなります。

 

部品リスト

DHT22 温湿度センサーモジュール                    1             アマゾン

GROVE16 x 2 LCD                                                      スイッチサイエンス

 

 

配線図

ソースリスト

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include "pico/stdlib.h"

#include "hardware/i2c.h"

#include "hardware/rtc.h"

#include "hardware/adc.h"

 

//#define PICO_DEFAULT_LED_PIN 25

#define LED_PIN PICO_DEFAULT_LED_PIN

#define I2C_PORT i2c0

#define I2C_SDA 8

#define I2C_SCL 9

#define DHT_PIN 10

 

//ADc

const float ConversionFactor = 3.3f / (1 << 12);

 

int WaitTerminalStartup(int timeout_msec) {

    int btnin;

    uint32_t st = time_us_32();

    while(true)

    {

        if(stdio_usb_connected())

        {

            return 0;

        }  

        if(timeout_msec != 0){

            uint32_t cur = time_us_32();

            if((cur - st) > (timeout_msec*1000)) {

                return 0;

            }

        }

        gpio_put(LED_PIN, 1);

        sleep_ms(200);

        gpio_put(LED_PIN, 0);

        sleep_ms(200);

    }

}

void ScanI2CBus() {

    printf("\nI2C Bus Scan\n");

    printf("   0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F\n");

    for (int addr = 0; addr < (1 << 7); ++addr) {

        if (addr % 16 == 0) {

            printf("%02x ", addr);

        }

        int ret;

        uint8_t rxdata;

        ret = i2c_read_blocking(I2C_PORT, addr, &rxdata, 1, false);

        sleep_ms(10);

 

        printf(ret < 0 ? "-" : "*");

        printf(addr % 16 == 15 ? "\n" : "  ");

    }

}

 

void InitAdc()

{

    adc_init();

    adc_set_temp_sensor_enabled(true);

}

 

float ReadOnBoardTemperature()

{

    adc_select_input(4);

    float tempV = (float)adc_read() * ConversionFactor;

    float tempC = 27.0f - (tempV - 0.706f) / 0.001721f;

    return tempC;

}

 

void InitRtc()

{

    char datetime_buf[256];

    char *datetime_str = &datetime_buf[0];

 

    //Start on 2023/5/9 Tuesday 10:24:00

    datetime_t t = {

            .year  = 2023,

            .month = 5,

            .day   = 9,

            .dotw  = 2, // 0:Sunday - 5:Friday

            .hour  = 10,

            .min   = 24,

            .sec   = 00

    };

 

    rtc_init();

    rtc_set_datetime(&t);

    sleep_ms(1);

}

 

//dht22-----------------------------

void WaitFallingEdge() {

    while(gpio_get(DHT_PIN) == 0){};

    while(gpio_get(DHT_PIN) == 1){};

}

uint32_t getData(){

    uint32_t t2;

    uint32_t data = 0;

    uint32_t t1 = time_us_32();

    for (int i = 0; i < 32; i++) {

        WaitFallingEdge();

        t2 = time_us_32();

        data = data << 1;

        data = data | ((t2 - t1) > 100);

        t1 = t2;    

    }

    return data;

}

 

uint8_t getCheck(){

    uint8_t checksum = 0;

    uint32_t t2;

    uint32_t t1 = time_us_32();

    for (int i = 0; i < 8; i++) {

        WaitFallingEdge();

        t2 = time_us_32();

        checksum = checksum << 1;

        checksum = checksum  | ((t2 - t1) > 100);

        t1 = t2;

    }

    return checksum;

}

 

void dhtInitialize(){

    gpio_init(DHT_PIN);

    gpio_set_dir(DHT_PIN, GPIO_OUT);

   

    gpio_put(DHT_PIN, 1);

    sleep_ms(1);

    gpio_put(DHT_PIN, 0);

    sleep_ms(1);

 

    gpio_set_dir(DHT_PIN, GPIO_IN);

    WaitFallingEdge();

    WaitFallingEdge();

}

typedef struct {

    float temperature;

    float humidity;

    bool error;

} dhtData;

void dhtRead(dhtData *reading){

    dhtInitialize();

    uint32_t data = getData();

    uint8_t checksum = getCheck();

 

    uint8_t byte1 = data >> 24 & 0xFF;

    uint8_t byte2 = data >> 16 & 0xFF;

    uint8_t byte3 = data >> 8 & 0xFF;

    uint8_t byte4 = data & 0xFF;

 

    reading->error = (checksum != ((byte1 + byte2 + byte3 + byte4) & 0xFF));

    reading->humidity = (float)((byte1 << 8) | byte2)/10.0;

 

    int neg = byte3 & 0x80;

    byte3 = byte3 & 0x7F;

    reading->temperature = (float)((byte3 << 8) | byte4)/10.0;

    if(neg > 0){

        reading->temperature = -reading->temperature;

    }

}

 

//lcd -------------------------------

#define LCD_ADDR 0x27

// commands

const int LCD_CLEARDISPLAY = 0x01;

const int LCD_RETURNHOME = 0x02;

const int LCD_ENTRYMODESET = 0x04;

const int LCD_DISPLAYCONTROL = 0x08;

const int LCD_CURSORSHIFT = 0x10;

const int LCD_FUNCTIONSET = 0x20;

const int LCD_SETCGRAMADDR = 0x40;

const int LCD_SETDDRAMADDR = 0x80;

 

//display entry mode

const int LCD_ENTRYSHIFTINCREMENT = 0x01;

const int LCD_ENTRYLEFT = 0x02;

 

//display and cursor control

const int LCD_BLINKON = 0x01;

const int LCD_CURSORON = 0x02;

const int LCD_DISPLAYON = 0x04;

 

//display and cursor shift

const int LCD_MOVERIGHT = 0x04;

const int LCD_DISPLAYMOVE = 0x08;

 

//function set

const int LCD_5x10DOTS = 0x04;

const int LCD_2LINE = 0x08;

const int LCD_8BITMODE = 0x10;

 

//backlight control

const int LCD_BACKLIGHT = 0x08;

const int LCD_ENABLE_BIT = 0x04;

 

#define LCD_CHARACTER  1

#define LCD_COMMAND    0

//#define MAX_LINES      2

//#define MAX_CHARS      16

#define MAX_LINES      2

#define MAX_CHARS      16

#define DELAY_US 600

 

void i2c_write_byte(uint8_t val) {

    i2c_write_blocking(I2C_PORT, LCD_ADDR, &val, 1, false);

}

void lcd_toggle_enable(uint8_t val) {

    sleep_us(DELAY_US);

    i2c_write_byte(val | LCD_ENABLE_BIT);

    sleep_us(DELAY_US);

    i2c_write_byte(val & ~LCD_ENABLE_BIT);

    sleep_us(DELAY_US);

}

void lcd_send_byte(uint8_t val, int mode) {

    uint8_t high = mode | (val & 0xF0) | LCD_BACKLIGHT;

    uint8_t low = mode | ((val << 4) & 0xF0) | LCD_BACKLIGHT;

 

    i2c_write_byte(high);

    lcd_toggle_enable(high);

    i2c_write_byte(low);

    lcd_toggle_enable(low);

}

void lcd_clear(void) {

    lcd_send_byte(LCD_CLEARDISPLAY, LCD_COMMAND);

}

void lcd_set_cursor(int line, int position) {

    int addr[4] = {0x80, 0xc0, 0x94, 0xd4};

    int val = addr[line] + position;

    lcd_send_byte(val, LCD_COMMAND);

}

static void inline lcd_char(char val) {

    lcd_send_byte(val, LCD_CHARACTER);

}

void lcd_string(const char *s) {

    while(true) {

        if(*s == 0) {

            break;

        }

        lcd_char(*s);

        s++;

    }

}

void lcd_init() {

    lcd_send_byte(0x03, LCD_COMMAND);

    lcd_send_byte(0x03, LCD_COMMAND);

    lcd_send_byte(0x03, LCD_COMMAND);

    lcd_send_byte(0x02, LCD_COMMAND);

 

    lcd_send_byte(LCD_ENTRYMODESET | LCD_ENTRYLEFT, LCD_COMMAND);

    lcd_send_byte(LCD_FUNCTIONSET | LCD_2LINE, LCD_COMMAND);

    lcd_send_byte(LCD_DISPLAYCONTROL | LCD_DISPLAYON, LCD_COMMAND);

    lcd_clear();

}

 

int main()

{

    stdio_init_all();

 

    gpio_init(LED_PIN);

    gpio_set_dir(LED_PIN, GPIO_OUT);

    gpio_put(LED_PIN, 0);

   

    i2c_init(I2C_PORT, 400*1000);

    gpio_set_function(I2C_SDA, GPIO_FUNC_I2C);

    gpio_set_function(I2C_SCL, GPIO_FUNC_I2C);

    gpio_pull_up(I2C_SDA);

    gpio_pull_up(I2C_SCL);

 

    WaitTerminalStartup(30*1000);

    printf("\nTerminal connected\n");

    ScanI2CBus();   

    printf("I2C Scan completed\n");

 

    lcd_init();

    InitAdc();

    InitRtc();

 

    char buf[128];

    datetime_t nowdt;

    int presec = -1;

    dhtData readData;

    while (1) {

        rtc_get_datetime(&nowdt);

        if(presec != nowdt.sec)

        {

            float bTemp = ReadOnBoardTemperature();

            dhtRead(&readData);

 

            sprintf(buf, "%02d:%02d:%02d AD:%4.1f", nowdt.hour,nowdt.min, nowdt.sec, bTemp);

            lcd_set_cursor(0, 0);

            lcd_string(buf);

 

            if(!readData.error) {

                sprintf(buf, "     %4.1fC %4.1f%%", readData.temperature, readData.humidity);

                printf("%4d/%02d/%02d %02d:%02d:%02d DhtTemp:%4.1fC AdcTemp:%4.1fC DhtHumi:%4.1f%%\n", 

                        nowdt.year, nowdt.month, nowdt.day,

                        nowdt.hour,nowdt.min, nowdt.sec, readData.temperature, bTemp, readData.humidity);

            } else {

                sprintf(buf, "Checksum error! ");   

                printf("Checksum error\n");

            }

            lcd_set_cursor(1, 0);

            lcd_string(buf);

        }

        presec = nowdt.sec;

        sleep_ms(200);

    }

    return 0;

 

}

温度データは変動が少なく、安定しており、精度は良いと思われます。