diff --git a/App/app_set_clock.c b/App/app_set_clock.c index e56cf53..24f9682 100644 --- a/App/app_set_clock.c +++ b/App/app_set_clock.c @@ -12,7 +12,7 @@ extern SystemState current_state; extern volatile u16 ms_tick; // 本应用私有的时间编辑状态 -static u8 time_edit_field = 1; // 标识当前聚焦在哪一个参数上进行微调 (1:修改小时, 2:修改分钟) +static u8 time_edit_field = 1; // 当前聚焦调节的字段 (1:小时, 2:分钟, 3:日, 4:月, 5:年) static u8 time_edit_blink_on = 1; // 时钟修改时光标闪烁周期状态位 // 声明本应用的生命周期回调函数 @@ -49,7 +49,7 @@ static void SetClockApp_OnStart(void) MOTOR = 0; // 渲染显示时间编辑界面,默认高亮编辑小时字段,消隐位开启 - UI_ShowSetTimePage(current_hour, current_min, time_edit_field, 1); + UI_ShowSetTimePage(current_hour, current_min, current_day, current_month, current_year, current_weekday, time_edit_field, 1); XTELL_LOG("[SetClockApp] Started\r\n"); } @@ -63,8 +63,8 @@ static void SetClockApp_onRun(void) if (blink != time_edit_blink_on) { time_edit_blink_on = blink; - // 每次闪烁状态发生变化,只局部刷新正在调节的那个数字,不整屏重绘 - UI_UpdateSetTimeDigit(current_hour, current_min, time_edit_field, time_edit_blink_on); + // 每次闪烁状态发生变化,只局部刷新正在调节的那个字段,不整屏重绘 + UI_UpdateSetTimeDigit(current_hour, current_min, current_day, current_month, current_year, current_weekday, time_edit_field, time_edit_blink_on); } } @@ -84,49 +84,83 @@ static EventResult SetClockApp_onEvent(SystemEvent *evt) { if (evt->key_event == KEY_EVENT_UP_CLICK) { - // 短按 ▲ 键增加数值 (小时/分钟循环相加) - if (time_edit_field == 1) { - current_hour = (current_hour + 1) % 24; - } else { - current_min = (current_min + 1) % 60; + // 短按 ▲ 键增加当前聚焦字段的数值 (各字段独立循环) + switch (time_edit_field) { + case 1: current_hour = (current_hour + 1) % 24; break; + case 2: current_min = (current_min + 1) % 60; break; + case 3: + current_day = (current_day >= Days_In_Month(current_year, current_month)) ? 1 : (current_day + 1); + Clock_RecalcWeekday(); + break; + case 4: + current_month = (current_month >= 12) ? 1 : (current_month + 1); + // 月份变化后,若当前日超出新月份的最大天数,截断到最大天数 + if (current_day > Days_In_Month(current_year, current_month)) { + current_day = Days_In_Month(current_year, current_month); + } + Clock_RecalcWeekday(); + break; + default: // 5: 年 + current_year = (current_year >= 99) ? 0 : (current_year + 1); + if (current_day > Days_In_Month(current_year, current_month)) { + current_day = Days_In_Month(current_year, current_month); + } + Clock_RecalcWeekday(); + break; } time_edit_blink_on = 1; // 调值后强制显示 (不处于消隐周期) - UI_UpdateSetTimeDigit(current_hour, current_min, time_edit_field, 1); + UI_UpdateSetTimeDigit(current_hour, current_min, current_day, current_month, current_year, current_weekday, time_edit_field, 1); return EVENT_HANDLED; } if (evt->key_event == KEY_EVENT_DOWN_CLICK) { - // 短按 ▼ 键减小数值 - if (time_edit_field == 1) { - current_hour = (current_hour == 0) ? 23 : (current_hour - 1); - } else { - current_min = (current_min == 0) ? 59 : (current_min - 1); + // 短按 ▼ 键减小当前聚焦字段的数值 (各字段独立循环) + switch (time_edit_field) { + case 1: current_hour = (current_hour == 0) ? 23 : (current_hour - 1); break; + case 2: current_min = (current_min == 0) ? 59 : (current_min - 1); break; + case 3: + current_day = (current_day <= 1) ? Days_In_Month(current_year, current_month) : (current_day - 1); + Clock_RecalcWeekday(); + break; + case 4: + current_month = (current_month <= 1) ? 12 : (current_month - 1); + if (current_day > Days_In_Month(current_year, current_month)) { + current_day = Days_In_Month(current_year, current_month); + } + Clock_RecalcWeekday(); + break; + default: // 5: 年 + current_year = (current_year == 0) ? 99 : (current_year - 1); + if (current_day > Days_In_Month(current_year, current_month)) { + current_day = Days_In_Month(current_year, current_month); + } + Clock_RecalcWeekday(); + break; } time_edit_blink_on = 1; // 调值后强制显示 (不处于消隐周期) - UI_UpdateSetTimeDigit(current_hour, current_min, time_edit_field, 1); + UI_UpdateSetTimeDigit(current_hour, current_min, current_day, current_month, current_year, current_weekday, time_edit_field, 1); return EVENT_HANDLED; } if (evt->key_event == KEY_EVENT_CONFIRM_LONG) { - // 长按 ■ 确认键切换调节字段 (在修改小时与修改分钟间跳转) - if (time_edit_field == 1) { - time_edit_field = 2; - } else { - time_edit_field = 1; - } - time_edit_blink_on = 1; // 切换焦点后两个字段都应处于可见状态 - // 两个数字区域都局部刷新一次,避免切换前正处于消隐周期的那个数字停留在涂黑状态 - UI_UpdateSetTimeDigit(current_hour, current_min, 1, 1); - UI_UpdateSetTimeDigit(current_hour, current_min, 2, 1); + // 长按 ■ 确认键切换调节字段 (小时 -> 分钟 -> 日 -> 月 -> 年 -> 循环回小时) + time_edit_field = (time_edit_field >= 5) ? 1 : (time_edit_field + 1); + time_edit_blink_on = 1; // 切换焦点后所有字段都应处于可见状态 + // 全部字段各局部刷新一次,避免切换前正处于消隐周期的那个字段停留在涂黑状态 + UI_UpdateSetTimeDigit(current_hour, current_min, current_day, current_month, current_year, current_weekday, 1, 1); + UI_UpdateSetTimeDigit(current_hour, current_min, current_day, current_month, current_year, current_weekday, 2, 1); + UI_UpdateSetTimeDigit(current_hour, current_min, current_day, current_month, current_year, current_weekday, 3, 1); + UI_UpdateSetTimeDigit(current_hour, current_min, current_day, current_month, current_year, current_weekday, 4, 1); + UI_UpdateSetTimeDigit(current_hour, current_min, current_day, current_month, current_year, current_weekday, 5, 1); return EVENT_HANDLED; } if (evt->key_event == KEY_EVENT_CONFIRM_CLICK) { - // 短按 ■ 确认键保存最新时钟配置,退出到主菜单 (父 App) + // 短按 ■ 确认键保存最新时间与日期配置,退出到主菜单 (父 App) current_state = STATE_PAIR_MENU; - // 同步将最新时间 (hour, min, 0秒) 写入 PCF8563 芯片寄存器 - PCF8563_WriteTime(current_hour, current_min, 0); + // 同步将最新时间与日期 (含算好的星期) 一次性写入 PCF8563 芯片寄存器 + PCF8563_WriteDateTime(current_hour, current_min, 0, current_day, current_month, current_year, current_weekday); // 退出短振反馈 MOTOR = 1; Delay_ms(50); MOTOR = 0; diff --git a/App/ui.c b/App/ui.c index 7da2408..e2cd975 100644 --- a/App/ui.c +++ b/App/ui.c @@ -480,13 +480,14 @@ void UI_ShowSetTimePage(u8 hour, u8 min, u8 day, u8 month, u8 year, u8 weekday, /** * @brief 局部刷新时间设置界面里"正在调节的那一个"字段 (小时/分钟/日/月/年) + * @param weekday 根据当前日期算出的星期 (0=周日, ..., 6=周六),调节日/月/年时顺带刷新星期缩写 * @param selection 1:小时, 2:分钟, 3:日, 4:月, 5:年 * @param blink_on 1:显示数值, 0:消隐(涂黑),用于 500ms 周期闪烁效果 * @details 小时/分钟用 32x32px 大字体区域;日/月/年用日期栏里对应的 16x16px 小字体区域, * 都只重画自己那一小块,不触碰锁头/电池/冒号/AM-PM/星期文字等其它内容, * 避免每次闪烁或调值都整屏 LCD_Clear() 造成全屏闪烁。 */ -void UI_UpdateSetTimeDigit(u8 hour, u8 min, u8 day, u8 month, u8 year, u8 selection, u8 blink_on) +void UI_UpdateSetTimeDigit(u8 hour, u8 min, u8 day, u8 month, u8 year, u8 weekday, u8 selection, u8 blink_on) { char buf[3]; u16 x; @@ -503,6 +504,12 @@ void UI_UpdateSetTimeDigit(u8 hour, u8 min, u8 day, u8 month, u8 year, u8 select default: x = DATE_BAR_YEAR_X; y = DATE_BAR_Y; w = DATE_BAR_FIELD_W; h = 16; value = year; break; } + // 调节日/月/年时,星期缩写可能因为日期变化而改变,顺带刷新一下 (不参与闪烁,始终显示) + if (selection >= 3) { + LCD_FillRect(DATE_BAR_START_X, DATE_BAR_Y, 24, 16, COLOR_BLACK); + LCD_ShowString(DATE_BAR_START_X, DATE_BAR_Y, Lang_Get((StringID)(STR_WEEKDAY_SUN + weekday)), COLOR_GRAY, COLOR_BLACK); + } + if (!blink_on) { // 灭周期:直接把这一小块涂黑,形成消隐效果 LCD_FillRect(x, y, w, h, COLOR_BLACK); diff --git a/App/ui.h b/App/ui.h index f4cad1d..c2af64a 100644 --- a/App/ui.h +++ b/App/ui.h @@ -91,9 +91,10 @@ void UI_ShowSetTimePage(u8 hour, u8 min, u8 day, u8 month, u8 year, u8 weekday, /** * @brief 局部刷新时间设置界面里正在调节的那一个字段 (小时/分钟/日/月/年),用于闪烁/调值时避免整屏重绘 + * @param weekday 根据当前日期算出的星期 (0=周日, ..., 6=周六),调节日/月/年时顺带刷新星期缩写 * @param selection 1:小时, 2:分钟, 3:日, 4:月, 5:年 * @param blink_on 1:显示数值, 0:消隐(涂黑) */ -void UI_UpdateSetTimeDigit(u8 hour, u8 min, u8 day, u8 month, u8 year, u8 selection, u8 blink_on); +void UI_UpdateSetTimeDigit(u8 hour, u8 min, u8 day, u8 month, u8 year, u8 weekday, u8 selection, u8 blink_on); #endif // __UI_H__ diff --git a/Drivers/pcf8563.c b/Drivers/pcf8563.c index 07174ad..a6c631b 100644 --- a/Drivers/pcf8563.c +++ b/Drivers/pcf8563.c @@ -310,45 +310,6 @@ bit PCF8563_ReadDateTime(u8 *hour, u8 *min, u8 *sec, u8 *day, u8 *month, u8 *yea return 1; } -/** - * @brief 从 PCF8563 读取当前时间 (兼容旧接口,只取时分秒,丢弃日期部分) - */ -bit PCF8563_ReadTime(u8 *hour, u8 *min, u8 *sec) -{ - u8 day, month, year; - return PCF8563_ReadDateTime(hour, min, sec, &day, &month, &year); -} - -/** - * @brief 将时间精准写入 PCF8563 RTC 芯片 (只写时分秒三个寄存器,不触碰日期寄存器) - */ -bit PCF8563_WriteTime(u8 hour, u8 min, u8 sec) -{ - I2C_Start(); - I2C_SendByte(PCF8563_ADDR_WRITE); - if (!I2C_WaitAck()) return 0; - - // 定位写入起始寄存器 0x02 - I2C_SendByte(REG_VL_SECONDS); - if (!I2C_WaitAck()) return 0; - - // 写入秒 - I2C_SendByte(DEC2BCD(sec & 0x7F)); - if (!I2C_WaitAck()) return 0; - - // 写入分 - I2C_SendByte(DEC2BCD(min & 0x7F)); - if (!I2C_WaitAck()) return 0; - - // 写入时 - I2C_SendByte(DEC2BCD(hour & 0x3F)); - if (!I2C_WaitAck()) return 0; - - I2C_Stop(); - - return 1; -} - /** * @brief 将时间与日期一次性连续写入 PCF8563 RTC 芯片 (寄存器 0x02~0x08 共 7 字节连续写入) */ diff --git a/Drivers/pcf8563.h b/Drivers/pcf8563.h index 39f5216..9ea0f43 100644 --- a/Drivers/pcf8563.h +++ b/Drivers/pcf8563.h @@ -24,24 +24,6 @@ */ bit PCF8563_Init(void); -/** - * @brief 从 PCF8563 芯片读取当前时间 (时、分、秒) - * @param hour 小时指针 (0~23) - * @param min 分钟指针 (0~59) - * @param sec 秒钟指针 (0~59) - * @return bit 1: 读取成功, 0: 通讯失败 - */ -bit PCF8563_ReadTime(u8 *hour, u8 *min, u8 *sec); - -/** - * @brief 将指定的时间 (时、分、秒) 写入 PCF8563 芯片 - * @param hour 小时 (0~23) - * @param min 分钟 (0~59) - * @param sec 秒钟 (0~59) - * @return bit 1: 写入成功, 0: 通讯失败 - */ -bit PCF8563_WriteTime(u8 hour, u8 min, u8 sec); - /** * @brief 从 PCF8563 芯片连续读取时间与日期 (时/分/秒/日/月/年) * @param hour 小时指针 (0~23)