單片機開發(fā)中,有時會用到屏幕來顯示內(nèi)容,當需要逐級顯示內(nèi)容時,就需要使用多級菜單的形式了。
1 多級菜單
多級菜單的實現(xiàn),大體分為兩種設(shè)計思路:
通過雙向鏈表實現(xiàn)
通過數(shù)組查表實現(xiàn)
總體思路都是把菜單的各個界面聯(lián)系起來,可以從上級菜單跳到下級菜單,也可從下級菜單返回上級菜單。
數(shù)組查表的方式比較簡單,易于理解,本篇就來使用數(shù)組查表發(fā)在STM32上實現(xiàn)多級菜單的顯示。
2 代碼實現(xiàn)
2.1 數(shù)組查表
首先需要定義一個結(jié)構(gòu)體:
typedef struct
{
uchar current;
uchar up;//向上翻索引號
uchar down;//向下翻索引號
uchar enter;//確認索引號
void (*current_operation)();
} key_table;
current:當前頁面的索引號
up:按下“向上翻“按鈕后要跳轉(zhuǎn)到的頁面索引號
down:按下“向下翻“按鈕后要跳轉(zhuǎn)到的頁面索引號
enter:按下“確認“按鈕后要跳轉(zhuǎn)到的頁面索引號
current_operation:當前頁面的索引號要執(zhí)行的顯示函數(shù),這是一個函數(shù)指針
注意:對于菜單顯示的操作,用到了3個按鍵,分別是向下、向下和確認,如果單片機上的IO資源較為緊張,還可以把“向上翻”按鈕省去,只通過“向下翻”按鈕來實現(xiàn)循環(huán)訪問,對應(yīng)的結(jié)構(gòu)體也可以去掉該成員。
然后定義一個表,用來定義各個頁面間如何跳轉(zhuǎn)
key_table table[30]=
{
//第0層
{0,0,0,1,(*fun_0)},
//第1層
{1,4,2, 5,(*fun_a1)},
{2,1,3, 9,(*fun_b1)},
{3,2,4,13,(*fun_c1)},
{4,3,1, 0,(*fun_d1)},
//第2層
{5,8,6,17,(*fun_a21)},
{6,5,7,18,(*fun_a22)},
{7,6,8,19,(*fun_a23)},
{8,7,5, 1,(*fun_a24)},
{ 9,12,10,20,(*fun_b21)},
{10, 9,11,21,(*fun_b22)},
{11,10,12,22,(*fun_b23)},
{12,11, 9, 2,(*fun_b24)},
{13,16,14,23,(*fun_c21)},
{14,13,15,24,(*fun_c22)},
{15,14,16,25,(*fun_c23)},
{16,15,13, 3,(*fun_c24)},
//第3層
{17,17,17,5,(*fun_a31)},
{18,18,18,6,(*fun_a32)},
{19,19,19,7,(*fun_a33)},
{20,20,20, 9,(*fun_b31)},
{21,21,21,10,(*fun_b32)},
{22,22,22,11,(*fun_b33)},
{23,23,23,13,(*fun_c31)},
{24,24,24,14,(*fun_c32)},
{25,25,25,15,(*fun_c33)},
};
這里解釋一下該表是如何工作的:
此表,表示了4級菜單的顯示關(guān)系(注意第0層其實只是一個歡迎界面)
第一層菜單,只有4個選項,因此這里只列了4行(注意最后一個選項用作返回上一級,無實際內(nèi)容含義)
第二層菜單,就是對第一層菜單中的3個實際的選項進行進一步的介紹,每種介紹又有4個子項(注意最后一個選項也是用作返回上一級,無實際內(nèi)容含義),因此,這里的第二層菜單列了3x4=12行
第三層菜單,又是對第二層菜單中的子項進行進一步的介紹(3個分類,每類有3個子項),所以第三層菜單列了9行
注意數(shù)組中每一行的第1個數(shù)組,是索引號,先列舉一個實際的例子進行分析:
上圖就是一個實際的4級菜單要顯示的內(nèi)容,每個條目前,標記了索引號(0~25),即對應(yīng)數(shù)組在定義的索引號。
比如數(shù)組關(guān)于第0層和第1層的定義:
//第0層
{0,0,0,1,(*fun_0)},
//第1層
{1,4,2, 5,(*fun_a1)},
{2,1,3, 9,(*fun_b1)},
{3,2,4,13,(*fun_c1)},
{4,3,1, 0,(*fun_d1)},
先看第一行:索引是0,顯示歡迎界面;后面的兩個0表示此時按“上翻”和“下翻”無效,繼續(xù)顯示歡迎界面;再后面的1表示按下“確認”按鈕后,跳轉(zhuǎn)到索引1處(即顯示第1級目錄,且指向第1級的第1個子項);最后是此索引要顯示的具體內(nèi)容,fun_0就是控制屏幕顯示歡迎界面
再看第二行:索引是1,顯示第1級目錄,且指向第1級的第1個子項(天氣);后面的4表示此時按“上翻”跳轉(zhuǎn)到索引4,即顯示第1級目錄,且指向第1級的第4個子項(Return);再后面的2表示此時按“下翻”跳轉(zhuǎn)到索引2,即顯示第1級目錄,且指向第1級的第2個子項(音樂);再后面的5表示按下“確認”按鈕后,跳轉(zhuǎn)到索引5處(即顯示第2級目錄,且指向第2級的第1個子項-杭州);最后是此索引要顯示的具體內(nèi)容,fun_a1就是控制屏幕顯示第1級目錄,且指向第1級的第1個子項(天氣)
其它行的含義與之類似
通過分析,不難發(fā)現(xiàn),這些數(shù)組在空間上的關(guān)系:
對于菜單的最底層,因為沒有上翻和下翻的功能需求,因此每行的前3個數(shù)字都是當前的索引號:
//第3層
{17,17,17,5,(*fun_a31)},
{18,18,18,6,(*fun_a32)},
{19,19,19,7,(*fun_a33)},
{20,20,20, 9,(*fun_b31)},
{21,21,21,10,(*fun_b32)},
{22,22,22,11,(*fun_b33)},
{23,23,23,13,(*fun_c31)},
{24,24,24,14,(*fun_c32)},
{25,25,25,15,(*fun_c33)},
2.2 具體的顯示函數(shù)
對于函數(shù)要顯示的具體內(nèi)容,根據(jù)自己的實現(xiàn)需要顯示即可。
這里我使用的是OLED屏幕,借助U8g2圖形庫進行內(nèi)容顯示,以下是部分顯示示例:
/*********第1層***********/
void fun_a1()
{
u8g2_DrawStr(&u8g2,0,16,">");
u8g2_DrawStr(&u8g2,16,16,"[1]Weather");
u8g2_DrawStr(&u8g2,16,32,"[2]Music");
u8g2_DrawStr(&u8g2,16,48,"[3]Device Info");
u8g2_DrawStr(&u8g2,16,64,"<--");
}
void fun_b1()
{
u8g2_DrawStr(&u8g2,0,32,">");
u8g2_DrawStr(&u8g2,16,16,"[1]Weather");
u8g2_DrawStr(&u8g2,16,32,"[2]Music");
u8g2_DrawStr(&u8g2,16,48,"[3]Device Info");
u8g2_DrawStr(&u8g2,16,64,"<--");
}
void fun_c1()
{
u8g2_DrawStr(&u8g2,0,48,">");
u8g2_DrawStr(&u8g2,16,16,"[1]Weather");
u8g2_DrawStr(&u8g2,16,32,"[2]Music");
u8g2_DrawStr(&u8g2,16,48,"[3]Device Info");
u8g2_DrawStr(&u8g2,16,64,"<--");
}
void fun_d1()
{
u8g2_DrawStr(&u8g2,0,64,">");
u8g2_DrawStr(&u8g2,16,16,"[1]Weather");
u8g2_DrawStr(&u8g2,16,32,"[2]Music");
u8g2_DrawStr(&u8g2,16,48,"[3]Device Info");
u8g2_DrawStr(&u8g2,16,64,"<--");
}
/*********第2層***********/
void fun_a21()
{
u8g2_DrawStr(&u8g2,0,16,">");
u8g2_DrawStr(&u8g2,16,16,"* HangZhou");
u8g2_DrawStr(&u8g2,16,32,"* BeiJing");
u8g2_DrawStr(&u8g2,16,48,"* ShangHai");
u8g2_DrawStr(&u8g2,16,64,"<--");
}
//省略...
2.3 按鍵切換頁面
頁面的切換,這里里簡單的按鈕輪詢?yōu)槔热?strong>初始顯示歡迎界面的狀態(tài)下,按下不同按鍵后,通過數(shù)組查表,確定要跳轉(zhuǎn)到的索引號,然后根據(jù)索引號,通過函數(shù)指針執(zhí)行索引號對應(yīng)的顯示函數(shù),即實現(xiàn)了一次頁面切換。
然后,就是在新的頁面狀態(tài),收到下一個按鈕指令,再切換到下一個顯示狀態(tài)。
void (*current_operation_index)(); //定義一個函數(shù)指針
//...
while(1)
{
if((KEY1==0)||(KEY2==0)||(KEY3==0))
{
delay_ms(10);//消抖
if(KEY1==0)
{
func_index = table[func_index].up; //向上翻
while(!KEY1);//松手檢測
}
if(KEY2==0)
{
func_index = table[func_index].down; //向下翻
while(!KEY2);
}
if(KEY3==0)
{
func_index = table[func_index].enter; //確認
while(!KEY3);
}
}
if (func_index != last_index)
{
current_operation_index = table[func_index].current_operation;
u8g2_ClearBuffer(&u8g2);
(*current_operation_index)();//執(zhí)行當前操作函數(shù)
u8g2_SendBuffer(&u8g2);
last_index = func_index;
}
}
3 演示
測試效果如下:https://www.bilibili.com/video/BV1r5411R7eA
4 總結(jié)
本篇介紹了一種簡易的多級菜單的顯示方法,本質(zhì)是通過數(shù)組查表,實現(xiàn)各級菜單的各個頁面(狀態(tài))的切換(跳轉(zhuǎn)),并在STM32上編程實現(xiàn),通過OLED屏幕,以及借助U8g2圖形庫,測試了多級菜單的顯示功能。
-
單片機
+關(guān)注
關(guān)注
6026文章
44455瀏覽量
630916 -
嵌入式
+關(guān)注
關(guān)注
5052文章
18912瀏覽量
300809 -
STM32
+關(guān)注
關(guān)注
2263文章
10847瀏覽量
353779
發(fā)布評論請先 登錄
相關(guān)推薦
評論