【前言】
使用菜单系统可以分块展示用户所关心的内容,同时也可以为用户交互提供更加友好的界面。这一篇将分享如何创简单的菜单。
1、创建两个用户菜单的文件menu.c/h
2、菜单设计
这次设计了两个菜单,一个用于展示RTC日期与时间,另一个菜单用于展示心率与血氧。在menu.c中设计菜单显示如下:
// 显示日期页面 static void show_date_page(void) { uint32_t timesecond; uint16_t year; uint8_t mon, day, hour, min, sec; timesecond = RTC_GetCount(); RTC_GetDate(timesecond, &year, &mon, &day, &hour, &min, &sec); OLED_Clear(0); GUI_ShowString(0, 0, (uint8_t *)"Date Page", 16, 1); GUI_ShowString(0, 16, (uint8_t *)"------------", 16, 1); char date_str[20]; snprintf(date_str, sizeof(date_str), "%04d-%02d-%02d", year, mon, day); GUI_ShowString(0, 32, (uint8_t *)date_str, 16, 1); char time_str[20]; snprintf(time_str, sizeof(time_str), "%02d:%02d:%02d", hour, min, sec); GUI_ShowString(0, 48, (uint8_t *)time_str, 16, 1); OLED_Display(); } // 显示心率页面 extern BloodData g_blooddata; static void show_heart_rate_page(void) { OLED_Clear(0); GUI_ShowString(0, 0, (uint8_t *)"Heart Rate Page", 16, 1); GUI_ShowString(0, 16, (uint8_t *)"------------", 16, 1); char hr_str[20]; snprintf(hr_str, sizeof(hr_str), "HR: %d BPM", (int)g_blooddata.heart); GUI_ShowString(0, 32, (uint8_t *)hr_str, 16, 1); char spo2_str[20]; snprintf(spo2_str, sizeof(spo2_str), "SpO2: %.1f%%", g_blooddata.SpO2); GUI_ShowString(0, 48, (uint8_t *)spo2_str, 16, 1); OLED_Display(); }
3、菜单的切换,我在前面分享了按键处理的文章:【MAX32625PICO开发板】高效按键处理-电子产品世界论坛
在它的工程基础上,实现当键按下后,实现两个菜单的切换,首先创建菜单刷新任务:
// 菜单刷新任务 void vTaskMenu(void *pvParameters) { menu_init(); TickType_t last_wake_time = xTaskGetTickCount(); while (1) { if (xSemaphoreTake(xMenuMutex, pdMS_TO_TICKS(100)) == pdTRUE) { switch (current_menu) { case MENU_DATE: show_date_page(); break; case MENU_HEART_RATE: show_heart_rate_page(); break; default: break; } xSemaphoreGive(xMenuMutex); } vTaskDelayUntil(&last_wake_time, pdMS_TO_TICKS(200)); } }
在按键任务中,如捕获取有按键按下,那么就执行menu中的menu_process_key,并传递event。
void vTaskKeyScan(void *pvParameters) { key_init(); while (1) { key_event_t event = key_get_click(); if (event != KEY_NONE) { menu_process_key(event); // 关键修改:将按键事件传递给菜单系统 printf("Key event: %d\n", event); } vTaskDelay(pdMS_TO_TICKS(10)); } }
在菜单按键任执行后,解除锁,并根据按键不同,切换菜单
// 处理按键切换菜单 void menu_process_key(key_event_t key) { if (xSemaphoreTake(xMenuMutex, pdMS_TO_TICKS(100)) == pdTRUE) { if (key == KEY_SW2_CLICK) { current_menu = (current_menu + 1) % MENU_COUNT; printf("Menu changed to: %d\n", current_menu); } else if (key == KEY_SW3_CLICK) { current_menu = (current_menu - 1 + MENU_COUNT) % MENU_COUNT; printf("Menu changed to: %d\n", current_menu); } xSemaphoreGive(xMenuMutex); } }
最后,创建一个任务,并在main的任务创建中执行创建菜单任务:
void vCreateMenuTask(void) { xTaskCreate(vTaskMenu, "MenuTask", 512, NULL, tskIDLE_PRIORITY + 2, NULL); }
【实现效果】
按下开发板中的SW2、SW3实现菜单切换。