HDC1080の記事を書いたあとに、「産業用高精度 温度湿度」センサーと書いてあったのできっとすごいセンサーだと思って amazonでポチッた
ポチったあとにデータシートみて驚愕したんだけどI2Cのアドレスは 0x40 固定だった
HDC1080とまったく同じだ。
RaspberryPi3 だと I2Cが一個しかないので一個しかぶら下げられない。なんという事でしょう。Pi4なら複数のI2Cがあるけど
温度/湿度なんてI2Cほど速度いらないから1-wireのほうがいいのかな。こちらはデバイス毎に固有アドレスがあるし。
どこかからソースパクってこよう、は安易すぎた
なかなか古いデバイスのようで、GoLang + Si7021 でググるといくつか github にヒットする
けどなんかこうGoLangのバージョン依存してたり、OS依存しててコンパイルできなかったりした
結局 ここのデータシート 読んで自分で書いた方が早かった。3時間も無駄にしたよ..
CRCはちゃんと計算しよう
最初10分で書いた信頼性がなさすぎた実験でケーブルが短い時は大丈夫だったけど、3mの単芯ケーブルにしたら通信エラーが起きているっぽくで、湿度が-50%とかになってる
他のセンサー(DC-CO2-20)では通信エラーが起きていないので、デバイスのドライブが弱いのかな、と人のせいにしてはいけない 。ちゃんとCRC計算しよう...
ハードウェアの結線
Raspberry PIとの結線は SDA,SDL, 3.3V , GND の4本だけ
GoLang は 1.16 で macOSを使用
アドレスの確認
# i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
0x40にいた。HCM1080と同じアドレスだ。困る。
I2Cをsudoしなくても読めるようにする
# sudo usermod -aG i2c zabbix
パッケージの準備
% mkdir si7021
% cd si7021
% go mod init si7021
go: creating new go.mod: module si7021
go: to add module requirements and sums:
go mod tidy
% go mod tidy
go: finding module for package github.com/davecheney/i2c
go: found github.com/davecheney/i2c in github.com/davecheney/i2c v0.0.0-20140823063045-caf08501bef2
ソース
// macOS closs compile
// GOOS=linux GOARCH=arm go build
package main
import (
"fmt"
"os"
"time"
"github.com/davecheney/i2c" // go get github.com/davecheney/i2c
"encoding/binary"
)
const (
wait = 100 * time.Millisecond // 100milisec
)
func write(dev *i2c.I2C, s string) {
chars := []byte(s)
dev.Write(append([]byte{0x40}, chars...))
time.Sleep(wait)
}
func help() {
fmt.Println( "exp: hdc1080 0 or 1 (0=Ondo 1=Shitudo 9=reset")
}
// 2byteの値から1byteのcrcを返す
func calcCRC(seed byte, buf []byte) byte {
for i := 0; i < len(buf); i++ {
seed ^= buf[i]
for j := 0; j < 8; j++ {
if seed&0x80 != 0 {
seed <<= 1
seed ^= 0x31
} else {
seed <<= 1
}
}
}
return seed
}
func Reset() {
dev, _ := i2c.New(0x40, 1)
dev.Write([]byte{0xFE}) // CMD_RESET
time.Sleep(wait * 5)
}
func ReadData(cmd byte) float32 {
var i float32
var b = []byte{0, 0, 0}
var b2 = []byte{0, 0}
// 0x40 is I2C address , 1 is /dev/i2c-1
dev, _ := i2c.New(0x40, 1)
cnt := 0;
again:
dev.Write([]byte{cmd}) // CMD_TEMPTURE
time.Sleep(wait)
dev.Read(b) // 3byte読み込み
b2[0] = b[0]
b2[1] = b[1] // 素人すぎるプログラムww
crc := calcCRC( 0x00 , b2 )
if crc != b[2] {
fmt.Fprintln( os.Stderr , "CRC error")
time.Sleep( wait * 10 ) // 1秒
Reset()
time.Sleep( wait * 10 ) // 1秒
cnt += 1
if cnt > 5 {
return -1
} // error
goto again
}
i = float32(binary.BigEndian.Uint16(b2))
time.Sleep(wait)
return i
}
func main() {
if len(os.Args) < 2 {
help()
os.Exit(-1)
}
switch os.Args[1] {
case "0":
f32 := ReadData(0xF3) // / CMD_TEMPTURE
if ( f32 != -1 ) {
c := float32(f32) * 175.72 / 65536. - 46.85
fmt.Printf("%.2f\n",c)
} else {
fmt.Println(-1)
}
case "1":
f32 := ReadData(0xF5) // / CMD_HUM
if ( f32 != -1 ) {
c := float32(f32) * 125. / 65536. - 6.
fmt.Printf("%.2f\n",c)
} else {
fmt.Println(-1)
}
case "9":
Reset()
default:
help()
}
}
コンパイル
GOOS=linux GOARCH=arm go build
これでバイナリができたので、RaspberryPIに scp して実行
# 温度
$ ./si7021 0
21.715549316406246
# 湿度
$ ./si7021 1
39.543670654296875
# リセット送信 (いるのかな? )
$ ./si7021 9
高精度?
うーんと、精度はどうなんだろう
hdc1080と温度で0.5度くらい、湿度で1%くらいの差くらい
hdc1080も割と高精度なんでは...
おしまい