本文へスキップ
ysk-hack-log
戻る

MCP3208+LM35DZでアナログ温度を読む|Raspberry PiのSPIとADC【連載④】

「MCP3208+LM35DZでアナログ温度を読む|Raspberry PiのSPIとADC【連載④】」の記事アイキャッチ

前回(第3回) はデジタルなLED/ボタンでした。今回はいよいよ温度センサーです。ここが連載の山場になります。

Table of contents

Open Table of contents

なぜADC(MCP3208)が必要なのか

Raspberry Pi にはアナログ入力がありません。 GPIOはHigh/Lowのデジタルしか読めないため、電圧が連続的に変わるアナログセンサー LM35DZ(10mV/℃)の出力を直接は読めません。

そこで ADC(アナログ-デジタル変換IC)MCP3208 を挟みます。MCP3208は SPI接続の12bit ADCで、アナログ電圧を 0〜4095 の数値に変換してくれます。

SPIを有効化する

sudo raspi-config

Interface Options → SPI → Enable を選び、再起動します。

配線

MCP3208 は MCP3008 とピン配置が同じ(16ピン)なので、MCP3008の配線図がそのまま使えます。

LM35DZ(正面から見て左からVs・出力・GND):

配線図

Iot.Device.Bindings を追加

dotnet add package Iot.Device.Bindings

温度を読むサービス

MCP3208をラップしたシングルトンサービスを作ります。

// Services/TemperatureService.cs
using System.Device.Spi;
using Iot.Device.Adc;

public sealed class TemperatureService : IDisposable
{
    private const int Channel = 0;     // LM35DZ を CH0 に接続
    private const double VRef = 3.3;   // MCP3208 の VREF
    private const int MaxValue = 4096; // 12bit(0〜4095)

    private readonly SpiDevice _spi;
    private readonly Mcp3208 _adc;
    private readonly object _gate = new(); // SPIはスレッドセーフでないため排他

    public TemperatureService()
    {
        var settings = new SpiConnectionSettings(busId: 0, chipSelectLine: 0)
        {
            ClockFrequency = 1_000_000, // 速すぎると不安定。1MHz程度が無難
            Mode = SpiMode.Mode0,
        };
        _spi = SpiDevice.Create(settings);
        _adc = new Mcp3208(_spi);
    }

    public double ReadCelsius()
    {
        lock (_gate) // 複数スレッドから同時に読んでも壊れないよう直列化
        {
            int raw = _adc.Read(Channel);          // 0〜4095
            double volts = raw * VRef / MaxValue;   // 数値 → 電圧
            return volts * 100.0;                   // LM35: 10mV/℃ なので ×100
        }
    }

    public void Dispose()
    {
        _adc.Dispose();
        _spi.Dispose();
    }
}

Program.cs に登録します。

builder.Services.AddSingleton<TemperatureService>();

換算のしくみ

Blazorに温度を表示

@* Components/Pages/Temperature.razor *@
@page "/temperature"
@rendermode InteractiveServer
@implements IDisposable
@inject TemperatureService Temp

<h1>現在の温度</h1>
<p style="font-size:2rem"><b>@temperature.ToString("F1") ℃</b></p>

@code {
    private double temperature;
    private Timer? _timer;

    protected override void OnInitialized()
    {
        _timer = new Timer(_ =>
        {
            temperature = Temp.ReadCelsius();
            InvokeAsync(StateHasChanged);
        }, null, 0, 1000); // 1秒ごとに更新
    }

    public void Dispose() => _timer?.Dispose();
}

実機で dotnet run --urls "http://0.0.0.0:5000" し、/temperature を開いて室温付近の値が出れば成功です。

💡 値が小刻みに揺れる場合は、数回読んで平均するとノイズが減って安定します。

ブラウザ画面

つまずきポイント

まとめ

次回(第5回)は、この温度をSignalRでリアルタイムのライブグラフにします。ポーリングより滑らかで、Blazor Serverの強みが活きる回です。


前の記事:連載③ BlazorのWeb画面からGPIOを操作する(LED・ボタン)


この記事をシェア:

前の記事
BlazorのWeb画面からGPIOを操作する|LEDとボタン(Raspberry Pi)【連載③】
次の記事
温度をSignalRでライブグラフ表示する|Blazor Serverのリアルタイム更新【連載⑤】