[应用相关] 基于STM32的OLED多级菜单GUI实现(简化版智能手表)

[复制链接]
4674|82
 楼主| 鱿鱼丝 发表于 2023-3-27 11:06 | 显示全部楼层
 楼主| 鱿鱼丝 发表于 2023-3-27 11:07 | 显示全部楼层
 楼主| 鱿鱼丝 发表于 2023-3-27 11:07 | 显示全部楼层
4、RTC配置:年月日,时分秒;
 楼主| 鱿鱼丝 发表于 2023-3-27 11:07 | 显示全部楼层
 楼主| 鱿鱼丝 发表于 2023-3-27 11:07 | 显示全部楼层
 楼主| 鱿鱼丝 发表于 2023-3-27 11:08 | 显示全部楼层
5、TIM2配置:由上面可知DHT11的使用需要us级的延迟函数,HAL库自带只有ms的,所以需要自己设计一个定时器;

642416421089950e33.png
 楼主| 鱿鱼丝 发表于 2023-3-27 11:20 | 显示全部楼层
6、KEY按键配置:PE3,PE4和PA0设置为端口输入(开发板原理图)
 楼主| 鱿鱼丝 发表于 2023-3-27 11:20 | 显示全部楼层
 楼主| 鱿鱼丝 发表于 2023-3-27 11:20 | 显示全部楼层
7、时钟树配置:

9165564210b932fb1d.png
 楼主| 鱿鱼丝 发表于 2023-3-27 11:21 | 显示全部楼层
8、文件配置
1687764210ba3cbc37.png
 楼主| 鱿鱼丝 发表于 2023-3-27 11:21 | 显示全部楼层
五、代码
5.1 OLED驱动代码

        此部分OLED的基本驱动函数,笔者使用的是I2C驱动的0.96寸OLED屏幕。所以,首先需要使用GPIO模拟I2C通讯。随后,使用I2C通讯去驱动OLED。此部分代码包含了屏幕驱动与基础显示
 楼主| 鱿鱼丝 发表于 2023-3-27 11:22 | 显示全部楼层
oled.h:
  1. #ifndef __OLED_H
  2. #define __OLED_H

  3. #include "main.h"

  4. #define u8 uint8_t
  5. #define u32 uint32_t

  6. #define OLED_CMD  0        //写命令
  7. #define OLED_DATA 1        //写数据

  8. #define OLED0561_ADD        0x78  // OLED I2C地址
  9. #define COM                                0x00  // OLED
  10. #define DAT                         0x40  // OLED

  11. #define OLED_MODE 0
  12. #define SIZE 8
  13. #define XLevelL                0x00
  14. #define XLevelH                0x10
  15. #define Max_Column        128
  16. #define Max_Row                64
  17. #define        Brightness        0xFF
  18. #define X_WIDTH         128
  19. #define Y_WIDTH         64


  20. //-----------------OLED IIC GPIO进行模拟----------------

  21. #define OLED_SCLK_Clr() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET) //GPIO_ResetBits(GPIOB,GPIO_Pin_10)//SCL
  22. #define OLED_SCLK_Set() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET) //GPIO_SetBits(GPIOB,GPIO_Pin_10)

  23. #define OLED_SDIN_Clr() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET) // GPIO_ResetBits(GPIOB,GPIO_Pin_11)//SDA
  24. #define OLED_SDIN_Set() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET) // GPIO_SetBits(GPIOB,GPIO_Pin_11)


  25. //I2C GPIO模拟
  26. void IIC_Start();
  27. void IIC_Stop();
  28. void IIC_WaitAck();
  29. void IIC_WriteByte(unsigned char IIC_Byte);
  30. void IIC_WriteCommand(unsigned char IIC_Command);
  31. void IIC_WriteData(unsigned char IIC_Data);
  32. void OLED_WR_Byte(unsigned dat,unsigned cmd);


  33. //功能函数
  34. void OLED_Init(void);
  35. void OLED_WR_Byte(unsigned dat,unsigned cmd);

  36. void OLED_FillPicture(unsigned char fill_Data);
  37. void OLED_SetPos(unsigned char x, unsigned char y);
  38. void OLED_DisplayOn(void);
  39. void OLED_DisplayOff(void);
  40. void OLED_Clear(void);
  41. void OLED_On(void);
  42. void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size);
  43. u32 oled_pow(u8 m,u8 n);
  44. void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2);
  45. void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size);

  46. #endif
 楼主| 鱿鱼丝 发表于 2023-3-27 11:22 | 显示全部楼层
oled.c:
  1. #include "oled.h"
  2. #include "asc.h"    //字库(可以自己制作)
  3. #include "main.h"



  4. /********************GPIO 模拟I2C*******************/
  5. //注意:这里没有直接使用HAL库中的模拟I2C
  6. /**********************************************
  7. //IIC Start
  8. **********************************************/
  9. void IIC_Start()
  10. {

  11.         OLED_SCLK_Set() ;
  12.         OLED_SDIN_Set();
  13.         OLED_SDIN_Clr();
  14.         OLED_SCLK_Clr();
  15. }

  16. /**********************************************
  17. //IIC Stop
  18. **********************************************/
  19. void IIC_Stop()
  20. {
  21.         OLED_SCLK_Set() ;
  22.         OLED_SDIN_Clr();
  23.         OLED_SDIN_Set();

  24. }

  25. void IIC_WaitAck()
  26. {
  27.         OLED_SCLK_Set() ;
  28.         OLED_SCLK_Clr();
  29. }
  30. /**********************************************
  31. // IIC Write byte
  32. **********************************************/

  33. void IIC_WriteByte(unsigned char IIC_Byte)
  34. {
  35.         unsigned char i;
  36.         unsigned char m,da;
  37.         da=IIC_Byte;
  38.         OLED_SCLK_Clr();
  39.         for(i=0;i<8;i++)
  40.         {
  41.                         m=da;
  42.                 //        OLED_SCLK_Clr();
  43.                 m=m&0x80;
  44.                 if(m==0x80)
  45.                 {OLED_SDIN_Set();}
  46.                 else OLED_SDIN_Clr();
  47.                         da=da<<1;
  48.                 OLED_SCLK_Set();
  49.                 OLED_SCLK_Clr();
  50.         }


  51. }
  52. /**********************************************
  53. // IIC Write Command
  54. **********************************************/
  55. void IIC_WriteCommand(unsigned char IIC_Command)
  56. {
  57.    IIC_Start();
  58.    IIC_WriteByte(0x78);            //Slave address,SA0=0
  59.         IIC_WaitAck();
  60.    IIC_WriteByte(0x00);                        //write command
  61.         IIC_WaitAck();
  62.    IIC_WriteByte(IIC_Command);
  63.         IIC_WaitAck();
  64.    IIC_Stop();
  65. }
  66. /**********************************************
  67. // IIC Write Data
  68. **********************************************/
  69. void IIC_WriteData(unsigned char IIC_Data)
  70. {
  71.    IIC_Start();
  72.    IIC_WriteByte(0x78);                        //D/C#=0; R/W#=0
  73.         IIC_WaitAck();
  74.    IIC_WriteByte(0x40);                        //write data
  75.         IIC_WaitAck();
  76.    IIC_WriteByte(IIC_Data);
  77.         IIC_WaitAck();
  78.    IIC_Stop();
  79. }

  80. void OLED_WR_Byte(unsigned dat,unsigned cmd)
  81. {
  82.         if(cmd)
  83.         {
  84.                 IIC_WriteData(dat);
  85.         }
  86.         else
  87.         {
  88.                 IIC_WriteCommand(dat);
  89.         }
  90. }

  91. void OLED_Init(void)
  92. {
  93.         HAL_Delay(100);                //这个延迟很重要
  94.        
  95.         OLED_WR_Byte(0xAE,OLED_CMD);//--display off
  96.         OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
  97.         OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
  98.         OLED_WR_Byte(0x40,OLED_CMD);//--set start line address
  99.         OLED_WR_Byte(0xB0,OLED_CMD);//--set page address
  100.         OLED_WR_Byte(0x81,OLED_CMD); // contract control
  101.         OLED_WR_Byte(0xFF,OLED_CMD);//--128
  102.         OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap
  103.         OLED_WR_Byte(0xA6,OLED_CMD);//--normal / reverse
  104.         OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
  105.         OLED_WR_Byte(0x3F,OLED_CMD);//--1/32 duty
  106.         OLED_WR_Byte(0xC8,OLED_CMD);//Com scan direction
  107.         OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset
  108.         OLED_WR_Byte(0x00,OLED_CMD);//

  109.         OLED_WR_Byte(0xD5,OLED_CMD);//set osc division
  110.         OLED_WR_Byte(0x80,OLED_CMD);//

  111.         OLED_WR_Byte(0xD8,OLED_CMD);//set area color mode off
  112.         OLED_WR_Byte(0x05,OLED_CMD);//

  113.         OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-Charge Period
  114.         OLED_WR_Byte(0xF1,OLED_CMD);//

  115.         OLED_WR_Byte(0xDA,OLED_CMD);//set com pin configuartion
  116.         OLED_WR_Byte(0x12,OLED_CMD);//

  117.         OLED_WR_Byte(0xDB,OLED_CMD);//set Vcomh
  118.         OLED_WR_Byte(0x30,OLED_CMD);//

  119.         OLED_WR_Byte(0x8D,OLED_CMD);//set charge pump enable
  120.         OLED_WR_Byte(0x14,OLED_CMD);//

  121.         OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
  122.         HAL_Delay(100);       
  123.         OLED_FillPicture(0x0);

  124. }


  125. /********************************************
  126. // OLED_FillPicture
  127. ********************************************/
  128. void OLED_FillPicture(unsigned char fill_Data)
  129. {
  130.         unsigned char m,n;
  131.         for(m=0;m<8;m++)
  132.         {
  133.                 OLED_WR_Byte(0xb0+m,0);                //page0-page1
  134.                 OLED_WR_Byte(0x00,0);                //low column start address
  135.                 OLED_WR_Byte(0x10,0);                //high column start address
  136.                 for(n=0;n<128;n++)
  137.                         {
  138.                                 OLED_WR_Byte(fill_Data,1);
  139.                         }
  140.         }
  141. }

  142. //坐标设置
  143. void OLED_SetPos(unsigned char x, unsigned char y)
  144. {         OLED_WR_Byte(0xb0+y,OLED_CMD);
  145.         OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
  146.         OLED_WR_Byte((x&0x0f),OLED_CMD);
  147. }
  148. //开启OLED显示
  149. void OLED_DisplayOn(void)
  150. {
  151.         OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
  152.         OLED_WR_Byte(0X14,OLED_CMD);  //DCDC ON
  153.         OLED_WR_Byte(0XAF,OLED_CMD);  //DISPLAY ON
  154. }
  155. //关闭OLED显示
  156. void OLED_DisplayOff(void)
  157. {
  158.         OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
  159.         OLED_WR_Byte(0X10,OLED_CMD);  //DCDC OFF
  160.         OLED_WR_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
  161. }
  162. //清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
  163. void OLED_Clear(void)
  164. {
  165.         u8 i,n;
  166.         for(i=0;i<8;i++)
  167.         {
  168.                 OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
  169.                 OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
  170.                 OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址
  171.                 for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA);
  172.         } //更新显示
  173. }
  174. void OLED_On(void)
  175. {
  176.         u8 i,n;
  177.         for(i=0;i<8;i++)
  178.         {
  179.                 OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
  180.                 OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
  181.                 OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址
  182.                 for(n=0;n<128;n++)OLED_WR_Byte(1,OLED_DATA);
  183.         } //更新显示
  184. }
  185. //在指定位置显示一个字符,包括部分字符
  186. //x:0~127
  187. //y:0~63
  188. //mode:0,反白显示;1,正常显示
  189. //size:选择字体 16/12
  190. void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size)
  191. {
  192.         unsigned char c=0,i=0;
  193.                 c=chr-' ';//得到偏移后的值
  194.                 if(x>Max_Column-1){x=0;y=y+2;}
  195.                 if(Char_Size ==16)
  196.                         {
  197.                         OLED_SetPos(x,y);
  198.                         for(i=0;i<8;i++)
  199.                         OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
  200.                         OLED_SetPos(x,y+1);
  201.                         for(i=0;i<8;i++)
  202.                         OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
  203.                         }
  204.                         else {
  205.                                 OLED_SetPos(x,y);
  206.                                 for(i=0;i<6;i++)
  207.                                 OLED_WR_Byte(F6x8[c][i],OLED_DATA);

  208.                         }
  209. }

  210. //m^n函数
  211. u32 oled_pow(u8 m,u8 n)
  212. {
  213.         u32 result=1;
  214.         while(n--)result*=m;
  215.         return result;
  216. }

  217. //显示2个数字
  218. //x,y :起点坐标
  219. //len :数字的位数
  220. //size:字体大小
  221. //mode:模式        0,填充模式;1,叠加模式
  222. //num:数值(0~4294967295);
  223. void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2)
  224. {
  225.         u8 t,temp;
  226.         u8 enshow=0;
  227.         for(t=0;t<len;t++)
  228.         {
  229.                 temp=(num/oled_pow(10,len-t-1))%10;
  230.                 if(enshow==0&&t<(len-1))
  231.                 {
  232.                         if(temp==0)
  233.                         {
  234. //                                OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
  235.                                 OLED_ShowChar(x+(size2/2)*t,y,'0',size2);
  236.                                 continue;
  237.                         }else enshow=1;

  238.                 }
  239.                  OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2);
  240.         }
  241. }

  242. //显示一个字符号串
  243. void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size)
  244. {
  245.         unsigned char j=0;
  246.         while (chr[j]!='\0')
  247.         {                OLED_ShowChar(x,y,chr[j],Char_Size);
  248.                         x+=8;
  249.                 if(x>120){x=0;y+=2;}
  250.                         j++;
  251.         }
  252. }
 楼主| 鱿鱼丝 发表于 2023-3-27 11:22 | 显示全部楼层
5.2 谷歌小恐龙游戏图形绘制代码

        该部分为整个项目代码的核心部分之一,任何一个游戏都是需要去绘制和构建游戏的图形以及模型的。好的游戏往往都具有很好的游戏模型和精美UI,很多3A大作都具备这样的特性。
 楼主| 鱿鱼丝 发表于 2023-3-27 11:23 | 显示全部楼层
dinogame.h:
  1. #ifndef __DINOGAME_H
  2. #define __DINOGAME_H

  3. void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[]);
  4. void OLED_DrawBMPFast(const unsigned char BMP[]);
  5. void oled_drawbmp_block_clear(int bx, int by, int clear_size);
  6. void OLED_DrawGround();
  7. void OLED_DrawCloud();
  8. void OLED_DrawDino();
  9. void OLED_DrawCactus();
  10. int OLED_DrawCactusRandom(unsigned char ver, unsigned char reset);
  11. int OLED_DrawDinoJump(char reset);
  12. void OLED_DrawRestart();
  13. void OLED_DrawCover();

  14. #endif
 楼主| 鱿鱼丝 发表于 2023-3-27 11:23 | 显示全部楼层
dinogame.c代码:
  1. #include "oled.h"
  2. #include "oledfont.h"
  3. #include "stdlib.h"

  4. /***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
  5. void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
  6. {
  7. unsigned int j=0;
  8. unsigned char x,y;

  9.   if(y1%8==0) y=y1/8;
  10.   else y=y1/8+1;
  11.         for(y=y0;y<y1;y++)
  12.         {
  13.                 OLED_SetPos(x0,y);
  14.                 for(x=x0;x<x1;x++)
  15.             {
  16.                     OLED_WR_Byte(BMP[j++],OLED_DATA);
  17.             }
  18.         }
  19. }



  20. // 快速绘制图像
  21. void OLED_DrawBMPFast(const unsigned char BMP[])
  22. {
  23.         unsigned int j = 0;
  24.         unsigned char x, y;

  25.         for (y = 0; y < 8; y++)
  26.         {
  27.                 OLED_SetPos(0, y);
  28.                 IIC_Start();
  29.                 IIC_WriteByte(0x78);
  30.                 IIC_WaitAck();
  31.                 IIC_WriteByte(0x40);
  32.                 IIC_WaitAck();
  33.                 for (x = 0; x < 128; x++)
  34.                 {
  35.                         IIC_WriteByte(BMP[j++]);
  36.                         IIC_WaitAck();
  37.                 }
  38.                 IIC_Stop();
  39.         }
  40. }

  41. void oled_drawbmp_block_clear(int bx, int by, int clear_size)
  42. {
  43.         unsigned int i;
  44.         OLED_SetPos(bx, by);
  45.         IIC_Start();
  46.         IIC_WriteByte(0x78);
  47.         IIC_WaitAck();
  48.         IIC_WriteByte(0x40);
  49.         IIC_WaitAck();

  50.         for (i = 0; i < clear_size; i++)
  51.         {
  52.                 if (bx + i>128) break;
  53.                 IIC_WriteByte(0x0);
  54.                 IIC_WaitAck();
  55.         }
  56.         IIC_Stop();
  57. }

  58. void OLED_DrawGround()
  59. {
  60.         static unsigned int pos = 0;
  61.         unsigned char speed = 5;
  62.         unsigned int ground_length = sizeof(GROUND);
  63.         unsigned char x;

  64.         OLED_SetPos(0, 7);
  65.         IIC_Start();
  66.         IIC_WriteByte(0x78);
  67.         IIC_WaitAck();
  68.         IIC_WriteByte(0x40);
  69.         IIC_WaitAck();
  70.         for (x = 0; x < 128; x++)
  71.         {
  72.                 IIC_WriteByte(GROUND[(x+pos)%ground_length]);
  73.                 IIC_WaitAck();
  74.         }
  75.         IIC_Stop();

  76.         pos = pos + speed;
  77.         //if(pos>ground_length) pos=0;
  78. }


  79. // 绘制云朵
  80. void OLED_DrawCloud()
  81. {
  82.         static int pos = 128;
  83.         static char height=0;
  84.         char speed = 3;
  85.         unsigned int i=0;
  86.         int x;
  87.         int start_x = 0;
  88.         int length = sizeof(CLOUD);
  89.         unsigned char byte;

  90.         //if (pos + length <= -speed) pos = 128;

  91.         if (pos + length <= -speed)
  92.         {
  93.                 pos = 128;
  94.                 height = rand()%3;
  95.         }
  96.         if(pos < 0)
  97.         {
  98.                 start_x = -pos;
  99.                 OLED_SetPos(0, 1+height);
  100.         }
  101.         else
  102.         {
  103.                 OLED_SetPos(pos, 1+height);
  104.         }

  105.         IIC_Start();
  106.         IIC_WriteByte(0x78);
  107.         IIC_WaitAck();
  108.         IIC_WriteByte(0x40);
  109.         IIC_WaitAck();
  110.         for (x = start_x; x < length + speed; x++)
  111.         {
  112.                 if (pos + x > 127) break;
  113.                 if (x < length) byte = CLOUD[x];
  114.                 else byte = 0x0;

  115.                 IIC_WriteByte(byte);
  116.                 IIC_WaitAck();
  117.         }
  118.         IIC_Stop();

  119.         pos = pos - speed;
  120. }

  121. // 绘制小恐龙
  122. void OLED_DrawDino()
  123. {
  124.         static unsigned char dino_dir = 0;
  125.         unsigned int j=0;
  126.         unsigned char x, y;
  127.         unsigned char byte;

  128.         dino_dir++;
  129.         dino_dir = dino_dir%2;
  130.         for(y=0; y<2; y++)
  131.         {
  132.                 OLED_SetPos(16, 6+y);
  133.                 IIC_Start();
  134.                 IIC_WriteByte(0x78);
  135.                 IIC_WaitAck();
  136.                 IIC_WriteByte(0x40);
  137.                 IIC_WaitAck();
  138.                 for (x = 0; x < 16; x++)
  139.                 {
  140.                         j = y*16 + x;
  141.                         byte = DINO[dino_dir][j];

  142.                         IIC_WriteByte(byte);
  143.                         IIC_WaitAck();
  144.                 }
  145.                 IIC_Stop();
  146.         }
  147. }

  148. // 绘制仙人掌障碍物
  149. void OLED_DrawCactus()
  150. {
  151.         char speed = 5;
  152.         static int pos = 128;
  153.         int start_x = 0;
  154.         int length = sizeof(CACTUS_2)/2;

  155.         unsigned int j=0;
  156.         unsigned char x, y;
  157.         unsigned char byte;

  158.         if (pos + length <= 0)
  159.         {
  160.                 oled_drawbmp_block_clear(0, 6, speed);
  161.                 pos = 128;
  162.         }

  163.         for(y=0; y<2; y++)
  164.         {
  165.                 if(pos < 0)
  166.                 {
  167.                         start_x = -pos;
  168.                         OLED_SetPos(0, 6+y);
  169.                 }
  170.                 else
  171.                 {
  172.                         OLED_SetPos(pos, 6+y);
  173.                 }

  174.                 IIC_Start();
  175.                 IIC_WriteByte(0x78);
  176.                 IIC_WaitAck();
  177.                 IIC_WriteByte(0x40);
  178.                 IIC_WaitAck();

  179.                 for (x = start_x; x < length; x++)
  180.                 {
  181.                         if (pos + x > 127) break;
  182.                         j = y*length + x;
  183.                         byte = CACTUS_2[j];
  184.                         IIC_WriteByte(byte);
  185.                         IIC_WaitAck();
  186.                 }
  187.                 IIC_Stop();
  188.         }
  189.         oled_drawbmp_block_clear(pos + length, 6, speed); // 清除残影
  190.         pos = pos - speed;
  191. }


  192. // 绘制随机出现的仙人掌障碍物
  193. int OLED_DrawCactusRandom(unsigned char ver, unsigned char reset)
  194. {
  195.         char speed = 5;
  196.         static int pos = 128;
  197.         int start_x = 0;
  198.         int length = 0;

  199.         unsigned int i=0, j=0;
  200.         unsigned char x, y;
  201.         unsigned char byte;
  202.         if (reset == 1)
  203.         {
  204.                 pos = 128;
  205.                 oled_drawbmp_block_clear(0, 6, speed);
  206.                 return 128;
  207.         }
  208.         if (ver == 0) length = 8; //sizeof(CACTUS_1) / 2;
  209.         else if (ver == 1) length = 16; //sizeof(CACTUS_2) / 2;
  210.         else if (ver == 2 || ver == 3) length = 24;

  211.         for(y=0; y<2; y++)
  212.         {
  213.                 if(pos < 0)
  214.                 {
  215.                         start_x = -pos;
  216.                         OLED_SetPos(0, 6+y);
  217.                 }
  218.                 else
  219.                 {
  220.                         OLED_SetPos(pos, 6+y);
  221.                 }

  222.                 IIC_Start();
  223.                 IIC_WriteByte(0x78);
  224.                 IIC_WaitAck();
  225.                 IIC_WriteByte(0x40);
  226.                 IIC_WaitAck();

  227.                 for (x = start_x; x < length; x++)
  228.                 {
  229.                         if (pos + x > 127) break;

  230.                         j = y*length + x;
  231.                         if (ver == 0) byte = CACTUS_1[j];
  232.                         else if (ver == 1) byte = CACTUS_2[j];
  233.                         else if(ver == 2) byte = CACTUS_3[j];
  234.                         else byte = CACTUS_4[j];

  235.                         IIC_WriteByte(byte);
  236.                         IIC_WaitAck();
  237.                 }
  238.                 IIC_Stop();
  239.         }

  240.         oled_drawbmp_block_clear(pos + length, 6, speed);

  241.         pos = pos - speed;
  242.         return pos + speed;
  243. }




  244. // 绘制跳跃小恐龙
  245. int OLED_DrawDinoJump(char reset)
  246. {
  247.         char speed_arr[] = {1, 1, 3, 3, 4, 4, 5, 6, 7};
  248.         static char speed_idx = sizeof(speed_arr)-1;
  249.         static int height = 0;
  250.         static char dir = 0;
  251.         //char speed = 4;

  252.         unsigned int j=0;
  253.         unsigned char x, y;
  254.         char offset = 0;
  255.         unsigned char byte;
  256.         if(reset == 1)
  257.         {
  258.                 height = 0;
  259.                 dir = 0;
  260.                 speed_idx = sizeof(speed_arr)-1;
  261.                 return 0;
  262.         }
  263.         if (dir==0)
  264.         {
  265.                 height += speed_arr[speed_idx];
  266.                 speed_idx --;
  267.                 if (speed_idx<0) speed_idx = 0;
  268.         }
  269.         if (dir==1)
  270.         {
  271.                 height -= speed_arr[speed_idx];
  272.                 speed_idx ++;
  273.                 if (speed_idx>sizeof(speed_arr)-1) speed_idx = sizeof(speed_arr)-1;
  274.         }
  275.         if(height >= 31)
  276.         {
  277.                 dir = 1;
  278.                 height = 31;
  279.         }
  280.         if(height <= 0)
  281.         {
  282.                 dir = 0;
  283.                 height = 0;
  284.         }
  285.         if(height <= 7) offset = 0;
  286.         else if(height <= 15) offset = 1;
  287.         else if(height <= 23) offset = 2;
  288.         else if(height <= 31) offset = 3;
  289.         else offset = 4;

  290.         for(y=0; y<3; y++) // 4
  291.         {
  292.                 OLED_SetPos(16, 5- offset + y);

  293.                 IIC_Start();
  294.                 IIC_WriteByte(0x78);
  295.                 IIC_WaitAck();
  296.                 IIC_WriteByte(0x40);
  297.                 IIC_WaitAck();
  298.                 for (x = 0; x < 16; x++) // 32
  299.                 {
  300.                         j = y*16 + x; // 32
  301.                         byte = DINO_JUMP[height%8][j];

  302.                         IIC_WriteByte(byte);
  303.                         IIC_WaitAck();
  304.                 }
  305.                 IIC_Stop();
  306.         }
  307.         if (dir == 0) oled_drawbmp_block_clear(16, 8- offset, 16);
  308.         if (dir == 1) oled_drawbmp_block_clear(16, 4- offset, 16);
  309.         return height;
  310. }

  311. // 绘制重启
  312. void OLED_DrawRestart()
  313. {
  314.         unsigned int j=0;
  315.         unsigned char x, y;
  316.         unsigned char byte;
  317.         //OLED_SetPos(0, 0);
  318.         for (y = 2; y < 5; y++)
  319.         {
  320.                 OLED_SetPos(52, y);
  321.                 IIC_Start();
  322.                 IIC_WriteByte(0x78);
  323.                 IIC_WaitAck();
  324.                 IIC_WriteByte(0x40);
  325.                 IIC_WaitAck();
  326.                 for (x = 0; x < 24; x++)
  327.                 {
  328.                         byte = RESTART[j++];
  329.                         IIC_WriteByte(byte);
  330.                         IIC_WaitAck();
  331.                 }
  332.                 IIC_Stop();
  333.         }
  334.         OLED_ShowString(10, 3, "GAME", 16);
  335.         OLED_ShowString(86, 3, "OVER", 16);
  336. }
  337. // 绘制封面
  338. void OLED_DrawCover()
  339. {
  340.         OLED_DrawBMPFast(COVER);
  341. }
 楼主| 鱿鱼丝 发表于 2023-3-27 11:23 | 显示全部楼层
5.3 谷歌小恐龙的运行控制代码

control.h:
  1. #ifndef __CONTROL_H
  2. #define __CONTROL_H

  3. int get_key();
  4. void Game_control();

  5. #endif
 楼主| 鱿鱼丝 发表于 2023-3-27 11:23 | 显示全部楼层
control.c:
  1. #include "control.h"
  2. #include "oled.h"
  3. #include "dinogame.h"
  4. #include "stdlib.h"

  5. unsigned char key_num = 0;
  6. unsigned char cactus_category = 0;
  7. unsigned char cactus_length = 8;
  8. unsigned int score = 0;
  9. unsigned int highest_score = 0;
  10. int height = 0;
  11. int cactus_pos = 128;
  12. unsigned char cur_speed = 30;
  13. char failed = 0;
  14. char reset = 0;


  15. int get_key()
  16. {
  17.         if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4)==0)
  18.         {
  19.                 HAL_Delay(10);            //延迟
  20.                 if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4)==0)
  21.                 {
  22.                 return 2;
  23.                 }
  24.         }
  25.        
  26.         if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3)==0)
  27.         {
  28.                 HAL_Delay(10);            //延迟
  29.                 if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3)==0)
  30.                 {
  31.                 return 1;
  32.                 }
  33.         }

  34.         if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)==1)
  35.         {
  36.                 HAL_Delay(10);            //延迟
  37.                 if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)==1)
  38.                 {
  39.                 return 3;
  40.                 }
  41.         }
  42.        
  43.         return 0;
  44. }

  45. void Game_control()
  46. {
  47.        
  48.         while(1)
  49.         {
  50.        
  51.                 if(get_key() == 3)                //wk_up按键按下强制退出一次循环
  52.                 {
  53.                         break;
  54.                 }
  55.                
  56.                         if (failed == 1)
  57.                 {
  58.                         OLED_DrawRestart();

  59.                         key_num = get_key();
  60.                         if (key_num == 2)
  61.                         {
  62.                                 if(score > highest_score) highest_score = score;
  63.                                 score = 0;
  64.                                 failed = 0;
  65.                                 height = 0;
  66.                                 reset = 1;
  67.                                 OLED_DrawDinoJump(reset);
  68.                                 OLED_DrawCactusRandom(cactus_category, reset);
  69.                                 OLED_Clear();
  70.                         }
  71.                         continue;
  72.                 }


  73.                 score ++;
  74.                 if (height <= 0) key_num = get_key();

  75.                 OLED_DrawGround();
  76.                 OLED_DrawCloud();

  77.                 if (height>0 || key_num == 1) height = OLED_DrawDinoJump(reset);
  78.                 else OLED_DrawDino();

  79.                 cactus_pos = OLED_DrawCactusRandom(cactus_category, reset);
  80.                 if(cactus_category == 0) cactus_length = 8;
  81.                 else if(cactus_category == 1) cactus_length = 16;
  82.                 else cactus_length = 24;

  83.                 if (cactus_pos + cactus_length < 0)
  84.                 {
  85.                   cactus_category = rand()%4;
  86.                         OLED_DrawCactusRandom(cactus_category, 1);
  87.                 }

  88.                 if ((height < 16) && ( (cactus_pos>=16 && cactus_pos <=32) || (cactus_pos + cactus_length>=16 && cactus_pos + cactus_length <=32)))
  89.                 {
  90.                         failed = 1;
  91.                 }

  92.                
  93.                 OLED_ShowString(35, 0, "HI:", 12);
  94.                 OLED_ShowNum(58, 0, highest_score, 5, 12);
  95.                 OLED_ShowNum(98, 0, score, 5, 12);


  96.                 reset = 0;

  97.                 cur_speed = score/20;
  98.                 if (cur_speed > 29) cur_speed = 29;
  99.                 HAL_Delay(30 - cur_speed);
  100. //                HAL_Delay(500);
  101.                 key_num = 0;
  102.        
  103.         }
  104.        
  105. }
 楼主| 鱿鱼丝 发表于 2023-3-27 11:24 | 显示全部楼层
5.4 多级菜单核心代码:

menu.h:
  1. #ifndef __MENU_H
  2. #define __MENU_H

  3. #include "main.h"
  4. #define  u8 unsigned char

  5. //按键定义
  6. #define KEY0 HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4)                //低电平有效          KEY0
  7. #define KEY1 HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3)                //低电平有效
  8. #define WK_UP HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)                //高电平有效


  9. typedef struct
  10. {
  11.     u8 current;        //当前状态索引号
  12.     u8 next;                 //向下一个
  13.     u8 enter;         //确定
  14.                 u8 back;                 //退出
  15.     void (*current_operation)(void); //当前状态应该执行的操作
  16. } Menu_table;

  17. //界面UI
  18. void home();
  19. void Temperature();
  20. void Palygame();
  21. void Setting();
  22. void Info();


  23. void  Menu_key_set(void);
  24. u8 KEY_Scan(u8 mode);

  25. void TestTemperature();
  26. void ConrtolGame();
  27. void Set();
  28. void Information();

  29. void LED();
  30. void RTC_display();

  31. #endif
 楼主| 鱿鱼丝 发表于 2023-3-27 11:24 | 显示全部楼层
menu.c:
  1. #include "menu.h"
  2. #include "oled.h"
  3. #include "gpio.h"
  4. #include "dinogame.h"
  5. #include "control.h"
  6. #include "DHT11.h"
  7. #include "rtc.h"

  8. RTC_DateTypeDef GetData;  //获取日期结构体

  9. RTC_TimeTypeDef GetTime;   //获取时间结构体


  10. //UI界面
  11. //主页
  12. /****************************************************/
  13. //UI库

  14. /****************************************************/

  15. void (*current_operation_index)();         

  16. Menu_table  table[30]=
  17. {
  18.     {0,0,1,0,(*home)},        //一级界面(主页面) 索引,向下一个,确定,退出
  19.                
  20.     {1,2,5,0,(*Temperature)},        //二级界面 温湿度
  21.     {2,3,6,0,(*Palygame)},        //二级界面 游戏
  22.     {3,4,7,0,(*Setting)},        //二级界面 设置
  23.     {4,1,8,0,(*Info)},        //二级界面 信息
  24.                
  25.                 {5,5,5,1,(*TestTemperature)},                //三级界面:DHT11测量温湿度
  26.                 {6,6,6,2,(*ConrtolGame)},                                //三级界面:谷歌小恐龙Dinogame
  27.                 {7,7,9,3,(*Set)},                                                                //三级界面:设置普通外设状态 LED
  28.                 {8,8,8,4,(*Information)},                                //三级界面:作者和相关项目信息

  29.                 {9,9,7,3,(*LED)},                //LED控制
  30. };

  31. uint8_t  func_index = 0;        //主程序此时所在程序的索引值

  32. void  Menu_key_set(void)
  33. {
  34.   if((KEY_Scan(1) == 1) && (func_index != 6))
  35.   {
  36.     func_index=table[func_index].next;        //按键next按下后的索引号
  37.     OLED_Clear();
  38.   }
  39.        
  40.   if((KEY_Scan(1) == 2) && (func_index != 6))
  41.   {
  42.     func_index=table[func_index].enter;        //按键enter按下后的索引号
  43.     OLED_Clear();
  44.   }

  45.         if(KEY_Scan(1) == 3)
  46.   {
  47.     func_index=table[func_index].back;        //按键back按下后的索引号
  48.     OLED_Clear();
  49.   }
  50.        
  51.   current_operation_index=table[func_index].current_operation;        //执行当前索引号所对应的功能函数
  52.   (*current_operation_index)();//执行当前操作函数
  53. }


  54. void home()
  55. {
  56.         RTC_display();
  57.         OLED_DrawBMP(0,0,20,3,signal_BMP);
  58.         OLED_DrawBMP(20,0,36,2,gImage_bulethouch);
  59.         OLED_DrawBMP(112,0,128,2,gImage_engery);
  60.         OLED_DrawBMP(4,6,20,8,gImage_yes);
  61.         OLED_DrawBMP(12,4,28,6,gImage_left);
  62.         OLED_DrawBMP(40,2,88,8,gImage_home);
  63.         OLED_DrawBMP(99,4,115,6,gImage_right);
  64.         OLED_DrawBMP(107,6,123,8,gImage_back);
  65. }

  66. void Temperature()
  67. {
  68.         RTC_display();
  69.         OLED_DrawBMP(0,0,20,3,signal_BMP);
  70.         OLED_DrawBMP(20,0,36,2,gImage_bulethouch);
  71.         OLED_DrawBMP(112,0,128,2,gImage_engery);
  72.         OLED_DrawBMP(4,6,20,8,gImage_yes);
  73.         OLED_DrawBMP(12,4,28,6,gImage_left);
  74.         OLED_DrawBMP(40,2,88,8,gImage_temp);
  75.         OLED_DrawBMP(99,4,115,6,gImage_right);
  76.         OLED_DrawBMP(107,6,123,8,gImage_back);
  77. }

  78. void Palygame()
  79. {
  80.         RTC_display();
  81.         OLED_DrawBMP(0,0,20,3,signal_BMP);
  82.         OLED_DrawBMP(20,0,36,2,gImage_bulethouch);
  83.         OLED_DrawBMP(112,0,128,2,gImage_engery);
  84.         OLED_DrawBMP(4,6,20,8,gImage_yes);
  85.         OLED_DrawBMP(12,4,28,6,gImage_left);
  86.         OLED_DrawBMP(40,2,88,8,gImage_playgame);
  87.         OLED_DrawBMP(99,4,115,6,gImage_right);
  88.         OLED_DrawBMP(107,6,123,8,gImage_back);
  89. }

  90. void Setting()
  91. {
  92.         RTC_display();
  93.         OLED_DrawBMP(0,0,20,3,signal_BMP);
  94.         OLED_DrawBMP(20,0,36,2,gImage_bulethouch);
  95.         OLED_DrawBMP(112,0,128,2,gImage_engery);
  96.         OLED_DrawBMP(4,6,20,8,gImage_yes);
  97.         OLED_DrawBMP(12,4,28,6,gImage_left);
  98.         OLED_DrawBMP(40,2,88,8,gImage_setting);
  99.         OLED_DrawBMP(99,4,115,6,gImage_right);
  100.         OLED_DrawBMP(107,6,123,8,gImage_back);
  101. }

  102. void Info()
  103. {
  104.         RTC_display();
  105.         OLED_DrawBMP(0,0,20,3,signal_BMP);
  106.         OLED_DrawBMP(20,0,36,2,gImage_bulethouch);
  107.         OLED_DrawBMP(112,0,128,2,gImage_engery);
  108.         OLED_DrawBMP(4,6,20,8,gImage_yes);
  109.         OLED_DrawBMP(12,4,28,6,gImage_left);
  110.         OLED_DrawBMP(40,2,88,8,gImage_info);
  111.         OLED_DrawBMP(99,4,115,6,gImage_right);
  112.         OLED_DrawBMP(107,6,123,8,gImage_back);
  113. }


  114. //按键函数,不支持连按
  115. u8 KEY_Scan(u8 mode)
  116. {
  117.         static u8 key_up=1;
  118.         if(mode)key_up=1;
  119.         if(key_up&&(KEY0==0||KEY1==0||WK_UP==1))
  120.         {
  121.                 HAL_Delay(100);                //消抖
  122.                 key_up=0;
  123.                 if(KEY0==0)return 1;
  124.                 else if(KEY1==0)return 2;
  125.                 else if(WK_UP==1)return 3;
  126.         }else if(KEY0==1&&KEY1==1&&WK_UP==0)key_up=1;
  127.         return 0;
  128. }

  129. void TestTemperature()
  130. {
  131.         DHT11();
  132. }

  133. void ConrtolGame()
  134. {
  135.         Game_control();
  136. }

  137. void Set()
  138. {
  139.         OLED_ShowString(0,0,"Peripherals: Lights",16);
  140.         OLED_ShowString(0,2,"Status: Closed",16);
  141.         HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
  142. }

  143. void Information()
  144. {
  145.         OLED_ShowString(0,0,"Author:Sneak",16);
  146.         OLED_ShowString(0,2,"Date:2022/8/23",16);
  147.         OLED_ShowString(0,4,"Lab: Multi-level menu",16);
  148. }

  149. void LED()
  150. {
  151.         OLED_ShowString(0,0,"Peripherals: Lights",16);
  152.         OLED_ShowString(0,2,"Status: Open",16);
  153.         HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
  154. }



  155. void RTC_display()                                //RTC????
  156. {
  157.           /* Get the RTC current Time */
  158.           HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);
  159.       /* Get the RTC current Date */
  160.     HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN);
  161.        
  162.                 /* Display date Format : yy/mm/dd */
  163.        
  164.         /* Display time Format : hh:mm:ss */
  165.                 OLED_ShowNum(40,0,GetTime.Hours,2,16);                                //hour
  166.                 OLED_ShowString(57,0,":",16);       
  167.                 OLED_ShowNum(66,0,GetTime.Minutes,2,16);                        //min
  168.                 OLED_ShowString(83,0,":",16);       
  169.                 OLED_ShowNum(93,0,GetTime.Seconds,2,16);                        //seconds
  170. }
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部