本帖最后由 cry1109 于 2019-8-13 21:31 编辑
看到别人炫酷的人机交互界面挺羡慕的,就想着啥时候我也搞个。最近没事儿呢就自己写写简单的界面,练练手,满足一下我的期望,哈哈哈。
先看几张效果图啦
一级菜单就是几张图片刷来刷去的,很浓的MP3风,哈哈哈。第一个按键实现界面切换,选择项切换,第二颗按键是确定/返回键,同时兼职数值输入,开关量控制,第三个按键是单片机的复位按键。板子比较粗糙,勉强着用啦。
顺带的实现一下波形动态扫描。
相信很多用到OLED12864的产品都可以看到这种界面,这个是一级主页界面下的二级界面,可以实现逻辑控制,参数设置,参数设置放到三级界面下。
噔噔噔~,这个就是3级参数设置界面啦。第一个按键切换要设置的参数项,同时该参数动态闪烁,提示当前当前要修改的是本参数,第二颗按键实现数值修改,由于只有两颗按键,所以数值只能一个一个的往上加啦,加到最大值后再从0开始加。至于数值怎么闪烁呢,当然是空格和数字轮流显示,和LED闪烁原理差不多就行啦。
上面界面里的显示内容不用管了,主要是想验证一下功能。
那么代码怎么实现各页面之间的跳转呢?请看下面。
void GUI_MainFuction(void) //开机后主界面功能
{
if((gui_menu.menugrade1_firstdraw_flag == 0)&&(gui_menu.gui_menu_grade == 0x01)) //一级界面
{
gui_menu.menugrade1_firstdraw_flag = 1; //一级界面全是图片,为了不在主循环中产生视觉停留,界面切换后只显示一次
Dpin_enable = 1;
Apin_enable = 1;
GUI_MenuFirst();
}
else if(gui_menu.gui_menu_grade == 0x02) //二级界面
{
bitA = 0;
GUI_MenuSecond();
}
else if(gui_menu.gui_menu_grade == 0x03) //三级界面
{
GUI_MenuThird();
}
else
{
//扩展多级界面
}
}
当然是用到C里最强大的逻辑判断语句if...else...啦。gui_menu.gui_menu_grade用于储存界面级别,每次不同级别的界面跳转之前,先把界面值写进gui_menu.gui_menu_grade,下次主循环判断该值就可跳转到对应的界面啦,哦,对了,我的所有界面都放在主循环里了。Dpin_enable ,Apin_enable用于限制当前界面哪些按键动作有效,哪些按键动作无效,防止好奇的小朋友乱点。if...else...比较灵活,后面还可以再扩展多级界面啦。
void GUI_MenuFirst(void) //一级菜单
{
switch(gui_menu.menugrade1_number)
{
case 0:
OLED_DrawBMP(0,0,128, 8,(vu8 *)pic2);
break;
case 1:
OLED_DrawBMP(0,0,128, 8,(vu8 *)pic3);
break;
case 2:
OLED_DrawBMP(0,0,128, 8,(vu8 *)pic4);
break;
case 3:
OLED_DrawBMP(0,0,128, 8,(vu8 *)pic5);
break;
case 4:
OLED_DrawBMP(0,0,128, 8,(vu8 *)pic6);
break;
}
TIMER_Delay(TIMER0,20000);
}
这个是一级菜单,就是刷图片啦。通过switch() case语句选择当前要显示的界面,也可以用if...else...代替,看你怎么习惯就怎么用啦。gui_menu.menugrade1_number存放界面序号,通过改变该变量值,就可切换界面。那么怎么改变该变量值呢,当然是按键啦,按键每次动作,该值加1,这样主循环中就可实现界面跳转啦,还是很容易实现的。按键扫描后面再说。
void GUI_MenuSecond(void) //二级菜单
{
switch(gui_menu.menugrade1_number) //根据一级菜单选择跳转的二级菜单
{
case 0:
Dpin_enable = 1;
Apin_enable = 1;
GUI_FunctionSelect();
break;
case 1:
//根据需要编写函数
break;
......
}
}
接着就来到二级界面啦。由于二级界面是从一级界面跳转过来的,所以具体要跳转到哪个二级界面当然还得根据一级界面来判断啦,switch(gui_menu.menugrade1_number)就是这条语句实现的。看到Dpin_enable = 0;Apin_enable = 1;了没,每张界面下最好都要限制一下哪些按键可以动作哪些按键不可以动作,这样就不怕乱点啦。
void GUI_MenuThird() //三级菜单,实现参数设置,被选中的待设置参数闪烁
{
vu8 i;
switch(select)
{
case 4:
Dpin_enable = 0;
//根据需要编写函数
break;
......
}
}
最后就来到我们的3级界面啦。三级界面是二级界面跳转过来的,所以同理就要判断二级界面啦,select就是我代码中二级界面的一个标志。
好啦,界面的主要思路就是这些了,下面说一下如何通过按键实现不同切面的切换,数值输入等。
开始的时候我把按键放在外部中断里了,可是发现,按键按下不松开时,就一直外部中断里,此时黑屏了,按键松开后才刷新界面。。。很影响操作流畅度,所以我就把按键扫描放在定时器中断里啦,每1ms扫描一次键值,当然也要做好消抖,要不然本来只想一次按键动作,页面可能跳转好多次。
void TMR2_IRQHandler(void)
{
TIMER_ClearIntFlag(TIMER2);
key_scan();
}
这样就搞定了。由于只有两颗按键,我们总不能给每张界都配几个按键吧,那么如何才能做到当前界面的按键动作只对当前界面有效,而不会影响到其他界面呢?答案就是,还是if...else...和switch() case啦。思路就是,首先为每张界面分配不同的键值寄存器用于储存当前界面的按键动作,按键动作有效后,通过if...else...或switch() case判断当前所处界面,然后改变相应界面的键值寄存器就可以了。代码如下:
void key_scan(void)
{
vu16 tempD15;
vu16 tempA1;
static vu16 delayD;
static vu16 delayA;
static vu16 passAdelay;
tempD15 = GPIO_GET_IN_DATA(PD)&0xf000;
tempA1 = GPIO_GET_IN_DATA(PA)&0x000f;
if(Dpin_enable == 1)
{
if((tempD15|0x7000) == 0x7000)
{
if(delayD<90) //实测延时90ms不会产生误按键动作,防止多次进入键值判断
{
delayD++;
}
else
{
if((tempD15|0x7000) == 0x7000)
{
if((gui_menu.gui_menu_grade == 0x02)&&(gui_menu.menugrade1_number == 0)) //二级界面0页
{
select = select+1;
if(select == 6)
{
select = 0;
}
}
else if(gui_menu.gui_menu_grade == 0x03) //三级界面下的数值输入
{
number=number+1;
if(number == 7) //闪烁序号
{
number = 0;
}
}
else
{
//其他界面按键动作
}
....... }
}
}
if(Apin_enable == 1)
{
if((tempA1|0x000D) == 0x000D)
{
if(delayA<90)
{
delayA++;
}
else
{
if((gui_menu.gui_menu_grade == 0x02)&&(gui_menu.menugrade1_number == 0)&&(sect==0)) //主页下的二级菜单pinA动作,开关指示灯
{
if(ledstatus == true)
{
ledstatus = false;
}
else
{
ledstatus = true;
}
}
else if((gui_menu.gui_menu_grade == 0x02)&&(sect==5)) //二级菜单下时间设置栏点击A键,打开三级菜单时间设置菜单
{
gui_menu.menugrade3_enable = 1;
}
else if((gui_menu.gui_menu_grade == 0x02)&&(sect==4))
{
gui_menu.menugrade3_enable = 1;
}
else if((gui_menu.gui_menu_grade == 0x03)&&(sect == 5)) //三级菜单下时间设置
{
switch(number)
{
case 0:
date.year1++;
if(date.year1 == 10)
{
date.year1 = 0;
}
break;
case 1:
//根据需要编写代码
break;
......
}
}
}
}
}
}
就是这样啦,内容比较多,只上部分代码。在前面写道进入界面时首先Dpin_enable = 1,在键值扫描程序中if(Dpin_enable == 1)就发挥用处啦,这个优先级别最高,只有Dpin_enable = 1此时该引脚使能,动作才有效。这里的selecct和number就是不同界面下的键值寄存器,这样不同界面下按键动作,只会影响到本界面的操作,而不会影响其他界面。
好啦,就这些了,后面可以试着扩展几级界面。
睡觉。
|
工程源码补上啦
代码补上啦
贴的代码怎么变成这样的啦