先日トマトの種を、3Dプリンターで作った育苗トレイに撒きました。

今日で7日目なのですが、やっと芽がでてきました。

とても小さくて、雑草かとも思いましたがトマトの芽のようなので取り敢えず安心しました。

今後も注意深く見守って育てていこうと思っています。

 

生活がかかってますからね。食べるものが無いのです。

苗を買うより、種で育てたほうが安いと思うのですが、苗まで育てるのも楽ではないですよね。

 

私は素人なので、今回初めての挑戦です。

この先どうなるかわかりませんが、また紹介していきたいと思います。

 

小さくてよく見えませんが、芽のようです。

 

 
 
 
見出し画像

今まで作った時計は、8x8マトリクスLEDのWIFI時計とMP3音声WIFI時計などを作っていますが、今回はマニュアルセットの簡単なデジタル時計にしてみました。

NANOにはWIFI接続する機能が無いので、消費電力の少ない手軽に使える時計がいいかなと思ったんです。

普通だとESP32でWIFI接続してサーバーから時刻取得させるのですが、意外と消費電力が高めなので、細かいことは検証していませんがバッテリー動作では長く持たないだろうと思っていたんです。

じゃ、どれだけNANOは持つのかということですが、検証を始めています。
プログラムをやっとAI頼みで作りましたが、トラブル続きで1日かかりました。自分で作る以上にはるかに簡単ではあるのですが、意外と欠落する部分もあって動かないことも多々あり、配線が悪いのかソフトが悪いのか、それとも部品なのか等々ハマってしまい、最終的にはコマンドが漏れて表示が出ないなどのトラブルがあって、調べるのに時間がかかって目が疲れます。

取り敢えず試作完了できたので、バッテリーがどのくらい持つのか動作させてみました。
バッテリーは18650の2000mAh3.7Vを5Vに昇圧してやりましたが、満充電で2日くらいだったような、期待ハズレで記憶が飛んでしまいましたが、「そんなものなんだ」という結果でした。
しかし、このバッテリー自体が本当にこの容量なのかは不明です。なんせC国製なので、まがい物もあるようですしきちんと調べたいところですが、面倒くさいこともあり、今度はニッケル水素電池で試してみたいと思います。

 

画像
試作動作テスト写真


時計の機能は、年月日と時刻の同時表示アラーム機能、そしてバッテリーの残量表示を付けただけです。
電源を入れて、年月日と時刻をセットして動かすだけです。バッテリーが切れてもRTCモジュールの電池で時刻データが保存されているので、バッテリーを交換するだけで使えるようにしました。
バッテリーの残量表示を付けてはみましたが、バッテリーの特性上で電圧が急に下がって時計の動作が停止してしまうので、意味のない機能になっています。
興味ある方は、下記プログラムを記載しますので、遊んでみてください。
皆さんの参考になれば幸いです。

 

画像
OLED表示内容
// arduinoNANOで作る手動調整デジタル時計 Manually adjusted clock
//(年月日時刻アラームセット、バッテリー残表示)
// 必要部品:NANO,DS2321,OLED,圧電ブザー他
// 2026/02/23 konan0119
#include <Wire.h>
#include <RTClib.h>
#include <U8g2lib.h>
// ▼ OLED(I2C)
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
RTC_DS3231 rtc;
// ▼ フォント設定(自由に変更可能)
#define FONT_YEAR   u8g2_font_fub17_tf   // 年(中)
#define FONT_MONTH  u8g2_font_fub25_tf   // 月(中)
#define FONT_DAY    u8g2_font_fub25_tf   // 日(大)
#define FONT_TIME   u8g2_font_fub25_tf   // 時・分(大)
#define FONT_SEC    u8g2_font_fub17_tf   // 秒(中)
// ▼ ボタン
const int BTN_SET = 2;//接続ピン
const int BTN_UP  = 3;//接続ピン
const int BTN_DOWN = 4;//接続ピン
// ▼ ブザー
const int BUZZER = 8;//接続ピン
// ▼ モード
int mode = 0;
// ▼ アラーム
int alarmHour = -1;
int alarmMin = -1;
bool alarmActive = false;
unsigned long alarmStart = 0;
// ▼ ボタン用タイマー
unsigned long lastSet = 0;
unsigned long lastUp = 0;
unsigned long lastDown = 0;
// ▼ バッテリー電圧取得
float getBatteryVoltage() {
  int raw = analogRead(A0);//接続ピン
  float v = raw * (5.0 / 1023.0);
  return v * 2.0;  // 分圧補正
}
// ▼ バッテリー残量(%)
int getBatteryPercent(float v) {
  if (v >= 4.20) return 100;
  if (v >= 3.95) return 75;
  if (v >= 3.80) return 50;
  if (v >= 3.65) return 25;
  if (v >= 3.30) return 10;
  return 0;
}

void setup() {
  pinMode(BTN_SET, INPUT_PULLUP);
  pinMode(BTN_UP, INPUT_PULLUP);
  pinMode(BTN_DOWN, INPUT_PULLUP);
  pinMode(BUZZER, OUTPUT);
  Wire.begin();
  rtc.begin();
  u8g2.begin();
}

void drawDate(DateTime now) {
  int yy = now.year() % 100;
  
  u8g2.setFont(FONT_YEAR);
  char ybuf[5];
  sprintf(ybuf, "%02d", yy);
  u8g2.drawStr(0, 25, ybuf);
  
  u8g2.setFont(FONT_MONTH);
  char mbuf[5];
  sprintf(mbuf, ".%02d.", now.month());
  u8g2.drawStr(28, 25, mbuf);
  
  u8g2.setFont(FONT_DAY);
  char dbuf[5];
  sprintf(dbuf, "%02d", now.day());
  u8g2.drawStr(90, 25, dbuf);
}

void drawTime(DateTime now) {
  u8g2.setFont(FONT_TIME);
  char hm[10];
  sprintf(hm, "%02d:%02d:", now.hour(), now.minute());
  u8g2.drawStr(0, 55, hm);
  
  u8g2.setFont(FONT_SEC);
  char ss[5];
  sprintf(ss, "%02d", now.second());
  u8g2.drawStr(100, 55, ss);
}

void adjustTime(DateTime now, int diff) {
  int y = now.year();
  int mo = now.month();
  int d = now.day();
  int h = now.hour();
  int mi = now.minute();
  int s = now.second();
  if (mode == 1) { h += diff; if (h < 0) h = 23; if (h > 23) h = 0; }
  if (mode == 2) { mi += diff; if (mi < 0) mi = 59; if (mi > 59) mi = 0; }
  if (mode == 3) { y += diff; if (y < 2000) y = 2099; if (y > 2099) y = 2000; }
  if (mode == 4) { mo += diff; if (mo < 1) mo = 12; if (mo > 12) mo = 1; }
  if (mode == 5) { d += diff; if (d < 1) d = 31; if (d > 31) d = 1; }
  rtc.adjust(DateTime(y, mo, d, h, mi, s));
}

void adjustAlarm(int diff) {
  if (mode == 6) {
    alarmHour += diff;
    if (alarmHour < 0) alarmHour = 23;
    if (alarmHour > 23) alarmHour = 0;
  }
  if (mode == 7) {
    alarmMin += diff;
    if (alarmMin < 0) alarmMin = 59;
    if (alarmMin > 59) alarmMin = 0;
  }
  alarmActive = true;
}

void loop() {
  DateTime now = rtc.now();
  // ▼ SETボタン(長押し優先)
  if (!digitalRead(BTN_SET)) {
    // 長押し判定(アラーム解除)
    unsigned long t = millis();
    while (!digitalRead(BTN_SET)) {
      if (millis() - t > 800) {// 0.8秒以上で長押し
        alarmActive = false;
        alarmStart = 0;
        noTone(BUZZER);
        lastSet = millis();// チャタリング防止
        return; // ← ここが重要!短押し処理をさせない
      }
    }

    // 短押し判定(mode++)
    if (millis() - lastSet > 200) {
      mode++;
      if (mode > 7) mode = 0;
      lastSet = millis();
    }
  }

  // ▼ UPボタン
  if (!digitalRead(BTN_UP)) {
    if (millis() - lastUp > 120) {
      if (mode <= 5) adjustTime(now, +1);
      else adjustAlarm(+1);
      lastUp = millis();
    }
  }

  // ▼ DOWNボタン
  if (!digitalRead(BTN_DOWN)) {
    if (millis() - lastDown > 120) {
      if (mode <= 5) adjustTime(now, -1);
      else adjustAlarm(-1);
      lastDown = millis();
    }
  }
  // ▼ アラーム開始条件
  if (alarmActive &&
      now.hour() == alarmHour &&
      now.minute() == alarmMin &&
      now.second() <= 2 &&   // ← 0〜2秒の間ならOK
      alarmStart == 0) {     // ← 多重起動防止

      alarmStart = millis();
  }

  // ▼ アラーム鳴動(ピピピ)
  if (millis() - alarmStart < 30000 && alarmStart != 0) {
    unsigned long t = millis() - alarmStart;
    unsigned long cycle = t % 1000;// 1秒周期

    if (cycle < 100 || (cycle >= 200 && cycle < 300) || (cycle >= 400 && cycle < 500)) {
      tone(BUZZER, 2000);// ピ
    } else {
      noTone(BUZZER); // 無音
    }
  } else {
    noTone(BUZZER);
  }

  // ▼ 描画開始
  u8g2.clearBuffer();

  drawDate(now);
  drawTime(now);

  // ▼ アラーム or バッテリー表示
  if (alarmActive) {
    u8g2.setFont(u8g2_font_6x12_tf);
    char abuf[20];
    sprintf(abuf, "ALARM %02d:%02d", alarmHour, alarmMin);
    u8g2.drawStr(0, 64, abuf);
  } else {
    float v = getBatteryVoltage();
    int p = getBatteryPercent(v);

    u8g2.setFont(u8g2_font_6x12_tf);
    char bbuf[20];
    sprintf(bbuf, "BAT %d%%", p);
    u8g2.drawStr(0, 64, bbuf);
  }

  // ▼ 設定モード表示
  if (mode != 0) {
    u8g2.setFont(u8g2_font_6x12_tf);
    const char* modes[] = {
      "", "HOUR", "MINUTE", "YEAR",
      "MONTH", "DAY", "ALM-H", "ALM-M"
    };
    u8g2.drawStr(90, 64, modes[mode]);
  }

  u8g2.sendBuffer();
}