5ドル!ラズパイ・ゼロ(Raspberry pi Zero)でIoT (21) ディジタル温度センサ6 独自形式 LMT01
■2本だけで信号を伝える温度センサ
1-Wireセンサは信号線が1本ですが、電源が必要なので、3線もしくは2線で接続します。LMT01は、2本しかリード線がありません。1本は電源で、片方から信号がパルスで出力されます。デフォルトでHighが0.8V程度なので、ラズパイで扱うにはトランジスタによるレベル・シフト回路が必要です。
●温度データはパルス数で表現
LMT01は、約100msの周期で、約11.3usのパルス幅でパルスが出力されるので、このパルスをカウントすれば、温度に変換できます。データシートによれば、-50℃は26パルス、0℃は808パルス、20℃は1125パルス、30℃は1284パルス(いずれもtypical)です。常温は約1200カウント前後です。
●LMT01のスペック
- 電源電圧;2.0~5.5V
- 変換時の電流;34uA
- 温度の確度;±0.5℃(-20~90℃)
- 測定温度;-50~150℃
- 温度の分解能;0.0625℃
- 1サイクル;100ms
- データ転送時間;約50ms
●パルス数と温度の換算
データシートには、温度とパルスの対応表が掲載されています。-20℃から+50℃までのデータを読み取り、エクセルに入れ、補正関数を求めました。
y = 15.837 x + 809.07 温度 = (カウント数 - 809.07 )/ 15.837 |
●接続
LMT01のVp端子を3.3Vへ、Vn端子を6.8kΩでグラウンドにつないだとき、Vn端子には約0.8Vp-pのパルスが出ます。このままではラズパイが常にLowという判断をするので、データシートにあるようにトランジスタでレベル・シフトをします。小信号用のトランジスタのコレクタに入っている負荷抵抗が100kΩのとき、High電圧は2.7Vp-pぐらいになりました。
●プログラムの構成
カウント・プログラムは、100msの期間、パルスの立ち上がりもしくは立ち下がりの回数を測ります。つぎの構成を考えました。mainではGPIOのピンを指定して、エッジが変化するときに割り込みがかかるように設定し、100ms待ち、カウント数を表示、温度に換算して表示します。
割り込みプログラムedges内では、カウンタをインクリメントします。
Pythonで割り込みが記述できるのにライブラリにRPi.GPIOやpigpioがあります。
割り込み部分はカウンタをインクリメントするだけの最小限のプログラムを記述しましたが、どちらも、1kHzを超え始めると、取りこぼしが出ました。測定する周波数は88kHz前後です。pigpioのC言語用ライブラリでは500kHzが計測できると書かれています。
pigpioのサンプル・ページにあるFrequency Counter 1を修正して利用しました。最初に主な関数の利用方法を説明します。
◆割り込み処理に使うコールバック関数の要求
int gpioSetAlertFunc(unsigned user_gpio, gpioAlertFunc_t f) |
user_gpioはGPIOの番号(BCM表記)、f はコールバック関数(割り込み)名。
◆コールバック関数の記述
void callback関数名(int gpio, int level, uint32_t tick) |
gpioはポート番号、level;1は立ち上がり、0は立ち下がりエッジ。
◆GPIOのモード指定
int gpioSetMode(unsigned gpio, unsigned mode) |
user_gpioはGPIOの番号(BCM表記)、modeは、入力がPI_INPUT、出力はPI_OUTPUT。
◆時間待ち
uint32_t gpioDelay(uint32_t micros) |
microsはus単位。
◆初期化
int gpioInitialise(void) |
◆ポーリング・レートの設定
int gpioCfgClock(unsigned cfgMicros, unsigned cfgPeripheral, unsigned cfgSource) |
cfgMicrosはGPIOポートの変化をポーリングしているCPUパワーにかかわり、5だと10%、1だと25%、cfgPeripheralはPCMなので1、PWMなら0、cfgSourceは無視される。
●Cによるプログラム
gateTime=93は、測定時間を決めています。LMT01のマニュアルではデータを送り出す間隔は約100ms周期となっているので、絶対的な時間はわかりません。デバイスやラズパイの種類によって修正して、正しいデータがカウントできるように数字を調整します。
ファイル名をlmt01.cとし、実行ファイルをlmt01とすると、コンパイルは次のようにします。実行は sudo ./lmt01 です。
gcc -o lmt01 lmt01.c -lpigpio -lpthread |
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <pigpio.h>
//gcc -o lmt01 lmt01.c -lpigpio -lpthread
int inputGPIOpin = 26; //GPIO26
double temp;
int g_reset_counts = 0;
int g_pulse_count = 0;
int gateTime = 93;
//callback function
void edges(int gpio, int level, uint32_t tick)
{
//printf("call warikomi");
if (g_reset_counts)
{
g_reset_counts = 0;
g_pulse_count = 0;
}
/* high to low edges */
if (level == 0) g_pulse_count += 1;
//printf(" %d ",g_pulse_count);
}
int main()
{
gpioCfgClock(1, 1, 1);
gpioSetMode(inputGPIOpin, PI_INPUT);
if (gpioInitialise()<0) return 1;
/* monitor gpioPin level changes */
gpioSetAlertFunc(inputGPIOpin, edges);
while (1)
{
g_reset_counts = 1;
temp = (g_pulse_count-809 )/15.837;
printf("count= %d temp= %f",g_pulse_count,temp);
printf("\n");
gpioDelay(gateTime * 1000);
}
gpioTerminate();
}
●問題点
gpioCfgClock()のcfgMicrosを5とすると、27℃の室温を測ると約25℃と2℃ほどずれます。cfgMicrosを1にするとほぼ27℃になりますが、ときどき外れた値をカウントします。原因は不明です。ほかのプロセスによって100msが伸びてしまったのかもしれません。10回読み出したデータの中央値をとって表示するようなプログラムを作れば回避できるのではないかと思います。
センサは温度変化に大変敏感です。
実行結果です。
コラム Pythonによるカウント・プログラム例
いずれも最大で1kHzを少し超える周波数までカウントできました。
◆RPi.GPIO
#!usr/bin/env python
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.cleanup()
GPIOpin = 26
GPIO.setup(GPIOpin,GPIO.IN)
counter = 0.0
#callback
def callback_count( pin ):
global counter
counter += 1
# print counter
#main
data = [0]
print ("data "),data,time.time()
'''
while 1 : # find Low
i = 0
while i<5 :
i += 1
data.append ( GPIO.input(GPIOpin) )
# print (data)
if ( 1 in data):
data = [0]
else :
print("find start condition ")
break
'''
print time.time(),("start counter "),counter
GPIO.add_event_detect(GPIOpin,GPIO.RISING,callback=callback_count)
time.sleep(1)
print ("LAST counter "),counter◆pigpio
ターミナルで、sudo pigpiod というプログラムを実行してデーモンを動かしておきます。なお、このデーモンが動いていると、本文のCのプログラムは動きません。
#!usr/bin/env pytho
#sudo pigpiod
import time
GPIOpin = 26
import pigpio
pi = pigpio.pi()
pi.set_mode(GPIOpin,pigpio.INPUT)
counter = 0.0
#callback
def callback_count( gpio, level, tick):
global counter
counter += 1
# print counter
#main
data = [0]
print ("data "),data,time.time()
'''
while 1 : # find Low
i = 0
while i<5 :
i += 1
data.append ( pi.read(GPIOpin))
# print (data)
if ( 1 in data):
data = [0]
else :
print("find start condition ")
break
'''
print time.time(),("start counter "),counter
pi.callback(GPIOpin,pigpio.RISING_EDGE,callback_count)
time.sleep(1)
print ("LAST counter "),counter