05.T-Watch S3 plusでアラーム時刻設定画面テスト


05.T-Watch S3 plusでアラーム時刻設定画面テスト

T-Watch S3 plusにて、アラーム時刻を設定する画面をLVGL 9 で作ります。examples/others/observer/lv_example_observer_3.c を参照し、lv_observer, lv_roller 等を使用します。

画面説明

1行目

・Cancelボタン : 何もしません。後の連結時は、時計画面に戻る予定です。
・Setボタン : シリアルモニタに設定時刻を表示します。後の連結時は、時計画面に戻り、アラーム設定時刻を表示する予定です。

2行目

・ローラーで設定した時刻をリアルタイムで表示します。
例 1+ 1:30は、翌日のam1:30です。初期値は、今日の昼12:30(0+ 12:30)とします。

3行目

・左  : ローラーを上下に回転し、今日(0)か翌日(1)にあわせます。
・中央 : ローラーを上下に回転し、時(0~23)を合わせます。
・右  : ローラーを上下に回転し、分(0~59)を合わせます。
ローラーはエンドレスとします。..., 58, 59, 0, 1, ...

スケッチ


// アラーム時刻セット画面
// examples/others/observer/lv_example_observer_3.c 参照
#include <LilyGoLib.h>  // LilyGoLib 0.1.0(最新)を使用
#include <LV_Helper.h>  // LVGL 9.2.2(固定)を使用

static lv_subject_t day_subject;     // 今日/翌日 値が変わると、登録コールバックが呼ばれます
static lv_subject_t hour_subject;    // 時
static lv_subject_t minute_subject;  // 分
static lv_subject_t time_subject;    // 上3つが入るグループ

static lv_subject_t *time_group_array_subject[] = { &day_subject, &hour_subject, &minute_subject };  // グループにする
const char *day_options = "0\n1";                                                                    // 今日/翌日
const char *hour_options =
  "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23";  // 時 0-23
const char *minute_options =                                                               // 分 0-59
  "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36\n37\n38\n39\n40\n41\n42\n43\n44\n45\n46\n47\n48\n49\n50\n51\n52\n53\n54\n55\n56\n57\n58\n59";
int32_t setDay, setHour, setMinute;  // set_btnで引き渡す日&時&分


static void time_observer_cb(lv_observer_t *observer, lv_subject_t *subject) {  // ローラーの値をlabelに表示
  int32_t day = lv_subject_get_int(lv_subject_get_group_element(subject, 0));
  int32_t hour = lv_subject_get_int(lv_subject_get_group_element(subject, 1));
  int32_t minute = lv_subject_get_int(lv_subject_get_group_element(subject, 2));
  // lv_subject_get_int( )は、整数Subjectの現在の値を取得(Subjectへのpointer)、戻り値:現在の値
  // lv_subject_get_group_element( )は、
  // Subject Groupのリストから要素を取得(Group型のSubjectへのpointer,取得する要素のインデックス)
  // 戻り値:リスト内のインデックス付Subjectへのpointer インデックスが範囲外の場合はNULL
  setDay = day;        // set_btnをクリックしたら引き渡す 日
  setHour = hour;      // 時
  setMinute = minute;  // 分

  lv_obj_t *label = (lv_obj_t *)lv_observer_get_target(observer);
  // Observerのターゲットを取得(Observerへのpointer)、戻り値:保存されたターゲットへのpointer
  lv_label_set_text_fmt(label, "Alam   %" LV_PRId32 "+ %" LV_PRId32 " : %02" LV_PRId32, day, hour, minute);  // ローラーの値
}


static void set_btn_clicked_event_cb(lv_event_t *e) {  // set_btnを押したら呼出される関数
  lv_obj_t *set_btn = lv_event_get_target_obj(e);
  // イベントの元のターゲットobjを取得(イベント記述子へのpointer)、戻り値:event_codeの元のターゲットへのpointer
  Serial.printf("Alam %1d+ %2d:%02d", setDay, setHour, setMinute);  // シリアルモニタに日時分を表示
}


static void cxl_clicked_event_cb(lv_event_t *e) {  // cxl_btnを押したら
  // そのまま時計画面に戻る予定
}


void setup() {
  Serial.begin(115200);       // シリアルモニタの通信速度
  instance.begin();           // LilyGoLibを初期化
  beginLvglHelper(instance);  // LVGLを初期化
  lv_task_handler();
  instance.setBrightness(100);  // 明るさ0-255

  lv_subject_init_int(&day_subject, 0);      // 初期値 0今日
  lv_subject_init_int(&hour_subject, 12);    // 初期値 12時
  lv_subject_init_int(&minute_subject, 30);  // 初期値 30分
  //整数型のSubjectを初期化(Subjectへのpointer,初期値)
  lv_subject_init_group(&time_subject, time_group_array_subject, 3);
  // グループ型サブジェクトを初期化(グループ型サブジェクトへのpointer,
  // 他のサブジェクトアドレスのリスト,list[]内の要素数)

  // キャンセルボタン ------------------------------
  lv_obj_t *cxl_btn = lv_button_create(lv_screen_active());  // cxl_btnを作成
  lv_obj_set_pos(cxl_btn, 2, 5);                             // btnの位置

  lv_obj_t *cxl_label = lv_label_create(cxl_btn);                    // cxl_btnにlabelを作成
  lv_obj_set_style_text_font(cxl_label, &lv_font_montserrat_24, 0);  // 英数文字サイズ24,28,32,36,40,44,48
  lv_label_set_text(cxl_label, "Cancel");                            // labelのtextを設定

  // ラベル ------------------------------
  lv_obj_t *time_label = lv_label_create(lv_screen_active());         // time_labelを作成
  lv_obj_set_style_text_font(time_label, &lv_font_montserrat_28, 0);  // 英数文字サイズ24,28,32,36,40,44,48
  lv_subject_add_observer_obj(&time_subject, time_observer_cb, time_label, NULL);
  // ウィジェットのサブジェクトにオブザーバーを追加(サブジェクトへのポインタ,
  // 通知コールバック,ウィジェットへのpointer,オプションのユーザーデータ)
  // 戻り値:新しく作成されたオブザーバーへのpointer
  // ウィジェットが削除されると、オブザーバーはサブジェクトから自動的に登録解除。
  // 注:この方法で作成されたオブザーバーは呼出さない。
  // これらのオブザーバーは、次のいずれかの方法でのみクリーンアップしてください。
  // lv_observer_remove()ウィジェットを削除するか、
  // すべてのオブザーバーを適切に分離して削除するには、lv_subject_deinit() を呼出す。
  lv_obj_set_pos(time_label, 0, 60);  // ラベルの位置 70,20

  // セットボタン ------------------------------
  lv_obj_t *set_btn = lv_button_create(lv_screen_active());                        // set_btnを作成
  lv_obj_set_pos(set_btn, 120, 5);                                                 // btnの位置
  lv_obj_set_width(set_btn, 115);                                                  // btn幅
  lv_obj_add_event_cb(set_btn, set_btn_clicked_event_cb, LV_EVENT_CLICKED, NULL);  // set_btnを押したらコールバック関数へ

  lv_obj_t *set_label = lv_label_create(set_btn);                    // btnにlabelを作成
  lv_obj_set_style_text_font(set_label, &lv_font_montserrat_24, 0);  // 英数文字サイズ24,28,32,36,40,44,48
  lv_label_set_text(set_label, "    Set");                           // labelのtextを設定

  // 翌日ローラー ------------------------------
  lv_obj_t *day_roller = lv_roller_create(lv_screen_active());              // 画面に翌日用ローラーを作成
  lv_roller_set_options(day_roller, day_options, LV_ROLLER_MODE_INFINITE);  // 永久スクロール
  lv_roller_bind_value(day_roller, &day_subject);                           // 関連付
  lv_obj_set_pos(day_roller, 10, 105);                                      // rollerの位置
  lv_obj_set_style_text_font(day_roller, &lv_font_montserrat_28, 0);        // 英数文字サイズ24,28,32,36,40,44,48

  // 時ローラー ------------------------------
  lv_obj_t *hour_roller = lv_roller_create(lv_screen_active());  // 画面に時用ローラーを作成
  lv_obj_add_flag(hour_roller, LV_OBJ_FLAG_FLEX_IN_NEW_TRACK);
  // 1つ以上のフラグを設定(objへのpointer, 設定する値のOR演算)
  // LV_OBJ_FLAG_FLEX_IN_NEW_TRACK:このアイテムで新しいFlexトラックを開始
  lv_roller_set_options(hour_roller, hour_options, LV_ROLLER_MODE_INFINITE);  // 永久スクロール ...22,23,0,1,...
  // ローラーのオプションを設定(ローラーobjへのpointer,\nで区切られた文字列,
  // or LV_ROLER_MODE_NORMAL LV_ROLLER_MODE_INFINITE)
  // LV_ROLLER_MODE_NORMAL:ローラーはオプションの最後で停止
  // LV_ROLLER_MODE_INFINITE:ローラーは永久にスクロール
  lv_roller_bind_value(hour_roller, &hour_subject);
  // 整数SubjectをRollerの値に関連付(Rollerへのpointer,Subjectへのpointer)
  // 戻り値:新しく作成されたObserverへのpointer
  lv_obj_set_pos(hour_roller, 85, 105);                                // rollerの位置
  lv_obj_set_style_text_font(hour_roller, &lv_font_montserrat_28, 0);  // 英数文字サイズ24,28,32,36,40,44,48

  // 分ローラー ------------------------------
  lv_obj_t *min_roller = lv_roller_create(lv_screen_active());                 // 画面に分用のローラーを作成
  lv_roller_set_options(min_roller, minute_options, LV_ROLLER_MODE_INFINITE);  // 永久スクロール 上と同様
  lv_roller_bind_value(min_roller, &minute_subject);                           // 関連付け 上と同様
  lv_obj_set_pos(min_roller, 160, 105);                                        // rollerの位置
  lv_obj_set_style_text_font(min_roller, &lv_font_montserrat_28, 0);           // 英数文字サイズ24,28,32,36,40,44,48
}

void loop() {
  lv_task_handler();
  delay(5);  // 5mS待つ
}
* flash memory(3.1Mbyte)のうち、スケッチが31%使用。RAM(327kbyte)のうち、global変数が7%使用、local変数で301kbyte使用可能。(1000byte=1kbyteで計算)
LilyGoLib 0.1.0
FFat 3.3.5
FS 3.3.5
Wire 3.3.5
SensorLib 0.3.3
SPI 3.3.5
RadioLib 7.1.0
TinyGPSPlus 1.1.0
ESP_I2S 3.3.5
lvgl 9.2.2
esptool 5.1.0