一.为什么要用菜单
二.菜单的简单演示
三.STM32 HAL库编写菜单界面
1.按键与菜单事件的链接
(1)编写key触发代码(包括消抖)
功能描述:①.短按key,使状态位置1②key不能多次翻转状态位(消抖)
#define click 1
#define doubleclick 2
#define longclick 3
struct Key_def {
volatile uint8 key_status;
uint8 key_pressed_flag;
uint8 judge_step;
uint16 last_time;
uint16 keep_time;
};
struct Key_def Key[4]={0,0,0,0};
void Key_Scan(void) {
uint8 i=0;
uint8 a=0;
Key[0].key_status = HAL_GPIO_ReadPin(Button1_GPIO_Port,Button1_Pin);
Key[1].key_status = HAL_GPIO_ReadPin(Button2_GPIO_Port,Button2_Pin);
Key[2].key_status = HAL_GPIO_ReadPin(Button3_GPIO_Port,Button3_Pin);
Key[3].key_status = HAL_GPIO_ReadPin(Button4_GPIO_Port,Button4_Pin);
for (i=0;i<4;++i) {
switch(Key[i].judge_step) {
case 0: {
if (Key[i].key_status == 0) Key[i].judge_step = 1;
} break;
case 1: {
if (Key[i].key_status == 0) {
Key[i].judge_step = 2;
Key[i].key_pressed_flag = click;
}
else Key[i].judge_step = 0;
}break;
case 2: {
if (Key[i].key_status == 1) Key[i].judge_step = 0;
} break;
default:Key[i].judge_step = 0;break;
}
}
(2)按键单击事件与菜单链接
功能描述:①如果key状态位为1,则触发事件并且清除状态位
void UI_link_KEY(void) {
if (Key[0].key_pressed_flag == click) {
UI_PressUp();
Key[0].key_pressed_flag = 0;
}
if (Key[1].key_pressed_flag == click) {
UI_PressDown();
Key[1].key_pressed_flag = 0;
}
if (Key[2].key_pressed_flag == click) {
UI_PressIn();
Key[2].key_pressed_flag = 0;
}
if (Key[3].key_pressed_flag == click) {
UI_PressOut();
Key[3].key_pressed_flag = 0;
}
}
2.四个按键的服务程序编写
屏幕单行刷新的代码:
uint8 UI_pointer_none[]=" ";
uint8 UI_pointer[]="<-- ";
uint8 UI_pointer_pressed[]="<==>";
void UI_line_fresh(uint8 c,uint8 p_type){
uint8 fresh_info[20]={0};
uint8 *pointer_type=UI_pointer_none;
switch (p_type) {
case 0:pointer_type=UI_pointer_none;break;
case 1:pointer_type=UI_pointer;break;
case 2:pointer_type=UI_pointer_pressed;break;
default:break;
};
switch (menu_now->line_value_type[c]) {
case type_NULL:snprintf(fresh_info,20,"%s %s",menu_now->line_name[c],pointer_type);break;
case type_char:snprintf(fresh_info,20,"%s %s %d ",menu_now->line_name[c],pointer_type,*(char*)(menu_now->line_value[c]));break;
case type_int:snprintf(fresh_info,20,"%s %s %d ",menu_now->line_name[c],pointer_type,*(int*)(menu_now->line_value[c]));break;
case type_float:snprintf(fresh_info,20,"%s %s %.2f ",menu_now->line_name[c],pointer_type,*(float*)(menu_now->line_value[c]));break;
default:break;
};
LCD_DisplayStringLine(c * 24,fresh_info);
}
(1)上,对应的服务程序编写
void UI_PressUp(void)
{
uint8 page_num=0;
while(menu_now->line_name[page_num][0] != 0) {
page_num++;
}
if (menu_now->cursor_pressed == false) {
UI_line_fresh(menu_now->cursor,0);
menu_now->cursor -= 1;
if (menu_now->cursor == -1) menu_now->cursor = page_num - 1;
UI_line_fresh(menu_now->cursor,1);
} else {
UI_data_change(menu_now->cursor,1);
UI_line_fresh(menu_now->cursor,2);
}
}
(2)下
void UI_PressDown(void)
{
uint8 page_num=0;
while(menu_now->line_name[page_num][0] != 0) {
page_num++;
}
if (menu_now->cursor_pressed == false) {
UI_line_fresh(menu_now->cursor,0);
menu_now->cursor += 1;
if (menu_now->cursor == page_num) menu_now->cursor = 0;
UI_line_fresh(menu_now->cursor,1);
} else {
UI_data_change(menu_now->cursor,0);
UI_line_fresh(menu_now->cursor,2);
}
}
(3)确定
void UI_PressIn(void)
{
uint8 i=1;
if (menu_now->cursor_pressed == false) {
if (menu_now->line_value_type[menu_now->cursor] != type_NULL) {
menu_now->cursor_pressed = true;
UI_line_fresh(menu_now->cursor,2);
}
}
}
(4)退出
void UI_PressOut(void)
{
if (menu_now->cursor_pressed == true) {
menu_now->cursor_pressed = false;
UI_line_fresh(menu_now->cursor,1);
}
}
3.使用结构体表达某个界面
typedef void (*UI_handler_def) (void);
struct UI_def {
uint8 line_name[10][10];
void *line_value[10];
uint8 line_value_type[10];
int8 cursor;
volatile bool cursor_pressed;
struct UI_def *next_menu[10];
UI_handler_def function[10];
};
struct UI_def menu_main={
{" ","price","number",NULL},
{NULL,NULL,NULL,NULL},
{type_NULL,type_NULL,type_NULL,type_NULL},
0,
false,
{NULL,&menu_price,&menu_number,NULL},
{NULL,NULL,NULL,NULL}
};
char raw=1;
int cai=1;
float dan=1.1;
struct UI_def menu_price= {
{"BACK","raw","cai","dan",NULL},
{NULL,&raw,&cai,&dan,NULL},
{type_NULL,type_char,type_int,type_float,type_NULL},
0,
false,
{&menu_main,NULL,NULL,NULL,NULL},
{NULL,NULL,NULL,NULL,NULL}
};
struct UI_def menu_number= {
{"BACK","rou","cai","dan",NULL},
{NULL,&raw,&cai,&dan,NULL},
{type_NULL,type_char,type_int,type_float,type_NULL},
0,
false,
{&menu_main,NULL,NULL,NULL,NULL},
{NULL,NULL,NULL,NULL,NULL}
};
4.使用单向链表链接下一个界面
void UI_PressIn(void)
{
uint8 i=1;
if (menu_now->cursor_pressed == false) {
if (menu_now->line_value_type[menu_now->cursor] != type_NULL) {
menu_now->cursor_pressed = true;
UI_line_fresh(menu_now->cursor,2);
}
else if (menu_now->next_menu[menu_now->cursor] != NULL) {
menu_now->cursor_pressed = false;
menu_now=menu_now->next_menu[menu_now->cursor];
menu_now->cursor = 0;
LCD_Clear(White); //ÇåÆÁ
UI_line_fresh(menu_now->cursor,1);
while(menu_now->line_name[i][0] != 0) {
UI_line_fresh(i,0);
i++;
}
}
}
}