温度・湿度センサーの経年劣化について

[公開:any]

[電子工作/AVR]
[HDC1000,SHT31,SHT11,DHT22,RHT03,AVR,湿度計]

origin 2017-04-28


秋月電子のサイトを見ていたら、SHT31の取り扱いが始まっていました(発売日は2017-06-14)。価格も950円と手ごろです。(2017-06-22追記)


 温度・湿度センサーのDHT22(RHT03)の経年劣化については、「DHT22を使った温度計・湿度計の製作」でレポートしていますが、およそ1年で湿度が高めに測定される経年劣化が見られました。(使用方法に問題がある可能性は排除できませんが、使用環境については室内使用なので問題は少ないと思います。)

温湿度センサーDHT22

 これまで使用したセンサーでは、ストロベリーリナックスで取り扱いのあるSHT11が良いのはわかっていますが、価格が高いので秋月電子で取り扱いの始まったHDC1000を使用したところ、SHT11と近い値が測定され精度も十分であることが確認できました。HDC1000は価格も手ごろなので「HDC1000を使った温度計・湿度計の製作」で新たに製作すると同時に既存のDHT22を使用した温湿度計もこのセンサーに変更しました。

 HDC1000の使用を始めたのが2015年7月頃なのであれから1年半以上経過した2017年の3月頃に、家族から「今年の冬は部屋が乾燥することがなくて加湿器をほとんど使用しなかった」と聞かされました。部屋が乾燥したかどうかをHDC1000を使用した温湿度計で見ていたようです。・・・暖房器具(エアコン)を同じように使用していたのに例年よりも湿度が高かったとは思えません。HDC1000の測定する湿度を検証してみました。SHT11を使用したもの2台と比較すると湿度が20%近く高めに測定されます。これは、使用していたHDC1000の2つともほぼ同じように表示されます。

HDC1000

 予備として買い置きしてあった新品のHDC1000に交換してみると今度はSHT11に比較して10%以上低く測定されます。新品と古いものとの差は30~40%もあります。・・ということで、まずはっきりしたことは「HDC1000は経年劣化(1年半ほど)で湿度が高く測定されるようになる」ということです。ただ、SHT11も経年劣化している可能性もあるので、HDC1000の新品とSHT11のどちらが正しいかはっきりはわかりません。


 このままHDC1000を使用しても1年半後にはダメになることがわかったので別のセンサーを使用することにします。SHT11を取り扱っているストロベリーリナックスで同じセンシリオン社のSHT31というセンサーが発売されています。このセンサーをHDC1000の代わりに使用することにします。2台のセンサーを交換してプログラム変更を行います。SHT31はHDC1000と同じI2Cによる制御なのでプログラム変更も簡単にできます。SHT31は、SHT11と比較してみると湿度が6%程度低く測定されます。

温湿度センサー SHT31

 実際の設置場所でSHT31、SHT11と乾湿計の比較観測を行いました。数日間、状況を見ましたが、気温はどれもほぼ同じ値となります。湿度は、SHT11よりもSHT31が6~7%程度高めに測定されます。乾湿計による湿度の値は、SHT11に近似します。(画像の撮影時には乾球19.5℃、湿球14℃なので湿度54%程度となります。)
 SHT11を最初に使用したのは2009年です。その後、2011年と2014年にも追加購入し、現在も4個のセンサーを使用していますが、並べて比較するといずれのセンサーも測定値が近似します。つまり、センサーの経年劣化は極めて小さいと判断できます。

温湿度センサー SHT31

 これまで使用した温度・湿度センサーについてまとめてみました。値段を調べるために秋月電子でHDC1000を探したのですが、取り扱いがなくなっていました(2017年4月28日現在)。SHT31の長期評価はでていませんが、SHT11とSHT31の価格差は400円程度です。趣味で数個使用する程度であればSHT11を使用したほうが良いと思われます。ただし、SHT11は変則的(I2Cライク)なシリアル通信です。プログラミングは、正式にI2Cに対応したSHT31が簡単です。

型名 メーカー 価格(円) 購入先 精度(短期) 精度(長期) 備考
CHS-UGR TDK 3456(共立電子) 忘れました 不明 湿度のみ
HS-15P General Electric Company(GE) 500 秋月電子 不明 湿度のみ
SHT11 Sensirion 2095 ストロベリーリナックス
DHT22(RHT03) MaxDetect 940 ストロベリーリナックス ×(1年程度)
HDC1000 Texas Instrument 680 秋月電子 ×(1年半程度)
SHT31 Sensirion 1680 ストロベリーリナックス 評価中

 今回使用したプログラムソースです。I2C関連はHDC1000の製作時と同じです。AVRはATmega88Pを対象としたものです。もう1台はATTiny861Aを使用したものですが、I2Cライブラリが異なるだけでSHT31制御関連はほぼ同じです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/*
 * sht-31_temp_hum.c
 *
 * Created: 2017/04/15 14:15:03
 *  Author: www.henteko.org
 */ 

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdlib.h>

#include "i2c.h"

unsigned int seg[6];
unsigned int mx;
unsigned int temp, humd;

#define SHT31_I2C_ADDR    0x44
#define cbi(addr, bit)     addr &= ~(1<<bit)
#define sbi(addr, bit)     addr |=  (1<<bit)

// milisecond order delay
void delay_ms(unsigned int t)
{
    while(t--)
        _delay_ms(1);
}

// Returns mask 7-seg. display
unsigned int mask(unsigned int num) {
    switch (num) {
        case 0 : return 0xfa;
        case 1 : return 0x42;
        case 2 : return 0x79;
        case 3 : return 0x6b;
        case 4 : return 0xc3;
        case 5 : return 0xab;
        case 6 : return 0xbb;
        case 7 : return 0x62;
        case 8 : return 0xfb;
        case 9 : return 0xeb;
        case 10 : return 0x01;  // -
        case 11 : return 0xb9;    // E
        case 12 : return 0x11;    // r
        case 99 : return 0x00;     // space
        default: return 0x10;
    }
}

// Timer0 Overflow interrupt
ISR(TIMER0_OVF_vect)
{
    TCNT0 = 160;
    PORTB = seg[mx];
    switch(mx) {
        case 0: PORTD = 0x01; break;
        case 1: PORTD = 0x04; PORTB |= _BV(PORTB2); break;    // with DP.
        case 2: PORTD = 0x02; break;
        case 3: PORTD = 0x20; break;
        case 4: PORTD = 0x08; PORTB |= _BV(PORTB2); break;    // with DP.
        case 5: PORTD = 0x10; break;
    }
    mx++;
    if(mx > 5)
        mx = 0;
}

void sht31_init(void)
{
    i2c_start((SHT31_I2C_ADDR << 1) | 0x00);
    i2c_send(0x30);
    i2c_send(0xa2);
    i2c_stop();
}

void sht31_read()
{
    unsigned char buf[6];
    
    // 精度高、クロックストレッチ無効
    i2c_start((SHT31_I2C_ADDR << 1) | 0x00);
    i2c_send(0x24);
    i2c_send(0x00);
    i2c_stop();
    
    delay_ms(50);

    i2c_start((SHT31_I2C_ADDR << 1) | 0x01);
    buf[0] = i2c_recv(1);
    buf[1] = i2c_recv(1);
    buf[2] = i2c_recv(1);
    buf[3] = i2c_recv(1);
    buf[4] = i2c_recv(1);
    buf[5] = i2c_recv(0);

    // CRCは処理しない(無視する)
    temp = buf[0] << 8;
    temp |= buf[1];
    humd = buf[3] << 8;
    humd |= buf[4];

    i2c_stop();
}

int main(void)
{
    unsigned int i;
    int tem, hum;
    int di;

     DDRB = 0b11111111;        // 7SegLED Segment Control
    DDRC = 0b11111111;        // PC4,5 I2C
    DDRD = 0b11111111;        // 7SegLED Multiplex Control
    PORTC = 0b00000000;

    TCCR0B = 0b00000100;    // Timer0 prescaler 1/64 
    TIMSK0 = _BV(TOIE0);     // Timer0 Overflow Interrupt Enable

    delay_ms(15);
    i2c_init();
    delay_ms(15);
    sht31_init();
    
    cbi(PORTC, PC0);
    cbi(PORTC, PC1);
    cbi(PORTC, PC2);

    sei();

    while(1) {

        sht31_read();

        // 整数3桁表示にするために10倍
        tem = (temp * 175.0 / 65535.0 - 45.0) * 10;
        hum = humd * 100.0 / 65535.0 * 10;
        
        // 不快指数の計算
        di = 0.81 * (tem * 0.1) + (0.01 * (hum * 0.1)) * (0.99 * (tem * 0.1) - 14.3) + 46.3;
        
        // 不快指数用LED表示
        if(di >= 75) {
            sbi(PORTC, PC0); cbi(PORTC, PC1); cbi(PORTC, PC2);
        } else if(di < 75 && di >= 60) {
            cbi(PORTC, PC0); cbi(PORTC, PC1); sbi(PORTC, PC2);
        } else {
            cbi(PORTC, PC0); sbi(PORTC, PC1); cbi(PORTC, PC2);
        }
        
        if(tem > 999 || tem < -99) {
            seg[3] = mask(11);
            seg[4] = mask(12);
            seg[5] = mask(12);
        } else {
            if(tem < 0) {
                seg[3] = mask(10);
            } else {
                i = (tem / 100u) % 10u;
                if(i == 0)
                    i = 99;
                seg[3] = mask(i);
            }
            i = (tem / 10u) % 10u;
            seg[4] = mask(i);
            i = tem % 10u;
            seg[5] = mask(i);
        }
        if(hum > 999 || hum < 0) {
            seg[0] = mask(11);
            seg[1] = mask(12);
            seg[2] = mask(12);
        } else {
            i = (hum / 100u) % 10u;
            if(i == 0)
                i = 99;
            seg[0] = mask(i);
            i = (hum / 10u) % 10u;
            seg[1] = mask(i);
            i = hum % 10u;
            seg[2] = mask(i);
        }
        delay_ms(1000);
    }
}

▲ページ Top へ...