已用更好的方式实现,但是原理差不多,最好使用后面更新的实现,公众号第一篇文章链接:https://mp.weixin.qq.com/s/OOFBPmeIjepWr6Fn6f9dtQ,也可在后面的博文中找到。
已用更好的方式实现,但是原理差不多,最好使用后面更新的实现,公众号第一篇文章链接:https://mp.weixin.qq.com/s/OOFBPmeIjepWr6Fn6f9dtQ,也可在后面的博文中找到。
已用更好的方式实现,但是原理差不多,最好使用后面更新的实现,公众号第一篇文章链接:https://mp.weixin.qq.com/s/OOFBPmeIjepWr6Fn6f9dtQ,也可在后面的博文中找到。
菜单选项的移动方式类似于 windows 文件管理器中的文件选择方式(查看方式为图标方式),目前实现了菜单翻页功能,只读页面翻页显示功能,数值修改功能等,思路就是把所有选项看成一整列,但是一整列里面分成多行多列,之前使用二维数组实现过,但是发现这种方式代码量和逻辑都更简单,便采用此种方式,如果需要借鉴,不明白思路的可以先用键盘上下左右操作一下 windows 文件管理器中的文件选项。因为仅个人使用,所以并没有考虑通用和移植,我觉得代码都不重要,重要的是思路,目前已经在项目中使用,仅提供参考,勿评。
#ifndef __MENU_H
#define __MENU_H
#include <string.h>
#include <stdint.h>
/*菜单级数深度*/
#define MENU_MAX_LEVELS 12
/*最大可设置数值位数*/
#define VALID_MAX_SET_NUM 12
#ifndef COUNTOF
#define COUNTOF(a) (sizeof(a) / sizeof(*(a)))
#endif
#ifndef ABS
#define ABS(a) ((a) > 0?(a):-(a))
#endif
typedef enum {
MENU_KEY_DEF,
MENU_KEY_X,
MENU_KEY_Y,
MENU_KEY_Z,
MENU_KEY_IPV4,
MENU_KEY_IPV6,
}menu_keyTypeDef;
typedef void(*tMenuFunc)(void);
typedef struct sValueSet *tValueSet;
typedef struct sTitle *tTitle;
typedef struct sMenuItem *tMenuItem;
typedef struct sMenu *tMenu;
struct sTitle {
char *str;//标题名
uint8_t x;//行坐标
uint8_t y;//列坐标
// uint8_t f_w;//字体宽
// uint8_t f_h;//字体高
};
struct sValueSet {
int64_t value;
int64_t max;//数值最大值
int64_t min;//数值最小值
int32_t nBit;//数值位数(整数部分)
int32_t nBit_f;//数值位数(小数部分)
uint8_t bitIdx;
uint8_t aBit[VALID_MAX_SET_NUM];
uint16_t ipv6[8];//用于 ipv6 设置
};
struct sMenuHMIFunc {
tMenuFunc pfMenuKeyUp;
tMenuFunc pfMenuKeyDown;
tMenuFunc pfMenuKeyLeft;
tMenuFunc pfMenuKeyRight;
tMenuFunc pfMenuKeyEnter;
tMenuFunc pfMenuKeyExit;
//静态内容显示
tMenuFunc pfMenuDispStatic;
//动态内容显示
tMenuFunc pfMenuDispDynamic;
};
struct sMenuItem {
tTitle pszTitle;//选项标题
tMenu psSubMenu;//子菜单
};
struct sMenu {
tTitle pszTitle;//菜单标题
tMenuItem psItem;//子选项
uint8_t nItems;//子选项数量或页数
uint8_t idx;//当前索引
uint8_t nRow;//单页要排列的行
uint8_t nCol;//单页要排列的列
int id;
struct sMenuHMIFunc HMIFunc;
menu_keyTypeDef menu_key;
};
struct sMenuHandle {
tMenu psPreMenu[MENU_MAX_LEVELS];//存储各级菜单
uint8_t Level;//当前菜单级数
tMenu psCurMenu;//当前菜单
tValueSet psValueSet;
};
/*获取当前菜单*/
inline struct sMenu *MenuGetCur(void)
{
extern struct sMenuHandle hMenu;
return hMenu.psCurMenu;
}
/*获取当前菜单*/
inline void MenuSetCur(struct sMenu *set)
{
extern struct sMenuHandle hMenu;
hMenu.psCurMenu = set;
}
/*获取数值设置*/
inline struct sValueSet *MenuGetValueSet(void)
{
extern struct sMenuHandle hMenu;
return hMenu.psValueSet;
}
/*计算 val 的 n 次方*/
uint64_t CalPower(uint64_t val, uint32_t n);
//计算 10 的次方
double CalPowerOfTen(int32_t n);
/*获取数值位数*/
int32_t GetNumBit(uint64_t num);
/*获取浮点数的整数位数和小数位数*/
void GetNumBit_f(double num,int32_t *d,int32_t *f);
/*初始化菜单*/
void MenuInit(struct sMenu *pFirstMenu);
/*反初始化菜单*/
void MenuDeInit(void);
/*显示菜单*/
void MenuDisp(void);
/*更新静态内容*/
void Updatestatic(void);
/*更新动态内容*/
void UpdateDynamic(void);
/*按键扫描*/
void MenuBspKeyScan(void);
/*menu replace(注意 const)*/
void MenuReplace(struct sMenu re[]);
/*进入选中的子菜单*/
void MenuEnter(void);
/*退出到上一级菜单*/
void MenuExit(void);
#endif/*__MENU_H*/
#include "./menu.h"
#include "debug.h"
#include "./key_board/key_board.h"
#include "./oled.h"
#define OPT_DBG_INF 1U
struct sMenuHandle hMenu;
static struct sValueSet tmpSet;
void MenuUp(void);
void MenuDown(void);
void MenuLeft(void);
void MenuRight(void);
void MenuUp_x(void);
void MenuDown_x(void);
void MenuLeft_x(void);
void MenuRight_x(void);
void MenuUp_y(void);
void MenuDown_y(void);
void MenuLeft_y(void);
void MenuRight_y(void);
void MenuUp_z(void);
void MenuDown_z(void);
void MenuLeft_z(void);
void MenuRight_z(void);
void MenuUp_IPv4(void);
void MenuDown_IPv4(void);
void MenuLeft_IPv4(void);
void MenuRight_IPv4(void);
void MenuUp_IPv6(void);
void MenuDown_IPv6(void);
void MenuLeft_IPv6(void);
void MenuRight_IPv6(void);
/*计算 val 的 n 次方*/
uint64_t CalPower(uint64_t val, uint32_t n)
{
uint64_t tmp = 1;
if(val == 0){ return 0; }
while(n--)
{
tmp *= val;
}
return tmp;
}
//计算 10 的次方
double CalPowerOfTen(int32_t n)
{
double tmp = 1;
int32_t tmpN = ABS(n);
if(n > 0)
{
while(n--)
{
tmp *= 10;
}
}
else if(n < 0)
{
while(tmpN--)
{
tmp /= 10;
}
}
return tmp;
}
/*获取数值位数*/
int32_t GetNumBit(uint64_t num)
{
char aTmp[20] = {0};//max 4bytes
return sprintf(aTmp,"%llu",num);
}
/*获取浮点数的整数位数和小数位数(有缺陷,如果小数点后保留位为全 0)*/
void GetNumBit_f(double num,int32_t *d,int32_t *f)
{
char aTmp[32] = {0};
int32_t i = 0;
*d = 0;*f = 0;
if((double)0 == num)
{
*d = 1;
return ;
}
*d = sprintf(aTmp,"%d",ABS((int32_t)num));
i = sprintf(aTmp,"%f",ABS(num));
while(aTmp[--i] == '0')
{
//除去默认精度补的零个数
}
i += 1;
//除去整数位数和小数点
*f = i - *d - 1;
}
/*初始化菜单*/
void MenuInit(struct sMenu *pFirstMenu)
{
pFirstMenu->HMIFunc.pfMenuKeyUp = MenuUp;
pFirstMenu->HMIFunc.pfMenuKeyDown = MenuDown;
pFirstMenu->HMIFunc.pfMenuKeyLeft = MenuLeft;
pFirstMenu->HMIFunc.pfMenuKeyRight = MenuRight;
pFirstMenu->HMIFunc.pfMenuKeyEnter = MenuEnter;
pFirstMenu->HMIFunc.pfMenuKeyExit = MenuExit;
hMenu.psCurMenu = pFirstMenu;
hMenu.Level = 0;
hMenu.psPreMenu[hMenu.Level] = pFirstMenu;
hMenu.psValueSet = &tmpSet;
MenuDisp();
}
/*反初始化菜单*/
void MenuDeInit(void)
{
memset(&hMenu,NULL,sizeof(struct sMenuHandle));
}
/*显示菜单*/
void MenuDisp(void)
{
uint32_t i = 0,tmpIdx = 0,tmp = 0;
tTitle pTmp2 = NULL;
OLED_clcScreen();
/*刷新静态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispStatic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispStatic();
}
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
tmp = hMenu.psCurMenu->nRow * hMenu.psCurMenu->nCol;
/*如果单页行列元素小于最大选项数*/
if(tmp && (tmp < hMenu.psCurMenu->nItems))
{
//计算当前索引对应页的开始选项
i = hMenu.psCurMenu->idx - (hMenu.psCurMenu->idx % tmp);
tmpIdx = i;
}
for( ;(i < hMenu.psCurMenu->nItems) && (i < (tmp + tmpIdx));i++)
{
pTmp2 = hMenu.psCurMenu->psItem[i].pszTitle;
if(pTmp2 && pTmp2->str)
{
OLED_INT_CharDisp(pTmp2->x, pTmp2->y, i == hMenu.psCurMenu->idx?1:0, pTmp2->str);
}
}
}
/*更新静态内容*/
void Updatestatic(void)
{
/*刷新静态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispStatic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispStatic();
}
}
/*更新动态内容*/
void UpdateDynamic(void)
{
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
}
/*按键扫描*/
void MenuBspKeyScan(void)
{
if(hMenu.psCurMenu == NULL)
{
return ;
}
if (KeyGetState(KEY_UP) == KEY_RELEASE)//up
{
if(hMenu.psCurMenu->HMIFunc.pfMenuKeyUp != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuKeyUp();
}
}
if (KeyGetState(KEY_DOWN) == KEY_RELEASE)//down
{
if(hMenu.psCurMenu->HMIFunc.pfMenuKeyDown != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuKeyDown();
}
}
if (KeyGetState(KEY_LEFT) == KEY_RELEASE)//left
{
if(hMenu.psCurMenu->HMIFunc.pfMenuKeyLeft != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuKeyLeft();
}
}
if (KeyGetState(KEY_RIGHT) == KEY_RELEASE)//right
{
if(hMenu.psCurMenu->HMIFunc.pfMenuKeyRight != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuKeyRight();
}
}
if (KeyGetState(KEY_ENTER) == KEY_RELEASE)//enter
{
if(hMenu.psCurMenu->HMIFunc.pfMenuKeyEnter != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuKeyEnter();
}
}
if (KeyGetState(KEY_EXIT) == KEY_RELEASE)//exit
{
if(hMenu.psCurMenu->HMIFunc.pfMenuKeyExit != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuKeyExit();
}
}
}
/*menu replace(注意 const)*/
void MenuReplace(struct sMenu re[])
{
hMenu.psCurMenu = re;
}
/*enter key*/
void MenuEnter(void)
{
if((&hMenu.psCurMenu->psItem[hMenu.psCurMenu->idx] != NULL) &&
(hMenu.psCurMenu->psItem[hMenu.psCurMenu->idx].psSubMenu != NULL))
{
hMenu.psPreMenu[hMenu.Level] = hMenu.psCurMenu;
if(!(++hMenu.Level < MENU_MAX_LEVELS))
{
hMenu.Level--;
}
hMenu.psCurMenu = hMenu.psCurMenu->psItem[hMenu.psCurMenu->idx].psSubMenu;
MenuDisp();
}
switch(hMenu.psCurMenu->menu_key)
{
case MENU_KEY_DEF:
hMenu.psCurMenu->HMIFunc.pfMenuKeyUp = MenuUp;
hMenu.psCurMenu->HMIFunc.pfMenuKeyDown = MenuDown;
hMenu.psCurMenu->HMIFunc.pfMenuKeyLeft = MenuLeft;
hMenu.psCurMenu->HMIFunc.pfMenuKeyRight = MenuRight;
break;
case MENU_KEY_X:
hMenu.psCurMenu->HMIFunc.pfMenuKeyUp = MenuUp_x;
hMenu.psCurMenu->HMIFunc.pfMenuKeyDown = MenuDown_x;
hMenu.psCurMenu->HMIFunc.pfMenuKeyLeft = MenuLeft_x;
hMenu.psCurMenu->HMIFunc.pfMenuKeyRight = MenuRight_x;
break;
case MENU_KEY_Y:
hMenu.psCurMenu->HMIFunc.pfMenuKeyUp = MenuUp_y;
hMenu.psCurMenu->HMIFunc.pfMenuKeyDown = MenuDown_y;
hMenu.psCurMenu->HMIFunc.pfMenuKeyLeft = MenuLeft_y;
hMenu.psCurMenu->HMIFunc.pfMenuKeyRight = MenuRight_y;
break;
case MENU_KEY_Z:
hMenu.psCurMenu->HMIFunc.pfMenuKeyUp = MenuUp_z;
hMenu.psCurMenu->HMIFunc.pfMenuKeyDown = MenuDown_z;
hMenu.psCurMenu->HMIFunc.pfMenuKeyLeft = MenuLeft_z;
hMenu.psCurMenu->HMIFunc.pfMenuKeyRight = MenuRight_z;
break;
case MENU_KEY_IPV4:
hMenu.psCurMenu->HMIFunc.pfMenuKeyUp = MenuUp_IPv4;
hMenu.psCurMenu->HMIFunc.pfMenuKeyDown = MenuDown_IPv4;
hMenu.psCurMenu->HMIFunc.pfMenuKeyLeft = MenuLeft_IPv4;
hMenu.psCurMenu->HMIFunc.pfMenuKeyRight = MenuRight_IPv4;
break;
case MENU_KEY_IPV6:
hMenu.psCurMenu->HMIFunc.pfMenuKeyUp = MenuUp_IPv6;
hMenu.psCurMenu->HMIFunc.pfMenuKeyDown = MenuDown_IPv6;
hMenu.psCurMenu->HMIFunc.pfMenuKeyLeft = MenuLeft_IPv6;
hMenu.psCurMenu->HMIFunc.pfMenuKeyRight = MenuRight_IPv6;
break;
default:
break;
}
if(hMenu.psCurMenu->HMIFunc.pfMenuKeyEnter == NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuKeyEnter = MenuEnter;
}
if(hMenu.psCurMenu->HMIFunc.pfMenuKeyExit == NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuKeyExit = MenuExit;
}
}
/*exit key*/
void MenuExit(void)
{
if(hMenu.Level > 0)
{
hMenu.Level--;
hMenu.psCurMenu = hMenu.psPreMenu[hMenu.Level];
MenuDisp();
}
switch(hMenu.psCurMenu->menu_key)
{
case MENU_KEY_DEF:
hMenu.psCurMenu->HMIFunc.pfMenuKeyUp = MenuUp;
hMenu.psCurMenu->HMIFunc.pfMenuKeyDown = MenuDown;
hMenu.psCurMenu->HMIFunc.pfMenuKeyLeft = MenuLeft;
hMenu.psCurMenu->HMIFunc.pfMenuKeyRight = MenuRight;
break;
case MENU_KEY_X:
hMenu.psCurMenu->HMIFunc.pfMenuKeyUp = MenuUp_x;
hMenu.psCurMenu->HMIFunc.pfMenuKeyDown = MenuDown_x;
hMenu.psCurMenu->HMIFunc.pfMenuKeyLeft = MenuLeft_x;
hMenu.psCurMenu->HMIFunc.pfMenuKeyRight = MenuRight_x;
break;
case MENU_KEY_Y:
hMenu.psCurMenu->HMIFunc.pfMenuKeyUp = MenuUp_y;
hMenu.psCurMenu->HMIFunc.pfMenuKeyDown = MenuDown_y;
hMenu.psCurMenu->HMIFunc.pfMenuKeyLeft = MenuLeft_y;
hMenu.psCurMenu->HMIFunc.pfMenuKeyRight = MenuRight_y;
break;
case MENU_KEY_Z:
hMenu.psCurMenu->HMIFunc.pfMenuKeyUp = MenuUp_z;
hMenu.psCurMenu->HMIFunc.pfMenuKeyDown = MenuDown_z;
hMenu.psCurMenu->HMIFunc.pfMenuKeyLeft = MenuLeft_z;
hMenu.psCurMenu->HMIFunc.pfMenuKeyRight = MenuRight_z;
break;
case MENU_KEY_IPV4:
hMenu.psCurMenu->HMIFunc.pfMenuKeyUp = MenuUp_IPv4;
hMenu.psCurMenu->HMIFunc.pfMenuKeyDown = MenuDown_IPv4;
hMenu.psCurMenu->HMIFunc.pfMenuKeyLeft = MenuLeft_IPv4;
hMenu.psCurMenu->HMIFunc.pfMenuKeyRight = MenuRight_IPv4;
break;
case MENU_KEY_IPV6:
hMenu.psCurMenu->HMIFunc.pfMenuKeyUp = MenuUp_IPv6;
hMenu.psCurMenu->HMIFunc.pfMenuKeyDown = MenuDown_IPv6;
hMenu.psCurMenu->HMIFunc.pfMenuKeyLeft = MenuLeft_IPv6;
hMenu.psCurMenu->HMIFunc.pfMenuKeyRight = MenuRight_IPv6;
break;
default:
break;
}
if(hMenu.psCurMenu->HMIFunc.pfMenuKeyEnter == NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuKeyEnter = MenuEnter;
}
if(hMenu.psCurMenu->HMIFunc.pfMenuKeyExit == NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuKeyExit = MenuExit;
}
}
/*up key 用于选择菜单*/
void MenuUp(void)
{
tTitle pTmp1 = hMenu.psCurMenu->psItem[hMenu.psCurMenu->idx].pszTitle;
uint8_t currentPage = 0,updatePage = 0;
/*如果索引为 0 则直接退出*/
if(!(hMenu.psCurMenu->idx > 0))
{
return ;
}
//计算当前索引处于的页数
currentPage = hMenu.psCurMenu->idx / (hMenu.psCurMenu->nRow * hMenu.psCurMenu->nCol);
if(pTmp1)
{
//取消当前选中
OLED_INT_CharDisp(pTmp1->x, pTmp1->y, 0, pTmp1->str);
}
/*如果索引小于当前页列数则跳到第一列,否则跳到上一行对应列*/
if(hMenu.psCurMenu->idx < hMenu.psCurMenu->nCol)
{
hMenu.psCurMenu->idx = 0;
}
else
{
hMenu.psCurMenu->idx -= hMenu.psCurMenu->nCol;
}
pTmp1 = hMenu.psCurMenu->psItem[hMenu.psCurMenu->idx].pszTitle;
if(pTmp1)
{
//选中下一个
OLED_INT_CharDisp(pTmp1->x, pTmp1->y, 1, pTmp1->str);
}
//计算更新索引后处于的页数
updatePage = hMenu.psCurMenu->idx / (hMenu.psCurMenu->nRow * hMenu.psCurMenu->nCol);
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
if((hMenu.psCurMenu->nRow * hMenu.psCurMenu->nCol) < hMenu.psCurMenu->nItems)
{
/*更新索引后对应的页数小于了更新前的页数则跳到上一页*/
if(updatePage < currentPage)
{
MenuDisp();
}
}
}
/*down key 用于选择菜单*/
void MenuDown(void)
{
tTitle pTmp1 = hMenu.psCurMenu->psItem[hMenu.psCurMenu->idx].pszTitle;
uint8_t currentPage = 0,updatePage = 0;
/*如果当前索引大于最大选项数则直接退出*/
if(!(hMenu.psCurMenu->idx < (hMenu.psCurMenu->nItems - 1)))
{
return ;
}
//计算当前索引处于的页数
currentPage = hMenu.psCurMenu->idx / (hMenu.psCurMenu->nRow * hMenu.psCurMenu->nCol);
if(pTmp1)
{
//取消当前选中
OLED_INT_CharDisp(pTmp1->x, pTmp1->y, 0, pTmp1->str);
}
/*如果跳到下一行对应列大于了最大选项数则跳到最后一个元素,否则跳到下一行对应列*/
if((hMenu.psCurMenu->idx + hMenu.psCurMenu->nCol) > (hMenu.psCurMenu->nItems - 1))
{
hMenu.psCurMenu->idx = hMenu.psCurMenu->nItems - 1;
}
else
{
hMenu.psCurMenu->idx += hMenu.psCurMenu->nCol;
}
pTmp1 = hMenu.psCurMenu->psItem[hMenu.psCurMenu->idx].pszTitle;
if(pTmp1)
{
//选中下一个
OLED_INT_CharDisp(pTmp1->x, pTmp1->y, 1, pTmp1->str);
}
//计算更新索引后处于的页数
updatePage = hMenu.psCurMenu->idx / (hMenu.psCurMenu->nRow * hMenu.psCurMenu->nCol);
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
if((hMenu.psCurMenu->nRow * hMenu.psCurMenu->nCol) < hMenu.psCurMenu->nItems)
{
/*更新索引后对应的页数大于了更新前的页数则跳到下一页*/
if(updatePage > currentPage)
{
MenuDisp();
}
}
}
/*left key 用于选择菜单*/
void MenuLeft(void)
{
tTitle pTmp1 = hMenu.psCurMenu->psItem[hMenu.psCurMenu->idx].pszTitle;
uint8_t currentPage = 0,updatePage = 0;
if(!hMenu.psCurMenu->psItem)
{
return ;
}
//计算当前索引处于的页数
currentPage = hMenu.psCurMenu->idx / (hMenu.psCurMenu->nRow * hMenu.psCurMenu->nCol);
if(pTmp1)
{
//取消当前选中
OLED_INT_CharDisp(pTmp1->x, pTmp1->y, 0, pTmp1->str);
}
if(hMenu.psCurMenu->idx > 0)
{
hMenu.psCurMenu->idx--;
}
else
{
hMenu.psCurMenu->idx = hMenu.psCurMenu->nItems - 1;
}
pTmp1 = hMenu.psCurMenu->psItem[hMenu.psCurMenu->idx].pszTitle;
if(pTmp1)
{
//选中下一个
OLED_INT_CharDisp(pTmp1->x, pTmp1->y, 1, pTmp1->str);
}
//计算更新索引后处于的页数
updatePage = hMenu.psCurMenu->idx / (hMenu.psCurMenu->nRow * hMenu.psCurMenu->nCol);
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
if((hMenu.psCurMenu->nRow * hMenu.psCurMenu->nCol) < hMenu.psCurMenu->nItems)
{
/*更新索引后对应的页数小于了更新前的页数或更新后的索引循环了一次则跳到上一页*/
if((updatePage < currentPage) || (hMenu.psCurMenu->idx == (hMenu.psCurMenu->nItems - 1)))
{
MenuDisp();
}
}
}
/*right key 用于选择菜单*/
void MenuRight(void)
{
tTitle pTmp1 = hMenu.psCurMenu->psItem[hMenu.psCurMenu->idx].pszTitle;
uint8_t currentPage = 0,updatePage = 0;
if(!hMenu.psCurMenu->psItem)
{
return ;
}
//计算当前索引处于的页数
currentPage = hMenu.psCurMenu->idx / (hMenu.psCurMenu->nRow * hMenu.psCurMenu->nCol);
if(pTmp1)
{
//取消当前选中
OLED_INT_CharDisp(pTmp1->x, pTmp1->y, 0, pTmp1->str);
}
if(hMenu.psCurMenu->idx < (hMenu.psCurMenu->nItems - 1))
{
hMenu.psCurMenu->idx++;
}
else
{
hMenu.psCurMenu->idx = 0;
}
pTmp1 = hMenu.psCurMenu->psItem[hMenu.psCurMenu->idx].pszTitle;
if(pTmp1)
{
//选中下一个
OLED_INT_CharDisp(pTmp1->x, pTmp1->y, 1, pTmp1->str);
}
//计算更新索引后处于的页数
updatePage = hMenu.psCurMenu->idx / (hMenu.psCurMenu->nRow * hMenu.psCurMenu->nCol);
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
if((hMenu.psCurMenu->nRow * hMenu.psCurMenu->nCol) < hMenu.psCurMenu->nItems)
{
/*更新索引后对应的页数大于了更新前的页数或更新后的索引循环了一次则跳到下一页*/
if((updatePage > currentPage) || (hMenu.psCurMenu->idx == 0))
{
MenuDisp();
}
}
}
/*up key 用于翻页*/
void MenuUp_x(void)
{
if(hMenu.psCurMenu->idx > 0)
{
hMenu.psCurMenu->idx--;
MenuDisp();
}
}
/*down key 用于翻页*/
void MenuDown_x(void)
{
if(hMenu.psCurMenu->idx < (hMenu.psCurMenu->nItems - 1))
{
hMenu.psCurMenu->idx++;
MenuDisp();
}
}
/*left key 用于翻页*/
void MenuLeft_x(void)
{
}
/*right key 用于翻页*/
void MenuRight_x(void)
{
}
/*up key 用于数值设置(各位之间互不影响)*/
void MenuUp_y(void)
{
/*数值加范围(0~9)*/
if(++hMenu.psValueSet->aBit[hMenu.psValueSet->bitIdx] >= 10)
{
hMenu.psValueSet->aBit[hMenu.psValueSet->bitIdx] = 0;
}
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
}
/*down key 用于数值设置(各位之间互不影响)*/
void MenuDown_y(void)
{
/*数值减范围(0~9)*/
if(hMenu.psValueSet->aBit[hMenu.psValueSet->bitIdx]-- <= 0)
{
hMenu.psValueSet->aBit[hMenu.psValueSet->bitIdx] = 9;
}
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
}
/*left key 用于数值设置(各位之间互不影响)*/
void MenuLeft_y(void)
{
if(hMenu.psValueSet->nBit > VALID_MAX_SET_NUM)
{
hMenu.psValueSet->nBit = VALID_MAX_SET_NUM;
}
/*移动索引*/
if(hMenu.psValueSet->bitIdx-- <= 0)
{
hMenu.psValueSet->bitIdx = hMenu.psValueSet->nBit - 1;
}
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
}
/*right key 用于数值设置(各位之间互不影响)*/
void MenuRight_y(void)
{
if(hMenu.psValueSet->nBit > VALID_MAX_SET_NUM)
{
hMenu.psValueSet->nBit = VALID_MAX_SET_NUM;
}
/*移动索引*/
if(++hMenu.psValueSet->bitIdx >= hMenu.psValueSet->nBit)
{
hMenu.psValueSet->bitIdx = 0;
}
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
}
/*up key 用于数值设置*/
void MenuUp_z(void)
{
/*数值修改*/
hMenu.psValueSet->value += CalPowerOfTen(hMenu.psValueSet->nBit + hMenu.psValueSet->nBit_f - hMenu.psCurMenu->idx - 1);
if(hMenu.psValueSet->value > hMenu.psValueSet->max)
{
hMenu.psValueSet->value = hMenu.psValueSet->max;
}
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
}
/*down key 用于数值设置*/
void MenuDown_z(void)
{
/*数值修改*/
hMenu.psValueSet->value -= CalPowerOfTen(hMenu.psValueSet->nBit + hMenu.psValueSet->nBit_f - hMenu.psCurMenu->idx - 1);
if(hMenu.psValueSet->value < hMenu.psValueSet->min)
{
hMenu.psValueSet->value = hMenu.psValueSet->min;
}
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
}
/*left key 用于数值设置*/
void MenuLeft_z(void)
{
/*移动索引*/
if(hMenu.psCurMenu->idx-- <= 0)
{
hMenu.psCurMenu->idx = (hMenu.psValueSet->nBit + hMenu.psValueSet->nBit_f) - 1;
}
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
}
/*right key 用于数值设置*/
void MenuRight_z(void)
{
/*移动索引*/
if(++hMenu.psCurMenu->idx >= (hMenu.psValueSet->nBit + hMenu.psValueSet->nBit_f))
{
hMenu.psCurMenu->idx = 0;
}
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
}
/*up key 用于 IPv4 设置*/
void MenuUp_IPv4(void)
{
uint8_t tmp = 0x00;
/*记录修改前的值*/
tmp = hMenu.psValueSet->aBit[hMenu.psCurMenu->idx / 3];
/*数值修改范围(0~255)*/
hMenu.psValueSet->aBit[hMenu.psCurMenu->idx / 3] += CalPowerOfTen((3 - 1) - (hMenu.psCurMenu->idx % 3));
if(hMenu.psValueSet->aBit[hMenu.psCurMenu->idx / 3] < tmp)
{
hMenu.psValueSet->aBit[hMenu.psCurMenu->idx / 3] = tmp;
}
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
}
/*down key 用于 IPv4 设置*/
void MenuDown_IPv4(void)
{
uint8_t tmp = 0x00;
/*记录修改前的值*/
tmp = hMenu.psValueSet->aBit[hMenu.psCurMenu->idx / 3];
/*数值修改范围(0~255)*/
hMenu.psValueSet->aBit[hMenu.psCurMenu->idx / 3] -= CalPowerOfTen((3 - 1) - (hMenu.psCurMenu->idx % 3));
if(hMenu.psValueSet->aBit[hMenu.psCurMenu->idx / 3] > tmp)
{
hMenu.psValueSet->aBit[hMenu.psCurMenu->idx / 3] = tmp;
}
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
}
/*right key 用于 IPv4 设置*/
void MenuLeft_IPv4(void)
{
if(hMenu.psValueSet->nBit > 12)
{
hMenu.psValueSet->nBit = 12;
}
/*移动索引*/
if(hMenu.psCurMenu->idx-- <= 0)
{
hMenu.psCurMenu->idx = hMenu.psValueSet->nBit - 1;
}
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
}
/*right key 用于 IPv4 设置*/
void MenuRight_IPv4(void)
{
if(hMenu.psValueSet->nBit > 12)
{
hMenu.psValueSet->nBit = 12;
}
/*移动索引*/
if(++hMenu.psCurMenu->idx >= hMenu.psValueSet->nBit)
{
hMenu.psCurMenu->idx = 0;
}
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
}
/*up key 用于 IPv6 设置*/
void MenuUp_IPv6(void)
{
/*数值修改*/
hMenu.psValueSet->ipv6[hMenu.psCurMenu->idx / 4] += (0x1000UL >> ((hMenu.psCurMenu->idx % 4) * 4));
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
}
/*down key 用于 IPv6 设置*/
void MenuDown_IPv6(void)
{
/*数值修改*/
hMenu.psValueSet->ipv6[hMenu.psCurMenu->idx / 4] -= (0x1000UL >> ((hMenu.psCurMenu->idx % 4) * 4));
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
}
/*right key 用于 IPv6 设置*/
void MenuLeft_IPv6(void)
{
if(hMenu.psValueSet->nBit > 32)
{
hMenu.psValueSet->nBit = 32;
}
/*移动索引*/
if(hMenu.psCurMenu->idx-- <= 0)
{
hMenu.psCurMenu->idx = hMenu.psValueSet->nBit - 1;
}
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
}
/*right key 用于 IPv6 设置*/
void MenuRight_IPv6(void)
{
if(hMenu.psValueSet->nBit > 32)
{
hMenu.psValueSet->nBit = 32;
}
/*移动索引*/
if(++hMenu.psCurMenu->idx >= hMenu.psValueSet->nBit)
{
hMenu.psCurMenu->idx = 0;
}
/*刷新动态内容*/
if(hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic != NULL)
{
hMenu.psCurMenu->HMIFunc.pfMenuDispDynamic();
}
}
使用示例:
1、自己封装一个菜单初始化函数,如:
/*菜单初始化*/
void OLED_MenuInit(void)
{
struct sMenu *pStart = NULL;
OLED_clcScreen();
pStart = pageStart;
MenuInit(pStart);
}
2、使用结构体方式定义菜单所需要的元素,如:
void page1S_f(void);
void page1D_f(void);
void page1E_f(void);
struct sMenu page1[] = {NULL,NULL,0,0,0,0,
-1,
{.pfMenuDispStatic = page1S_f,
.pfMenuDispDynamic = page1D_f,
.pfMenuKeyEnter = page1E_f,
},
MENU_KEY_Z};
void page1S_f(void)
{
/*根据需求完成此函数,最好用来显示静态的内容*/
}
void page1D_f(void)
{
/*根据需求完成此函数,最好用来显示动态的内容*/
}
void page1E_f(void)
{
/*根据需求完成此函数,最好用来执行按下确认键后的操作*/
}
/**********************************************************/
void page2S_f(void);
void page2D_f(void);
void page2E_f(void);
struct sTitle page2_o_t[] = {
{"关闭",29,88},
{"打开",29,136},
};
struct sMenuItem page2_o[] = {
{&page2_o_t[0],NULL},
{&page2_o_t[1],NULL},
};
struct sTitle page2_t[] = {"子菜单2",0,0};
struct sMenu page2[] = {page2_t,page2_o,COUNTOF(page2_o),0,1,2,
-1,
{.pfMenuDispStatic = page2S_f,
.pfMenuDispDynamic = page2D_f,
.pfMenuKeyEnter = page2E_f,
}};
void page2S_f(void)
{
/*根据需求完成此函数,最好用来显示静态的内容*/
}
void page2D_f(void)
{
/*根据需求完成此函数,最好用来显示动态的内容*/
}
void page2E_f(void)
{
/*根据需求完成此函数,最好用来执行按下确认键后的操作*/
}
/**********************************************************/
void pageStart_S_f(void);
void pageStart_D_f(void);
struct sTitle pageStart_o_t[] = {
{"子菜单1",29,28},
{"子菜单2",29,100},
};
struct sMenuItem pageStart_o[] = {
{&pageStart_o_t[0],page1},
{&pageStart_o_t[1],page2},
};
struct sTitle pageStart_t[] = {"主界面",0,0};
struct sMenu pageStart[] = {pageStart_t,NULL,0,0,0,0,
-1,
{.pfMenuDispStatic = pageStart_S_f,
.pfMenuDispDynamic = pageStart_D_f,
}};
static void pageStart_S_f(void)
{
/*根据需求完成此函数,最好用来显示静态的内容*/
}
static void pageStart_D_f(void)
{
/*根据需求完成此函数,最好用来显示动态的内容*/
}
3、按照类似的方法便可容易的做出多级菜单的效果