HDC1000を使った温度計・湿度計の製作

[公開:any]

[電子工作/AVR]
[AVR,ATmega88,HDC1000,湿度計]

origin 2015-07-13



 「DHT22を使った温度計・湿度計の製作」で使用した温度・湿度センターのDHT22(RHT03)は、1年以上使用すると湿度が高めに測定されるという不具合がありました。過去2回、センサーを交換していますが、今回のセンサーも2年目にして湿度が高めに測定されるようになりました。センサーそのものの不具合の可能性もありますが、使い方がよくない可能性もあります。

DHT22温度計・湿度計

 DHT22(およびその互換品)は、秋月電子でも取り扱いが始まったので入手には不便しませんが、1年程度で故障する可能性のある部品なので使用はあきらめます。これまで使用した温度・湿度センサーではセンシリオン社のSHT11が良いのですが、値段はそれなりにします。秋月電子では、DHT22よりも格安センサーとしてテキサス社のHDC1000というセンサーの取り扱いがあるので調達してみました。

 ブレッドボードで開発しますが、もとは「SHT11を使った温度計・湿度計の製作」と同じ回路でセンサーをHDC1000に交換したものです。SHT11は変則的なI2Cによるシリアル通信でしたが、HDC1000は、まともなI2Cで通信できます ・・・・が、

HDC1000

 HDC1000のアドレスが0x40(7ビット)とあるので、少しはまりました。オシロスコープでシリアル通信をモニタすると通信が正常に行えていないことがわかったので、アドレスをいろいろと試して正常動作までこぎつけました。


 回路図です。SHT11を使用したものと同じ回路で、3桁7セグメントLED2個をダイナミック点灯させます。LEDの電流制限抵抗は330Ωなので、1桁全点灯した場合は、8個のLEDに合計120mA程度の電流をAVRから供給します。かなりの電流ですが仕様では問題ありません。

HDC1000温度計・湿度計回路図

 実装図も過去のものを使いまわします。基板は秋月電子の大きなユニバーサル基板です。


 部品実装した基板の裏表です。HDC1000は、他の部品から影響を受けないように横に飛び出すように取り付けました。電源コネクタ近くの大きなLED(キャップをかぶせてあります)は、3色LEDです。温度と湿度から不快指数を計算し、指数75以上の暑いときは赤色、指数60〜75で快適を示す緑色、指数60以下の寒いときはを青色で表示するようにしました。(回路図には記載してありません)


 SHT11を使用したものと比較してみました。エアコンを使用せずにやっているので暑い室内ですが、温度、湿度とも測定値に大きな差は見られません。「不快」を示す赤いLEDも正常に点灯しました。^^;


 ケースも、これまでの温度計・湿度計で使用しているものと同じ100円ショップのフォトスタンドです。壁にかけて使用するのですが、周りがオープンなので測定に支障がありません。


 使用したプログラムのソースリストです。メイン関数とI2C関連のソースです。I2Cのライブラリは、ネットを参考にしたものですが、参照先がわからなくなったのでCopyrightなしです。ATMEL StudioとGCCで作成してあります。Arduino(アルドゥイーノ)を使用した製作例は、ネットに数多くあるのですが、素のAVRを使用したものはあまり見られないので参考までに載せときます。(スミマセン。コメントなしです。やっていることはArduinoでの作例と同じなので、そちらを参考にしてください。^^;)
 HDC1000からの読み込みは2秒間隔としています。間隔が短いと自身の発熱で温度が高めに出るようですが、2秒とそれ以上では、差は見られませんでした。(実装は、回路図とIOポートの接続が異なっているので注意が必要です。このプログラムは、実装図の接続を前提としています。)

I2Cのライブラリでストップコンディション呼び出し時にHDC1000が無反応になることが稀に発生することがわかりました。原因はよくわかっていませんが、とりあえずストップコンディションでTWSTOビットの変化を待つことをやめて対処しています。(2015-08-06)

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
/*
 * adc1000_temp_hum.c
 *
 * Created: 2015/07/05 10:08: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 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)
{
    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 hdc1000_init()
{
    i2c_start(0x80);
    i2c_send(0x02);
    i2c_send(0x10);
    i2c_send(0x00);
    i2c_stop();
}

void hdc1000_read()
{
    i2c_start(0x80);
    i2c_send(0x00);
    i2c_stop();
    
    delay_ms(15);

    i2c_start(0x81);

    temp = i2c_recv(1) << 8;
    temp += i2c_recv(1);
    humd = i2c_recv(1) << 8;
    humd += i2c_recv(0);

    i2c_stop();
}

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

     DDRB = 0b11111111;        // 7SegLED Segment Control
    DDRC = 0b11111111;        // PC5 SHT-data PC4 SHT-sck Control
    DDRD = 0b11111111;        // 7SegLED Multiplex Control
    PORTC = 0b00000000;

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

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

    sei();

    while(1) {

        hdc1000_read();

        tem = (temp / 65536.0 * 165.0 - 40.0) * 10;
        hum = (humd / 65536.0 * 100.0) * 10;
        
        // 不快指数の計算
        di = 0.81 * (tem * 0.1) + (0.01 * (hum * 0.1)) * (0.99 * (tem * 0.1) - 14.3) + 46.3;
        
        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 / 100) % 10;
                if(i == 0)
                    i = 99;
                seg[3] = mask(i);
            }
            i = abs((tem / 10) % 10);
            seg[4] = mask(i);
            i = abs(tem % 10);
            seg[5] = mask(i);
        }
        if(hum > 999 || hum < 0) {
            seg[0] = mask(11);
            seg[1] = mask(12);
            seg[2] = mask(12);
        } else {
            i = (hum / 100) % 10;
            if(i == 0)
                i = 99;
            seg[0] = mask(i);
            i = (hum / 10) % 10;
            seg[1] = mask(i);
            i = hum % 10;
            seg[2] = mask(i);
        }
        delay_ms(2000);
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*
 * i2c.h
 *
 * Created: 2015/07/05 11:11:54
 *  Author: www.henteko.org
 */ 

#include <util/twi.h>

void i2c_init(void);
int i2c_start(unsigned char adress);
void i2c_stop(void);
int i2c_send(unsigned char data);
unsigned char i2c_recv(unsigned char ack);

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
/*
 * i2c.c
 *
 * Created: 2015/07/05 11:11:10
 *  Author: www.henteko.org
 */ 

#include <avr/io.h>

#include "i2c.h"

#define F_SCL (100000L)    // 100kHz
#define F_CPU 8000000L    // 8MHz internal clock

void i2c_init(void)
{
    TWSR = 0b00000000;                    // TWI Prescaler 1/1
    TWBR = ((F_CPU / F_SCL - 16) / 2);    
    TWCR = _BV(TWEN);
}

int i2c_start(unsigned char adress)
{
    TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);
    loop_until_bit_is_set(TWCR, TWINT);

    if(((TW_STATUS & 0xf8) != TW_START) && ((TW_STATUS & 0xf8) != TW_REP_START))
        return 1;

    TWDR = adress;
    TWCR = _BV(TWINT) | _BV(TWEN);
    loop_until_bit_is_set(TWCR, TWINT);
    if(((TW_STATUS & 0xf8) != TW_MT_SLA_ACK) && ((TW_STATUS & 0xf8) != TW_MR_SLA_ACK))
        return 1;

    return 0;
}

void i2c_stop(void)
{
    TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
    // loop_until_bit_is_set(TWCR, TWSTO);
}

int i2c_send(unsigned char data)
{
    TWDR = data;
    TWCR = _BV(TWINT) | _BV(TWEN);
    loop_until_bit_is_set(TWCR, TWINT);
    
    if(((TW_STATUS & 0xf8) != TW_MT_DATA_ACK) && ((TW_STATUS & 0xf8) != TW_MT_DATA_NACK))
        return 1;

    return 0;
}

unsigned char i2c_recv(unsigned char ack)
{
    if(ack == 1)
        TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN);
    else
        TWCR = _BV(TWINT) | _BV(TWEN);

    loop_until_bit_is_set(TWCR, TWINT);
    
    return TWDR;
}

▲ページ Top へ...