统计
  • 建站日期:2021-03-10
  • 文章总数:3772 篇
  • 评论总数:29 条
  • 分类总数:43 个
  • 最后更新:5月19日
文章 未分类

简化版智能手表怎么用 (简化版智能手表 基于STM32的OLED多级菜单GUI成功)

小菜鸡
首页 未分类 正文

前言,本文的OLED多级菜单UI为一个综合性的STM32小名目,经常使用多传感器与OLED显示屏成功智能终端的成果,名目中的多级菜单UI经常使用了较为经常出现的结构体索引法去成功性能与性能之间的来回切换,搭配DHT11,RTC,LED,KEY等器件成功高度智能化一体化操作,前期自己打板设计结构,可以衍生为智能手表等小玩意,目前,名目属...。

简化版智能手表怎么用(简化版智能手表基于STM32的OLED多级菜单GUI成功)
-IT菜鸡教程网-IT技术博客
-第1
张图片

前言: 本文的 OLED多级菜单UI 为一个 综合性 的STM32 小名目 ,经常使用 多传感器OLED显示屏 成功 智能终端 的成果。名目中的多级菜单UI经常使用了较为经常出现的 结构体索引法 去成功性能与性能之间的来回切换,搭配 DHT11,RTC,LED,KEY 等器件成功高度智能化一体化操作。前期自己打板设计结构,可以衍生为 智能手表 等小玩意。目前,名目属于 裸机形态CPU占用率100% ),前期或许会加上 RTOS系统 。( 本名目源码在本文末尾启动开源!

配件实物图:


简化版智能手表怎么用(简化版智能手表基于STM32的OLED多级菜单GUI成功)
-IT菜鸡教程网-IT技术博客
-第2
张图片 成果图:

温度计:

游戏机:

引脚衔接:

一、多级菜单

随着工业化和智能化的开展,如今基本上一切名目都离不开 显示终端 。而 多级菜单 更是终端显示名目中必无法少的组成起因,其实 TFT-LCD屏幕 上可以自创移植很多 低劣的开源多级菜单GUI,比如:LVGL ),而 0.96寸的OLED屏幕 上通常须要自己去适配和编程多级菜单。

精巧的多级菜单:

网上的广泛驳回的多级菜单的计划是 基于索引 或许 结构树 ,其中, 索引法居多索引法的好处 :可阅读性好,拓展性也不错,查找的性能差不多是最优,就是有点 占用内存空间

二、索引法多级菜单成功

网上关于索引法成功多级菜单性能有很多基础教程,笔者就依照 本名目 中的详细实现代码环节给大家解说一下 索引法成功多级菜单特意说明: 本名目间接经常使用了误点原子的精英板作为外围板,所以读者好友复现代码还是很繁难的。

首先,基于 索引法成功多级菜单首要条件 是先确定名目中将经常使用到 几特性能按键比如:向前,向后,确定,分开等等 )本名目中,笔者经常使用到了 3个按键下一个(next)确定(enter)分开(back) 。所以,接下首先定义一个 结构体 ,结构体中一共有 5个变量3 + 2 ),区分为: 以后索引序号(current)向下一个(next)确定(enter)分开(back)以后口头函数(void) 。其中,标红的为须要设计的按键(笔者这里有3个),标绿的则为固定的 索引号该索引下须要口头的函数

typedef struct
{u8 current;        //以后形态索引号u8 next;       //向下一个u8 enter;         //确定u8 back;        //分开void (*current_operation)(void); //以后形态应该口头的操作
} Menu_table;

接上去就是 定义一个数组 去选择整个名目菜单的 逻辑顺序应用索引号

Menu_table  table[30]=
{{0,0,1,0,(*home)}, //一级界面(主页面) 索引,向下一个,确定,分开{1,2,5,0,(*Temperature)},  //二级界面 温湿度{2,3,6,0,(*Palygame)},    //二级界面 游戏{3,4,7,0,(*Setting)},  //二级界面 设置{4,1,8,0,(*Info)}, //二级界面 消息{5,5,5,1,(*TestTemperature)},      //三级界面:DHT11测量温湿度{6,6,6,2,(*ControlGame)},              //三级界面:谷歌小恐龙Dinogame{7,7,9,3,(*Set)},                               //三级界面:设置普通外设形态 LED{8,8,8,4,(*Information)},                //三级界面:作者和关系名目消息{9,9,7,3,(*LED)},       //LED管理
};

这里解释一下这个数组中各元素的意义,因为咱们在前面先定义了 Menu_table 结构体 , 结构体成员变量 区分与 数组中元素 对应。比如: {0,0,1,0,(*home)} ,代表了 索引号为0 按向下键(next) 转入索引号为0, 按确定键(enter) 转入索引号为1, 按分开键(back) 转入索引号为0,索引号为0时 口头home函数

在举一个例子协助大家了解一下,比如,咱们以后程序处在 索引号为2(游戏界面) ,就会口头 Playgame函数 。此时,假设按下 next按键 ,程序以后索引号就会变为3,并且口头索引号为3时刻的 Setting函数 。假设按下 enter按键 ,程序以后索引号就会变为6,并且口头索引号为6时刻的 ControlGame函数 。假设按下 back按键 ,程序以后索引号就会变为0,并且口头索引号为0时刻的 home函数

再接下就是 按键解决函数

uint8_t  func_index = 0;    //主程序此时所在程序的索引值void  Menu_key_set(void)
{if((KEY_Scan(1) == 1) && (func_index != 6))        //屏蔽掉索引6下的状况,适配游戏{ func_index=table[func_index].next;   //按键next按下后的索引号OLED_Clear(); }if((KEY_Scan(1) == 2) && (func_index != 6)){func_index=table[func_index].enter;   //按键enter按下后的索引号OLED_Clear();}if(KEY_Scan(1) == 3){func_index=table[func_index].back;   //按键back按下后的索引号OLED_Clear(); }current_operation_index=table[func_index].current_operation;  //口头以后索引号所对应的性能函数(*current_operation_index)();//口头以后操作函数
}//按键函数
u8 KEY_Scan(u8 mode)
{static u8 key_up=1;if(mode)key_up=1; if(key_up&&(KEY0==0||KEY1==0||WK_UP==1)){HAL_Delay(100);      //消抖key_up=0;if(KEY0==0)return 1;else if(KEY1==0)return 2;else if(WK_UP==1)return 3;}else if(KEY0==1&&KEY1==1&&WK_UP==0)key_up=1; return 0;
}

说明2点:

(1) 因为是目前本名目是 裸机形态 下运转的,所以 CPU占用率自动是100% 的,所以这里经常使用按键 允许连按 时,关于菜单的切换更好些。

(2) 或许部分索引号下的口头函数,须要经常使用到曾经定义的3个按键(比如,本名目中的DInogame中)。所以,可以 在须要差异化的索引号下去屏蔽原先的按键性能 。如下:

  if((KEY_Scan(1) == 1) && (func_index != 6))        //屏蔽掉索引6下的状况,适配游戏{ func_index=table[func_index].next;  //按键next按下后的索引号OLED_Clear(); }if((KEY_Scan(1) == 2) && (func_index != 6))        //屏蔽掉索引6下的状况,适配游戏{func_index=table[func_index].enter;  //按键enter按下后的索引号OLED_Clear();}

(3) 笔者这里是经常使用 全屏刷新 去切换性能界面,同时,没有启用初级算法去减速显示,所以或许在切换界面的时刻成果普通。读者好友可以试试依据自己的UI状况经常使用 部分刷新 ,这样或许名目会愈加丝滑一点。

本名目中的菜单索引图:

三、此名目外部性能成功(简化智能手表)

3.1 OLED显示

OLED就是反常的驱动与显示,有才干的读者好友可以经常使用初级算法去减速OLED屏幕的刷新率,可以使自己的多级菜单切换起来更丝滑。假设对OLED驱动与显示不太相熟的好友可以去看看自己另一篇博客:【剧烈介绍】基于stm32的OLED各种显示成功(含灵活图)_混分巨兽龙某某的博客-CSDN博客_stm32oled显示

惟一须要留意的点就是须要去制造 菜单外面的UI图标 (注用意片大小能否适宜):

假设是 黑色图片 的话,可以间接经常使用 PCtoLCD2002完美版 启动取模:

3.2 KEY按键

KEY按键 留意消抖(倡导裸机状况下允许延续按动) ,同时留意自己实践配件状况去启动编程( 电阻能否存在上拉或许下拉 )。

3.3 DinoGame成功

谷歌公司最近比拟盛行的小游戏,笔者之前有文章启动了STM32的成功复刻。博客地址:基于STM32的小游戏——谷歌小恐龙(Chrome Dino Game)_混分巨兽龙某某的博客-CSDN博客_谷歌恐龙

3.4 LED管理和DHT11模块

LED和DHT11模块 其实都属于 外设管理 ,这里读者好友可以依据自己的实践状况去取舍。须要留意的是尽或许适配一下自己多级菜单( 外设管理也须要留意一下按键布置,可以参考笔者名目的设计 )。

四、CubeMX性能

1、RCC性能外部高速晶振(精度更高)——HSE;

2、SYS性能:Debug设置成Serial Wire否则或许造成芯片自锁 );

3、I2C2性能:这里不间接经常使用CubeMX的I2C2,经常使用GPIO模拟(PB10:CLK;PB11:SDA)

4、RTC性能:年月日,时分秒;

5、TIM2性能:由下面可知DHT11的经常使用须要us级的提前函数,HAL库自带只要ms的,所以须要自己设计一个定时器;

6、KEY按键性能:PE3,PE4和PA0设置为端口输入(开发板原理图)

7、时钟树性能:

8、文件性能

五、代码

5.1 OLED驱动代码

此部分OLED的基本驱动函数,笔者经常使用的是 I2C驱动的0.96寸OLED屏幕 。所以,首先须要经常使用 GPIO模拟I2C通讯 。随后,经常使用I2C通讯去驱动OLED。(此部分代码蕴含了屏幕驱动与基础显示,假设对OLED显示不太了解的好友可以去看看上文提到的笔者的另一篇文章)

oled.h:

#ifndef __OLED_H
#define __OLED_H#include "main.h"#define u8 uint8_t
#define u32 uint32_t#define OLED_CMD  0 //写命令
#define OLED_DATA 1 //写数据#define OLED0561_ADD   0x78  // OLED I2C地址
#define COM             0x00  // OLED 
#define DAT             0x40  // OLED #define OLED_MODE 0
#define SIZE 8
#define XLevelL     0x00
#define XLevelH     0x10
#define Max_Column  128
#define Max_Row     64
#define Brightness  0xFF
#define X_WIDTH     128
#define Y_WIDTH     64//-----------------OLED IIC GPIO启动模拟----------------#define OLED_SCLK_Clr() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET) //GPIO_ResetBits(GPIOB,GPIO_Pin_10)//SCL
#define OLED_SCLK_Set() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET) //GPIO_SetBits(GPIOB,GPIO_Pin_10)#define OLED_SDIN_Clr() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET) // GPIO_ResetBits(GPIOB,GPIO_Pin_11)//SDA
#define OLED_SDIN_Set() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET) // GPIO_SetBits(GPIOB,GPIO_Pin_11)//I2C GPIO模拟
void IIC_Start();
void IIC_Stop();
void IIC_WaitAck();
void IIC_WriteByte(unsigned char IIC_Byte);
void IIC_WriteCommand(unsigned char IIC_Command);
void IIC_WriteData(unsigned char IIC_Data);
void OLED_WR_Byte(unsigned dat,unsigned cmd);//性能函数
void OLED_Init(void);
void OLED_WR_Byte(unsigned dat,unsigned cmd);void OLED_FillPicture(unsigned char fill_Data);
void OLED_SetPos(unsigned char x, unsigned char y);
void OLED_DisplayOn(void);
void OLED_DisplayOff(void);
void OLED_Clear(void);
void OLED_On(void);
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size);
u32 oled_pow(u8 m,u8 n);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2);
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size);#endif

oled.c:

#include "oled.h"
#include "asc.h"    //字库(可以自己制造)
#include "main.h"/********************GPIO 模拟I2C*******************/
//留意:这里没有间接经常使用HAL库中的模拟I2C
/**********************************************
//IIC Start
**********************************************/
void IIC_Start()
{OLED_SCLK_Set() ;OLED_SDIN_Set();OLED_SDIN_Clr();OLED_SCLK_Clr();
}/**********************************************
//IIC Stop
**********************************************/
void IIC_Stop()
{OLED_SCLK_Set() ;OLED_SDIN_Clr();OLED_SDIN_Set();}void IIC_WaitAck()
{OLED_SCLK_Set() ;OLED_SCLK_Clr();
}
/**********************************************
// IIC Write byte
**********************************************/void IIC_WriteByte(unsigned char IIC_Byte)
{unsigned char i;unsigned char m,da;da=IIC_Byte;OLED_SCLK_Clr();for(i=0;i<8;i++){m=da;//    OLED_SCLK_Clr();m=m&0x80;if(m==0x80){OLED_SDIN_Set();}else OLED_SDIN_Clr();da=da<<1;OLED_SCLK_Set();OLED_SCLK_Clr();}}
/**********************************************
// IIC Write Command
**********************************************/
void IIC_WriteCommand(unsigned char IIC_Command)
{IIC_Start();IIC_WriteByte(0x78);            //Slave address,SA0=0IIC_WaitAck();IIC_WriteByte(0x00);            //write commandIIC_WaitAck();IIC_WriteByte(IIC_Command);IIC_WaitAck();IIC_Stop();
}
/**********************************************
// IIC Write><strong>外围部分之</strong>一,任何一个游戏都是须要去<strong>绘制</strong>和<strong>构建</strong><strong>游戏的图形以及模型的</strong>。好的游戏往往都具有很好的<strong>游戏模型</strong>和<strong>精巧UI</strong>,很多3A大作都具有这样的特性。 
<p class="quietlee_f4b9e_c30ad"><strong>dinogame.h:</strong></p> 
#ifndef __DINOGAME_H
#define __DINOGAME_Hvoid OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[]);
void OLED_DrawBMPFast(const unsigned char BMP[]);
void oled_drawbmp_block_clear(int bx, int by, int clear_size);
void OLED_DrawGround();
void OLED_DrawCloud();
void OLED_DrawDino();
void OLED_DrawCactus();
int OLED_DrawCactusRandom(unsigned char ver, unsigned char reset);
int OLED_DrawDinoJump(char reset);
void OLED_DrawRestart();
void OLED_DrawCover();#endif 
<p class="quietlee_26657_d5ff9"><strong>dinogame.c代码:</strong></p> 
#include "oled.h"
#include "oledfont.h"
#include "stdlib.h"/***********性能形容:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
{unsigned int j=0;unsigned char x,y;if(y1%8==0) y=y1/8;else y=y1/8+1;for(y=y0;y<y1;y++){OLED_SetPos(x0,y);for(x=x0;x<x1;x++){OLED_WR_Byte(BMP[j++],OLED_DATA);}}
}// 极速绘制图像
void OLED_DrawBMPFast(const unsigned char BMP[])
{unsigned int j = 0;unsigned char x, y;for (y = 0; y < 8; y++){OLED_SetPos(0, y);IIC_Start();IIC_WriteByte(0x78);IIC_WaitAck();IIC_WriteByte(0x40);IIC_WaitAck();for (x = 0; x < 128; x++){IIC_WriteByte(BMP[j++]);IIC_WaitAck();}IIC_Stop();}
}void oled_drawbmp_block_clear(int bx, int by, int clear_size)
{unsigned int i;OLED_SetPos(bx, by);IIC_Start();IIC_WriteByte(0x78);IIC_WaitAck();IIC_WriteByte(0x40);IIC_WaitAck();for (i = 0; i < clear_size; i++){if (bx + i>128) break;IIC_WriteByte(0x0);IIC_WaitAck();}IIC_Stop();
}void OLED_DrawGround()
{static unsigned int pos = 0;unsigned char speed = 5;unsigned int ground_length = sizeof(GROUND);unsigned char x;OLED_SetPos(0, 7);IIC_Start();IIC_WriteByte(0x78);IIC_WaitAck();IIC_WriteByte(0x40);IIC_WaitAck();for (x = 0; x < 128; x++){IIC_WriteByte(GROUND[(x+pos)%ground_length]);IIC_WaitAck();}IIC_Stop();pos = pos + speed;//if(pos>ground_length) pos=0;
}// 绘制云朵
void OLED_DrawCloud()
{static int pos = 128;static char height=0;char speed = 3;unsigned int i=0;int x;int start_x = 0;int length = sizeof(CLOUD);unsigned char byte;//if (pos + length <= -speed) pos = 128;if (pos + length <= -speed){pos = 128;height = rand()%3;}if(pos < 0){start_x = -pos;OLED_SetPos(0, 1+height);}else{OLED_SetPos(pos, 1+height);}IIC_Start();IIC_WriteByte(0x78);IIC_WaitAck();IIC_WriteByte(0x40);IIC_WaitAck();for (x = start_x; x < length + speed; x++){if (pos + x > 127) break;if (x < length) byte = CLOUD[x];else byte = 0x0;IIC_WriteByte(byte);IIC_WaitAck();}IIC_Stop();pos = pos - speed;
}// 绘制小恐龙
void OLED_DrawDino()
{static unsigned char dino_dir = 0;unsigned int j=0;unsigned char x, y;unsigned char byte;dino_dir++;dino_dir = dino_dir%2;for(y=0; y<2; y++){OLED_SetPos(16, 6+y);IIC_Start();IIC_WriteByte(0x78);IIC_WaitAck();IIC_WriteByte(0x40);IIC_WaitAck();for (x = 0; x < 16; x++){j = y*16 + x;byte = DINO[dino_dir][j];IIC_WriteByte(byte);IIC_WaitAck();}IIC_Stop();}
}// 绘制仙人掌阻碍物
void OLED_DrawCactus()
{char speed = 5;static int pos = 128;int start_x = 0;int length = sizeof(CACTUS_2)/2;unsigned int j=0;unsigned char x, y;unsigned char byte;if (pos + length <= 0){oled_drawbmp_block_clear(0, 6, speed);pos = 128;}for(y=0; y<2; y++){if(pos < 0){start_x = -pos;OLED_SetPos(0, 6+y);}else{OLED_SetPos(pos, 6+y);}IIC_Start();IIC_WriteByte(0x78);IIC_WaitAck();IIC_WriteByte(0x40);IIC_WaitAck();for (x = start_x; x < length; x++){if (pos + x > 127) break;j = y*length + x;byte = CACTUS_2[j];IIC_WriteByte(byte);IIC_WaitAck();}IIC_Stop();}oled_drawbmp_block_clear(pos + length, 6, speed); // 肃清残影pos = pos - speed;
}// 绘制随机发生的仙人掌阻碍物
int OLED_DrawCactusRandom(unsigned char ver, unsigned char reset)
{char speed = 5;static int pos = 128;int start_x = 0;int length = 0;unsigned int i=0, j=0;unsigned char x, y;unsigned char byte;if (reset == 1){pos = 128;oled_drawbmp_block_clear(0, 6, speed);return 128;}if (ver == 0) length = 8; //sizeof(CACTUS_1) / 2;else if (ver == 1) length = 16; //sizeof(CACTUS_2) / 2;else if (ver == 2 || ver == 3) length = 24;for(y=0; y<2; y++){if(pos < 0){start_x = -pos;OLED_SetPos(0, 6+y);}else{OLED_SetPos(pos, 6+y);}IIC_Start();IIC_WriteByte(0x78);IIC_WaitAck();IIC_WriteByte(0x40);IIC_WaitAck();for (x = start_x; x < length; x++){if (pos + x > 127) break;j = y*length + x;if (ver == 0) byte = CACTUS_1[j];else if (ver == 1) byte = CACTUS_2[j];else if(ver == 2) byte = CACTUS_3[j];else byte = CACTUS_4[j];IIC_WriteByte(byte);IIC_WaitAck();}IIC_Stop();}oled_drawbmp_block_clear(pos + length, 6, speed);pos = pos - speed;return pos + speed;
}// 绘制腾跃小恐龙
int OLED_DrawDinoJump(char reset)
{char speed_arr[] = {1, 1, 3, 3, 4, 4, 5, 6, 7};static char speed_idx = sizeof(speed_arr)-1;static int height = 0;static char dir = 0;//char speed = 4;unsigned int j=0;unsigned char x, y;char offset = 0;unsigned char byte;if(reset == 1){height = 0;dir = 0;speed_idx = sizeof(speed_arr)-1;return 0;}if (dir==0){height += speed_arr[speed_idx];speed_idx --;if (speed_idx<0) speed_idx = 0;}if (dir==1){height -= speed_arr[speed_idx];speed_idx ++;if (speed_idx>sizeof(speed_arr)-1) speed_idx = sizeof(speed_arr)-1;}if(height >= 31){dir = 1;height = 31;}if(height <= 0){dir = 0;height = 0;}if(height <= 7) offset = 0;else if(height <= 15) offset = 1;else if(height <= 23) offset = 2;else if(height <= 31) offset = 3;else offset = 4;for(y=0; y<3; y++) // 4{OLED_SetPos(16, 5- offset + y);IIC_Start();IIC_WriteByte(0x78);IIC_WaitAck();IIC_WriteByte(0x40);IIC_WaitAck();for (x = 0; x < 16; x++) // 32{j = y*16 + x; // 32byte = DINO_JUMP[height%8][j];IIC_WriteByte(byte);IIC_WaitAck();}IIC_Stop();}if (dir == 0) oled_drawbmp_block_clear(16, 8- offset, 16);if (dir == 1) oled_drawbmp_block_clear(16, 4- offset, 16);return height;
}// 绘制重启
void OLED_DrawRestart()
{unsigned int j=0;unsigned char x, y;unsigned char byte;//OLED_SetPos(0, 0);for (y = 2; y < 5; y++){OLED_SetPos(52, y);IIC_Start();IIC_WriteByte(0x78);IIC_WaitAck();IIC_WriteByte(0x40);IIC_WaitAck();for (x = 0; x < 24; x++){byte = RESTART[j++];IIC_WriteByte(byte);IIC_WaitAck();}IIC_Stop();}OLED_ShowString(10, 3, "GAME", 16);OLED_ShowString(86, 3, "OVER", 16);
}
// 绘制封面
void OLED_DrawCover()
{OLED_DrawBMPFast(COVER);
} 
<h3>5.3 谷歌小恐龙的运转管理代码</h3> 
<p class="quietlee_ed3d2_c2199"><strong>control.h:</strong></p> 
#ifndef __CONTROL_H
#define __CONTROL_Hint get_key();
void Game_control();#endif 
<p class="quietlee_f8991_39df5"><strong>control.c:</strong></p> 
#include "control.h"
#include "oled.h"
#include "dinogame.h"
#include "stdlib.h"unsigned char key_num = 0;
unsigned char cactus_category = 0;
unsigned char cactus_length = 8;
unsigned int score = 0;
unsigned int highest_score = 0;
int height = 0;
int cactus_pos = 128;
unsigned char cur_speed = 30;
char failed = 0;
char reset = 0;int get_key()
{if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4)==0){HAL_Delay(10);            //提前if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4)==0){return 2;}}if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3)==0){HAL_Delay(10);            //提前if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3)==0){return 1;}}if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)==1){HAL_Delay(10);            //提前if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)==1){return 3;}}return 0;
}void Game_control()
{while(1){if(get_key() == 3)        //wk_up按键按下强迫分开一次性循环{break;}if (failed == 1){OLED_DrawRestart();key_num = get_key();if (key_num == 2){if(score > highest_score) highest_score = score;score = 0;failed = 0;height = 0;reset = 1;OLED_DrawDinoJump(reset);OLED_DrawCactusRandom(cactus_category, reset);OLED_Clear();}continue;}score ++;if (height <= 0) key_num = get_key();OLED_DrawGround();OLED_DrawCloud();if (height>0 || key_num == 1) height = OLED_DrawDinoJump(reset);else OLED_DrawDino();cactus_pos = OLED_DrawCactusRandom(cactus_category, reset);if(cactus_category == 0) cactus_length = 8;else if(cactus_category == 1) cactus_length = 16;else cactus_length = 24;if (cactus_pos + cactus_length < 0){cactus_category = rand()%4;OLED_DrawCactusRandom(cactus_category, 1);}if ((height < 16) && ( (cactus_pos>=16 && cactus_pos <=32) || (cactus_pos + cactus_length>=16 && cactus_pos + cactus_length <=32))){failed = 1;}OLED_ShowString(35, 0, "HI:", 12);OLED_ShowNum(58, 0, highest_score, 5, 12);OLED_ShowNum(98, 0, score, 5, 12);reset = 0;cur_speed = score/20;if (cur_speed > 29) cur_speed = 29;HAL_Delay(30 - cur_speed);
//      HAL_Delay(500);key_num = 0;}} 
<h3>5.4 多级菜单外围代码:</h3> 
<p class="quietlee_ec895_6637a"><strong>menu.h:</strong></p> 
#ifndef __MENU_H
#define __MENU_H#include "main.h"
#define  u8 unsigned char//按键定义
#define KEY0 HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4)        //低电平有效     KEY0
#define KEY1 HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3)        //低电平有效
#define WK_UP HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)       //高电平有效typedef struct
{u8 current;    //以后形态索引号u8 next;       //向下一个u8 enter;     //确定u8 back;        //分开void (*current_operation)(void); //以后形态应该口头的操作
} Menu_table;//界面UI
void home();
void Temperature();
void Palygame();
void Setting();
void Info();void  Menu_key_set(void);
u8 KEY_Scan(u8 mode);void TestTemperature();
void ConrtolGame();
void Set();
void Information();void LED();
void RTC_display();#endif

<p class="quietlee_c9e10_74f5b"><strong>menu.c:</strong></p> 
#include "menu.h"
#include "oled.h"
#include "gpio.h"
#include "dinogame.h"
#include "control.h"
#include "DHT11.h"
#include "rtc.h"RTC_DateTypeDef GetData;  //失掉日期结构体RTC_TimeTypeDef GetTime;   //失掉期间结构体//UI界面
//主页
/****************************************************/
//UI库/****************************************************/void (*current_operation_index)();    Menu_table  table[30]=
{{0,0,1,0,(*home)}, //一级界面(主页面) 索引,向下一个,确定,分开{1,2,5,0,(*Temperature)},  //二级界面 温湿度{2,3,6,0,(*Palygame)},    //二级界面 游戏{3,4,7,0,(*Setting)},  //二级界面 设置{4,1,8,0,(*Info)}, //二级界面 消息{5,5,5,1,(*TestTemperature)},      //三级界面:DHT11测量温湿度{6,6,6,2,(*ConrtolGame)},              //三级界面:谷歌小恐龙Dinogame{7,7,9,3,(*Set)},                               //三级界面:设置普通外设形态 LED{8,8,8,4,(*Information)},                //三级界面:作者和关系名目消息{9,9,7,3,(*LED)},       //LED管理
};uint8_t  func_index = 0;  //主程序此时所在程序的索引值void  Menu_key_set(void)
{if((KEY_Scan(1) == 1) && (func_index != 6)){ func_index=table[func_index].next;    //按键next按下后的索引号OLED_Clear(); }if((KEY_Scan(1) == 2) && (func_index != 6)){func_index=table[func_index].enter;   //按键enter按下后的索引号OLED_Clear();}if(KEY_Scan(1) == 3){func_index=table[func_index].back;   //按键back按下后的索引号OLED_Clear(); }current_operation_index=table[func_index].current_operation;  //口头以后索引号所对应的性能函数(*current_operation_index)();//口头以后操作函数
}void home()
{RTC_display();OLED_DrawBMP(0,0,20,3,signal_BMP);OLED_DrawBMP(20,0,36,2,gImage_bulethouch);OLED_DrawBMP(112,0,128,2,gImage_engery);OLED_DrawBMP(4,6,20,8,gImage_yes);OLED_DrawBMP(12,4,28,6,gImage_left);OLED_DrawBMP(40,2,88,8,gImage_home);OLED_DrawBMP(99,4,115,6,gImage_right);OLED_DrawBMP(107,6,123,8,gImage_back);
}void Temperature()
{RTC_display();OLED_DrawBMP(0,0,20,3,signal_BMP);OLED_DrawBMP(20,0,36,2,gImage_bulethouch);OLED_DrawBMP(112,0,128,2,gImage_engery);OLED_DrawBMP(4,6,20,8,gImage_yes);OLED_DrawBMP(12,4,28,6,gImage_left);OLED_DrawBMP(40,2,88,8,gImage_temp);OLED_DrawBMP(99,4,115,6,gImage_right);OLED_DrawBMP(107,6,123,8,gImage_back);
}void Palygame()
{RTC_display();OLED_DrawBMP(0,0,20,3,signal_BMP);OLED_DrawBMP(20,0,36,2,gImage_bulethouch);OLED_DrawBMP(112,0,128,2,gImage_engery);OLED_DrawBMP(4,6,20,8,gImage_yes);OLED_DrawBMP(12,4,28,6,gImage_left);OLED_DrawBMP(40,2,88,8,gImage_playgame);OLED_DrawBMP(99,4,115,6,gImage_right);OLED_DrawBMP(107,6,123,8,gImage_back);
}void Setting()
{RTC_display();OLED_DrawBMP(0,0,20,3,signal_BMP);OLED_DrawBMP(20,0,36,2,gImage_bulethouch);OLED_DrawBMP(112,0,128,2,gImage_engery);OLED_DrawBMP(4,6,20,8,gImage_yes);OLED_DrawBMP(12,4,28,6,gImage_left);OLED_DrawBMP(40,2,88,8,gImage_setting);OLED_DrawBMP(99,4,115,6,gImage_right);OLED_DrawBMP(107,6,123,8,gImage_back);
}void Info()
{RTC_display();OLED_DrawBMP(0,0,20,3,signal_BMP);OLED_DrawBMP(20,0,36,2,gImage_bulethouch);OLED_DrawBMP(112,0,128,2,gImage_engery);OLED_DrawBMP(4,6,20,8,gImage_yes);OLED_DrawBMP(12,4,28,6,gImage_left);OLED_DrawBMP(40,2,88,8,gImage_info);OLED_DrawBMP(99,4,115,6,gImage_right);OLED_DrawBMP(107,6,123,8,gImage_back);
}//按键函数,不允许连按
u8 KEY_Scan(u8 mode)
{static u8 key_up=1;if(mode)key_up=1; if(key_up&&(KEY0==0||KEY1==0||WK_UP==1)){HAL_Delay(100);      //消抖key_up=0;if(KEY0==0)return 1;else if(KEY1==0)return 2;else if(WK_UP==1)return 3;}else if(KEY0==1&&KEY1==1&&WK_UP==0)key_up=1; return 0;
}void TestTemperature()
{DHT11();
}void ConrtolGame()
{Game_control();
}void Set()
{OLED_ShowString(0,0,"Peripherals: Lights",16);OLED_ShowString(0,2,"Status: Closed",16);HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
}void Information()
{OLED_ShowString(0,0,"Author:Sneak",16);OLED_ShowString(0,2,"Date:2022/8/23",16);OLED_ShowString(0,4,"Lab: Multi-level menu",16);
}void LED()
{OLED_ShowString(0,0,"Peripherals: Lights",16);OLED_ShowString(0,2,"Status: Open",16);HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
}void RTC_display()             //RTC????
{/* Get the RTC current Time */HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);/* Get the RTC current Date */HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN);/* Display date Format : yy/mm/dd *//* Display time Format : hh:mm:ss */OLED_ShowNum(40,0,GetTime.Hours,2,16);               //hourOLED_ShowString(57,0,":",16); OLED_ShowNum(66,0,GetTime.Minutes,2,16);            //minOLED_ShowString(83,0,":",16);  OLED_ShowNum(93,0,GetTime.Seconds,2,16);            //seconds
} 
<h2>六、名目展示</h2> 
 <p class="quietlee_a97da_629b0">多级菜单(简化版智能手表)</p> 

<h2>总结与代码开源</h2> 
<p class="quietlee_a3c65_c2974"><strong>        总结:</strong>本名目目前还处于<strong>最后辈版本</strong>,十分繁难,前期笔者将抽期间去精进优化该多级菜单名目。其中,UI界面中的<strong>电池与信号</strong>目前都还处于<strong>贴图形态</strong>,前期笔者会加上<strong>库仑计测量电池</strong>电量等。文章中指出了须要留意的中央与可以改良的点,感兴味的好友可以彼此交换交换。(<strong>积分够的好友可以允许一下,假设不够的话,点个关注,评论区留下邮箱,笔者看到会尽快发送名目代码。</strong>)</p> 
<p class="quietlee_2723d_092b6"><strong>代码地址:</strong>基于STM32的OLED多级菜单名目(简化版智能手表)-嵌入式文档类资源-CSDN文库</p>

版权说明
文章采用: 《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权。
客服邮箱:kefu@itcaiji.cn
版权声明:未标注转载均为本站原创,转载时请以链接形式注明文章出处。如有侵权、不妥之处,请联系站长删除。敬请谅解!

-- 展开阅读全文 --
cwindowssystem32config不可用 (C#WindowsForm罕用窗体工具)
« 上一篇
python课程 网课推荐 (Python 你好2024! 2024新年烟花代码第二part)
下一篇 »
为了防止灌水评论,登录后即可评论!

热门文章

1
2
什么是高防CDN
4
推特计划推出点对点支付功能
5
p5.js 3D图形-立方体

标签