#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); //这是比较常用的0.9寸的OLED显示器的驱动
typedef struct
{
char *str; // 字符串
int len; // 用于设置选择框的长度
}Ui_list_t;
// 按键值结构体
typedef struct
{
byte val;
byte last_val;
}KEY_T;
// 按键属性
typedef struct
{
byte id;
byte press; // 按键按下标志
byte update_flag; // 按键更新标志
byte res;
}KEY_MSG;
Ui_list_t list[] =
{
{"test1",7},
{"test251",9},
{"4tet", 6},
{"tet4", 6}
};
KEY_T key[3] = {0};
KEY_MSG key_msg = {0};
int16_t x ,x_trg ;
int16_t y = 10, y_trg = 10;
int16_t menu_x, menu_x_trg;
int16_t menu_y = 40, menu_y_trg = 40;
int16_t frame_len = 5, frame_len_trg = 5; // 选择框的宽度
int16_t frame_y = 0, frame_y_trg = 0; // 选择框的高度
int16_t ui_select_index = 0; // 选择索引
int list_len = sizeof(list) / sizeof(Ui_list_t); // 选择页面数量
uint8_t single_line_length=63/list_len;
uint8_t total_line_length=single_line_length*list_len+1;
int16_t line_y,line_y_trg;//线的位置
uint8_t box_width,box_width_trg;//框的宽度
int16_t box_y,box_y_trg;//框的当前值和目标值
/* res为当前值 , res_trg为目标值, step为步长 */
int ui_run(int16_t *res, int16_t *res_trg, int16_t step)
{
if (*res < *res_trg)
{
*res += step;
if (*res > *res_trg) *res = *res_trg; // 加完溢出
}
else if (*res > *res_trg)
{
*res -= step;
if (*res < *res_trg) *res = *res_trg; // 减完溢出
}
else
{
return 0;
}
return 1;
}
/* 按键读取函数 */
bool button_read(uint8_t ch)
{
if(ch == 0)
{
return digitalRead(2);
}
if (ch == 1)
{
return digitalRead(3);
}
if (ch == 2)
{
return digitalRead(4);
}
}
/* 按键初始化函数 */
void button_init(void)
{
/* 按键初始化 */
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
/* 按键赋初值 */
for (uint8_t i=0; i < 3; i++)
{
key[i].val = key[i].last_val = button_read(i);
}
}
/* 按键处理函数 */
void button_scan(void)
{
for(uint8_t i = 0;i<3;i++)
{
key[i].val = button_read(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; // 将按下标志位置1
key_msg.update_flag = 1; // 将更新标志位置1
Serial.println(key_msg.id);
}
}
}
}
/* 进度条移动函数 */
bool move_bar(int8_t *a, int8_t* a_trg)
{
if (*a < *a_trg)
{
uint8_t step=16/4;//判断步数
uint8_t width_speed=((single_line_length%step)==0?(single_line_length/step):(single_line_length/step+1)); //计算步长
*a+=width_speed;
if (*a>*a_trg) *a=*a_trg; // 溢出时
}
else if(*a>*a_trg)
{
uint8_t step=16/4;//判断步数
uint8_t width_speed=((single_line_length%step)==0?(single_line_length/step):(single_line_length/step+1)); //计算步长
*a-=width_speed;
if (*a < *a_trg) *a = *a_trg; // 溢出时
}
else
{
return true;//到达目标
}
return false;//未到达
}
/* 选择框UI绘制 */
void select_ui_show(void)
{
u8g2.setDrawColor(2); // 异或,颜色反转
u8g2.drawRBox(x,frame_y,frame_len,12,1); // 绘制选择框
u8g2.setDrawColor(1); // 异或,颜色恢复
ui_run(&frame_y, &frame_y_trg, 2); // y轴移动
ui_run(&frame_len, &frame_len_trg, 10); // x轴移动
}
int8_t max_bar; // 进度条最底部位置
/* 进度条绘制测试 */
void select_test_ui_show(void)
{
u8g2.drawVLine(126,0,total_line_length); // 长竖线
u8g2.drawPixel(125,0); // 进度条最上面的小横线
u8g2.drawPixel(127,0);
for(uint8_t i=0;i<list_len;++i)
{
// u8g2.drawStr(x,16*i+y+12,list[i].str); // 第一段输出位置
u8g2.drawPixel(125,single_line_length*(i+1)); // 分段小横线
u8g2.drawPixel(127,single_line_length*(i+1));
max_bar = single_line_length*(i+1); // 进度条最底部位置
}
u8g2.drawVLine(125,line_y,single_line_length-1); // 进度条小框(左上角坐标x,左上角坐标y, 高度)
u8g2.drawVLine(127,line_y,single_line_length-1);
ui_run(&line_y,&line_y_trg,3); // 进度条移动
}
/* 菜单页UI绘制 */
void menu_ui_show(void)
{
// u8g2.clearBuffer(); // 清除缓存
for (int i = 0; i < 3; i++ )
{
u8g2.drawStr(menu_x+50+i*90, menu_y, "test");
}
ui_run(&menu_x, &menu_x_trg,10); // ui移动
ui_run(&menu_y, &menu_y_trg,5); // ui移动
// u8g2.sendBuffer(); // 将缓存发送并显示
}
/* ui显示函数 */
void Ui_show(void)
{
u8g2.clearBuffer(); // 清除缓存
for (int i = 0; i < list_len; i++ )
{
u8g2.drawStr(x+5, y+i*10, list[i].str);
}
select_ui_show(); // 选择框UI绘制
select_test_ui_show();
// ui_run(&y, &y_trg,10);
u8g2.sendBuffer(); // 将缓存发送并显示
}
/* ui处理函数 */
void ui_proc(void)
{
// int list_len = sizeof(list) / sizeof(Ui_list_t); // 选项列表的个数
if(key_msg.update_flag && key_msg.press) // 当更新标志位和按下标志位都为1
{
key_msg.update_flag = 0;
if(key_msg.id == 1)
{
// y_trg += 10;
// Serial.println("y_trg:");
// Serial.println(y_trg);
ui_select_index ++;
/* 防溢出 */
if( line_y_trg < (max_bar - single_line_length - 1))
{
line_y_trg+=single_line_length;
}
if (ui_select_index >= list_len)
{
ui_select_index = list_len - 1;
}
Serial.println("line_y_trg:");
Serial.println(line_y_trg);
}
else
{
// y_trg -= 10;
// Serial.println("y_trg:");
// Serial.println(y_trg);
ui_select_index --;
/* 防溢出 */
if( line_y_trg > single_line_length -2)
{
line_y_trg-=single_line_length;
}
if (ui_select_index <= 0)
{
ui_select_index = 0;
}
Serial.println("line_y_trg:");
Serial.println(line_y_trg);
// /* 防止溢出 */
// if(y_trg < 10 )
// {
// y_trg = 10;
// }
}
}
frame_y_trg = ui_select_index * 10;
frame_len_trg = list[ui_select_index].len *5;
Ui_show();
}
void setup(void)
{
Serial.begin(115200);
button_init(); // 按键初始化函数
u8g2.begin();
u8g2.setFont(u8g2_font_ncenB08_tr); // 设置字体
}
void loop(void)
{
button_scan(); // 按键处理函数
ui_proc(); // ui 处理函数
}