MSP430G2553 - 温湿度センサ
概要
MSP430G2553の特徴である低消費電力、高速起動、豊富なペリフェラルを活用することで、バッテリー駆動の温湿度センサシステムを構築できる。
DHT11 / DHT21はサーミスタと異なり、温度と湿度のキャリブレーション済みの状態で出荷されているセンサ (デジタル信号) である。
DHT11では温度は2[℃]程度の誤差、湿度は5[%]程度の誤差で測定できる。
DHT21 (AM2301) は高精度であり、温度は0.5[℃]程度、湿度は3[%]程度の誤差で測定可能である。
ピンの割り当ては、下図の通りである。
4本のピンは左から順に、VDD、DATA、NC (非接続)、GNDである。

VDDへの供給電圧は、DHT11が3.0[V]〜5.5[V]の範囲、DHT21が3.3[V]〜5.5[V]の範囲である。
VDDとGNDの間にパワーフィルタリングとして0.1[uF]のセラミックコンデンサを配置することが推奨される。
データはシングル・バス・データフォーマットで伝送される。
データのサンプリング間隔は最短で1[s]なので、ソフトウェア側でデータを取得する時に待機する必要がある。
2番ピンであるDATAピンはプルアップして使用する。
プルアップ抵抗は、ワイヤが20[m]以下の場合は、4.7[kΩ]〜10[kΩ]程度が推奨される。
MSP430G2553の内部プルアップ抵抗は約35[kΩ]であるため、外部にプルアップ抵抗を追加することが推奨される。
ただし、短い配線であれば内部プルアップのみでも動作する可能性がある。
DHT11 / DHT21は1線式通信プロトコルを使用するため、タイミングの正確な制御が必要である。
また、高度な機能として、以下に示すような拡張が可能である。
- Timer_Aを使用した高精度タイミング制御
- UART / I2C / SPI経由でのデータ送信
- 低電力モード (LPM3) を活用した省電力動作
- 複数のDHTセンサからのデータ収集
- LCDディスプレイへのデータ表示
- ADC10を併用した他のセンサとの統合
MSP430G2553の基本仕様
主要スペック
- CPU
- 16ビット RISCアーキテクチャ、最大16[MHz]動作
- フラッシュROM
- 16[KB]
- RAM
- 512[B]
- GPIO
- 24ピン (Port P1, P2, P3)
- タイマ
- 16ビット Timer_A (2個、Timer0_A3、Timer1_A3)
- 通信インターフェース
- USCI_A0 (UART/SPI)、USCI_B0 (I2C/SPI)
- ADC
- 10ビット SAR型 ADC、8チャンネル
- 動作電圧
- 1.8[V]〜3.6[V]
- 低消費電流
- アクティブモード 約230[uA/MHz]、スタンバイモード(LPM3) 約0.7[uA]
- パッケージ
- PDIP20、TSSOP28、VQFN32
クロックシステム
MSP430G2553は、Basic Clock Module+を搭載しており、以下に示すクロックソースを提供する。
- MCLK (Main Clock)
- CPUクロック、最大16[MHz]
- デフォルト設定 : DCO 約1[MHz]
- SMCLK (Sub-Main Clock)
- ペリフェラルクロック
- デフォルト設定 : DCO 約1[MHz]
- ACLK (Auxiliary Clock)
- 低速クロック、32768[Hz]の水晶発振器
- デフォルト設定 : VLO 約12[kHz] (水晶未実装時)
DCO (Digitally Controlled Oscillator) は内蔵の高速クロック源であり、起動時間が1[us]未満と非常に高速である。
低電力モード
MSP430G2553は、6種類の動作モードを持つ。
- Active Mode (AM)
- 全てのクロックが動作
- LPM0
- CPUが停止、ACLK、SMCLKが動作
- LPM1
- CPUが停止、ACLK、SMCLKが動作、DCOのDC生成器が停止
- LPM2
- CPUが停止、MCLKとSMCLKが停止、ACLKが動作
- LPM3
- CPUが停止、MCLKとSMCLKが停止、ACLKが動作、DCOが完全停止
- LPM4
- 全てのクロックが停止、最低消費電力モード
GPIO設定レジスタ
MSP430G2553のGPIOは、以下に示すレジスタで制御される。
以下は、Port P1の例である。(Port 2 / 3も同様である)
- P1IN (0x0020)
- 入力レジスタ (読み取り専用)
- P1OUT (0x0021)
- 出力レジスタ
- P1DIR (0x0022)
- 方向制御レジスタ (0 : 入力、1 : 出力)
- P1IFG (0x0023)
- 割り込みフラグレジスタ
- P1IES (0x0024)
- 割り込みエッジ選択 (0 : 立ち上がり、1 : 立ち下がり)
- P1IE (0x0025)
- 割り込み許可レジスタ
- P1SEL (0x0026)
- 機能選択レジスタ
- P1REN (0x0027)
- プルアップ / プルダウン抵抗有効化レジスタ
- P1SEL2 (0x0041)
- 第2機能選択レジスタ
MSP430G2553 と DHT11/DHT21の接続
ハードウェア接続
| DHT11 / DHT21 | MSP430G2553 | 備考 |
|---|---|---|
| VDD | VCC (Pin 1) | 3.3[V]または5[V]供給 |
| DATA | P1.6 (Pin 14) | プルアップ抵抗必要 |
| NC | 未接続 | - |
| GND | VSS (Pin 20) | グランド |
外部プルアップ抵抗 (4.7[kΩ]〜10[kΩ]) をDATAピンとVDDの間に接続することが推奨される。
また、VDDとGNDの間には0.1[uF]のセラミックコンデンサを配置してノイズ対策を行う。
推奨回路図
MSP430G2553 DHT11/DHT21
Pin 1 (VCC) ---+-------- VDD
|
[0.1uF]
|
Pin 20 (VSS) --+-------- GND
Pin 14 (P1.6) --[4.7k]-- VDD
|
+--------------- DATA
※注意
[4.7k]はプルアップ抵抗
[0.1uF]はパスコン
DHT11 / DHT21の通信プロトコル
データフォーマット
DHT11 / DHT21は1線式通信を使用し、5[byte] (40[bit]) のデータを送信する。
- 1[byte]
- 湿度の整数部 (DHT11) または 湿度上位バイト (DHT21)
- 2[byte]
- 湿度の小数部 (DHT11では常に0) または 湿度下位バイト (DHT21)
- 3[byte]
- 温度の整数部 (DHT11) または 温度上位バイト (DHT21)
- 4[byte]
- 温度の小数部 (DHT11では常に0) または 温度下位バイト (DHT21)
- 5[byte]
- チェックサム (1[byte]〜4[byte]の合計の下位8ビット)
通信シーケンス
1. スタート信号
MSP430G2553がDATAラインをLOWに18[ms]以上保持後、20〜40[us]の間HIGHにする。
2. 応答信号
センサがDATAラインを80[us]間LOWにした後、80[us]間HIGHにする。
3. データ送信
各ビットは以下のタイミングで送信される。
- ビット開始
- センサがDATAラインを50[μs]間LOWにする
- データビット0
- 26〜28[us]間HIGHを保持
- データビット1
- 70[us]間HIGHを保持
タイミングチャート
下図に、DHT11 / DHT21のタイミングチャートを示す。
- MSP430G2553からセンサへの開始信号
- 18[ms] LOW + 40[us] HIGH
- センサからの応答信号
- 80[us] LOW + 80[us] HIGH
- データビット "0" の送信
- 50[us] LOW + 26〜28[us] HIGH
- データビット "1" の送信
- 50[us] LOW + 70[us] HIGH

サンプルコード
基本
以下の例では、MSP430G2553を使用してDHT11 / DHT21から温度と湿度を取得している。
/*
* MSP430G2553とDHT11/DHT21温湿度センサのサンプルプログラム
*
* 接続:
* P1.6 - DHT11/DHT21 DATA pin (4.7kΩプルアップ推奨)
* VCC - DHT11/DHT21 VDD (3.3Vまたは5V)
* GND - DHT11/DHT21 GND
*
* データシート参照:
* MSP430G2x13/MSP430G2x53 Datasheet (SLAS735)
* - GPIO設定: Section 8.2 Digital I/O
* - Timer_A: Section 12 Timer_A
* - Clock System: Section 5 Basic Clock Module+
*/
#include <msp430g2553.h>
#include <stdint.h>
// DHTセンサのデータピン定義
#define DHT_PIN BIT6 // P1.6をDATAピンとして使用
#define DHT_DIR P1DIR // P1.6の方向制御レジスタ
#define DHT_OUT P1OUT // P1.6の出力レジスタ
#define DHT_IN P1IN // P1.6の入力レジスタ
#define DHT_REN P1REN // P1.6のプルアップ/ダウン制御レジスタ
// DHT11とDHT21の選択
#define USE_DHT11 1 // DHT11使用時は1、DHT21使用時は0
// データ構造体
typedef struct {
uint16_t humidity; // 湿度 (10倍値、DHT11: 整数値のみ、DHT21: 0.1%単位)
uint16_t temperature; // 温度 (10倍値、DHT11: 整数値のみ、DHT21: 0.1℃単位)
uint8_t checksum_ok; // チェックサムが正しければ1
} DHT_Data;
// 関数プロトタイプ
void init_clock(void);
void init_gpio(void);
void delay_ms(uint16_t ms);
void delay_us(uint16_t us);
void dht_set_output(void);
void dht_set_input(void);
uint8_t dht_read_bit(void);
uint8_t dht_read_byte(void);
uint8_t dht_start(void);
uint8_t dht_read_data(DHT_Data *data);
/*
* メイン関数
*/
int main(void)
{
DHT_Data dht_data;
uint8_t result;
WDTCTL = WDTPW | WDTHOLD; // ウォッチドッグタイマを停止
// WDTPW (0x5A00) : パスワード
// WDTHOLD : タイマ停止ビット
init_clock(); // クロックシステムの初期化
init_gpio(); // GPIOの初期化
__enable_interrupt(); // グローバル割り込み許可
while(1)
{
// DHTセンサからデータを読み取り
result = dht_read_data(&dht_data);
if(result && dht_data.checksum_ok)
{
// データ読み取り成功
// ここで温度と湿度のデータを使用
// 例: UART経由で送信、LCD表示等
// 温度と湿度は10倍値で格納されている
// 実際の値 = dht_data.temperature / 10.0
// dht_data.humidity / 10.0
}
else
{
// データ読み取り失敗
// エラー処理
}
// 次の測定まで最低2秒待機 (DHT11/DHT21の仕様)
delay_ms(2000);
// 低電力モードに移行 (オプション)
// __bis_SR_register(LPM0_bits + GIE);
}
return 0;
}
/*
* クロックシステムの初期化
*
* MCLK = SMCLK = DCO 約1[MHz] (デフォルト設定)
* ACLK = VLO 約12[kHz]
*
* データシート参照: Section 5.2 (Basic Clock Module+ Registers)
* レジスタ:
* DCOCTL (0x0056): DCO制御レジスタ
* BCSCTL1 (0x0057): 基本クロック制御1
* BCSCTL2 (0x0058): 基本クロック制御2
* BCSCTL3 (0x0053): 基本クロック制御3
*/
void init_clock(void)
{
// DCOを1[MHz]に設定 (キャリブレーション値を使用)
// キャリブレーション値はInfoメモリSegment Aに保存されている
if (CALBC1_1MHZ != 0xFF) // キャリブレーション値が有効かチェック
{
DCOCTL = 0; // DCO制御レジスタをクリア
BCSCTL1 = CALBC1_1MHZ; // 基本クロック制御1にキャリブレーション値設定
DCOCTL = CALDCO_1MHZ; // DCO制御にキャリブレーション値設定
}
// MCLK = DCO, SMCLK = DCO (デフォルト)
BCSCTL2 = 0; // BCSCTL2レジスタ
// SELM_0: MCLK = DCOCLK
// DIVM_0: MCLK分周なし
// SELS: SMCLK = DCOCLK
// DIVS_0: SMCLK分周なし
// ACLK = VLO (~12kHz)
BCSCTL3 = LFXT1S_2; // LFXT1S_2: VLOを選択
// 外部水晶がない場合はVLOを使用
}
/*
* GPIOの初期化
*
* P1.6をDHTセンサのDATAピンとして設定
*
* データシート参照: Section 8.2 (Digital I/O)
* レジスタアドレス:
* P1DIR (0x0022): ポート1方向レジスタ
* P1OUT (0x0021): ポート1出力レジスタ
* P1SEL (0x0026): ポート1機能選択レジスタ
* P1SEL2 (0x0041): ポート1機能選択レジスタ2
* P1REN (0x0027): ポート1プルアップ/ダウン有効化
*/
void init_gpio(void)
{
// P1.6をGPIOとして設定
P1SEL &= ~DHT_PIN; // P1SEL.6 = 0: GPIO機能を選択
P1SEL2 &= ~DHT_PIN; // P1SEL2.6 = 0: GPIO機能を選択
// 初期状態は入力に設定
DHT_DIR &= ~DHT_PIN; // P1DIR.6 = 0: 入力モード
// 内部プルアップを有効化 (オプション、外部プルアップ推奨)
DHT_REN |= DHT_PIN; // P1REN.6 = 1: プルアップ/ダウン有効
DHT_OUT |= DHT_PIN; // P1OUT.6 = 1: プルアップを選択
// (P1OUT=0でプルダウン、P1OUT=1でプルアップ)
}
/*
* ミリ秒単位の遅延関数
*
* MCLK = 1[MHz]を前提とした簡易的な遅延
* より正確な遅延が必要な場合はTimer_Aを使用
*/
void delay_ms(uint16_t ms)
{
volatile uint16_t i;
while(ms--)
{
for(i = 0; i < 1000; i++)
{
__delay_cycles(1); // 1サイクル遅延 (1[MHz]時は1[us])
}
}
}
/*
* マイクロ秒単位の遅延関数
*
* MCLK = 1[MHz]を前提
* __delay_cycles()はコンパイラ組み込み関数
*/
void delay_us(uint16_t us)
{
while(us--)
{
__delay_cycles(1); // 1[MHz]時 : 1サイクル = 1[us]
}
}
/*
* DHTピンを出力モードに設定
*/
void dht_set_output(void)
{
DHT_DIR |= DHT_PIN; // P1DIR.6 = 1: 出力モード
}
/*
* DHTピンを入力モードに設定
*/
void dht_set_input(void)
{
DHT_DIR &= ~DHT_PIN; // P1DIR.6 = 0: 入力モード
}
/*
* DHTセンサから1ビット読み取り
*
* 戻り値 : 0または1
*/
uint8_t dht_read_bit(void)
{
uint8_t count = 0;
// DATAラインがLOWになるまで待機 (タイムアウト付き)
while(DHT_IN & DHT_PIN)
{
delay_us(1);
if(++count > 100) return 0;
}
// DATAラインがLOWの間待機 (約50μs)
count = 0;
while(!(DHT_IN & DHT_PIN))
{
delay_us(1);
if(++count > 100) return 0;
}
// DATAラインがHIGHの期間を測定
// HIGHの期間が26〜28[us]ならビット0、70[us]ならビット1
delay_us(35); // 35[us]待機
if(DHT_IN & DHT_PIN) // まだHIGHならビット1
{
return 1;
}
else // LOWに戻っていればビット0
{
return 0;
}
}
/*
* DHTセンサから1バイト(8ビット)読み取り
*
* 戻り値: 読み取った8ビットデータ
*/
uint8_t dht_read_byte(void)
{
uint8_t i, byte = 0;
for(i = 0; i < 8; i++)
{
byte <<= 1; // 左シフト
byte |= dht_read_bit(); // ビットを読み取って追加
}
return byte;
}
/*
* DHTセンサへ開始信号を送信
*
* 戻り値 : 応答があれば1、なければ0
*/
uint8_t dht_start(void)
{
uint8_t count = 0;
// 1. MCUが開始信号を送信
dht_set_output(); // 出力モードに設定
DHT_OUT &= ~DHT_PIN; // DATAラインをLOWに
delay_ms(20); // 20[ms]間LOWを保持
DHT_OUT |= DHT_PIN; // DATAラインをHIGHに
delay_us(30); // 30[us]待機
// 2. 入力モードに切り替えてセンサの応答を待つ
dht_set_input(); // 入力モードに設定
// センサがDATAラインをLOWにするまで待機
while(DHT_IN & DHT_PIN)
{
delay_us(1);
if(++count > 100) return 0; // タイムアウト
}
// センサがDATAラインを約80μs間LOWに保持
count = 0;
while(!(DHT_IN & DHT_PIN))
{
delay_us(1);
if(++count > 100) return 0; // タイムアウト
}
// センサがDATAラインを約80[us]間HIGHに保持
count = 0;
while(DHT_IN & DHT_PIN)
{
delay_us(1);
if(++count > 100) return 0; // タイムアウト
}
// 応答成功
return 1;
}
/*
* DHTセンサからデータを読み取り
*
* 引数 : data - データを格納する構造体へのポインタ
* 戻り値 : 成功時1、失敗時0
*/
uint8_t dht_read_data(DHT_Data *data)
{
uint8_t i;
uint8_t raw_data[5]; // 5バイトの生データ
uint8_t checksum;
// 開始信号を送信
if(!dht_start())
{
return 0; // 開始失敗
}
// 5バイト (40ビット) のデータを読み取り
for(i = 0; i < 5; i++)
{
raw_data[i] = dht_read_byte();
}
// チェックサムの検証
checksum = raw_data[0] + raw_data[1] + raw_data[2] + raw_data[3];
data->checksum_ok = (checksum == raw_data[4]);
#if USE_DHT11
// DHT11の場合
data->humidity = raw_data[0] * 10; // 湿度は整数部のみ
data->temperature = raw_data[2] * 10; // 温度は整数部のみ
#else
// DHT21 (AM2301) の場合
data->humidity = ((uint16_t)raw_data[0] << 8) | raw_data[1];
data->temperature = ((uint16_t)raw_data[2] << 8) | raw_data[3];
// 温度の符号処理 (DHT21は負の温度に対応)
if(data->temperature & 0x8000)
{
data->temperature = -(data->temperature & 0x7FFF);
}
#endif
return 1; // 読み取り成功
}
外部デバイスとの連携
以下の例では、温度と湿度をUART経由でPC等の外部デバイスに出力している。
/*
* MSP430G2553とDHT11/DHT21温湿度センサ
*
* 追加接続:
* P1.1 - UART TXD (PC等と接続)
* P1.2 - UART RXD (PC等と接続)
*
* UART設定: 9600bps, 8bit, No Parity, 1 Stop bit
*/
#include <msp430g2553.h>
#include <stdint.h>
#include <stdio.h>
// 前述のDHT関連定義と関数をここに含める
// ...
// UART関連の関数プロトタイプ
void init_uart(void);
void uart_send_char(char c);
void uart_send_string(const char *str);
void uart_send_number(int16_t num);
/*
* UART初期化 (USCI_A0を使用)
*
* ボーレート: 9600[bps]
* MCLK = SMCLK = 1MHz
*
* データシート参照: Section 15 (USCI_A)
* レジスタ:
* UCA0CTL1 (0x0061) : USCI_A0 制御レジスタ1
* UCA0CTL0 (0x0060) : USCI_A0 制御レジスタ0
* UCA0BR0 (0x0062) : ボーレート制御レジスタ0
* UCA0BR1 (0x0063) : ボーレート制御レジスタ1
* UCA0MCTL (0x0064) : モジュレーション制御レジスタ
*/
void init_uart(void)
{
// UARTピンの機能を有効化
P1SEL |= BIT1 + BIT2; // P1.1 = RXD, P1.2 = TXD
P1SEL2 |= BIT1 + BIT2; // P1SEL2も設定
// USCI_A0をUARTモードで初期化
UCA0CTL1 |= UCSSEL_2; // SMCLK (1MHz) を選択
// ボーレート設定: 9600[bps] @ 1[MHz]
// N = 1000000 / 9600 = 104.166
UCA0BR0 = 104; // 下位バイト
UCA0BR1 = 0; // 上位バイト
UCA0MCTL = UCBRS0; // モジュレーション UCBRSx = 1
UCA0CTL1 &= ~UCSWRST; // USCI状態マシンを初期化
}
/*
* UART経由で1文字送信
*/
void uart_send_char(char c)
{
while (!(IFG2 & UCA0TXIFG)); // 送信バッファが空になるまで待機
UCA0TXBUF = c; // 文字を送信バッファに書き込み
}
/*
* UART経由で文字列送信
*/
void uart_send_string(const char *str)
{
while(*str)
{
uart_send_char(*str++);
}
}
/*
* UART経由で数値送信 (符号付き整数)
*/
void uart_send_number(int16_t num)
{
char buffer[8];
sprintf(buffer, "%d", num);
uart_send_string(buffer);
}
/*
* メイン関数
*/
int main(void)
{
DHT_Data dht_data;
uint8_t result;
WDTCTL = WDTPW | WDTHOLD; // ウォッチドッグタイマを停止
init_clock(); // クロックシステムの初期化
init_gpio(); // GPIOの初期化
init_uart(); // UARTの初期化
__enable_interrupt(); // グローバル割り込み許可
// 起動メッセージ
uart_send_string("\r\n=== MSP430G2553 DHT11/DHT21 Test ===\r\n");
while(1)
{
// DHTセンサからデータを読み取り
result = dht_read_data(&dht_data);
if(result && dht_data.checksum_ok)
{
// データ読み取り成功
uart_send_string("Temp: ");
uart_send_number(dht_data.temperature / 10);
uart_send_char('.');
uart_send_number(dht_data.temperature % 10);
uart_send_string(" C, Humidity: ");
uart_send_number(dht_data.humidity / 10);
uart_send_char('.');
uart_send_number(dht_data.humidity % 10);
uart_send_string(" %\r\n");
}
else
{
// データ読み取り失敗
uart_send_string("ERROR: Failed to read DHT sensor\r\n");
}
// 次の測定まで2秒待機
delay_ms(2000);
}
return 0;
}
トラブルシューティング
タイミングの調整
- DHTセンサの通信プロトコルはタイミングに敏感なため、待機時間の精度が重要となる。
- MSP430G2553のクロック周波数が変更された場合は、delay_us関数 と delay_ms関数を調整する必要がある。
- 正確なタイミングが必要な場合は、Timer_Aモジュールを使用することを推奨する。
プルアップ抵抗
- 外部プルアップ抵抗 (4.7[kΩ]〜10[kΩ]) を使用することが推奨される。
- 内部プルアップ抵抗のみでも動作する場合があるが、信号品質が低下する可能性がある。
- 配線が長い場合 (20[m]以上) は、プルアップ抵抗値を小さくする (5[kΩ]程度) 必要がある。
電源とノイズ対策
- VDDとGNDの間には必ず0.1[uF]のセラミックコンデンサを配置する。
- センサとMCUの間の配線は可能な限り短くする。
- ノイズの多い環境では、追加のフィルタリングが必要な場合がある。
データ取得間隔
- DHT11 / DHT21は連続測定には対応していない。
- 最低でも1秒、推奨では2秒以上の間隔を空けてデータを取得する。
- 連続して読み取ると、センサが応答しなくなる場合がある。
低消費電力動作
MSP430G2553の低電力モードを活用することで、バッテリー駆動時間を延ばすことができる。
// 測定間隔の待機時にLPM3モードに移行
// Timer_Aの割り込みで復帰
void main(void)
{
// ... 初期化処理 ...
while(1)
{
// データ取得処理
result = dht_read_data(&dht_data);
// データ処理
// ...
// Timer_Aを設定して2秒後に割り込み発生
TA0CCR0 = 32768 * 2; // ACLK = 32768[Hz]の場合
TA0CTL = TASSEL_1 + MC_1; // ACLK, Up mode
TA0CCTL0 = CCIE; // 割り込み許可
// LPM3モードに移行 (ACLKのみ動作)
__bis_SR_register(LPM3_bits + GIE);
}
}
// Timer_A0割り込みサービスルーチン
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A0_ISR(void)
{
TA0CTL = 0; // Timer停止
__bic_SR_register_on_exit(LPM3_bits); // LPM3から復帰
}
エラッタ情報
MSP430G2553には既知のエラッタ (不具合) が存在する。
BCL12 : DCOクロック切り替え時の問題
RSELxビットを切り替える時、DCOが停止する可能性がある。
回避策として、RSELx > 13 から RSELx < 12に切り替える時は、中間値 (RSEL=13) を経由する。
TA12: Timer_A割り込み消失
ACLK等の低速クロックを使用する場合、割り込みが消失する可能性がある。
回避策として、CCRxレジスタを更新する前に、TARレジスタとCCRxレジスタの差を確認する。
詳細は、MSP430G2553のエラッタ情報を参照すること。