いい感じ。表示した時の消費電流が4.6mAとやや大きかった(サーボの非動作時電流3.6mAくらいより大きい)のでon/offスイッチもつけた。
表示を消した時の消費電流は忘れたけど1mAちょい。ついでに今計ったら湿度センサDHT20は0.5mA、ATtiney85は7.3mAくらい。特にスリープとか使ってないんでこんなもんか。本当はもっと省電力にして電池駆動にしたいけど面倒なのでやらない。
ちょっと長いけど全コード。ATtiny85のメモリぎりぎり、printf()はめちゃめちゃメモリ食うことが判明した。
#include <Wire.h> #include "DHT20.h" #include "SSD1306Ascii.h" #include "SSD1306AsciiWire.h" #define SERVO_PIN 3 #define CHECK_BUTTON_PIN 4 #define NO_BUTTON_PRESSED 0 #define TOGGLE_OLED_PRESSED 1 #define LEVEL_UP_PRESSED 2 #define LEVEL_DOWN_PRESSED 3 #define MIN_MODE_DURATION 180000 // 3 minutes #define INTERVAL 2.5f DHT20 DHT; int humidTarget = 50; long modeInTime = -MIN_MODE_DURATION; bool isTurnedOn = false; bool isOledOn = false; #define I2C_ADDRESS 0x3C #define RST_PIN -1 SSD1306AsciiWire oled; // Uses CHECK_BUTTON_PIN=4 void adcSettings() { //https://www.hackster.io/Ned_zib/getting-started-with-adc-and-serial-attiny85-0db9f6 ADMUX = (0 << ADLAR) | // do not left shift result (for 10-bit values) (0 << REFS2) | // Sets ref. voltage to internal VCC, bit 2 (0 << REFS1) | // Sets ref. voltage to internal VCC, bit 1 (0 << REFS0) | // Sets ref. voltage to internal VCC, bit 0 (0 << MUX3) | // use ADC2 for input (PB4), MUX bit 3 (0 << MUX2) | // use ADC2 for input (PB4), MUX bit 2 (1 << MUX1) | // use ADC2 for input (PB4), MUX bit 1 (0 << MUX0); // use ADC2 for input (PB4), MUX bit 0 ADCSRA = (1 << ADEN) | // Enable ADC (1 << ADPS2) | // set prescaler to 64, bit 2 (1 << ADPS1) | // set prescaler to 64, bit 1 (1 << ADPS0); // set prescaler to 64, bit 0 } int readAdc() { //https://www.hackster.io/Ned_zib/getting-started-with-adc-and-serial-attiny85-0db9f6 uint8_t adc_lobyte; uint16_t raw_adc; int var=0; ADCSRA |= (1 << ADSC); // start ADC measurement adc_lobyte = ADCL; // get the sample value from ADCL raw_adc = ADCH<<8 | adc_lobyte; // add lobyte and hibyte //raw_adc are our measure return raw_adc; } float getHumidity(float* temperature=NULL) { DHT.readStatus(); DHT.read(); if (temperature) { *temperature = DHT.getTemperature(); } return DHT.getHumidity(); } float turnOnHumidityValue() { return humidTarget; } float turnOffHumidityValue() { return humidTarget + INTERVAL; } void moveToHomePosition(int numLoops=7, int delayPeriod=1000) { for (int j = 0; j < numLoops; ++j) { digitalWrite(SERVO_PIN, HIGH); delayMicroseconds(500); digitalWrite(SERVO_PIN, LOW); delayMicroseconds(20000 - 500); } delay(delayPeriod); } void oledPrint(bool force=false) { if ((!isOledOn) && (!force)) { return; } oled.setCursor(0, 0); float temperature; int humidity = (int)getHumidity(&temperature); int temp10 = (int)(temperature * 10); oled.print(humidity); oled.print("% "); if (temperature < 10.0f) { oled.print(" "); } oled.print((int)temperature); oled.print("."); oled.print(temp10 % 10); oled.println("C"); oled.println(""); oled.print("SET "); oled.print(humidTarget); oled.println("%"); oled.print(isTurnedOn? "ON " : "OFF"); } void toggleOled() { oled.clear(); isOledOn = !isOledOn; } void pressSwitch() { for (int j = 0; j < 32; ++j) { digitalWrite(SERVO_PIN, HIGH); delayMicroseconds(2400); digitalWrite(SERVO_PIN, LOW); delayMicroseconds(20000 - 2400); } moveToHomePosition(); } int _checkButtonPress() { int val = readAdc(); if (val < 250) { return TOGGLE_OLED_PRESSED; } else if (val < 500) { return LEVEL_UP_PRESSED; } else if (val < 750) { return LEVEL_DOWN_PRESSED; } else { return NO_BUTTON_PRESSED; } } int checkButtonPress() { int firstCheck = _checkButtonPress(); delay(5); int secondCheck = _checkButtonPress(); if (firstCheck == secondCheck) { return firstCheck; } else { return NO_BUTTON_PRESSED; } } void handleButtons() { oledPrint(); int button = checkButtonPress(); if (button == NO_BUTTON_PRESSED) { return; } if (button == TOGGLE_OLED_PRESSED) { toggleOled(); delay(500); return; } bool isFirstPress = true; while(button == LEVEL_UP_PRESSED || button == LEVEL_DOWN_PRESSED) { int newTarget = humidTarget + ((button == LEVEL_UP_PRESSED)? 1 : -1); humidTarget = min(max(newTarget, 10), 99); oledPrint(true); if (isFirstPress) { delay(500); isFirstPress = false; } button = checkButtonPress(); } if (!isOledOn) { delay(1000); oled.clear(); } } void turnOnMode() { isTurnedOn = true; moveToHomePosition(); // beep; pressSwitch(); // turn on; modeInTime = millis(); while(getHumidity() < turnOffHumidityValue() || millis() - modeInTime <= MIN_MODE_DURATION) { handleButtons(); } moveToHomePosition(); // beep; pressSwitch(); // turn off isTurnedOn = false; } void setup() { adcSettings(); pinMode(SERVO_PIN, OUTPUT); pinMode(CHECK_BUTTON_PIN, INPUT_PULLUP); pinMode(SDA, INPUT); // LET DHT20 pull up the line pinMode(SCL, INPUT); // LET DHT20 pull up the line DHT.begin(); Wire.setClock(400000); delay(1000); oled.begin(&Adafruit128x64, I2C_ADDRESS); oled.setFont(System5x7); oled.set2X(); oled.clear(); oledPrint(true); moveToHomePosition(); // Test servo position pressSwitch(); delay(1000); pressSwitch(); oled.clear(); } void loop() { float humidity = getHumidity(); if (humidity < turnOnHumidityValue() && millis() - modeInTime > MIN_MODE_DURATION) { turnOnMode(); modeInTime = millis(); } handleButtons(); }