【Rust&RaspberryPi】I2C通信で温度センサ値を読み取る

3 min read読了の目安(約3000字

やること

  1. 回路作成
  2. 温度センサの値を読み取る
  3. 温度をLCDに表示する

参考にしたサイト

同じことをやっている方がいたので参考にさせていただきました。

https://dev.classmethod.jp/articles/rust-rpi-publish-temp-to-aws-iot/

1. 回路作成

回路図

書き方わからないので今しばらくお待ち下さい。

使用したポート

|PINNo. PIN名称 入出設定
1 3.3V 入力
3 I2C SDA
5 I2C SCL
6 GND

2. 温度センサの値を読み取る

動作概要

  • 温度センサ値から現在の温度を取得する
  • 取得した温度情報をコンソールに表示する

crate設定

Cargo.toml
[dependencies]
rppal = "0.11.3"
ctrlc = "3.1.8"

実装

main.rs
  1 use std::error::Error;
  2 use std::thread;
  3 use std::time::Duration;
  4 
  5 use rppal::i2c::I2c; 
  6 use rppal::system::DeviceInfo;
  7 
  8 use std::sync::atomic::{AtomicBool, Ordering};
  9 use std::sync::Arc;
 10     
 11 
 12 const BUS: u8 = 1;
 13 const ADT7410_ADDRESS: u16 = 0x48;
 14 const REGISTER_ADDRESS: u8 = 0x00;
 15 
 16 fn main() -> Result<(), Box<dyn Error>> {
 17     let running = Arc::new(AtomicBool::new(true));
 18     let r = running.clone();
 19     
 20     ctrlc::set_handler(move || {
 21         r.store(false, Ordering::SeqCst);
 22     }).expect("Error setting Ctrl-c handler");
 23         
 24     println!("Blinking an Switch Control LED {}", DeviceInfo::new()?.model());
 25     
 26     let mut i2c = I2c::with_bus(BUS).expect("Fail I2C Connection");
 27     i2c.set_slave_address(ADT7410_ADDRESS).expect("Fail Connect ADT7410");
 28 
 29     while running.load(Ordering::SeqCst) {
 30         thread::sleep(Duration::from_millis(500));
 31         let temp = read_temperature(&i2c);
 32         println!("Temperature is {}", temp); 
 33     }
 34     
 35     Ok(())
 36 }   
 37         
 38 fn read_temperature(i2c: &I2c) -> f32 {
 39     let word = i2c.smbus_read_word(REGISTER_ADDRESS).unwrap();
 40     let data = ((word & 0xff00) >> 8 | (word & 0xff) << 8) >> 3;
 41 
 42     if data & 0x1000 == 0 {
 43         data as f32 * 0.0625
 44     } else {
 45         ((!data & 0x1fff) + 1) as f32 * -0.0625
 46     }
 47 }

コード解説

  • I2Cの初期設定
 26     let mut i2c = I2c::with_bus(BUS).expect("Fail I2C Connection");
 27     i2c.set_slave_address(ADT7410_ADDRESS).expect("Fail Connect ADT7410");

with_bus(BUS)でバス1を指定してI2Cバスを構築しています。
自分が使っているのは、「Raspberry Pi 3 Model B+」です。
初期の頃のモデルの場合はバス0を指定する必要があるようです。
set_slave_address(ADT7410)で通信するデバイスのアドレスを指定しています。
※接続しているデバイスの調べ方は以下のコマンドで見れます。

i2cdetect -y 1
  • 温度センサADT7410との通信
 31         let temp = read_temperature(&i2c);

上記関数で温度センサとの通信を行っています。

 39     let word = i2c.smbus_read_word(REGISTER).unwrap();
 40     let data = ((word & 0xff00) >> 8 | (word & 0xff) << 8) >> 3;

39行目で通信を行い、40行目で温度センサADT7410の通信フォーマットとsmbus_read_wordの通信仕様の違いを修正しています。
このあたりの通信については知識不足なので勉強したら改めて記事にする予定です。
※SPI通信に失敗している要因もこのせいだと思われるので。。。

  • 読み取ったセンサ値を温度に変換
 42     if data & 0x1000 == 0 {
 43         data as f32 * 0.0625
 44     } else {
 45         ((!data & 0x1fff) + 1) as f32 * -0.0625
 46     }

取得したセンサ値を、ADT7410の仕様に合わせて加工して温度表示に直します。
43行目が+の値を取得した場合、45行目が-の値を取得した場合です。

3. 温度をLCDに表示する

時間切れのため後日追記予定。