内部温度センサー
この実装の例は、こちらにあります: 3_temperature.rs。
✅ 準備: コード内でボードとタイマー周辺機器を初期化しておいてください。
ドライバーを作成する必要がある外部センサーを扱い始める前に、まずはボードの内部温度センサーにアクセスします。HAL を見て、周辺機器へのアクセスが詳細にはどのように機能するのか、また Rust でメソッドがどのように機能するのかを詳しく見ていきます。
✅ nrf-hal-common 0.11.1 を開きます
✅ /src/temp.rs を開きます。ここには、ボードの温度センサーとの通信が実装されています。
統合された温度センサーは構造体です: pub struct Temp(TEMP)。外部から呼び出せるようにする必要があるため、public である必要があります。TEMP は peripheral access crate (pac) で定義されている型で、温度センサーのレジスタブロックにアクセスします。impl ブロック内には、Temp に対して定義されたすべてのメソッドがあります。
メソッドは、オブジェクトに結び付けられているという点で関数とは異なります。詳しく見てみましょう。
pub fn new() は TEMP を引数として受け取り、Temp を返します。このメソッドは温度センサーのレジスタブロックの所有権を取得します。
✅ コード内で Temp を使用できるようにするには、まずスコープに取り込む必要があります。次の行をコードに追加してください。
#![allow(unused)]
fn main() {
use nrf52840_hal::{
self as hal,
Temp,
Timer,
};
}
✅ board.TEMP を引数として new メソッドを呼び出し、温度センサーのレジスタブロックの所有権を取得します。この変数は mutable である必要があります。
#![allow(unused)]
fn main() {
let mut temp = Temp::new(board.TEMP);
}
これで温度センサーのインスタンスが得られたので、測定を行うことができます。
✅ HAL のコードにある temp.rs に戻ります。
fn measure() は、self への mutable な参照を引数として受け取ります。self は、fn new() で作成された温度センサーのインスタンスです。このメソッドは、すでに測定が開始されている場合はその測定を停止し、新しい測定を開始して、測定が完了するまでプログラムをブロックし、その後で固定小数点数 I30F2 を返します。もう 1 つの選択肢は、fn start_measurement() で測定を開始し、fn read() で測定値を読み取る方法で、これはノンブロッキングに動作します。測定は、レジスタに書き込むことで開始または停止されます。
ここではひとまず、ブロッキングメソッドである fn measure() を使います。
✅ コードに、測定を行う行と、温度値をログ出力する行を追加してください。
#![allow(unused)]
fn main() {
let temperature = temp.measure();
defmt::info!("{:?}", temperature);
}
この構文は、メソッドがオブジェクトに結び付けられていることを反映しています。引数 &mut self はドットの前にあるオブジェクトを指し、括弧の中は空のままです。
この時点でコードを実行すると、コンパイラーエラーが発生します。これは、fn measure() の戻り値の型である I30F2 に対して the trait defmt::Format is not implemented for I30F2 だからです。
✅ fn measure() の後ろに、さらに to_num() メソッドを追加します。このメソッドは固定小数点数を f32 にキャストします。表示できるようにするには、フォーマット文字列で型を指定する必要があります。
#![allow(unused)]
fn main() {
let temperature: f32 = temp.measure().to_num();
defmt::info!("{=f32} °C", temperature);
}
✅ 60 秒ごとに温度を測定して表示するループを初期化します。