STMCU小助手
发布时间:2022-8-21 22:29
|
单片机开发中,有时会用到屏幕来显示内容,当需要逐级显示内容时,就需要使用多级菜单的形式了。: l8 D& b# B! K+ O$ i4 F! H 7 t W$ U$ F; W' a
多级菜单的实现,大体分为两种设计思路:
总体思路都是把菜单的各个界面联系起来,可以从上级菜单跳到下级菜单,也可从下级菜单返回上级菜单。 数组查表的方式比较简单,易于理解,本篇就来使用数组查表发在RVB2601上实现多级菜单的显示。 2 代码实现2.1 数组查表首先需要定义一个结构体: typedefstruct& e' A; I4 g# }& t j) E9 e{& ~' g ]+ r0 v. ]% |$ J+ ` uchar current;8 {" Y3 X" b4 D- y uchar up;//向上翻索引号 uchar down;//向下翻索引号/ V+ t: J1 @( O' V$ u8 e uchar enter;//确认索引号* C6 c( z% Y8 U+ t2 x" B void (*current_operation)(); } key_table;
注意:对于菜单显示的操作,用到了3个按键,分别是向下、向下和确认,如果单片机上的IO资源较为紧张,还可以把“向上翻”按钮省去,只通过“向下翻”按钮来实现循环访问,对应的结构体也可以去掉该成员。 然后定义一个表,用来定义各个页面间如何跳转 key_table table[30]={ //第0层+ P9 {8 F# D8 c' U {0,0,0,1,(*fun_0)}, 7 E8 L, L6 U- T$ a0 a8 A+ m) U //第1层, N* L9 `- ~ v& _5 x& s {1,4,2, 5,(*fun_a1)}, {2,1,3, 9,(*fun_b1)},5 w1 g' U/ J8 o {3,2,4,13,(*fun_c1)}, {4,3,1, 0,(*fun_d1)},' Z! Q- [) x+ g, R //第2层 {5,8,6,17,(*fun_a21)}, 5 D7 Q' e) i7 T& V {6,5,7,18,(*fun_a22)}, {7,6,8,19,(*fun_a23)}, {8,7,5, 1,(*fun_a24)}, a9 J1 w. m( S4 ?* e { 9,12,10,20,(*fun_b21)}, ) Z) F- `5 S( S( N% c# G* ^+ m {10, 9,11,21,(*fun_b22)},* Y4 C& {6 |. J; F' h! [- P {11,10,12,22,(*fun_b23)}, 4 p! h5 W Y& x. ?! O {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)}, ) r5 d# F9 o' i; ?( t //第3层 {17,17,17,5,(*fun_a31)}, {18,18,18,6,(*fun_a32)}, 6 s v8 ^. |5 U+ c0 k$ r5 [ {19,19,19,7,(*fun_a33)}, {20,20,20, 9,(*fun_b31)}, {21,21,21,10,(*fun_b32)}, {22,22,22,11,(*fun_b33)}, 5 O! a0 Y. C1 a {23,23,23,13,(*fun_c31)}, {24,24,24,14,(*fun_c32)}, / ^+ Z7 m6 \! e, a. ] {25,25,25,15,(*fun_c33)}, ) X0 T' O. L, X0 E) {, Q8 |1 m };2 U# X0 t9 G# _# g2 J 这里解释一下该表是如何工作的:
上图就是一个实际的4级菜单要显示的内容,每个条目前,标记了索引号(0~25),即对应数组在定义的索引号。 比如数组关于第0层和第1层的定义: //第0层2 B% f+ H# l$ a7 w& |. s6 n{0,0,0,1,(*fun_0)},1 [7 J3 I/ F7 t //第1层 {1,4,2, 5,(*fun_a1)}, {2,1,3, 9,(*fun_b1)}, {3,2,4,13,(*fun_c1)}, * u2 a$ z, g7 W8 A" Q0 F {4,3,1, 0,(*fun_d1)},8 W! q v3 I, x" \% C' G+ S
通过分析,不难发现,这些数组在空间上的关系:
对于菜单的最底层,因为没有上翻和下翻的功能需求,因此每行的前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)},3 w3 A$ v K* e1 h% H v: n {23,23,23,13,(*fun_c31)}, : ]! J8 J, m1 G! t0 F {24,24,24,14,(*fun_c32)}, $ j) J) `. `) i) g3 H/ \ {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,"<--"); 8 ?/ y( L+ w, X }6 K" `& F e e" K$ g2 \ % \, [1 Q% e* S7 z( t void fun_b1() { u8g2_DrawStr(&u8g2,0,32,">");/ I3 J( a! P- b$ `$ }% r u8g2_DrawStr(&u8g2,16,16,"[1]Weather"); u8g2_DrawStr(&u8g2,16,32,"[2]Music");8 |2 ]9 U! U' }$ \& Y2 J4 u! s8 n u8g2_DrawStr(&u8g2,16,48,"[3]Device Info"); u8g2_DrawStr(&u8g2,16,64,"<--"); } ! X p/ {4 a1 F$ r void fun_c1() 2 E) F( v% d7 q7 D! z { u8g2_DrawStr(&u8g2,0,48,">");) X+ @+ i" k1 C' O/ L8 G$ D u8g2_DrawStr(&u8g2,16,16,"[1]Weather"); u8g2_DrawStr(&u8g2,16,32,"[2]Music"); u8g2_DrawStr(&u8g2,16,48,"[3]Device Info");: C2 l$ u+ F% o7 n/ G7 P; X" \ u8g2_DrawStr(&u8g2,16,64,"<--"); * X# G' z( e' f! z& x" `( x }5 M* D' ~' P, w/ L void fun_d1() { u8g2_DrawStr(&u8g2,0,64,">");- @) ]& l r' ]- Z1 j u8g2_DrawStr(&u8g2,16,16,"[1]Weather");8 d! b. X$ i! ~+ a6 z. { u8g2_DrawStr(&u8g2,16,32,"[2]Music");* f% r* _( F$ _) a u8g2_DrawStr(&u8g2,16,48,"[3]Device Info");- r4 C, {2 h e+ n u8g2_DrawStr(&u8g2,16,64,"<--"); }- `( r$ m' o8 ] 8 }* H( {8 d( j" p: v8 p8 s2 x! `+ P /*********第2层***********/. V4 p- |$ Q; `, E% _: { void fun_a21() { u8g2_DrawStr(&u8g2,0,16,">");/ Z( b) n# B; S f% s u8g2_DrawStr(&u8g2,16,16,"* HangZhou"); u8g2_DrawStr(&u8g2,16,32,"* BeiJing");4 V- N- n* A# Y5 y* | u8g2_DrawStr(&u8g2,16,48,"* ShangHai"); u8g2_DrawStr(&u8g2,16,64,"<--"); / ]/ G7 }' L' U( ~% ` }/ [( U8 c5 v+ s( m- p //省略...! e7 y7 N! R: W- }( k% |5 c" o 2.3 按键切换页面 页面的切换,这里里简单的按钮轮询为例,比如初始显示欢迎界面的状态下,按下不同按键后,通过数组查表,确定要跳转到的索引号,然后根据索引号,通过函数指针执行索引号对应的显示函数,即实现了一次页面切换。 然后,就是在新的页面状态,收到下一个按钮指令,再切换到下一个显示状态。 void (*current_operation_index)(); //定义一个函数指针! ^( l" e) U) q1 ]* B3 W% K//...- f) y- K# ^+ s# S& a6 t* Z while(1) {1 p. b. Z/ G# V9 G1 \1 {9 c if((KEY1==0)||(KEY2==0)||(KEY3==0)) { H) O) n _! ~6 r/ t/ ? e! e! ^ delay_ms(10);//消抖3 q6 [/ D7 g/ |7 @: M1 a1 z if(KEY1==0)" {9 y# s% [3 T2 F7 v9 t6 ^ { func_index = table[func_index].up; //向上翻* b2 Q5 ]5 m+ D% j+ c while(!KEY1);//松手检测 }9 S# ?* }! N. b: c! K3 f if(KEY2==0)6 ]1 b+ x, D/ h) X g { func_index = table[func_index].down; //向下翻 while(!KEY2); } if(KEY3==0)% ~( b* u, X! q% L$ n' E4 Q0 H% N { func_index = table[func_index].enter; //确认) Z1 z2 U. j: N- y while(!KEY3);1 [3 ^4 L" i$ \( O } } 3 L) h i1 N6 T( R if (func_index != last_index)4 X. W- t0 L" [4 h5 L) x { current_operation_index = table[func_index].current_operation; - B4 U5 a# d/ p) \, U u8g2_ClearBuffer(&u8g2); 5 Z8 V' {' s9 i- b% B( O1 Z6 R( s; r (*current_operation_index)();//执行当前操作函数- ~5 A% e+ y4 k0 N5 c u8g2_SendBuffer(&u8g2);: l5 U J: V' K: o: X! H* j/ Q 9 _7 c* f2 K% J3 l last_index = func_index; } } ! \- R2 _) a, }- A : s, Q% {$ ~* t' @& P 4 总结 本篇介绍了一种简易的多级菜单的显示方法,本质是通过数组查表,实现各级菜单的各个页面(状态)的切换(跳转),并在STM32上编程实现,通过OLED屏幕,以及借助U8g2图形库,测试了多级菜单的显示功能。 5 a1 R# R |2 Q6 g# N: {" ?( E' c& Y* D |
【STM32H735G-DK 测评】STM32H735G-DK External Loder 编译和测试
Keil-MDK 在线调试设置断点的高级用法
请教下STM32N6570 怎么把分辨率改成320x240并可以全屏显示
【福利三:逢7发帖赢大礼】想要充分利用STM32H743VI片内的RAM空间(但并不顺利)
基于stm32平台上的IC-MU磁绝对值编码器SPI通讯和码盘数据处理
使用STM32 MCU和MPU连接PDM数字麦克风
分享STM32资料-采用 STM32U031R8 MCU 的 STM32 Nucleo-64 开发板,官方资料,数据手册等资料
HRTIM 指南
使用 STM32 的 DWT 单元监控内存
DAC,COMP,HRTIM Fault 功能的使用
微信公众号
手机版