目的:適切なタイミングで植物に水をやれるようにする
植木鉢の土の電気抵抗を測定する回路を作る
抵抗値を図るには電極を2本植木鉢にさして電気を流せばいいのだが、直流電流をながちっぱなしにすると電極が陽極だけ消耗してゆく気がする。そこで、数秒に1回一瞬だけ電気を流して抵抗を測定することにする。さらに、電極の片減りを防ぐために測定時にプラスマイナスを入れ替えて矩形波の交流を流すことにする。
ArduinoのプログラムをATTiny13Aに流し込むことを覚えたのでこんな感じの回路にしてみる。
- 1番ピンはリセットなので空けておく。
- 2、3番ピンのH,Lを交互に入れ替えて矩形波交流を作る。
- 7番ピンで電圧を測ってそこから抵抗値を割り出す。
- 水やり時期になると5番ピンにつないだLEDが点滅して水やりを促す。
ソフトウエアの開発
プログラムによって電池の持ちが全く違ってくるので驚いた。
肝はできるだけスリープさせること。
- setup関数で約1秒ごとにsleepから復帰する設定をする。
- ISR関数のところでカウンタをインクリメントするとともに電気抵抗測定関数を呼び出す。
- カウンタが3を超えたら、つまり4秒たったら電気抵抗を測定して、回路が動作している証にLEDを1回点滅させ、カウンタをリセットさせる。
- 電気抵抗が閾値(ここでは2KΩ)を超えたらカウンタに関係なくLEDを1回点滅させる。これで、乾燥しているとLEDが毎秒光ることになる。
- 測定が終了したらAD変換機の回路をoffにして消費電力を抑え、スリープ。
Attiny13PlantHydrateCheck_sleep3.1.ino
# include <avr/interrupt.h>
# include <avr/sleep.h>
/* Deep sleep code from https://arduinodiy.wordpress.com/2015/06/22/flashing-an-led-with-attiny13/ */
# define PINA 3
# define PINB 4
# define PINI 1
# define LED 0
# define PIN2 2
# define SLEEP 2 /* 2S */
# define REF 10 /* 10K ohm */
# define DRY 3 /* define if >3K ohm */
# define BODS 7 //BOD Sleep bit in MCUCR
# define BODSE 2 //BOD Sleep enable bit in MCUCR
int counter=5;
int resistance;
ISR(WDT_vect) {
measure();
counter++;
/*
if(counter++>=4){ // around 4 seq
measure();
counter=0;
}
*/
}
void measure(){
int value;
if(counter > 3){
digitalWrite(PINA, HIGH);
value=analogRead(PINI);
digitalWrite(PINA, LOW);
digitalWrite(PINB, HIGH);
value=1023-analogRead(PINI);
digitalWrite(PINB, LOW);
resistance=checkResistance(value);
blink(7);
counter=0;
}else if(resistance >= DRY){
blink(7);
}
// disable ADC http://tetsuakibaba.jp/index.php?page=workshop/ArduinoBasis/sleep
ADCSRA &= ~(1 << ADEN);
}
void blink(char span){
digitalWrite(LED, HIGH);
delay(span);
digitalWrite(LED, LOW);
}
void setup(){
// Set PB3 to output
DDRB = 1<<DDB3;
//set timer to 4 sec
//WDTCR |= (1<<WDP3) | (0<<WDP2) | (0<<WDP1) | (0<<WDP0);
//set timer to 1 sec
WDTCR |= (0<<WDP3) | (1<<WDP2) | (1<<WDP1) | (0<<WDP0);
// set timer to 0.5s
//WDTCR |= (0<<WDP3) | (1<<WDP2) | (0<<WDP1) | (1<<WDP0);
// Set watchdog timer in interrupt mode
WDTCR |= (1<<WDTIE);
WDTCR |= (0<<WDE);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sei(); // Enable global interrupts
pinMode(PINI, INPUT);
pinMode(PINA, OUTPUT);
pinMode(PINB, OUTPUT);
pinMode(LED, OUTPUT);
digitalWrite(PINA, LOW);
digitalWrite(PINB, LOW);
digitalWrite(LED, LOW);
}
int checkResistance(int value){
int resistance;
int i;
if(value < 1000){
resistance=REF*value/(1023-value);
}else{
resistance=DRY;
}return resistance;
}
void loop() {
// Everything is already handled in the ISR
sleep_mode();
}
運用してみた結果
LR44ボタン電池2個を直列にして3Vを稼いでいる。3月くらいから運用しているけど、8月28日現在、電池交換なしで稼働してます。
ほかに、HT7733Aを使って単4電池1本で動くものも作っているけど、こちらも何か月も電池交換なしで動いています。
課題
- いろいろな植木鉢で試してみたところ、閾値2KΩでは乾燥しすぎの場合もあるので、閾値を調整する必要がありそう。
- あとは、水やり後の抵抗から肥料レベルを測定したり、一定時間乾燥させてから水やりを促したりできるといいけど、そのためにはきっと、もっとデータ集めが必要だと思う。
- 5,6,7番ピンで抵抗を測定して、2番か3番ピンでLEDを光らせると実装がもっとすっきりすると思う。
