#include "LittleClockUI.h" #include "string.h" #include "System.h" #include "BATADC.h" //定义的跨文件的全局变量 uint16_t fps = 0; //帧率 uint8_t update_flag = 0; //-------枚举id,唯一标识一个页面,防止有两个页面使用同一id enum { main_page_id = 0x00, calendar_page_id, clock_page_id, alarm_list_page_id, alarm1_page_id, alarm2_page_id, about_page_id, ring_page_id, //这个页面是单独游离的,只有闹钟时才会调出来 }; //--------定义页面对象 TitlePage main_page; DigitalPage calendar_page; DigitalPage clock_page; ListPage alarm_list_page; DigitalPage alarm1_page; DigitalPage alarm2_page; RaderPicPage about_page; RaderPicPage ring_page; //闹钟响起时的界面(空的RaderPicPage页面,用于自己绘制) //--------定义每个页面需要的一些参数 //部分页面内选项个数 #define MAIN_PAGE_NUM 5 #define CALENDAR_LABEL_NUM 7 #define ALARM_LIST_PAGE_NUM 3 #define ALARM12_LABEL_NUM 3 #define ABOUT_PAGE_NUM 1 //定义部分页面选项 //********main页面的选项 Option mian_option_array[MAIN_PAGE_NUM] = {///{ order,max,min,step,int_val,text,} //option的成员顺序,但对单纯title的页面来说,只有text需要赋值 {.text = "- Calendar"}, //前两个字符是前缀,不显示,用于标识一般选项(-),二值选项(+),数值弹窗(~),确认弹窗($) {.text = "- Clock"}, {.text = "- Alarm"}, {.text = "~ BATLevel", .item_max = 100, .item_min = 0, .step = 0,.val = 50,}, //数值弹窗电压显示(step = 0,则为只读,无法使用按键编辑(其实就是使操作+-0,无效)) {.text = "- Aoubt"}, }; //main页面的图标 Icon main_icon_array[MAIN_PAGE_NUM] = { [0] = {0xF0,0xF8,0x38,0x38,0x38,0x38,0x7F,0xFF,0x7F,0x38,0x38,0x38,0x38,0x38,0x38,0x38, 0x38,0x38,0x38,0x38,0x38,0x7F,0xFF,0xFF,0x38,0x38,0x38,0x38,0xF8,0xF0,0xFF,0xFF, 0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x8E,0x8E,0xCE,0xCE,0x0E,0x0E, 0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0xFF,0xFF,0xFF,0xFF,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x1F,0x3F,0x38,0x38,0x38,0x38, 0x38,0x38,0x38,0x38,0x38,0x39,0x3B,0x3B,0x39,0x39,0x3B,0x3B,0x39,0x38,0x38,0x38, 0x38,0x38,0x38,0x38,0x38,0x38,0x3F,0x1F}, //Canlendar [1] = {0x00,0x00,0xC0,0xE0,0xF0,0x38,0x1C,0x1C,0x0E,0x06,0x07,0x07,0x07,0x03,0xE3,0xE3, 0x03,0x07,0x07,0x07,0x06,0x0E,0x1C,0x1C,0x38,0xF0,0xE0,0xC0,0x00,0x00,0xFC,0xFF, 0x1F,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x80,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x1F,0xFF,0xFC,0x0F,0x3F,0xFE,0xE0, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x03,0x03,0x03,0x07, 0x07,0x07,0x07,0x06,0x0E,0xCE,0xE2,0xFE,0x3F,0x0F,0x00,0x00,0x00,0x01,0x03,0x07, 0x0E,0x0E,0x1C,0x18,0x38,0x38,0x38,0x30,0x30,0x30,0x30,0x38,0x38,0x38,0x18,0x1C, 0x0E,0x0E,0x07,0x03,0x01,0x00,0x00,0x00}, //clock [2] = {0xF0,0xF8,0x9C,0xCE,0xEE,0x76,0xBE,0xDC,0xEC,0x60,0x70,0x30,0x38,0x38,0xF8,0xF8, 0x38,0x38,0x30,0x30,0x70,0xEC,0xDC,0xFE,0xF6,0xEE,0xCE,0x9C,0xFC,0xF0,0x01,0x03, 0xE7,0xFB,0xFF,0x0F,0x03,0x01,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF,0x00,0x00, 0x00,0x00,0x00,0x00,0x01,0x03,0x0F,0xFE,0xFD,0xE7,0x03,0x01,0x00,0x00,0x01,0x1F, 0x7F,0xF8,0xE0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x80,0xC0,0xF0,0x7F,0x1F,0x03,0x00,0x00,0x00,0x00,0x00,0x0C,0x1E,0x0F, 0x07,0x03,0x07,0x07,0x0E,0x0E,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0E,0x0E,0x07,0x07, 0x03,0x03,0x07,0x0E,0x1C,0x08,0x00,0x00}, //alarm [3] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0x60, 0x30,0x18,0x18,0x10,0x30,0x70,0xD8,0x98,0x18,0x30,0xE0,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x80,0xC0,0xE0,0x30,0x18,0x4C,0x26,0x13,0x03,0x01,0x00,0x00,0x00,0x00, 0x0A,0x04,0x0A,0x00,0x00,0x81,0xC2,0x6F,0x39,0x00,0x00,0x00,0x00,0x00,0x1E,0x33, 0x41,0x81,0x00,0x10,0x20,0x40,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0x60,0x30,0x18, 0x0C,0x06,0x03,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x01,0x02,0x06,0x0C,0x08,0x08,0x0C,0x06,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, //Bat level [4] = {0x00,0x00,0xC0,0xE0,0xF0,0x38,0x1C,0x1C,0x0E,0x06,0x07,0x07,0x07,0x03,0x03,0x03, 0x03,0x03,0x07,0x07,0x06,0x0E,0x1C,0x1C,0x38,0xF0,0xE0,0xC0,0x00,0x00,0xFC,0xFF, 0x1F,0x01,0x00,0xC0,0xE0,0xE0,0xC0,0x00,0x00,0x00,0x00,0xC0,0xE0,0xE0,0xC0,0x00, 0x00,0x00,0x00,0xC0,0xE0,0xE0,0xC0,0x00,0x01,0x1F,0xFF,0xF8,0x0F,0x3F,0xFE,0xE0, 0xC0,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00, 0x00,0x00,0x01,0x01,0x00,0xC0,0xF0,0xFE,0x3F,0x0F,0x00,0x00,0x00,0x01,0x03,0x07, 0x0E,0x0E,0x1C,0x18,0x38,0x38,0x38,0x30,0x30,0x30,0x30,0x38,0x38,0x38,0x18,0x1C, 0x0E,0x0E,0x07,0x03,0x01,0x00,0x00,0x00}, //more }; //Calendar 页面的选项 Option calendar_option_array[3] = {///{ order,max,min,step,int_val,text,} [Digital_Pos_IndexLeft] = { .item_max = 99, .item_min = 0, .step = 1, .text = "Year"}, [Digital_Pos_IndexMid] = { .item_max = 12, .item_min = 1, .step = 1, .text = "Month"}, [Digital_Pos_IndexRight] = { .item_max = 31, .item_min = 1, .step = 1, .text = "day"}, }; //标签数组 String week_str[CALENDAR_LABEL_NUM] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}; //Clock页面选项 Option clock_option_array[3]= { [Digital_Pos_IndexLeft] = { .item_max = 23, .item_min = 0, .step = 1, .text = "Hour"}, [Digital_Pos_IndexMid] = { .item_max = 59, .item_min = 0, .step = 1, .text = "Minute"}, [Digital_Pos_IndexRight] = { .item_max = 59, .item_min = 0, .step = 1, .text = "Second"}, }; //alarm页面选项 Option alarm_list_option_array[3]= { {.text = " alarm list"}, {.text = "+ Alarm1", .val = 0,}, //为二值选项,单选项值由Alarm12页面控制(读全局update_flag中enable_msk位可以设置) {.text = "+ Alarm2", .val = 0,}, //默认值为0,close }; //alarm1页面选项 Option alarm1_option_array[3]= { [Digital_Pos_IndexLeft] = { .item_max = 23, .item_min = 0, .step = 1, .text = "Hour"}, [Digital_Pos_IndexMid] = { .item_max = 59, .item_min = 0, .step = 1, .text = "Minute"}, [Digital_Pos_IndexRight] = { .item_max = 59, .item_min = 0, .step = 1, .text = "Second"}, }; Option alarm2_option_array[3]= { [Digital_Pos_IndexLeft] = { .item_max = 23, .item_min = 0, .step = 1, .text = "Hour"}, [Digital_Pos_IndexMid] = { .item_max = 59, .item_min = 0, .step = 1, .text = "Minute"}, [Digital_Pos_IndexRight] = { .item_max = 59, .item_min = 0, .step = 0, .text = "Second"}, //DS3231只有两个闹钟,且闹钟2的秒无效,所以alarm2的step为0,为不可编辑模式 //(因为air001的内存不够,也不想做软件闹钟了) }; String alarm12_label_array[3] = { "Close", "Open", "Delete"}; //About页面 const uint8_t QRCode[] = { 0xFF,0xFF,0xFF,0x07,0x07,0xE7,0x27,0x27,0x27,0x27,0x27,0x27,0xE7,0x07,0x07,0xFF, 0xFF,0xDF,0x1F,0x1F,0x27,0x27,0x27,0x27,0xFF,0xC7,0xC7,0x27,0x27,0x1F,0x1F,0xFF, 0xFF,0xFF,0x07,0x07,0xE7,0x27,0x27,0x27,0x27,0x27,0x27,0xE7,0x07,0x07,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x80,0x9F,0x90,0x90,0x90,0x90,0x90,0x90,0x9F,0x80, 0x80,0xFF,0xFF,0x93,0xF0,0xF0,0x90,0x90,0xF3,0xF3,0x90,0x6F,0x6F,0x9F,0x9F,0xEC, 0xEC,0x0F,0xFF,0xFF,0x80,0x80,0x9F,0x90,0x90,0x90,0x90,0x90,0x90,0x9F,0x80,0x80, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x01,0x01,0x3F,0x31,0x31,0x3F,0x3F,0xF1,0xF1, 0x3F,0xCD,0xCD,0xC3,0xC3,0xCF,0x0F,0x0F,0xFF,0xFF,0x03,0x03,0x3F,0x00,0x00,0xCF, 0xCF,0xFD,0xFD,0x0C,0x3F,0x3F,0x03,0x03,0x0F,0xCD,0xCD,0xFF,0xFF,0xCF,0xCF,0x0D, 0xC3,0xC3,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x66,0x66,0x9E,0x86,0x86,0x9F,0x9F, 0x07,0x07,0x80,0x66,0x66,0x66,0x66,0xFE,0x86,0x86,0xE0,0xE0,0x98,0x98,0x7F,0x87, 0x87,0xE7,0xE7,0xFE,0xFE,0x78,0x1F,0x1F,0x60,0x60,0x66,0x1F,0x1F,0x78,0x78,0xE7, 0xE7,0x86,0xE0,0xE0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x03,0x03,0xF3,0x13,0x13, 0x13,0x13,0x13,0x13,0xF3,0x03,0x03,0xFF,0xFF,0x9C,0x00,0x00,0x73,0x73,0x10,0x10, 0xE0,0xEF,0xEF,0x80,0x80,0x70,0x70,0x00,0x1F,0x1F,0x93,0x93,0x1F,0x00,0x00,0x00, 0x00,0x7F,0x7F,0x80,0x80,0x80,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0xC0,0xCF, 0xC8,0xC8,0xC8,0xC8,0xC8,0xC8,0xCF,0xC0,0xC0,0xFF,0xFF,0xC9,0xC0,0xC0,0xFE,0xFE, 0xF6,0xF6,0xCF,0xF9,0xF9,0xFF,0xFF,0xF0,0xF0,0xC6,0xC8,0xC8,0xFF,0xFF,0xCE,0xF0, 0xF0,0xF6,0xF6,0xFE,0xFE,0xC7,0xC9,0xC9,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, }; //Qrcode RaderPic qrcode_raderpic[ABOUT_PAGE_NUM] = { {.pic = QRCode, .start_x = 7, .start_y = 7, .w = 50, .h = 50, .rd = RD_RIGHT_DOWN}, }; //--------定义每个页面的回调函数 void MainPage_CallBack(uint8_t self_page_id,Option* select_item) { switch (select_item->order) { case 0: OLED_UIJumpToPage(self_page_id,&calendar_page); break; case 1: OLED_UIJumpToPage(self_page_id,&clock_page); break; case 2: OLED_UIJumpToPage(self_page_id,&alarm_list_page); break; case 3: //更新电量 select_item->val = BATADC_Read(); break; case 4: OLED_UIJumpToPage(self_page_id,&about_page); break; default: break; } } void CalendarPage_CallBack(uint8_t self_page_id,Option* select_item) { uint8_t month_days[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; switch (select_item->order) { case Digital_Pos_Complete : //全部数据设置完成后,也会检测一次数据 SET_FLAG(update_flag,DATE_UPDATE_MSK); //同时会通知main函数设置rtc芯片 case Digital_Pos_IndexRight: //更正日期数据 if( calendar_page.option_array[Digital_Pos_IndexRight].val > //大于每个月的最大月数,更正日期 month_days[calendar_page.option_array[Digital_Pos_IndexMid].val -1]) OLED_DigitalPage_UpdateDigitalNumAnimation(&calendar_page, calendar_page.option_array[Digital_Pos_IndexLeft].val, calendar_page.option_array[Digital_Pos_IndexMid].val, month_days[calendar_page.option_array[Digital_Pos_IndexMid].val -1], Digital_Direct_Decrease); break; default:break; } } void ClockPage_CallBack(uint8_t self_page_id,Option* select_item) { if(select_item->order == Digital_Pos_Complete) //时间设置完成 SET_FLAG(update_flag,TIME_UPDATE_MSK); //通知主函数更新时间 } void AlarmList_CallBack(uint8_t self_page_id,Option* select_item) { switch (select_item->order) { // case 0: // OLED_UIJumpToPage(self_page_id, &ring_page); //只是作为绘制页面的跳转测试 // break; case 1: OLED_UIJumpToPage(self_page_id, &alarm1_page); //设置其标签 alarm1_page.select_label_index = (!!FLAG_IS_SET(update_flag, ALARM1_ENABLE_MSK)); //将数值变量转为逻辑 break; case 2: OLED_UIJumpToPage(self_page_id, &alarm2_page); alarm2_page.select_label_index = (!!FLAG_IS_SET(update_flag, ALARM2_ENABLE_MSK)); //将数值变量转为逻辑 break; default :break; } } void Alarm12_CallBack(uint8_t self_page_id,Option* select_item) { uint8_t update_msk = 0; uint8_t enable_msk = 0; if(self_page_id == alarm1_page_id){update_msk = ALARM1_UPDATE_MSK;enable_msk = ALARM1_ENABLE_MSK;} else if(self_page_id == alarm2_page_id){update_msk = ALARM2_UPDATE_MSK;enable_msk = ALARM2_ENABLE_MSK;} switch (select_item->order) { case Digital_Pos_Complete: //编辑完成 SET_FLAG(update_flag, update_msk); break; case Digital_Pos_IndexLabel: //click标签时 if(strcmp(select_item->text, alarm12_label_array[0]) == 0) //close CLEAR_FLAG(update_flag,enable_msk); else if(strcmp(select_item->text, alarm12_label_array[1]) == 0) //open SET_FLAG(update_flag,enable_msk); else if(strcmp(select_item->text, alarm12_label_array[2]) == 0) //Delete { CLEAR_FLAG(update_flag,enable_msk); //闹钟标志位关闭 if(self_page_id == alarm1_page_id) OLED_DigitalPage_UpdateDigitalNumAnimation(&alarm1_page, 0,0,0,Digital_Direct_Decrease); else if(self_page_id == alarm2_page_id) OLED_DigitalPage_UpdateDigitalNumAnimation(&alarm2_page, 0,0,0,Digital_Direct_Decrease); } default: break; } } void About_CallBack(uint8_t self_page_id,Option* select_item) { uint8_t buff[10] = {0}; sprintf((char*)buff, "fps:%d",fps); if(select_item->order == ABOUT_PAGE_NUM) //图像绘制完成后 { OLED_WinDrawStr(&w_all, 64, 7, 16, buff); OLED_WinDrawStr(&w_all, 64, 24, 16, "Scan"); OLED_WinDrawStr(&w_all, 64, 40, 16, "QrCode"); } } void Ring_CallBack(uint8_t self_page_id,Option* select_item) { static float x = 2; static float x_trg = 12; static uint8_t color = 1; OLED_Animation(&x, &x_trg, 200); OLED_WinDrawBMP(&w_all, 15, 15 , 30, 30 , main_icon_array[2], color); // 实色绘制闹钟图标 OLED_SetPointColor(2); //反色绘制 int16_t len = 62-2*x; OLED_WinDrawRBox(&w_all, x, x, len, len,2); OLED_SetPointColor(1); //恢复正常颜色 if(x == x_trg) { if(x_trg == 12){x_trg = 2;color =! color;} else if(x_trg == 2){x_trg = 12;color =! color;} } if(FLAG_IS_SET(update_flag, ALARM1_RING_MSK)) OLED_WinDrawStr(&w_all, 60, 8, 16, "Alarm1"); else if((FLAG_IS_SET(update_flag, ALARM2_RING_MSK))) OLED_WinDrawStr(&w_all, 60, 8, 16, "Alarm2"); OLED_WinDrawStr(&w_all, 60, 34, 8, "Press Any"); OLED_WinDrawStr(&w_all, 60, 44, 8, "Key to exit!"); } //-------------一些需要用的内部函数 //--------------给主函数调用的接口函数 void LittleClockUI_Init(void) { OLED_Init(); //硬件的初始化 LL_mDelay(100); OLED_ClearBuff(); //清空缓存 OLED_RefreshBuff(); //刷新屏幕(清空屏幕) OLED_SetPointColor(1); //设置绘制颜色 OLED_UiInit(); //必要的ui参数初始化 OLED_TitlePageInit(&main_page, main_page_id, MAIN_PAGE_NUM, mian_option_array, main_icon_array, MainPage_CallBack); OLED_DigitalPageInit(&calendar_page, calendar_page_id, calendar_option_array, CALENDAR_LABEL_NUM, week_str, '-', 0, 100, CalendarPage_CallBack); OLED_DigitalPageInit(&clock_page, clock_page_id, clock_option_array, CALENDAR_LABEL_NUM, week_str, ':', 50, 100, ClockPage_CallBack); //时钟页面的标签也显示周 OLED_ListPageInit(&alarm_list_page, alarm_list_page_id, ALARM_LIST_PAGE_NUM, alarm_list_option_array, AlarmList_CallBack); OLED_DigitalPageInit(&alarm1_page, alarm1_page_id, alarm1_option_array, ALARM12_LABEL_NUM, alarm12_label_array, ':', 50, 100, Alarm12_CallBack); OLED_DigitalPageInit(&alarm2_page, alarm2_page_id, alarm2_option_array, ALARM12_LABEL_NUM, alarm12_label_array, ':', 50, 100, Alarm12_CallBack); OLED_RaderPicPageInit(&about_page, about_page_id, ABOUT_PAGE_NUM, qrcode_raderpic, Rader_Pic_Mode_Hold, About_CallBack); OLED_RaderPicPageInit(&ring_page, ring_page_id, 0, NULL, Rader_Pic_Mode_Hold, Ring_CallBack); //相当于一个空的页面可以自由绘制 } void LittleClockUI_Proc(void) { OLED_UIProc(); //由updataflag接管 alarmlist中两个选框的选中与否 if(FLAG_IS_SET(update_flag,ALARM1_ENABLE_MSK))alarm_list_option_array[1].val = 1; else alarm_list_option_array[1].val = 0; if(FLAG_IS_SET(update_flag,ALARM2_ENABLE_MSK))alarm_list_option_array[2].val = 1; else alarm_list_option_array[2].val = 0; }