DS18B20デジタル温度センサの実装
本セクションでは、STM32マイコンのGPIOポートを用いて1-Wireバスプロトコルをソフトウェアでエミュレートし、DS18B20温度センサと通信を行う手順について解説します。取得した温度データはTFT LCDモジュール上にリアルタイムで表示されます。
1-Wireバスプロトコルの概要
1-Wireバスは、クロックとデータの両方を単一の信号線で双方向通信を行うプロトコルです。この仕様により、I/Oポートのリソースを大幅に節約でき、配線も簡素化されます。
DS18B20の通信シーケンス
DS18B20は-55℃から+125℃の測定範囲を持ち、9ビットのデジタル温度値を出力します。通信には以下のタイミング制約が存在します。
- リセットとプレゼンスパルス: マスターはバスを少なくとも480μs間Lowに保持してリセットパルスを送信します。その後バスを解放し、DS18B20が60~240μs間バスをLowに引っ張ることでプレゼンスパルスを返します。
- 書き込みタイミング: 「0」を書く場合は60μs間Lowを維持、「1」を書く場合は2μs間Lowにした後即座にHigh(解放)します。各書き込みシーケンスの間には最低1μsの回復時間が必要です。
- 読み出しタイミング: マスターが最低1μs間Lowにした後、バスを解放します。その後15μs以内にバスの状態をサンプリングすることで、デバイスからの送信データ(0または1)を判定します。
実装コード例:DS18B20へのバイト送信
以下に、1バイトのデータを送信する関数のコード例を示します。変数名やロジック構成を変更し、可読性を向上させています。
void ds18b20_send_byte(uint8_t data_byte)
{
uint8_t bit_mask;
ds18b20_config_gpio_output(); // ポートを出力モードに設定
for (bit_mask = 0x01; bit_mask != 0; bit_mask <<= 1) {
if (data_byte & bit_mask) {
// ビットが1の場合の書き込みシーケンス
ds18b20_write_pin(0);
delay_us(2);
ds18b20_write_pin(1); // バス解放
delay_us(60);
} else {
// ビットが0の場合の書き込みシーケンス
ds18b20_write_pin(0);
delay_us(60);
ds18b20_write_pin(1); // バス解放
delay_us(2);
}
}
}
メインルーチンによる温度監視
システム初期化後、メインループ内で温度変換コマンドを送信し、結果を読み取ってLCDに表示します。
int main(void)
{
uint16_t loop_counter = 0;
int16_t current_temp;
system_core_init(); // クロックおよび遅延関数の初期化
nvic_priority_group_config(NVIC_PriorityGroup_2);
uart_comm_init(115200);
lcd_panel_init();
lcd_show_text(30, 50, "STM32 PLATFORM");
lcd_show_text(30, 70, "DS18B20 SENSOR");
// センサの初期化確認
while (ds18b20_init_sensor()) {
lcd_show_text(30, 130, "Sensor Init Fail");
delay_ms(500);
lcd_clear_area(30, 130, 240, 16);
}
lcd_show_text(30, 130, "Sensor OK");
lcd_show_text(30, 150, "Temp: C");
while (1) {
// 周期的なデータ更新(約100ms毎)
if (loop_counter % 10 == 0) {
current_temp = ds18b20_read_temperature();
if (current_temp < 0) {
lcd_draw_char(30 + 40, 150, '-', 16);
current_temp = -current_temp; // 絶対値に変換
} else {
lcd_draw_char(30 + 40, 150, ' ', 16);
}
// 整数部と小数部を表示
lcd_show_number(30 + 48, 150, current_temp / 10, 2, 16);
lcd_show_number(30 + 72, 150, current_temp % 10, 1, 16);
}
delay_ms(10);
loop_counter++;
// LED点滅処理(ハートビート)
if (loop_counter >= 20) {
loop_counter = 0;
toggle_status_led();
}
}
}
DHT11温湿度センサの実装
次に、温度と湿度の両方を測定できるDHT11センサの使用方法について解説します。DS18B20と異なり、DHT11は湿度の検出が可能ですが、測定精度や範囲は限定的です(温度0~50℃、湿度20~90%RH)。
DHT11のデータフォーマット
通信フォーマットは40ビット(5バイト)のデータパケットで構成されています。
- 湿度整数部(8ビット)
- 湿度小数部(8ビット)
- 温度整数部(8ビット)
- 温度小数部(8ビット)
- チェックサム(8ビット)
チェックサムは最初の4バイトの合計値であり、データの整合性を確認するために使用されます。DHT11はマイコンからの開始信号を受信したときのみ測定を行います。
通信手順
データ転送は、バスを80μs間Highにした後に開始されます。各ビットは50μsのLow期間から始まり、その後のHigh期間の長さ(26~28μsで「0」、70μsで「1」)でデータ値を識別します。
メインルーチンによる温湿度表示
DHT11からのデータ読み出しとLCD表示を行うコード例を以下に示します。
int main(void)
{
uint8_t timer_tick = 0;
uint8_t temp_value = 0;
uint8_t humidity_value = 0;
system_delay_init();
nvic_set_priority_grouping(NVIC_PriorityGroup_2);
usart_init(115200);
led_indicator_init();
lcd_display_init();
lcd_show_text(30, 50, "STM32 SYSTEM");
lcd_show_text(30, 70, "DHT11 TEST");
// DHT11初期化待ち
while (dht11_startup_check()) {
lcd_show_text(30, 130, "DHT11 Error");
delay_ms(500);
lcd_fill_rectangle(30, 130, 239, 146, WHITE);
delay_ms(500);
}
lcd_show_text(30, 130, "DHT11 Ready");
lcd_show_text(30, 150, "Temp: C");
lcd_show_text(30, 170, "Humi: %");
while (1) {
// 定期的なセンサ読み出し
if (timer_tick % 10 == 0) {
// 温度湿度データの取得
dht11_read_sensor_data(&temp_value, &humidity_value);
// 温度表示
lcd_show_number(30 + 40, 150, temp_value, 2, 16);
// 湿度表示
lcd_show_number(30 + 40, 170, humidity_value, 2, 16);
}
delay_ms(10);
timer_tick++;
// ステータスLEDのトグル
if (timer_tick == 20) {
timer_tick = 0;
toggle_led();
}
}
}