#include <U8g2lib.h>
#include <Wire.h>
#define buttun_1 2 //按钮1 的引脚号
#define buttun_2 3 //按钮2 的引脚号
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);//该驱动是1.3寸的OLED屏幕。
//U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ SCL, /* data=*/ SDA); //0.9寸的OLED显示器的驱动使用硬件I2C
short x, x_trg; //x当前x坐标值,x_trg 目标x坐标值
short y = 15, y_trg = 15; //y坐标,目标y坐标
int state; //状态
byte CD_ChangDu;
u8g2_uint_t str_h; //菜单字符串高度
u8g2_uint_t str_w; //菜单字符串宽度
short frame_y , frame_y_trg; //方框的y坐标
short frame_len, frame_len_trg; //方框的宽度
char ui_select = 0; //菜单成员序号
typedef struct //定义别名为CAIDAN_LIEBIAO的结构
{
char *str; //指针变量用于指向菜单列表成员的地址
} CD_LIEBIAO;
CD_LIEBIAO LieBiao[] = { //定义结构体数组来存放菜单列表
{"abcd"}, {"a"}, {"ab"}, {"abc"}
};
typedef struct
{
byte val; //按钮键值
byte last_val; //上一次的按钮键值
} KEY_T;
KEY_T key[2] = {0}; //置0初始化
typedef struct
{
byte id; //按钮编号
byte press; //按钮状态
byte update_flag; //更新状态
byte res; //预留位
} KEY_MSG; //按钮消息
KEY_MSG key_msg = {0}; //初始化变量值
/***------------获取按钮键值------***/
byte get_io_val (byte ch)
{
if (ch == 0) //参数为0返回 按钮1 的信号,否则返回 按钮2 的信号
{
return digitalRead(buttun_1);
}
else
{
return digitalRead(buttun_2);
}
}
/***===================================================***/
/***------------按钮初始化函数------***/
void key_init(void) //按钮初始化
{
for (int i = 0; i < 2; i++)
{
key[i].val = key[i].last_val = get_io_val(i);
}
}
/***===================================================***/
/***---------------------------按钮扫描函数----------------------***/
void key_scan (void) //扫描按钮状态
{
for (int i = 0; i < 2; i++) //遍历按钮成员
{
key[i].val = get_io_val(i); //获取当前按钮键值
if (key[i].val != key[i].last_val) //如果当前键值与上一次的键值不相等
{
key[i].last_val = key[i].val; //将当前键值保存为上一次键值
if (key[i].val == 0) //如果按钮被按下,更新按钮消息
{
key_msg.id = i;
key_msg.press = 1;
key_msg.update_flag = 1;
}
}
}
}
/***===================================================***/
/***---------------------------菜单执行函数----------------------***/
void ui_proc (void)
{
if (key_msg.press && key_msg.update_flag) //如果按钮被按下且已更新键值
{
key_msg.update_flag = 0; //将更新键值状态置为0 (未更新键值)
if (key_msg.id) //判断被按下的是哪个按钮,buttun_1向上移,buttun_2向下移
{
ui_select ++; //下一个菜单成员
if (ui_select >= CD_ChangDu)
{
ui_select = CD_ChangDu - 1;
} else
{
frame_y_trg += (str_h );
}
}
else
{
ui_select --;
if (ui_select < 0)
{
ui_select = 0;
} else
{
frame_y_trg -= (str_h );
}
}
frame_len_trg = u8g2.getUTF8Width(LieBiao[ui_select].str) + 4; // 获取字符串的像素宽度
}
cd_show();
}
/***------------菜单移动(从当前坐标向目标坐标靠近)------***/
int cd_run(short *a, short *a_trg, byte temp) //两个指针变量分别指向代入坐标的地址,加减坐标的步长
{
if (*a < *a_trg) //取出两个地址中的数据(坐标值)进行比较,如果当前坐标小于目标坐标
{
temp = (*a_trg - *a) > temp ? temp : 1; //如果目标坐标-当前坐标小于步长,步长赋值为1,避免出现负数
*a += temp; //加大当前坐标值,向目标坐标靠近
}
else if ( *a > *a_trg)
{
temp = (*a_trg - *a) < temp ? temp : 1;
*a -= temp;
}
else
{
return 0; //如果两坐标相等,返回0
}
return 1; //不相等,返回1
}
/***===================================================***/
/***-------------------------菜单显示--------------------------***/
void cd_show(void)
{
u8g2.clearBuffer(); // 清除内部缓冲区
// u8g2.setFont(u8g2_font_helvB14_tn); // 设置数字字体
for (int i = 0; i < CD_ChangDu ; i++) //遍历列表成员
{
u8g2.drawStr(x + 10, y + i * str_h, LieBiao[i].str); // 输出列表成员
}
u8g2.drawRFrame(x + 8, frame_y, frame_len, str_h + 2, 3);
cd_run(&frame_y, &frame_y_trg, 3);
cd_run(&frame_len, &frame_len_trg, 4);
u8g2.sendBuffer(); // 将内存数据传输到显示器
}
/***===================================================***/
/***-------------------------菜单相关数据初始化--------------------------***/
void cd_init (void)
{
u8g2.begin(); //U8G2初始化
u8g2.setFont(u8g2_font_6x13_mr); // 设置字体
CD_ChangDu = sizeof(LieBiao) / sizeof(CD_LIEBIAO); //计算菜单列表的成员数量
str_h = u8g2.getAscent() - u8g2.getDescent() + 1; // 获取字体高度(基准线以上-基准线以下)
str_w = u8g2.getUTF8Width(LieBiao[0].str); // 获取字符串的像素宽度
frame_y = frame_y_trg = y + 1 - str_h; //初始化方框的y坐标
frame_len = frame_len_trg = str_w + 4; //初始化方框的宽度
}
/***===================================================***/
void setup(void)
{
pinMode(buttun_1, INPUT_PULLUP);
pinMode(buttun_2, INPUT_PULLUP);
key_init(); //按钮初始化
cd_init(); //菜单初始化
Serial.begin(115200);
}
void loop(void)
{
key_scan();
ui_proc();
}