STM32简易多级菜单(数组查表法)显示方法

发布时间:2023-09-07  

单片机开发中,有时会用到屏幕来显示内容,当需要逐级显示内容时,就需要使用多级菜单的形式了。

1f614d1971f7df3ef31d1228622feb24_poYBAGKeI_6ANO1kAAGkuV1ZiHM724.png

1 多级菜单

多级菜单的实现,大体分为两种设计思路:


通过双向链表实现


通过数组查表实现


总体思路都是把菜单的各个界面联系起来,可以从上级菜单跳到下级菜单,也可从下级菜单返回上级菜单。


数组查表的方式比较简单,易于理解,本篇就来使用数组查表发在STM32上实现多级菜单的显示。


2 代码实现

2.1 数组查表

首先需要定义一个结构体:


typedef struct

{

uchar current;

uchar up;//向上翻索引号

uchar down;//向下翻索引号

uchar enter;//确认索引号

void (*current_operation)();

} key_table;

current:当前页面的索引号


up:按下“向上翻“按钮后要跳转到的页面索引号


down:按下“向下翻“按钮后要跳转到的页面索引号


enter:按下“确认“按钮后要跳转到的页面索引号


current_operation:当前页面的索引号要执行的显示函数,这是一个函数指针


注意:对于菜单显示的操作,用到了3个按键,分别是向下、向下和确认,如果单片机上的IO资源较为紧张,还可以把“向上翻”按钮省去,只通过“向下翻”按钮来实现循环访问,对应的结构体也可以去掉该成员。


然后定义一个表,用来定义各个页面间如何跳转


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级菜单的显示关系(注意第0层其实只是一个欢迎界面)


第一层菜单,只有4个选项,因此这里只列了4行(注意最后一个选项用作返回上一级,无实际内容含义)


第二层菜单,就是对第一层菜单中的3个实际的选项进行进一步的介绍,每种介绍又有4个子项(注意最后一个选项也是用作返回上一级,无实际内容含义),因此,这里的第二层菜单列了3x4=12行


第三层菜单,又是对第二层菜单中的子项进行进一步的介绍(3个分类,每类有3个子项),所以第三层菜单列了9行


注意数组中每一行的第1个数组,是索引号,先列举一个实际的例子进行分析:

05882fe852559e57e61478e592b4252e_poYBAGKeJAmASjyyAAEEODx9hF0512.png

上图就是一个实际的4级菜单要显示的内容,每个条目前,标记了索引号(0~25),即对应数组在定义的索引号。


比如数组关于第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表示此时按“上翻”和“下翻”无效,继续显示欢迎界面;再后面的1表示按下“确认”按钮后,跳转到索引1处(即显示第1级目录,且指向第1级的第1个子项);最后是此索引要显示的具体内容,fun_0就是控制屏幕显示欢迎界面


再看第二行:索引是1,显示第1级目录,且指向第1级的第1个子项(天气);后面的4表示此时按“上翻”跳转到索引4,即显示第1级目录,且指向第1级的第4个子项(Return);再后面的2表示此时按“下翻”跳转到索引2,即显示第1级目录,且指向第1级的第2个子项(音乐);再后面的5表示按下“确认”按钮后,跳转到索引5处(即显示第2级目录,且指向第2级的第1个子项-杭州);最后是此索引要显示的具体内容,fun_a1就是控制屏幕显示第1级目录,且指向第1级的第1个子项(天气)


其它行的含义与之类似


通过分析,不难发现,这些数组在空间上的关系:

6bd4417c8399a3007c1da7015fb06409_pYYBAGKeJCeAV9SvAAHIdlcRifY269.png

对于菜单的最底层,因为没有上翻和下翻的功能需求,因此每行的前3个数字都是当前的索引号:


//第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 具体的显示函数

对于函数要显示的具体内容,根据自己的实现需要显示即可。


这里我使用的是OLED屏幕,借助U8g2图形库进行内容显示,以下是部分显示示例:


/*********第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 按键切换页面

页面的切换,这里里简单的按钮轮询为例,比如初始显示欢迎界面的状态下,按下不同按键后,通过数组查表,确定要跳转到的索引号,然后根据索引号,通过函数指针执行索引号对应的显示函数,即实现了一次页面切换。


然后,就是在新的页面状态,收到下一个按钮指令,再切换到下一个显示状态。


void (*current_operation_index)(); //定义一个函数指针


//...

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)();//执行当前操作函数

        u8g2_SendBuffer(&u8g2);


        last_index = func_index;

    }

}


3 演示

测试效果如下:https://www.bilibili.com/video/BV1r5411R7eA

467058770ca5b5e06edd65137c3942e5_poYBAGKeJIGAT-CjAAau4krxglU018.png

4 总结

本篇介绍了一种简易的多级菜单的显示方法,本质是通过数组查表,实现各级菜单的各个页面(状态)的切换(跳转),并在STM32上编程实现,通过OLED屏幕,以及借助U8g2图形库,测试了多级菜单的显示功能。


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>