秋月で950円買い、実験してみました。 データは、マニュアル RHT22.pdf に書いてあるように、 パルスの幅より得ます。 @スタート信号の出力 (1mS以上Lを出力し、ポートを入力にしハイインピ (プルアップでH) の状態でAを待つ) A応答の入力 (80μSのLを入力後、ハイインピ (プルアップでH) の状態でBを待つ) B40回のデータの入力 (Aと同様にパルスを入力する。ただし、パルスの幅で0か1を意味する) 0は50μSのL、26〜28μSのH (プログラムでは立下りエッジ間が100μS以下を0と見る) 1は50μSのL、70μSのH (プログラムでは立下りエッジ間が100μS以上を1と見る) プログラムの注意点は、データの取得中は割り込みなどで、パルス幅の取得が遅れてはなりません。 |
回路図
結果の図
実験風景
How to Compile (コンパイルのしかた) システムクロック:20MHzのプログラム /* * DHT22.c * 湿度センサ「DHT22」から湿度、温度を得て、 * 得られた湿度、温度をRS-232C(115200 8-N-1)で出力する。 * ATmega328P * * * Fuses(システムクロック:20MHz) * * 水晶 * EXTENDED 0xFD * HIGH 0xD9 * LOW 0xF7 */ #include <stdio.h> #include <stdlib.h> /* abs() */ #include <avr/io.h> #define F_CPU 20.0E6 /* 20 MHz */ #include <util/delay.h> ///void delay_us(unsigned short t){while(t--) _delay_us(1);} void delay_ms(unsigned short t){while(t--) _delay_ms(1);} void initUSART0(void); void Send0(char *str); int main(void) { int i; static unsigned char pri_data, current_data; unsigned char change_data; unsigned short last_tcnt1; static unsigned char data[5]; static char buffer[32]; unsigned char sum; short RH, T_; /* ATmega328系 */ DDRB = 0b00000000; /* XTAL2 XTAL1 SCK MISO MOSI ----- ----- ----- */ DDRC = 0b00000000; /* xxxxx RESET ----- ----- ----- ----- ----- DATA */ DDRD = 0b00000000; /* ----- ----- ----- ----- ----- ----- TXD RXD */ PORTB = 0b00111111; PORTC = 0b00111110; PORTD = 0b11111100; initUSART0(); TCCR1A = 0b00000000; /* ノーマル */ TCCR1B = 0b00000010; /* 20MHz / 8 = 2.5MHz (400n) */ Send0("START\r"); /* DHT22が準備するのを待つ */ delay_ms(2000); while(1){ /* 立下りエッジの検出回数リセット */ i = 0; /* スタート信号を送信 */ PORTC &= ~_BV(0); DDRC |= _BV(0); delay_ms(2); PORTC |= _BV(0); DDRC &= ~_BV(0); /* DHT22の出力波形より温湿度データを得る */ while(1){ /* 立下りエッジの検出 (42回) */ pri_data = current_data; current_data = PINC & _BV(0); change_data = pri_data ^ current_data; if(change_data != 0 && current_data == 0){ /* 立下りエッジ間の時間を得る */ last_tcnt1 = TCNT1; TCNT1 = 0; /* 立下りエッジ間の時間の長短によりビット値を得る */ /* 100us / 0.4us = 250 */ switch(i){ case 0: case 1: i++; break; case 2:case 3:case 4:case 5:case 6:case 7:case 8:case 9: data[0] <<= 1; if(last_tcnt1 > 250) data[0] += 1; i++; break; case 10:case 11:case 12:case 13:case 14:case 15:case 16:case 17: data[1] <<= 1; if(last_tcnt1 > 250) data[1] += 1; i++; break; case 18:case 19:case 20:case 21:case 22:case 23:case 24:case 25: data[2] <<= 1; if(last_tcnt1 > 250) data[2] += 1; i++; break; case 26:case 27:case 28:case 29:case 30:case 31:case 32:case 33: data[3] <<= 1; if(last_tcnt1 > 250) data[3] += 1; i++; break; case 34:case 35:case 36:case 37:case 38:case 39:case 40:case 41: data[4] <<= 1; if(last_tcnt1 > 250) data[4] += 1; i++; break; } } if(i == 42) break; } /* チェックサムの確認 */ sum = (unsigned char)(data[0] + data[1] + data[2] + data[3]); if(sum == data[4]){ /* 計算 */ RH = data[0] * 256 + data[1]; T_ = (data[2] & 0x7f) * 256 + data[3]; if((data[2] & 0x80) != 0) T_ = -T_; /* 表示 */ sprintf(buffer, "%d.%d %% %d.%d ℃\r", RH / 10, RH % 10, T_ / 10, abs(T_ % 10)); Send0(buffer); } /* サンプリング周期 */ delay_ms(2000); } } void initUSART0(void) { UBRR0 = 21; /* U2X0 = 1, 115200ボー/20MHzクロック */ UCSR0A = 0b00000010; /* U2X0 = 1 */ UCSR0B = 0b00001000; /* 送信イネーブル */ UCSR0C = 0b00000110; /* 8ビット, パリティなし, ストップ・ビット1 */ } /* * 1データ送信 */ void Tx0(char data) { while((UCSR0A & _BV(5)) == 0) ; UDR0 = (unsigned char)data; } /* * 文字列を送信 */ void Send0(char *str) { while(*str != '\0'){ Tx0(*str); str++; } } |
How to Compile (コンパイルのしかた) システムクロック:内臓8MHzのプログラム /* * DHT22_8MHz.c * システムクロック:内臓8MHz * 湿度センサ「DHT22」から湿度、温度を得て、 * 得られた湿度、温度をRS-232C(9600 8-N-1)で出力する。 * ATmega328P * * * Fuses(システムクロック:8MHz) * * Int. RC Osc * EXTENDED 0xFD * HIGH 0xD9 * LOW 0xE2 */ #include <stdio.h> #include <stdlib.h> /* abs() */ #include <avr/io.h> ///#define F_CPU 20.0E6 /* 20 MHz */ #define F_CPU 8.0E6 /* 8 MHz */ #include <util/delay.h> ///void delay_us(unsigned short t){while(t--) _delay_us(1);} void delay_ms(unsigned short t){while(t--) _delay_ms(1);} void initUSART0(void); void Send0(char *str); int main(void) { int i; static unsigned char pri_data, current_data; unsigned char change_data; unsigned short last_tcnt1; static unsigned char data[5]; static char buffer[32]; unsigned char sum; short RH, T_; /* ATmega328系 */ DDRB = 0b00000000; /* XTAL2 XTAL1 SCK MISO MOSI ----- ----- ----- */ DDRC = 0b00000000; /* xxxxx RESET ----- ----- ----- ----- ----- DATA */ DDRD = 0b00000000; /* ----- ----- ----- ----- ----- ----- TXD RXD */ PORTB = 0b00111111; PORTC = 0b00111110; PORTD = 0b11111100; initUSART0(); TCCR1A = 0b00000000; /* ノーマル */ /// TCCR1B = 0b00000010; /* 20MHz / 8 = 2.5MHz (400n) */ TCCR1B = 0b00000001; /* 8MHz / 1 = 8MHz (125n) */ Send0("START\r"); /* DHT22が準備するのを待つ */ delay_ms(2000); while(1){ /* 立下りエッジの検出回数リセット */ i = 0; /* スタート信号を送信 */ PORTC &= ~_BV(0); DDRC |= _BV(0); delay_ms(2); PORTC |= _BV(0); DDRC &= ~_BV(0); /* DHT22の出力波形より温湿度データを得る */ while(1){ /* 立下りエッジの検出 (42回) */ pri_data = current_data; current_data = PINC & _BV(0); change_data = pri_data ^ current_data; if(change_data != 0 && current_data == 0){ /* 立下りエッジ間の時間を得る */ last_tcnt1 = TCNT1; TCNT1 = 0; /* 立下りエッジ間の時間の長短によりビット値を得る */ /* 100us / 0.4us = 250 */ /* 100us / 0.125us = 800 */ switch(i){ case 0: case 1: i++; break; case 2:case 3:case 4:case 5:case 6:case 7:case 8:case 9: data[0] <<= 1; /// if(last_tcnt1 > 250) if(last_tcnt1 > 800) data[0] += 1; i++; break; case 10:case 11:case 12:case 13:case 14:case 15:case 16:case 17: data[1] <<= 1; /// if(last_tcnt1 > 250) if(last_tcnt1 > 800) data[1] += 1; i++; break; case 18:case 19:case 20:case 21:case 22:case 23:case 24:case 25: data[2] <<= 1; /// if(last_tcnt1 > 250) if(last_tcnt1 > 800) data[2] += 1; i++; break; case 26:case 27:case 28:case 29:case 30:case 31:case 32:case 33: data[3] <<= 1; /// if(last_tcnt1 > 250) if(last_tcnt1 > 800) data[3] += 1; i++; break; case 34:case 35:case 36:case 37:case 38:case 39:case 40:case 41: data[4] <<= 1; /// if(last_tcnt1 > 250) if(last_tcnt1 > 800) data[4] += 1; i++; break; } } if(i == 42) break; } /* チェックサムの確認 */ sum = (unsigned char)(data[0] + data[1] + data[2] + data[3]); if(sum == data[4]){ /* 計算 */ RH = data[0] * 256 + data[1]; T_ = (data[2] & 0x7f) * 256 + data[3]; if((data[2] & 0x80) != 0) T_ = -T_; /* 表示 */ sprintf(buffer, "%d.%d %% %d.%d ℃\r", RH / 10, RH % 10, T_ / 10, abs(T_ % 10)); Send0(buffer); } /* サンプリング周期 */ delay_ms(2000); } } void initUSART0(void) { UBRR0 = 103; /* U2X0 = 1, 9600ボー/8MHzクロック */ UCSR0A = 0b00000010; /* U2X0 = 1 */ UCSR0B = 0b00001000; /* 送信イネーブル */ UCSR0C = 0b00000110; /* 8ビット, パリティなし, ストップ・ビット1 */ } /* * 1データ送信 */ void Tx0(char data) { while((UCSR0A & _BV(5)) == 0) ; UDR0 = (unsigned char)data; } /* * 文字列を送信 */ void Send0(char *str) { while(*str != '\0'){ Tx0(*str); str++; } } |