嵌入式菜单LCD简单版

tech2026-01-09  27

嵌入式菜单需求

相信大家做嵌入式的东西的时候,会有许多的参数需要显示到显示屏幕上,那么这些参数肯定不是拿来看看这么简单,最好还可以用按键来调节大小参数。

任务要求

根据前面大家的需求,我们简单想想我们这个菜单需要做到什么程度,有了目标才可以更好的实现对吧。 基础要求: 1.至少参数需要可以显示到显示屏幕上 2.需要一个箭头“—>”来显示当前的指示行 3.在当前指示行中的参数可以改变大小

升级要求: 1.可以翻页,让显示屏不再拘于屏幕大小的限制 2.可以拓展参数的数量 3.只用四个按键解决,上下左右

特殊要求:简单的编程实现

实现方法

1.为了满足上述的要求,我将用switch case语句来向大家实现最简单的菜单,方便大家移植。 2.这次实验代码用正点原子的战舰f103板子,配用4.3寸的LCD屏幕,如果你的硬件和我的一样,那么可以直接用。 3.这次代码需要用到的c语言知识,需要掌握switch case语句,全局变量和局部变量的使用,指针的基本使用,指针地址的偏移。 4.需要你对于状态的变化有一个非常的清晰的逻辑变化,方便排除bug

首先创建一个menu.c的文件和一个menu.h的头文件

在.c中定义全局变量,这些变量是用来测试的,这都是可以自己改的。 首先我们来看看下面的指针变量,这个相当于一个容器,最主要的是掌握里面的是理解地址,然后就是普通的全局变量,这些变量就是你需要的参数了,不一定要在这里定义,你也可以在其他的.c文件中定义一个全局变量,然后再对应的.h文件中用extern来外部申明,就可以在menu.c中调用,用&变量来赋给指针。 同时大家也可以看到菜单的那些变量参数,也是后面大家拓展时用到的数据,比如你一页要六七个参数,改对应的hang_max,如果你要拓展页数的,,那么改掉page_max就可以了。这里的程序我们时一页展示四个参数,一共两页,可以来回切换

//*************全局变量****************// uint8_t *text_1; //菜单要显示的参数名字 uint8_t *text_2; uint8_t *text_3; uint8_t *text_4; uint8_t *text_5; uint8_t *text_6; uint8_t a=1; //菜单要现实的值,需要传递的值或是需要改变的值 uint8_t b=2; uint8_t c=3; uint8_t led_once=4; uint8_t sec_1=5; uint8_t sec_2=6; //*********************************// //*********菜单参数**********// u8 hang=1; //如果需要改变页数或者行数,从这段中直接修改值即可 u8 hang_max=4; u8 hang_min=1; u8 page=1; u8 page_min=1; u8 page_max=2; u8 page_statu=1; //页数的状态切换 //****************************//在这里插入代码片

定义完了,我们就需要给指针地址中的内容赋值初始化了。 这里我们用一个函数来封装,这个函数直接扔进主函数中初始化部分

void MENU_Init(void) { text_1=&a; //取要改变的值,进行指针的值的初始化 text_2=&b; text_3=&c; text_4=&led_once; text_5=&sec_1; text_6=&sec_2; } 在这里插入代码片

然后就是重头戏了,下面就是如何具体实现了 完整版先看一下,后面有分段的程序思路讲解

void MENU_processing(void) { if(page==1) { page_statu=page; switch(key_text) { case WKUP_PRES: hang--; if(hang>hang_max) {hang=hang_min;page=page+1;if(page>page_max)page=page_max;if(page<page_min)page=page_min;} if(hang<hang_min) {hang=hang_max;page=page-1;if(page>page_max)page=page_max;if(page<page_min)page=page_min;} LCD_Clear(WHITE);break; case KEY1_PRES: hang++; if(hang>hang_max) {hang=hang_min;page=page+1;if(page>page_max)page=page_max;if(page<page_min)page=page_min;} if(hang<hang_min) {hang=hang_max;page=page-1;if(page>page_max)page=page_max;if(page<page_min)page=page_min;} LCD_Clear(WHITE);break; case KEY0_PRES: *(text_1+hang-1)=*(text_1+hang-1)+1; LCD_Clear(WHITE);break; case KEY2_PRES: *(text_1+hang-1)=*(text_1+hang-1)-1; LCD_Clear(WHITE);break; } LCD_ShowString(30,1*25,200,200,16,"text_1:"); //如果移植,需要自己改变坐标 LCD_ShowString(30,2*25,200,200,16,"text_2:"); LCD_ShowString(30,3*25,200,200,16,"text_3:"); LCD_ShowString(30,4*25,200,200,16,"text_4:"); LCD_ShowxNum(80,1*25,*text_1,5,16,1); LCD_ShowxNum(80,2*25,*text_2,5,16,1); LCD_ShowxNum(80,3*25,*text_3,5,16,1); LCD_ShowxNum(80,4*25,*text_4,5,16,1); LCD_ShowString(1,hang*25,200,200,16,"--->"); if(page_statu!=page) {LCD_Clear(WHITE);} } else if(page==2) { page_statu=page; switch(key_text) { case WKUP_PRES: hang--; if(hang>hang_max) {hang=hang_min;page=page+1;if(page>page_max)page=page_max;if(page<page_min)page=page_min;} if(hang<hang_min) {hang=hang_max;page=page-1;if(page>page_max)page=page_max;if(page<page_min)page=page_min;} LCD_Clear(WHITE);break; case KEY1_PRES: hang++; if(hang>hang_max) {hang=hang_min;page=page+1;if(page>page_max)page=page_max;if(page<page_min)page=page_min;} if(hang<hang_min) {hang=hang_max;page=page-1;if(page>page_max)page=page_max;if(page<page_min)page=page_min;} LCD_Clear(WHITE);break; case KEY0_PRES: *(text_5+hang-1)=*(text_5+hang-1)+1; LCD_Clear(WHITE);break; case KEY2_PRES: *(text_5+hang-1)=*(text_5+hang-1)-1; LCD_Clear(WHITE);break; } LCD_ShowString(30,1*25,200,200,16,"text_5:"); LCD_ShowString(30,2*25,200,200,16,"text_6:"); LCD_ShowxNum(80,1*25,*text_5,5,16,1); LCD_ShowxNum(80,2*25,*text_6,5,16,1); LCD_ShowString(1,hang*25,200,200,16,"--->"); if(page_statu!=page) {LCD_Clear(WHITE);} } } 在这里插入代码片

大家先看一眼,用switch case是不是很方便,这个语句主要是解决按键的问题。我们利用hang的大小来表示当前指示行的改变,上下键可以改变这个箭头的位置,这里一定要注意限幅,因为按的时候我们一定是会多按或者是少按的,会产生误操作

case WKUP_PRES: hang--; if(hang>hang_max) {hang=hang_min;page=page+1;if(page>page_max)page=page_max;if(page<page_min)page=page_min;} if(hang<hang_min) {hang=hang_max;page=page-1;if(page>page_max)page=page_max;if(page<page_min)page=page_min;} LCD_Clear(WHITE);break; case KEY1_PRES: hang++; if(hang>hang_max) {hang=hang_min;page=page+1;if(page>page_max)page=page_max;if(page<page_min)page=page_min;} if(hang<hang_min) {hang=hang_max;page=page-1;if(page>page_max)page=page_max;if(page<page_min)page=page_min;} LCD_Clear(WHITE);break;在这里插入代码片

再用这句代码实现LCD_ShowString(1,hang*25,200,200,16,"—>");

那么下一个问题是如何改变当前指示行的参数的值,这里就要利用指针地址的偏移来解决了,这是第一页的改变

case KEY0_PRES: *(text_1+hang-1)=*(text_1+hang-1)+1; LCD_Clear(WHITE);break; case KEY2_PRES: *(text_1+hang-1)=*(text_1+hang-1)-1; LCD_Clear(WHITE);break;在这里插入代码片

这是第二页的,大家发现了,这两页的开始的指针不一样,每一页的第一行的参数为起始地址,然后偏移,所以这里的移植拓展就会有点麻烦,如果你要五六页的参数,拓展需要写五六个if,然后需要算一下每一页的起始指针是哪个,这里大家需要注意一下

case KEY0_PRES: *(text_5+hang-1)=*(text_5+hang-1)+1; LCD_Clear(WHITE);break; case KEY2_PRES: *(text_5+hang-1)=*(text_5+hang-1)-1; LCD_Clear(WHITE);break;在这里插入代码片

好了,下面便是升级了 增加页数起始很简单,用if语句解决就好,但是刷屏会存在一定的问题,所以我提出以下的解决方法,这个框架可以让先检查一下页的状态的然后进行状态改变。

if(page==1) { page_statu=page; ........ 此处省却代码 if(page_statu!=page) {LCD_Clear(WHITE);} 在这里插入代码片

利用上述的方法,就可以写一个简单的菜单程序了 给大家看一下效果,第一页 第二页 因为我的屏幕是4.3寸的,所以肯定显示的范围很大我也用不完,主要是测试翻页的效果,我后面想移植到1.14寸的LCD屏上,毕竟是嵌入式嘛,追求体积的小巧

如果有疑问,欢迎大家在下方留言,有更好更简单的方法也希望大家可以分享,我也想学习一下

最新回复(0)