ハンズ・オン - 4
※この記事に掲載されている情報は、2019年6月時点のものです。
温度測定
今回は、サーミスタを使用して温度を測定します。
使用パーツ
- サーミスタ(103AT)
- 抵抗器10kΩ
- ブレッドボード
サーミスタとは
温度によって抵抗値が変動する素子です。その抵抗値と温度の関係は下のような近似式で表現できます。
これをTについて解くとこうなります。
下図はデータシートの一部です。値BはB定数と呼ばれ、サーミスタ素子ごとに決まった値があります。 Toは25℃です。 Rrefは回路ごとに任意に決めてよく、ここでは10kΩとします。
出典 http://akizukidenshi.com/download/ds/semitec/at-thms.pdf
あとはRつまりサーミスタの抵抗値がわかれば、温度Tを求めることができます。 ではどうやってRを測定するのでしょうか? 下図をご覧ください。
この図の電圧値Vrefがわかればよいことを示しています。よく見ると、これもオームの法則ですね。
ESP32には(そして他の多くのワンチップマイコンにも)、ADC(アナログ・デジタル・コンバータ)が搭載されており、Vrefの値を測定できます。 ちなみにラズパイにはADCが搭載されていませんので、別途ADCチップを買ってきて回路を組む必要があります。
ブレッドボードに配線する
ESP32開発ボードと抵抗器、サーミスタをブレッドボードで接続しましょう。青い素子がサーミスタで、方向の決まりはありません。
回路図と見比べることで、「IO0」ピンを3.3Vに固定し、「IO4」ピンがVrefを計測するということを理解できると思います。
プログラムを書く
いままでのハンズ・オンと同様にテンプレートをcloneします。
cd $HOME/esp
git clone https://github.com/hasumikin/mrubyc-template-esp32.git measuring-temperature
cd measuring-temperature
main/main.c
#include "driver/gpio.h"
#include "driver/adc.h"
#include "esp_adc_cal.h"
#include "mrubyc.h"
#include "models/thermistor.h"
#include "loops/master.h"
#define DEFAULT_VREF 1100
#define NO_OF_SAMPLES 64
#define MEMORY_SIZE (1024*40)
static esp_adc_cal_characteristics_t *adc_chars;
static const adc_channel_t channel = ADC_CHANNEL_0; //GPIO4
static const adc_atten_t atten = ADC_ATTEN_DB_11;
static const adc_unit_t unit = ADC_UNIT_2;
static uint8_t memory_pool[MEMORY_SIZE];
static void c_gpio_init_output(mrb_vm *vm, mrb_value *v, int argc) {
int pin = GET_INT_ARG(1);
console_printf("init pin %d\n", pin);
gpio_set_direction(pin, GPIO_MODE_OUTPUT);
}
static void c_gpio_set_level(mrb_vm *vm, mrb_value *v, int argc){
int pin = GET_INT_ARG(1);
int level = GET_INT_ARG(2);
gpio_set_level(pin, level);
}
static void c_init_adc(mrb_vm *vm, mrb_value *v, int argc){
adc2_config_channel_atten((adc2_channel_t)channel, atten);
adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t));
esp_adc_cal_characterize(unit, atten, ADC_WIDTH_BIT_12, DEFAULT_VREF, adc_chars);
}
static void c_read_adc(mrb_vm *vm, mrb_value *v, int argc){
uint32_t adc_reading = 0;
for (int i = 0; i < NO_OF_SAMPLES; i++) {
int raw;
adc2_get_raw((adc2_channel_t)channel, ADC_WIDTH_BIT_12, &raw);
adc_reading += raw;
}
adc_reading /= NO_OF_SAMPLES;
uint32_t millivolts = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars);
SET_INT_RETURN(millivolts);
}
void app_main(void) {
mrbc_init(memory_pool, MEMORY_SIZE);
mrbc_define_method(0, mrbc_class_object, "gpio_init_output", c_gpio_init_output);
mrbc_define_method(0, mrbc_class_object, "gpio_set_level", c_gpio_set_level);
mrbc_define_method(0, mrbc_class_object, "init_adc", c_init_adc);
mrbc_define_method(0, mrbc_class_object, "read_adc", c_read_adc);
mrbc_create_task( thermistor, 0 );
mrbc_create_task( master, 0 );
mrbc_run();
}
mrblib/loops/master.rb
thermistor = Thermistor.new
while true
puts "temperature: #{thermistor.temperature}"
sleep 1
end
mrblib/models/thermistor.rb
B = 3435
To = 25
V = 3300 # mV
Rref = 10_000 # Ohm
class Thermistor
def initialize
gpio_init_output(0)
gpio_set_level(0, 1)
init_adc
end
def temperature
vref = read_adc
r = (V - vref).to_f / (vref.to_f/ Rref)
1.to_f / ( 1.to_f / B * Math.log(r / Rref) + 1.to_f / (To + 273) ) - 273
end
end
Mathクラスを有効化
対数を計算するために、mruby/cのMathクラス(数学計算のためのライブラリ)を有効にしなければなりません。デフォルトではオフになっているためです。
components/mrubyc/mrubyc_src/vm_config.h
を開き、この行を探し、
#define MRBC_USE_MATH 0
以下のように修正してください。0を1にするだけです。
#define MRBC_USE_MATH 1
ビルド、実行
もちろん make flash monitor
で実行できます(menuconfig画面のシリアルポート設定もお忘れなく)。
うまくいけば、1秒ごとに温度が表示されるはずです。