E32_433开发板程序
This commit is contained in:
1478
Middlewares/MultMenu/application/AirPlane.c
Normal file
1478
Middlewares/MultMenu/application/AirPlane.c
Normal file
File diff suppressed because it is too large
Load Diff
12
Middlewares/MultMenu/application/AirPlane.h
Normal file
12
Middlewares/MultMenu/application/AirPlane.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef _AirPlane_H
|
||||
#define _AirPlane_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h> // rand
|
||||
#include "menuConfig.h"
|
||||
|
||||
void AirPlane_Run(xpItem item);
|
||||
|
||||
#endif
|
||||
385
Middlewares/MultMenu/application/DinoGame.c
Normal file
385
Middlewares/MultMenu/application/DinoGame.c
Normal file
@ -0,0 +1,385 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Freescale Semiconductor, Inc.
|
||||
* Copyright 2016-2021 NXP
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/* Standard C Included Files */
|
||||
#include "DinoGame.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Definitions
|
||||
******************************************************************************/
|
||||
/* System Tick Configuration */
|
||||
#define SYS_TICK_PER_SECOND 1000
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Prototypes
|
||||
******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* Variables
|
||||
******************************************************************************/
|
||||
extern u8g2_t u8g2;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Code
|
||||
|
||||
******************************************************************************/
|
||||
static int random(int low, int high)
|
||||
{
|
||||
return rand() % (high - low + 1) + low;
|
||||
}
|
||||
|
||||
static unsigned long millis(void)
|
||||
{
|
||||
return ((unsigned long)HAL_GetTick() * 1000 / SYS_TICK_PER_SECOND );
|
||||
}
|
||||
|
||||
// https://github.com/sarafong/T-Rex-Runner/blob/master/TRexRunner/TRexRunner.ino
|
||||
|
||||
//Multiple Dino Bitmaps
|
||||
|
||||
//--------------------Bitmaps--------------------//
|
||||
|
||||
//----------Dimensions----------//
|
||||
#define smallcactus_width 8
|
||||
#define smallcactus_height 17
|
||||
#define standing_width 21
|
||||
#define standing_height 20
|
||||
#define frontLeg_width 21
|
||||
#define frontLeg_height 20
|
||||
#define backLeg_width 21
|
||||
#define backLeg_height 20
|
||||
#define gameover_width 99
|
||||
#define gameover_height 35
|
||||
#define easy_width 32
|
||||
#define easy_height 15
|
||||
#define medium_width 30
|
||||
#define medium_height 20
|
||||
#define hard_width 32
|
||||
#define hard_height 15
|
||||
#define insane_width 30
|
||||
#define insane_height 20
|
||||
#define menu_width 32
|
||||
#define menu_height 15
|
||||
#define replay_width 32
|
||||
#define replay_height 15
|
||||
|
||||
#define UP 3
|
||||
#define DOWN 2
|
||||
|
||||
//----------Bitmap Arrays----------//
|
||||
|
||||
static unsigned char smallcactus_bits[] = {
|
||||
0x18, 0x18, 0x98, 0x98, 0x99, 0x99, 0x99, 0x99, 0x79, 0x19, 0x1e, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18 };
|
||||
|
||||
static unsigned char standing_bits[] = {
|
||||
0x00, 0xf8, 0x0f, 0x00, 0xcc, 0x1f, 0x00, 0xf8, 0x1f, 0x00, 0xfc, 0x1f,
|
||||
0x00, 0xf8, 0x1f, 0x00, 0xfc, 0x00, 0x00, 0xf8, 0x07, 0x01, 0x3e, 0x00,
|
||||
0x01, 0x7f, 0x00, 0xc3, 0xff, 0x01, 0xef, 0x7f, 0x00, 0xff, 0x7f, 0x00,
|
||||
0xfe, 0x3f, 0x00, 0xfc, 0x3f, 0x00, 0xf8, 0x1f, 0x00, 0xf0, 0x07, 0x00,
|
||||
0xe0, 0x0e, 0x00, 0x60, 0x04, 0x00, 0x20, 0x08, 0x00, 0x60, 0x08, 0x00 };
|
||||
|
||||
static unsigned char frontLeg_bits[] = {
|
||||
0x00, 0xf0, 0x0f, 0x00, 0xdc, 0x1f, 0x00, 0xf8, 0x1f, 0x00, 0xf8, 0x1f,
|
||||
0x00, 0xf8, 0x1f, 0x00, 0xfc, 0x00, 0x00, 0xf8, 0x07, 0x01, 0x7e, 0x00,
|
||||
0x01, 0x7f, 0x00, 0xc3, 0xff, 0x01, 0xef, 0x7f, 0x01, 0xff, 0x7f, 0x00,
|
||||
0xfe, 0x7f, 0x00, 0xfc, 0x3f, 0x00, 0xf8, 0x1f, 0x00, 0xf0, 0x0f, 0x00,
|
||||
0xe0, 0x18, 0x00, 0xe0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x60, 0x00, 0x00 };
|
||||
|
||||
static unsigned char backLeg_bits[] = {
|
||||
0x00, 0xf8, 0x0f, 0x00, 0xd8, 0x1f, 0x00, 0xfc, 0x1f, 0x00, 0xf8, 0x1f,
|
||||
0x00, 0xfc, 0x1f, 0x00, 0xf8, 0x00, 0x00, 0xfc, 0x07, 0x01, 0x3e, 0x00,
|
||||
0x01, 0x7f, 0x00, 0xc3, 0xff, 0x01, 0xef, 0x7f, 0x00, 0xff, 0x7f, 0x00,
|
||||
0xfe, 0x3f, 0x00, 0xfc, 0x3f, 0x00, 0xf8, 0x1f, 0x00, 0xf0, 0x07, 0x00,
|
||||
0x60, 0x0e, 0x00, 0xc0, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, 0x0c, 0x00 };
|
||||
|
||||
static unsigned char gameover_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xc0, 0x03, 0x0e, 0xd8, 0xc0, 0x07, 0x80, 0x07, 0x24,
|
||||
0xe0, 0x01, 0x0f, 0x00, 0x20, 0x00, 0x09, 0xf8, 0x40, 0x00, 0x80, 0x04,
|
||||
0x66, 0x30, 0x80, 0x09, 0x00, 0x20, 0x03, 0x19, 0xe8, 0xc0, 0x03, 0x80,
|
||||
0x04, 0x3c, 0xe0, 0x01, 0x0d, 0x00, 0x60, 0x02, 0x1b, 0x88, 0x40, 0x00,
|
||||
0xc0, 0x0c, 0x18, 0x20, 0x00, 0x07, 0x00, 0xc0, 0x03, 0x11, 0x98, 0xc0,
|
||||
0x07, 0x80, 0x07, 0x08, 0xe0, 0x01, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54,
|
||||
0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7e, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1e, 0xe6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x4e, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce, 0xef, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0xef, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xe0, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0xf4, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
static unsigned char easy_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
|
||||
0x00, 0x00, 0x00, 0xc0, 0xf0, 0x00, 0x00, 0xf0, 0x10, 0x00, 0x00, 0xfc,
|
||||
0x50, 0x6d, 0x09, 0xff, 0x10, 0x2c, 0xc5, 0xff, 0x10, 0x4b, 0x06, 0xff,
|
||||
0xf0, 0x7e, 0x02, 0xfc, 0x00, 0x00, 0x02, 0xf0, 0x00, 0x00, 0x00, 0xc0,
|
||||
0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
static unsigned char medium_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x22, 0x40, 0x01, 0x00, 0x66, 0x40, 0x00, 0x00,
|
||||
0xaa, 0x75, 0xd5, 0x0f, 0xda, 0x4f, 0x61, 0x08, 0x82, 0x48, 0x45, 0x09,
|
||||
0x42, 0x77, 0x5d, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00,
|
||||
0x00, 0xe0, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, 0xf0, 0x01, 0x00,
|
||||
0x00, 0xf8, 0x03, 0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, 0xfc, 0x07, 0x00,
|
||||
0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe, 0x0f, 0x00 };
|
||||
|
||||
static unsigned char hard_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00, 0x1f, 0x40, 0x00, 0x20, 0x7f, 0x40, 0x04, 0x20,
|
||||
0xff, 0x41, 0xbb, 0x3b, 0xff, 0x43, 0x62, 0x24, 0xff, 0x41, 0x8c, 0x24,
|
||||
0x7f, 0x40, 0xb8, 0x38, 0x1f, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
static unsigned char insane_bits[] = {
|
||||
0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfc, 0x07, 0x00,
|
||||
0x00, 0xf8, 0x03, 0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, 0xf0, 0x01, 0x00,
|
||||
0x00, 0xf0, 0x01, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00,
|
||||
0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xc0, 0xdd, 0x9d, 0x03,
|
||||
0x50, 0x84, 0xa5, 0x03, 0x50, 0x52, 0x65, 0x00, 0x58, 0xdc, 0xa5, 0x03,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
static unsigned char menu_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00, 0x1f, 0x10, 0x01, 0x00, 0x7f, 0x30, 0x01, 0x00,
|
||||
0xff, 0xb1, 0xdd, 0x25, 0xff, 0x53, 0x5d, 0x26, 0xff, 0x11, 0x44, 0x4a,
|
||||
0x7f, 0x10, 0x5d, 0x3a, 0x1f, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
static unsigned char replay_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
|
||||
0x00, 0x00, 0x00, 0xc0, 0x07, 0x20, 0x00, 0xf0, 0x09, 0x20, 0x00, 0xfc,
|
||||
0xe9, 0xae, 0x4b, 0xff, 0xe7, 0x32, 0xeb, 0xff, 0x15, 0xb2, 0x34, 0xff,
|
||||
0xe9, 0xae, 0x13, 0xfc, 0x00, 0x02, 0x10, 0xf0, 0x00, 0x00, 0x00, 0xc0,
|
||||
0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
|
||||
|
||||
//----------Initializing Variables----------//
|
||||
static unsigned long dinoTimeToMove = 0; //Used to space out time(millis) between draws/moves
|
||||
static unsigned long dinoTimeToDraw = 0;
|
||||
|
||||
static int score;
|
||||
static int highScore = 0;
|
||||
static int multiplier; //Score multiplier
|
||||
|
||||
//bool ignoreRepeat = false; //Avoid Switch Bouncing
|
||||
static long compensation; //To compensate for the amount of time the Arduino has been running for after each run (essentially "resets" the time)
|
||||
static bool gameOver;
|
||||
static bool menu = true;
|
||||
|
||||
static bool down, jump; //Boolean values to check the state of the dinosaur
|
||||
// static int dinoSwitch; //Switch between dino bitmaps to simulate movement
|
||||
static int dinoY, cactiX1, cactiX2; //Positions of objects
|
||||
static int velocity; //Speed of entire game
|
||||
static int difficulty; //How fast the velocity increases
|
||||
|
||||
|
||||
//--------------------Functions--------------------//
|
||||
|
||||
//Set/Reset Loop for Playing Again
|
||||
void reset(){
|
||||
compensation = millis();
|
||||
gameOver = false;
|
||||
down = false;
|
||||
jump = false;
|
||||
// dinoSwitch = true;
|
||||
dinoY = 44;
|
||||
cactiX1 = 130;
|
||||
cactiX2 = cactiX1 + random(70, 120);
|
||||
velocity = 2;
|
||||
}
|
||||
|
||||
//Deteching Joystick Interaction
|
||||
void keyPress(xpItem item)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
if(item->state == MENU_UP)temp = DOWN;
|
||||
if(item->state == MENU_DOWN)temp = UP;
|
||||
if(menu & (temp != 0))
|
||||
{
|
||||
reset();
|
||||
menu = false;
|
||||
if(temp == DOWN)
|
||||
{
|
||||
difficulty = 7500;
|
||||
multiplier = 15000 / difficulty;
|
||||
}
|
||||
if(temp == UP)
|
||||
{
|
||||
difficulty = 2500;
|
||||
multiplier = 15000 / difficulty;
|
||||
}
|
||||
}
|
||||
else if ( gameOver && (temp!=0) ) { //Left -> PlayAgain // Right -> Menu
|
||||
//ignoreRepeat = false;
|
||||
reset();
|
||||
if ( temp == UP ) menu = true; //Pushing Down
|
||||
}
|
||||
else if ( dinoY == 44 && temp == DOWN ) { //Corresponds to pushing up on the joystick
|
||||
jump = true;
|
||||
down = true;
|
||||
}
|
||||
}
|
||||
|
||||
//Collision Detecting and Setting HighScore
|
||||
void collision(void)
|
||||
{
|
||||
if ( cactiX1 <= 23 && cactiX1 + smallcactus_width >= 15 && dinoY+20 >= 50 ) {
|
||||
if ( (millis()-compensation)*multiplier/250 > highScore && !gameOver ) highScore = (millis()-compensation)*multiplier/250; //Changes highscore if current score is greater
|
||||
gameOver = true;
|
||||
}
|
||||
}
|
||||
|
||||
void moveDino(void)
|
||||
{
|
||||
if ( dinoY > 44 ) dinoY = 44; //Resets dinosaur to it passes it
|
||||
if ( jump || dinoY <= 43 ) { //Allows jumping if on the ground
|
||||
jump = false;
|
||||
if ( dinoY >= 16 && down ) dinoY -= velocity; //Going up
|
||||
else { //Going down
|
||||
down = false;
|
||||
dinoY += velocity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void moveCactus(void)
|
||||
{
|
||||
cactiX1 -= velocity;
|
||||
cactiX2 -= velocity;
|
||||
if ( cactiX1 <= -15 ) { //Once cacti reaches left side of screen, resets to right side of screen
|
||||
cactiX1 = cactiX2;
|
||||
cactiX2 = cactiX1 + random(70, 150);
|
||||
}
|
||||
}
|
||||
|
||||
//-------Move Functions-------//
|
||||
void moveObjects(void)
|
||||
{
|
||||
if( millis() > dinoTimeToMove+50 )
|
||||
{ //Updates every 50 milliseconds
|
||||
velocity = (millis()-compensation)/difficulty + 2; //Increases velocity as game progresses
|
||||
moveDino();
|
||||
moveCactus();
|
||||
dinoTimeToMove = millis();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------Draw Functions-------//
|
||||
void drawDinoCactus(void)
|
||||
{
|
||||
if ( dinoY < 44 ) u8g2_DrawXBM(&u8g2, 10, dinoY, standing_width, standing_height, standing_bits); //While jumping don't change bitmap
|
||||
else if ( (millis()-compensation) % 16 > 9 ) u8g2_DrawXBM(&u8g2, 10, dinoY, frontLeg_width, frontLeg_height, frontLeg_bits); //Switch between bitmaps every 9 millis
|
||||
else u8g2_DrawXBM(&u8g2, 10, dinoY, backLeg_width, backLeg_height, backLeg_bits);
|
||||
u8g2_DrawXBM(&u8g2, cactiX1, 47, smallcactus_width, smallcactus_height, smallcactus_bits); //Draw cacti
|
||||
u8g2_DrawXBM(&u8g2, cactiX2, 47, smallcactus_width, smallcactus_height, smallcactus_bits);
|
||||
}
|
||||
|
||||
void drawScore(void)
|
||||
{
|
||||
char scoreBuff[50];
|
||||
if ( menu ) { //Print highscore on menu screen
|
||||
score = highScore;
|
||||
snprintf(scoreBuff, 50, "HighS: %d", score);
|
||||
}
|
||||
else if ( !gameOver )
|
||||
{ //Increments score ONLY while playing
|
||||
score = (millis() - compensation) / 250;
|
||||
snprintf(scoreBuff, 50, "Score: %d", score);
|
||||
}
|
||||
u8g2_SetFont(&u8g2, MENU_FONT);
|
||||
u8g2_DrawStr(&u8g2, 55, 8, scoreBuff );
|
||||
}
|
||||
|
||||
//Draws Game Over Screen
|
||||
void playAgain(void)
|
||||
{
|
||||
u8g2_DrawXBM(&u8g2, 14, 14, gameover_width, gameover_height, gameover_bits);
|
||||
u8g2_DrawXBM(&u8g2, 23, 30, replay_width, replay_height, replay_bits);
|
||||
u8g2_DrawXBM(&u8g2, 70, 30, menu_width, menu_height, menu_bits);
|
||||
}
|
||||
|
||||
//Draws Menu Screen
|
||||
void menuScreen(void)
|
||||
{
|
||||
u8g2_DrawXBM(&u8g2, 26, 30, easy_width, easy_height, easy_bits);
|
||||
u8g2_DrawXBM(&u8g2, 49, 12, medium_width, medium_height, medium_bits);
|
||||
u8g2_DrawXBM(&u8g2, 69, 30, hard_width, hard_height, hard_bits);
|
||||
u8g2_DrawXBM(&u8g2, 49, 43, insane_width, insane_height, insane_bits);
|
||||
}
|
||||
|
||||
void draw_DinoGame(void)
|
||||
{
|
||||
if( millis() > dinoTimeToDraw + 25 ){ //Draws every 25 milliseconds
|
||||
do {
|
||||
drawDinoCactus();
|
||||
drawScore();
|
||||
if ( menu ) menuScreen(); //Draw Menu Screen
|
||||
else if ( gameOver ) playAgain(); //Draw Game Over Screen
|
||||
} while( u8g2_NextPage(&u8g2) );
|
||||
dinoTimeToDraw = millis();
|
||||
}
|
||||
}
|
||||
/*!
|
||||
* @brief DinoGame_Task function
|
||||
*/
|
||||
void DinoGame_Run(xpItem item)
|
||||
{
|
||||
static uint8_t Dino_IntoState=false;
|
||||
if(Dino_IntoState==false)
|
||||
{
|
||||
/* set systick and start systick interrupt */
|
||||
SysTick_Config(SystemCoreClock/SYS_TICK_PER_SECOND);
|
||||
//u8g2_SetFont(&u8g2, u8g2_font_helvB08_tr);
|
||||
u8g2_SetFont(&u8g2, MENU_FONT);
|
||||
u8g2_SetFontDirection(&u8g2, 0);
|
||||
u8g2_SetFontRefHeightAll(&u8g2);
|
||||
reset();
|
||||
Dino_IntoState=true;
|
||||
}
|
||||
|
||||
u8g2_FirstPage(&u8g2);
|
||||
keyPress(item);
|
||||
if ( (!gameOver) && (!menu) )
|
||||
{
|
||||
moveObjects();
|
||||
}
|
||||
draw_DinoGame();
|
||||
collision();
|
||||
}
|
||||
12
Middlewares/MultMenu/application/DinoGame.h
Normal file
12
Middlewares/MultMenu/application/DinoGame.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef _DinoGame_H
|
||||
#define _DinoGame_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h> // rand
|
||||
#include "application.h"
|
||||
|
||||
void DinoGame_Run(xpItem item);
|
||||
|
||||
#endif
|
||||
799
Middlewares/MultMenu/application/application.c
Normal file
799
Middlewares/MultMenu/application/application.c
Normal file
@ -0,0 +1,799 @@
|
||||
#include "application.h"
|
||||
#include "dispDirver.h"
|
||||
#include "main.h"
|
||||
#include "e32_hal.h"
|
||||
#include "usart.h"
|
||||
|
||||
/**
|
||||
* 菜单 Setting > Work Mode 对应的工作模式显示名称
|
||||
*/
|
||||
static const char *mode_name[4] = {"Transparent","WOR Master ","WOR Slave ","Sleep "};
|
||||
|
||||
/**
|
||||
* 菜单 Setting > Rate Mode 对应的空速显示名称
|
||||
*/
|
||||
static const char *rate_name[8] = {" 2.4"," 2.4"," 2.4"," 4.8"," 9.6","19.2","19.2","19.2"};
|
||||
|
||||
/**
|
||||
* 菜单 Setting > 参数默认显示值
|
||||
*/
|
||||
menu_config_t user_config =
|
||||
{
|
||||
.work_mode = 3, // 工作模式
|
||||
.rate_mode = 2, // 空速模式 挡位选择
|
||||
.channel = 23, // 通信信道
|
||||
.tx_power = 30, // 发射功率 挡位选择
|
||||
.tx_count = 10, // 数据发送测试总次数
|
||||
};
|
||||
|
||||
/**
|
||||
* 注意为xbm格式数据 可以使用网络在线工具转换 https://convertio.co/zh/xbm-converter/
|
||||
*/
|
||||
static const unsigned char ebyte_logo[861] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,
|
||||
0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x70, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00,
|
||||
0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x80, 0x9C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x06, 0x18, 0x00, 0x00, 0x60, 0xC0, 0x01, 0x00, 0xC0, 0x26, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x0C, 0x00, 0x00, 0x60, 0x80, 0x01, 0x00,
|
||||
0x40, 0x26, 0x01, 0x00, 0x00, 0x00, 0x80, 0x01, 0x06, 0x00, 0x00, 0xC0,
|
||||
0x00, 0x03, 0x00, 0x40, 0x1E, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x03,
|
||||
0x03, 0x80, 0x81, 0x01, 0x07, 0x00, 0x40, 0x16, 0x01, 0x00, 0x00, 0x00,
|
||||
0xC0, 0x80, 0x83, 0x03, 0x80, 0x03, 0x03, 0x06, 0x00, 0xC0, 0x36, 0x01,
|
||||
0x00, 0x00, 0x00, 0x60, 0xC0, 0xC1, 0x01, 0x00, 0x07, 0x07, 0x0C, 0x00,
|
||||
0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x60, 0xC0, 0xC0, 0x00, 0x00, 0x06,
|
||||
0x06, 0x0C, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x60, 0xC0, 0x60,
|
||||
0xC0, 0x07, 0x0C, 0x06, 0x0C, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00,
|
||||
0x60, 0xC0, 0x60, 0xC0, 0x0F, 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x30, 0x60, 0x60, 0xE0, 0x0F, 0x08, 0x0C, 0x18, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0x20, 0xE0, 0x0F, 0x18,
|
||||
0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0x20,
|
||||
0xE0, 0x0F, 0x18, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x30, 0x60, 0x60, 0xC0, 0x0F, 0x18, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x20, 0x40, 0x60, 0x80, 0x03, 0x0C, 0x0C, 0x18, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xC0, 0x60, 0x00, 0x00, 0x0C,
|
||||
0x06, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xC0, 0xC0,
|
||||
0x00, 0x00, 0x06, 0x06, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x60, 0x80, 0xC1, 0x01, 0x00, 0x06, 0x07, 0x0C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xC0, 0x80, 0x83, 0x03, 0x80, 0x03, 0x03, 0x0E, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x03, 0x03, 0x80, 0x81,
|
||||
0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x06,
|
||||
0xC0, 0x07, 0xC0, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x03, 0x0C, 0xC0, 0x07, 0xE0, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xC0, 0x07, 0x00, 0x80, 0x01, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0xC0, 0x07, 0x00,
|
||||
0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00,
|
||||
0xC0, 0x07, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x0F, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xE7, 0xFF, 0x3F, 0xF0, 0x03, 0xE0, 0xCF, 0xFF, 0xFF, 0xCF,
|
||||
0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0xE0, 0x07, 0xE0, 0xC7,
|
||||
0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0xC1,
|
||||
0x0F, 0xF0, 0xC3, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x01, 0x3F, 0x00, 0xC0,
|
||||
0x07, 0xF8, 0xC3, 0x0F, 0xF8, 0x01, 0xC0, 0x0F, 0xC0, 0x0F, 0x00, 0x00,
|
||||
0x1F, 0x00, 0xC0, 0x07, 0xF0, 0x83, 0x1F, 0xFC, 0x00, 0xC0, 0x0F, 0xC0,
|
||||
0x07, 0x00, 0x00, 0x3F, 0x00, 0xC0, 0x07, 0xF0, 0x01, 0x3F, 0x7E, 0x00,
|
||||
0xC0, 0x0F, 0xC0, 0x07, 0x00, 0x00, 0x3F, 0x00, 0xE0, 0x07, 0xFC, 0x00,
|
||||
0x7E, 0x3E, 0x00, 0xC0, 0x0F, 0xC0, 0x0F, 0x00, 0x00, 0xFF, 0xFF, 0xC3,
|
||||
0xFF, 0x3F, 0x00, 0xFC, 0x1F, 0x00, 0xC0, 0x0F, 0xC0, 0xFF, 0xFF, 0x00,
|
||||
0xFF, 0xFF, 0xC3, 0xFF, 0x3F, 0x00, 0xF8, 0x0F, 0x00, 0xC0, 0x0F, 0xC0,
|
||||
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0x01, 0xF0, 0x07, 0x00,
|
||||
0xC0, 0x0F, 0xC0, 0xFF, 0xFF, 0x00, 0x3F, 0x00, 0xC0, 0x07, 0xF0, 0x03,
|
||||
0xE0, 0x03, 0x00, 0xC0, 0x0F, 0xC0, 0x07, 0x00, 0x00, 0x3F, 0x00, 0xC0,
|
||||
0x07, 0xE0, 0x03, 0xE0, 0x03, 0x00, 0xC0, 0x0F, 0xC0, 0x07, 0x00, 0x00,
|
||||
0x3F, 0x00, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x03, 0x00, 0xC0, 0x0F, 0xC0,
|
||||
0x07, 0x00, 0x00, 0x3F, 0x00, 0xC0, 0x07, 0xF0, 0x03, 0xE0, 0x03, 0x00,
|
||||
0xC0, 0x0F, 0xC0, 0x07, 0x00, 0x00, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0x03,
|
||||
0xE0, 0x03, 0x00, 0xC0, 0x0F, 0xC0, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xC7,
|
||||
0xFF, 0xFF, 0x01, 0xE0, 0x03, 0x00, 0xC0, 0x0F, 0xC0, 0xFF, 0xFF, 0x01,
|
||||
0xFF, 0xFF, 0xC7, 0xFF, 0x7F, 0x00, 0xE0, 0x03, 0x00, 0xC0, 0x0F, 0xC0,
|
||||
0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, };
|
||||
|
||||
/**
|
||||
* Tx Mode 数据发送测试 过程状态
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
TX_MODE_INIT = 0,
|
||||
TX_MODE_SEND,
|
||||
TX_MODE_WAIT,
|
||||
TX_MODE_END,
|
||||
}tx_state_t;
|
||||
|
||||
/**
|
||||
* Rx Mode 数据接收测试 过程状态
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
RX_MODE_INIT = 0,
|
||||
RX_MODE_RECV,
|
||||
RX_MODE_WAIT,
|
||||
RX_MODE_END,
|
||||
}rx_state_t;
|
||||
|
||||
/**
|
||||
* Rx Mode 数据接收测试 提示光标状态
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
HINT_WAIT = 0,
|
||||
HINT_DONE,
|
||||
}hint_state_t;
|
||||
|
||||
/**
|
||||
* Version 版本信息显示 过程状态
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
VERSION_START = 0,
|
||||
VERSION_WAIT,
|
||||
VERSION_END
|
||||
}version_state_t;
|
||||
|
||||
/**
|
||||
* @brief 菜单 进入首页
|
||||
*
|
||||
* @param item 指向项目状态的指针
|
||||
*/
|
||||
void logo_callback( xpItem item )
|
||||
{
|
||||
OLED_ClearBuffer();
|
||||
OLED_DrawXBMP(4, 6, 118, 57, ebyte_logo);
|
||||
OLED_SendBuffer();
|
||||
switch (item->state)
|
||||
{
|
||||
case MENU_UP:
|
||||
case MENU_DOWN:
|
||||
item->state = MENU_ENTER;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 菜单三级页面 模组工作模式设定 Setting > Work Mode
|
||||
*
|
||||
* @param item 指向项目状态的指针
|
||||
*/
|
||||
void work_mode_callback( xpItem item)
|
||||
{
|
||||
char value[20] = {0};
|
||||
int scrollbar_min = 0;
|
||||
int scrollbar_max = 3;
|
||||
|
||||
if (DialogScale_Show(0, 0, 127, 63))
|
||||
{
|
||||
switch (item->state)
|
||||
{
|
||||
case MENU_UP:
|
||||
(*item->data.ptr) = Draw_Scrollbar(8, 50, 111, 6, 0, scrollbar_min, scrollbar_max, 1, (*item->data.ptr));
|
||||
e32_hal_work_mode( (work_mode_t)(*item->data.ptr) );
|
||||
break;
|
||||
case MENU_DOWN:
|
||||
(*item->data.ptr) = Draw_Scrollbar(8, 50, 111, 6, 0, scrollbar_min, scrollbar_max, -1, (*item->data.ptr));
|
||||
e32_hal_work_mode( (work_mode_t)(*item->data.ptr) );
|
||||
break;
|
||||
default:
|
||||
Draw_Scrollbar(8, 50, 111, 6, 0, scrollbar_min, scrollbar_max, 0, (*item->data.ptr));
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf(value, "Mode: %d ", (*item->data.ptr));
|
||||
OLED_DrawStr(8, 25, value);
|
||||
sprintf(value, "%s", mode_name[(*item->data.ptr)]);
|
||||
OLED_DrawStr(8, 40, value);
|
||||
OLED_SendBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 菜单三级页面 模组通信空速设定 Setting > Rate Mode
|
||||
*
|
||||
* @param item 指向项目状态的指针
|
||||
*/
|
||||
void rate_mode_callback( xpItem item )
|
||||
{
|
||||
char value[20] = {0};
|
||||
int scrollbar_min = 2;
|
||||
int scrollbar_max = 5;
|
||||
|
||||
|
||||
if (DialogScale_Show(0, 0, 127, 63))
|
||||
{
|
||||
switch (item->state)
|
||||
{
|
||||
case MENU_UP:
|
||||
(*item->data.ptr) = Draw_Scrollbar(8, 50, 111, 6, 0, scrollbar_min, scrollbar_max, 1, (*item->data.ptr));
|
||||
break;
|
||||
case MENU_DOWN:
|
||||
(*item->data.ptr) = Draw_Scrollbar(8, 50, 111, 6, 0, scrollbar_min, scrollbar_max, -1, (*item->data.ptr));
|
||||
break;
|
||||
default:
|
||||
Draw_Scrollbar(8, 50, 111, 6, 0, scrollbar_min, scrollbar_max, 0, (*item->data.ptr));
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf(value, "Rate: %d ", (*item->data.ptr));
|
||||
OLED_DrawStr(8, 25, value);
|
||||
|
||||
sprintf(value, "%s Kbps", rate_name[(*item->data.ptr)]);
|
||||
OLED_DrawStr(8, 40, value);
|
||||
OLED_SendBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 菜单三级页面 模组通信信道设定 Setting > Channel
|
||||
*
|
||||
* @param item 指向项目状态的指针
|
||||
*/
|
||||
void channel_callback( xpItem item)
|
||||
{
|
||||
char value[20] = {0};
|
||||
int scrollbar_min = 0;
|
||||
int scrollbar_max = 41;
|
||||
|
||||
if (DialogScale_Show(0, 0, 127, 63))
|
||||
{
|
||||
|
||||
switch (item->state)
|
||||
{
|
||||
case MENU_UP:
|
||||
(*item->data.ptr) = Draw_Scrollbar(8, 50, 111, 6, 0, scrollbar_min, scrollbar_max, 1, (*item->data.ptr));
|
||||
break;
|
||||
case MENU_DOWN:
|
||||
(*item->data.ptr) = Draw_Scrollbar(8, 50, 111, 6, 0, scrollbar_min, scrollbar_max, -1, (*item->data.ptr));
|
||||
break;
|
||||
case MENU_ENTER:
|
||||
key_set_continue( KEY_NAME_UP, false );
|
||||
key_set_continue( KEY_NAME_DOWN, false );
|
||||
break;
|
||||
default:
|
||||
Draw_Scrollbar(8, 50, 111, 6, 0, scrollbar_min, scrollbar_max, 0, (*item->data.ptr));
|
||||
key_set_continue( KEY_NAME_UP, true );
|
||||
key_set_continue( KEY_NAME_DOWN, true );
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf(value, "Channel: %d ", (*item->data.ptr));
|
||||
OLED_DrawStr(8, 25, value);
|
||||
|
||||
sprintf(value, "%d MHz", ((*item->data.ptr) + 410 ));
|
||||
OLED_DrawStr(8, 40, value);
|
||||
OLED_SendBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 菜单三级页面 模组发射功率设定 Setting > TX Power
|
||||
*
|
||||
* @param item 指向项目状态的指针
|
||||
*/
|
||||
void tx_power_callback( xpItem item)
|
||||
{
|
||||
char value[20] = {0};
|
||||
int power_convert[4] = { 30, 27, 24, 21 };
|
||||
int scrollbar_min = 0;
|
||||
int scrollbar_max = 3;
|
||||
|
||||
/* 默认对应 power_convert 中的 30 */
|
||||
static int scrollbar_value = 0;
|
||||
|
||||
if (DialogScale_Show(0, 0, 127, 63))
|
||||
{
|
||||
|
||||
switch (item->state)
|
||||
{
|
||||
case MENU_UP:
|
||||
scrollbar_value = Draw_Scrollbar(8, 30, 111, 6, 0, scrollbar_min, scrollbar_max, 1, scrollbar_value);
|
||||
(*item->data.ptr) = power_convert[ scrollbar_value ];
|
||||
break;
|
||||
case MENU_DOWN:
|
||||
scrollbar_value = Draw_Scrollbar(8, 30, 111, 6, 0, scrollbar_min, scrollbar_max, -1, scrollbar_value);
|
||||
(*item->data.ptr) = power_convert[ scrollbar_value ];
|
||||
break;
|
||||
case MENU_ENTER:
|
||||
break;
|
||||
default:
|
||||
Draw_Scrollbar(8, 30, 111, 6, 0, scrollbar_min, scrollbar_max, 0, scrollbar_value);
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf(value, "Power: %d dBm", (*item->data.ptr));
|
||||
OLED_DrawStr(8, 25, value);
|
||||
OLED_SendBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 菜单三级页面 模组通信测试数据发射次数设定 Setting > TX Count
|
||||
*
|
||||
* @param item 指向项目状态的指针
|
||||
*/
|
||||
void tx_count_callback( xpItem item)
|
||||
{
|
||||
char value[20] = {0};
|
||||
int scrollbar_min = 10;
|
||||
int scrollbar_max = 100;
|
||||
|
||||
if (DialogScale_Show(0, 0, 127, 63))
|
||||
{
|
||||
|
||||
switch (item->state)
|
||||
{
|
||||
case MENU_UP:
|
||||
(*item->data.ptr) = Draw_Scrollbar(8, 30, 111, 6, 0, scrollbar_min, scrollbar_max, 10, (*item->data.ptr));
|
||||
break;
|
||||
case MENU_DOWN:
|
||||
(*item->data.ptr) = Draw_Scrollbar(8, 30, 111, 6, 0, scrollbar_min, scrollbar_max, -10, (*item->data.ptr));
|
||||
break;
|
||||
default:
|
||||
Draw_Scrollbar(8, 30, 111, 6, 0, scrollbar_min, scrollbar_max, 0, (*item->data.ptr));
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf(value, "Count: %d ", (*item->data.ptr));
|
||||
OLED_DrawStr(8, 25, value);
|
||||
OLED_SendBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 菜单三级页面 显示背景色设定 Setting > Back Color
|
||||
*
|
||||
* @param item 指向项目状态的指针
|
||||
*/
|
||||
void background_color_callback( xpItem item )
|
||||
{
|
||||
Set_BgColor(item->switchState);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tx Mode 数据发送测试 构造发送数据
|
||||
*
|
||||
* @param send_count 当前发送计数
|
||||
*/
|
||||
static void tx_e32_send( int send_count )
|
||||
{
|
||||
char value[30] = {0};
|
||||
uint8_t tx_length = 0;
|
||||
|
||||
gpio_led_tx_on();
|
||||
|
||||
tx_length = sprintf( value, "TX.%03d.%03d.", user_config.tx_count , send_count );
|
||||
e32_demo_transmit( (uint8_t*)value , tx_length + 1);
|
||||
|
||||
///@note 此时并不代表已发送完成
|
||||
gpio_led_tx_off();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tx Mode 数据发送测试 发送过程显示
|
||||
*
|
||||
* @param send_count 当前发送计数
|
||||
*/
|
||||
static void tx_display_count( int send_count )
|
||||
{
|
||||
char value[30] = {0};
|
||||
uint8_t bg_color;
|
||||
|
||||
|
||||
/* 如果进入页面后第一次 则刷新全部显示信息 */
|
||||
if( send_count == 0 )
|
||||
{
|
||||
/* display refresh */
|
||||
bg_color = Get_BgColor();
|
||||
|
||||
OLED_ClearBuffer();
|
||||
OLED_SetDrawColor(bg_color);
|
||||
OLED_DrawBox(0, 0, 128, 64);
|
||||
OLED_SetDrawColor(bg_color^0x01);
|
||||
|
||||
sprintf(value, "Channel:%d %dMHz ",user_config.channel,(user_config.channel+410));
|
||||
OLED_DrawStr(0, Font_Size*1, value );
|
||||
|
||||
OLED_DrawLine(0, Font_Size*1+3,127,Font_Size*1+3 );
|
||||
|
||||
sprintf(value, "Rate:%sK Pwr:%ddBm", rate_name[user_config.rate_mode] ,user_config.tx_power);
|
||||
OLED_DrawStr(0, Font_Size*2+3, value);
|
||||
|
||||
OLED_DrawLine(0, Font_Size*2+6,127,Font_Size*2+6 );
|
||||
|
||||
|
||||
sprintf(value, "Tx Total :%d", user_config.tx_count);
|
||||
OLED_DrawStr(0, Font_Size*3+9, value);
|
||||
}
|
||||
|
||||
/* 如果是最后一次发送 */
|
||||
if( send_count == user_config.tx_count )
|
||||
{
|
||||
OLED_DrawStr(0, Font_Size*3+9, "Tx Done ! ");
|
||||
OLED_DrawStr(0, Font_Size*4+9, "Press DOWN button");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(value, "Tx Number:%d", send_count);
|
||||
OLED_DrawStr(0, Font_Size*4+9, value);
|
||||
}
|
||||
|
||||
OLED_SendBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 菜单二级页面 模组发送测试 Tx Mode
|
||||
*
|
||||
* @param item 指向项目状态的指针
|
||||
*/
|
||||
void tx_mode_callback( xpItem item )
|
||||
{
|
||||
current_feature = FUNC_FEATURE2;
|
||||
static uint32_t send_count = 0; // 改为uint32_t防止溢出
|
||||
static tx_state_t tx_state = TX_MODE_END;
|
||||
|
||||
switch (item->state)
|
||||
{
|
||||
case MENU_UP:
|
||||
break;
|
||||
case MENU_DOWN:
|
||||
/* 按下DOWN键,触发一次发送 */
|
||||
if( tx_state == TX_MODE_SEND || tx_state == TX_MODE_WAIT )
|
||||
{
|
||||
send_count++;
|
||||
tx_display_count( send_count );
|
||||
tx_e32_send(send_count);
|
||||
}
|
||||
break;
|
||||
case MENU_ENTER:
|
||||
/* 结束 */
|
||||
tx_state = TX_MODE_END;
|
||||
|
||||
break;
|
||||
default:
|
||||
/* 开始 */
|
||||
if( tx_state == TX_MODE_END )
|
||||
{
|
||||
tx_state = TX_MODE_INIT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch( tx_state )
|
||||
{
|
||||
case TX_MODE_INIT:
|
||||
tx_display_count( 0 );
|
||||
e32_demo_menu_config( &user_config );
|
||||
send_count = 0;
|
||||
tx_display_count( send_count );
|
||||
tx_state = TX_MODE_SEND;
|
||||
break;
|
||||
|
||||
case TX_MODE_SEND:
|
||||
/* 等待用户按键触发发送,不再自动发送 */
|
||||
break;
|
||||
|
||||
case TX_MODE_WAIT:
|
||||
/* 等待用户按键 */
|
||||
break;
|
||||
|
||||
case TX_MODE_END:
|
||||
current_feature = FUNC_FEATURE1;
|
||||
default:
|
||||
tx_state = TX_MODE_END;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Rx Mode 数据接收测试 显示页面初始化
|
||||
*/
|
||||
static void rx_init_display(void)
|
||||
{
|
||||
char value[30] = {0};
|
||||
uint8_t bg_color;
|
||||
|
||||
bg_color = Get_BgColor();
|
||||
|
||||
OLED_ClearBuffer();
|
||||
OLED_SetDrawColor(bg_color);
|
||||
OLED_DrawBox(0, 0, 128, 64);
|
||||
OLED_SetDrawColor(bg_color^0x01);
|
||||
|
||||
sprintf(value, "Channel:%d %dMHz ",user_config.channel,(user_config.channel+410));
|
||||
OLED_DrawStr(0, Font_Size*1, value);
|
||||
|
||||
OLED_DrawLine(0, Font_Size*1+3,127,Font_Size*1+3 );
|
||||
|
||||
sprintf(value, "Rate:%sK",rate_name[user_config.rate_mode] );
|
||||
OLED_DrawStr(0, Font_Size*2+3, value );
|
||||
|
||||
OLED_DrawLine(0, Font_Size*2+6,127,Font_Size*2+6 );
|
||||
|
||||
|
||||
OLED_SendBuffer();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Rx Mode 数据接收测试 提示光标显示
|
||||
*
|
||||
* @param state 光标状态
|
||||
*/
|
||||
static void rx_hint( hint_state_t state )
|
||||
{
|
||||
static uint8_t hint_select = 0;
|
||||
static const char *hint[3]={"= ","== ","==="};
|
||||
|
||||
switch( state )
|
||||
{
|
||||
case HINT_WAIT:
|
||||
OLED_DrawStr(100, Font_Size*2+3, hint[hint_select++] );
|
||||
if(hint_select>2)
|
||||
{
|
||||
hint_select = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case HINT_DONE:
|
||||
OLED_DrawStr(100, Font_Size*2+3, "DONE" );
|
||||
break;
|
||||
}
|
||||
|
||||
OLED_SendBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Rx Mode 数据接收测试 无线数据包校验与数据解析
|
||||
*
|
||||
* @param buffer 执行接收数据缓存
|
||||
* @param length 接收数据长度
|
||||
* @param total_number 发送总数
|
||||
* @param current_number 当前包序号
|
||||
* @param rssi 数据包RSSI
|
||||
*/
|
||||
static bool rx_analysis( uint8_t *buffer , uint8_t length , uint32_t *total_number, uint32_t *current_number )
|
||||
{
|
||||
/* 长度至少10字节 */
|
||||
if( length < 10 )
|
||||
return false;
|
||||
|
||||
/* 帧头字符判断TX */
|
||||
if( buffer[0] != 'T' || buffer[1] != 'X' )
|
||||
return false;
|
||||
|
||||
/* 拆分出发送总计数与当前序号 */
|
||||
sscanf( ( char* )(buffer+3), "%d.%d.", total_number, current_number );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Rx Mode 数据接收测试 接收过程显示
|
||||
*
|
||||
* @param total_number 发送总数
|
||||
* @param current_number 但钱
|
||||
* @param rssi 数据包RSSI
|
||||
* @param lost_nubmer 已丢失数据包计数
|
||||
* @param lost_percent 已丢失数据包百分比
|
||||
*/
|
||||
static void rx_mode_display( uint32_t total_number , uint32_t current_number , uint32_t lost_nubmer , uint32_t lost_percent)
|
||||
{
|
||||
char value[30] = {0};
|
||||
|
||||
sprintf(value, "Total:%d ", total_number);
|
||||
OLED_DrawStr(0, Font_Size*3+5, value);
|
||||
|
||||
sprintf(value, "Current:%d ", current_number);
|
||||
OLED_DrawStr(60, Font_Size*3+5, value);
|
||||
|
||||
sprintf(value, "Lost :%d ", lost_nubmer);
|
||||
OLED_DrawStr(0, Font_Size*4+4, value);
|
||||
|
||||
sprintf(value, "Lost P%%:%d%% ", lost_percent);
|
||||
OLED_DrawStr(60, Font_Size*4+4, value);
|
||||
|
||||
OLED_SendBuffer();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief 菜单二级页面 模组通信测试数据发射次数设定 Rx Mode
|
||||
*
|
||||
* @param item 指向项目状态的指针
|
||||
*/
|
||||
void rx_mode_callback( xpItem item )
|
||||
{
|
||||
current_feature = FUNC_FEATURE2;
|
||||
static uint8_t rx_mode_buffer[255];
|
||||
static uint32_t rx_mode_length = 0;
|
||||
static rx_state_t rx_state = RX_MODE_INIT;
|
||||
static uint32_t tick_start;
|
||||
static uint32_t tx_number_record = 0;
|
||||
static uint32_t tx_total_number = 0;
|
||||
static uint32_t rx_count = 0; // 改为uint32_t防止溢出
|
||||
uint32_t tx_current_number = 0;
|
||||
|
||||
switch (item->state)
|
||||
{
|
||||
case MENU_UP:
|
||||
break;
|
||||
case MENU_DOWN:
|
||||
/* 再次开始 */
|
||||
if( rx_state == RX_MODE_WAIT )
|
||||
{
|
||||
rx_state = RX_MODE_INIT;
|
||||
}
|
||||
break;
|
||||
case MENU_ENTER:
|
||||
/* 结束 */
|
||||
rx_state = RX_MODE_END;
|
||||
|
||||
break;
|
||||
default:
|
||||
/* 开始 */
|
||||
if( rx_state == RX_MODE_END )
|
||||
{
|
||||
rx_state = RX_MODE_INIT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch( rx_state )
|
||||
{
|
||||
case RX_MODE_INIT:
|
||||
rx_init_display();
|
||||
e32_demo_menu_config( &user_config );
|
||||
tick_start = HAL_GetTick();
|
||||
rx_count = 0;
|
||||
tx_number_record = 0;
|
||||
rx_state = RX_MODE_RECV;
|
||||
break;
|
||||
|
||||
case RX_MODE_RECV:
|
||||
if( uart1_check_rx_done(rx_mode_buffer, &rx_mode_length) == true)
|
||||
{
|
||||
if( rx_analysis( rx_mode_buffer , rx_mode_length , &tx_total_number, &tx_current_number ) == true )
|
||||
{
|
||||
gpio_led_rx_on();
|
||||
|
||||
/* 其他情况,可能是发送端重新开始了,需要重新计数 */
|
||||
if( tx_number_record >= tx_current_number)
|
||||
{
|
||||
rx_count = 0;
|
||||
}
|
||||
|
||||
tx_number_record = tx_current_number;
|
||||
|
||||
/* 有效接收计数 */
|
||||
rx_count++;
|
||||
|
||||
rx_mode_display(tx_total_number,tx_current_number,(tx_number_record-rx_count), ((tx_number_record-rx_count)*100/tx_number_record));
|
||||
|
||||
// 注释掉自动完成判断,持续接收
|
||||
// if( tx_current_number == tx_total_number )
|
||||
// {
|
||||
// rx_state = RX_MODE_WAIT;
|
||||
// rx_hint( HINT_DONE );
|
||||
// }
|
||||
|
||||
gpio_led_rx_off();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (HAL_GetTick() - tick_start) > 1000 )
|
||||
{
|
||||
tick_start = HAL_GetTick();
|
||||
rx_hint( HINT_WAIT );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case RX_MODE_WAIT:
|
||||
/* 接收完成,等待用户按键 */
|
||||
break;
|
||||
|
||||
case RX_MODE_END:
|
||||
current_feature = FUNC_FEATURE1;
|
||||
default:
|
||||
rx_state = RX_MODE_END;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief 菜单二级页面 版本信息显示 Version
|
||||
*
|
||||
* @param item 指向项目状态的指针
|
||||
*/
|
||||
void version_callback( xpItem item )
|
||||
{
|
||||
current_feature = FUNC_FEATURE2;
|
||||
char e32_buffer[30] = {0};
|
||||
uint8_t opt_length = 0;
|
||||
static version_state_t version_state = VERSION_END;
|
||||
uint8_t bg_color;
|
||||
|
||||
switch (item->state)
|
||||
{
|
||||
case MENU_UP:
|
||||
break;
|
||||
case MENU_DOWN:
|
||||
break;
|
||||
case MENU_ENTER:
|
||||
/* 离开 */
|
||||
version_state = VERSION_END;
|
||||
break;
|
||||
default:
|
||||
/* 进入 */
|
||||
if( version_state == VERSION_END )
|
||||
{
|
||||
version_state = VERSION_START;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch( version_state )
|
||||
{
|
||||
case VERSION_START:
|
||||
bg_color = Get_BgColor();
|
||||
|
||||
OLED_ClearBuffer();
|
||||
OLED_SetDrawColor(bg_color);
|
||||
OLED_DrawBox(0, 0, 128, 64);
|
||||
OLED_SendBuffer();
|
||||
|
||||
OLED_SetDrawColor(bg_color^0x01);
|
||||
OLED_DrawStr(0, Font_Size*1, "Model Type:");
|
||||
|
||||
e32_demo_read_device_name( e32_buffer , &opt_length );
|
||||
OLED_DrawStr(8, Font_Size*2, e32_buffer + 8);
|
||||
OLED_DrawLine(0, Font_Size*2+3,127,Font_Size*2+3 );
|
||||
|
||||
OLED_DrawStr(0, Font_Size*3+3, "Model Fireware:");
|
||||
e32_demo_read_fireware_version( e32_buffer , &opt_length );
|
||||
OLED_DrawStr(8, Font_Size*4+3, e32_buffer + 7);
|
||||
OLED_DrawLine(0, Font_Size*4+6,127,Font_Size*4+6 );
|
||||
|
||||
OLED_SendBuffer();
|
||||
|
||||
version_state = VERSION_WAIT;
|
||||
break;
|
||||
|
||||
case VERSION_WAIT:
|
||||
case VERSION_END:
|
||||
current_feature = FUNC_FEATURE1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 菜单二级页面 重启复位
|
||||
*
|
||||
* @param item 指向项目状态的指针
|
||||
*/
|
||||
void reset_callback( xpItem item )
|
||||
{
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
32
Middlewares/MultMenu/application/application.h
Normal file
32
Middlewares/MultMenu/application/application.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef _APPLICATION_H
|
||||
#define _APPLICATION_H
|
||||
|
||||
#include "menu.h"
|
||||
#include "menuConfig.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int work_mode;
|
||||
int rate_mode;
|
||||
int channel;
|
||||
int tx_power;
|
||||
int tx_count;
|
||||
}menu_config_t;
|
||||
|
||||
extern menu_config_t user_config;
|
||||
|
||||
void logo_callback( xpItem item );
|
||||
|
||||
void work_mode_callback( xpItem item );
|
||||
void rate_mode_callback( xpItem item );
|
||||
void channel_callback( xpItem item );
|
||||
void tx_power_callback( xpItem item);
|
||||
void tx_count_callback( xpItem item);
|
||||
void background_color_callback( xpItem item );
|
||||
|
||||
void tx_mode_callback( xpItem item );
|
||||
void rx_mode_callback( xpItem item );
|
||||
void version_callback( xpItem item );
|
||||
void reset_callback( xpItem item );
|
||||
|
||||
#endif
|
||||
281
Middlewares/MultMenu/disp/dispDirver.c
Normal file
281
Middlewares/MultMenu/disp/dispDirver.c
Normal file
@ -0,0 +1,281 @@
|
||||
#include "dispDirver.h"
|
||||
#include "u8g2.h"
|
||||
#include "u8g2_hal.h"
|
||||
#include "menuConfig.h"
|
||||
|
||||
u8g2_t u8g2;
|
||||
|
||||
/**
|
||||
* 初始化显示设备。
|
||||
* 该函数负责初始化OLED显示器,并设置默认字体。
|
||||
*
|
||||
* @无参数
|
||||
* @无返回值
|
||||
*/
|
||||
void Disp_Init(void)
|
||||
{
|
||||
// 初始化U8g2库,为OLED显示做准备
|
||||
u8g2Init(&u8g2);
|
||||
// 设置默认使用的字体为MENU_FONT
|
||||
OLED_SetFont(MENU_FONT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除OLED显示缓冲区
|
||||
*
|
||||
* 该函数用于清空OLED显示器的缓冲区,为新的显示内容做准备。
|
||||
*
|
||||
* 参数:
|
||||
* 无
|
||||
*
|
||||
* 返回值:
|
||||
* 无
|
||||
*/
|
||||
void OLED_ClearBuffer(void)
|
||||
{
|
||||
u8g2_ClearBuffer(&u8g2); // 清除OLED显示缓冲区的具体实现,使用u8g2库提供的函数。
|
||||
}
|
||||
|
||||
/**
|
||||
* 向OLED发送缓冲区数据
|
||||
* 该函数无参数。
|
||||
* 该函数无返回值。
|
||||
*/
|
||||
void OLED_SendBuffer(void)
|
||||
{
|
||||
/* 将U8G2实例的缓冲区数据发送到OLED设备 */
|
||||
u8g2_SendBuffer(&u8g2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字符串在OLED显示设备上的宽度。
|
||||
*
|
||||
* @param s 指向要测量的字符串的指针。
|
||||
* @return 返回字符串在OLED显示设备上的宽度,单位为像素。
|
||||
*/
|
||||
uint16_t OLED_GetStrWidth(const char *s)
|
||||
{
|
||||
// 调用u8g2库的函数,获取字符串s的宽度
|
||||
return u8g2_GetStrWidth(&u8g2, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置OLED的最大剪辑窗口
|
||||
* 该函数无参数。
|
||||
* 该函数无返回值。
|
||||
*/
|
||||
void OLED_SetMaxClipWindow(void)
|
||||
{
|
||||
u8g2_SetMaxClipWindow(&u8g2); // 调用u8g2库的函数设置最大的剪辑窗口
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置OLED显示器的字体。
|
||||
*
|
||||
* @param font 指向要使用的字体的指针。该字体必须是提前定义并可用的。
|
||||
*
|
||||
* 说明:这个函数通过调用u8g2的设置函数,来更改当前OLED显示的字体。
|
||||
*/
|
||||
void OLED_SetFont(const uint8_t *font)
|
||||
{
|
||||
u8g2_SetFont(&u8g2, font); // 设置U8g2实例的字体
|
||||
}
|
||||
|
||||
/**
|
||||
* 在OLED屏幕上绘制一个像素点
|
||||
*
|
||||
* @param x 像素点的x坐标
|
||||
* @param y 像素点的y坐标
|
||||
*
|
||||
* 该函数调用u8g2的DrawPixel函数,来在指定位置绘制一个像素点。
|
||||
*/
|
||||
void OLED_DrawPixel(uint16_t x, uint16_t y)
|
||||
{
|
||||
u8g2_DrawPixel(&u8g2, x, y); // 调用u8g2库的绘制像素点函数
|
||||
}
|
||||
|
||||
/**
|
||||
* 在OLED显示器上绘制一条线。
|
||||
*
|
||||
* @param x1 起始点的X坐标。
|
||||
* @param y1 起始点的Y坐标。
|
||||
* @param x2 终点的X坐标。
|
||||
* @param y2 终点的Y坐标。
|
||||
*
|
||||
* 该函数调用u8g2的DrawLine函数,使用给定的起始点和终点坐标在OLED显示器上绘制一条线。
|
||||
*/
|
||||
void OLED_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
|
||||
{
|
||||
u8g2_DrawLine(&u8g2, x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在OLED屏幕上绘制字符串
|
||||
*
|
||||
* @param x 字符串起始绘制的x坐标
|
||||
* @param y 字符串起始绘制的y坐标
|
||||
* @param str 要绘制的字符串
|
||||
* @return 绘制后的光标位置(一般为字符串的结束位置),具体返回值意义可能依赖于u8g2库的实现
|
||||
*/
|
||||
uint16_t OLED_DrawStr(uint16_t x, uint16_t y, const char *str)
|
||||
{
|
||||
// 调用u8g2库的DrawStr函数,在指定位置绘制字符串
|
||||
return u8g2_DrawStr(&u8g2, x, y, str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置OLED显示设备的绘制颜色。
|
||||
*
|
||||
* @param color 指定的绘制颜色,使用uint8_t类型表示。颜色的具体编码取决于OLED驱动库的实现。
|
||||
*
|
||||
* 该函数通过调用u8g2库的u8g2_SetDrawColor函数,来设置当前绘制的颜色。绘制颜色会影响后续所有绘制操作。
|
||||
*/
|
||||
void OLED_SetDrawColor(uint8_t color)
|
||||
{
|
||||
u8g2_SetDrawColor(&u8g2, color); // 调用u8g2库的函数设置绘制颜色
|
||||
}
|
||||
|
||||
/**
|
||||
* 在OLED屏幕上绘制一个框架。
|
||||
*
|
||||
* @param x 框架的起始x坐标。
|
||||
* @param y 框架的起始y坐标。
|
||||
* @param w 框架的宽度。
|
||||
* @param h 框架的高度。
|
||||
*
|
||||
* 该函数调用u8g2的绘制框架函数,用于在指定位置和尺寸上绘制一个框架。
|
||||
*/
|
||||
void OLED_DrawFrame(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
|
||||
{
|
||||
u8g2_DrawFrame(&u8g2, x, y, w, h);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在OLED屏幕上绘制一个矩形边框。
|
||||
*
|
||||
* @param x 矩形左上角x坐标。
|
||||
* @param y 矩形左上角y坐标。
|
||||
* @param w 矩形的宽度。
|
||||
* @param h 矩形的高度。
|
||||
* @param r 矩形圆角的半径。
|
||||
*
|
||||
* 该函数调用u8g2的绘制函数,用于在指定位置以指定尺寸和圆角半径绘制一个矩形边框。
|
||||
*/
|
||||
void OLED_DrawRFrame(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r)
|
||||
{
|
||||
u8g2_DrawRFrame(&u8g2, x, y, w, h, r);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在OLED显示器上绘制一个矩形框。
|
||||
*
|
||||
* @param x 矩形框左上角的x坐标。
|
||||
* @param y 矩形框左上角的y坐标。
|
||||
* @param w 矩形框的宽度。
|
||||
* @param h 矩形框的高度。
|
||||
*
|
||||
* 该函数调用u8g2的绘制矩形框函数,传入指定的坐标和尺寸,在OLED屏幕上绘制矩形。
|
||||
*/
|
||||
void OLED_DrawBox(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
|
||||
{
|
||||
u8g2_DrawBox(&u8g2, x, y, w, h); // 调用u8g2库的绘制矩形函数
|
||||
}
|
||||
|
||||
/**
|
||||
* 在OLED显示器上绘制一个带圆角的矩形。
|
||||
*
|
||||
* @param x 矩形左上角的x坐标。
|
||||
* @param y 矩形左上角的y坐标。
|
||||
* @param w 矩形的宽度。
|
||||
* @param h 矩形的高度。
|
||||
* @param r 矩形圆角的半径。
|
||||
*
|
||||
* 该函数调用u8g2的绘制函数,以指定的坐标和尺寸,在OLED显示器上绘制一个带圆角的矩形。
|
||||
*/
|
||||
void OLED_DrawRBox(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r)
|
||||
{
|
||||
u8g2_DrawRBox(&u8g2, x, y, w, h, r);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在OLED显示器上绘制一个XBM图像。
|
||||
*
|
||||
* @param x 图像在显示器上的起始x坐标。
|
||||
* @param y 图像在显示器上的起始y坐标。
|
||||
* @param w 图像的宽度。
|
||||
* @param h 图像的高度。
|
||||
* @param bitmap 指向包含XBM图像数据的缓冲区的指针。
|
||||
*
|
||||
* 此函数使用u8g2库的u8g2_DrawXBMP函数来绘制图像。图像数据必须是XBM格式的。
|
||||
*/
|
||||
void OLED_DrawXBMP(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *bitmap)
|
||||
{
|
||||
u8g2_DrawXBMP(&u8g2, x, y, w, h, bitmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置OLED显示器的对比度。
|
||||
*
|
||||
* @param value 对比度值,有效范围通常为0到255,具体取决于硬件的限制。
|
||||
*
|
||||
* 该函数通过调用u8g2库中的u8g2_SetContrast函数,来设置OLED显示器的对比度。
|
||||
* 使用者需要根据具体的OLED显示器和u8g2配置来选择合适的对比度值。
|
||||
*/
|
||||
void OLED_SetContrast(uint8_t value)
|
||||
{
|
||||
u8g2_SetContrast(&u8g2, value); // 调用u8g2库函数设置对比度
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置OLED电源节省模式
|
||||
*
|
||||
* 本函数用于根据输入参数启用或禁用OLED的电源节省模式。当is_enable为1时,启用电源节省模式;
|
||||
* 当is_enable为0时,禁用电源节省模式。
|
||||
*
|
||||
* @param is_enable 一个无符号字符(uint8_t),用来控制是否启用电源节省模式。
|
||||
* 当其值为1时,启用电源节省模式;当其值为0时,禁用电源节省模式。
|
||||
*/
|
||||
void OLED_SetPowerSave(uint8_t is_enable)
|
||||
{
|
||||
u8g2_SetPowerSave(&u8g2, is_enable); // 调用u8g2库的函数,设置OLED的电源节省模式状态
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取OLED缓冲区的 tile 高度。
|
||||
*
|
||||
* 该函数不接受参数。
|
||||
*
|
||||
* @return 返回OLED缓冲区的tile高度。返回值为uint8_t类型,即无符号8位整数。
|
||||
*/
|
||||
uint8_t OLED_GetBufferTileHeight(void)
|
||||
{
|
||||
return u8g2_GetBufferTileHeight(&u8g2); // 调用u8g2库函数,获取当前OLED缓冲区的tile高度
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取OLED缓冲区的单个瓦片宽度。
|
||||
*
|
||||
* 该函数查询U8G2图形库当前配置的OLED缓冲区的单个瓦片宽度。瓦片宽度是指OLED屏幕
|
||||
* 在显示更新时,一次可以处理的像素宽度。这个值通常取决于OLED屏幕的物理分辨率
|
||||
* 和U8G2库的内部处理方式。
|
||||
*
|
||||
* @return 返回OLED缓冲区单个瓦片的宽度,单位为字节。
|
||||
*/
|
||||
uint8_t OLED_GetBufferTileWidth(void)
|
||||
{
|
||||
return u8g2_GetBufferTileWidth(&u8g2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取OLED显示缓冲区的指针
|
||||
*
|
||||
* 该函数用于获取当前OLED显示设备的显示缓冲区的指针。该缓冲区是一个uint8_t类型的数组,
|
||||
* 用于存储即将显示在OLED屏幕上的图像数据。
|
||||
*
|
||||
* @return 返回类型为uint8_t*,指向OLED显示缓冲区的起始位置。
|
||||
*/
|
||||
uint8_t *OLED_GetBufferPtr(void)
|
||||
{
|
||||
// 调用u8g2库的函数获取显示缓冲区指针
|
||||
return u8g2_GetBufferPtr(&u8g2);
|
||||
}
|
||||
29
Middlewares/MultMenu/disp/dispDirver.h
Normal file
29
Middlewares/MultMenu/disp/dispDirver.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef _DISP_DRIVER_H_
|
||||
#define _DISP_DRIVER_H_
|
||||
|
||||
//#include "main.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void Disp_Init(void);
|
||||
void OLED_ClearBuffer(void);
|
||||
void OLED_SendBuffer(void);
|
||||
uint16_t OLED_GetStrWidth(const char *s);
|
||||
void OLED_SetMaxClipWindow(void);
|
||||
void OLED_SetFont(const uint8_t *font);
|
||||
void OLED_DrawPixel(uint16_t x, uint16_t y);
|
||||
void OLED_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
|
||||
uint16_t OLED_DrawStr(uint16_t x, uint16_t y, const char *str);
|
||||
void OLED_SetDrawColor(uint8_t color);
|
||||
void OLED_DrawFrame(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
|
||||
void OLED_DrawRFrame(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r);
|
||||
void OLED_DrawBox(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
|
||||
void OLED_DrawRBox(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r);
|
||||
void OLED_DrawXBMP(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *bitmap);
|
||||
void OLED_SetContrast(uint8_t value);
|
||||
void OLED_SetPowerSave(uint8_t is_enable);
|
||||
uint8_t OLED_GetBufferTileHeight(void);
|
||||
uint8_t OLED_GetBufferTileWidth(void);
|
||||
uint8_t *OLED_GetBufferPtr(void);
|
||||
|
||||
#endif
|
||||
766
Middlewares/MultMenu/menu/menu.c
Normal file
766
Middlewares/MultMenu/menu/menu.c
Normal file
@ -0,0 +1,766 @@
|
||||
#include "menu.h"
|
||||
#include "dispDirver.h"
|
||||
#include "stdlib.h"
|
||||
#include "application.h"
|
||||
#include "DinoGame.h"
|
||||
#include "AirPlane.h"
|
||||
#include "usbd_cdc_if.h"
|
||||
#include "usart.h"
|
||||
#include "main.h"
|
||||
|
||||
|
||||
/* pid动画参数 */
|
||||
Pid_Error Cursor_Line = {600, 370, 30, 0, 0, 0}, Cursor_Wide = {250, 370, 30, 0, 0, 0};
|
||||
/* 线性动画参数 */
|
||||
Animation_Param AnimationParam = {10, 0, 0, 0, 0, 0, 0, 0, false};
|
||||
/* Page*/
|
||||
xPage Home_Page ;
|
||||
xPage setting_page;
|
||||
xPage tx_mode_page;
|
||||
xPage rx_mode_page;
|
||||
/* item */
|
||||
xItem HomeHead_Item ;
|
||||
xItem setting_item;
|
||||
xItem setting_exit_item;
|
||||
xItem work_mode_item;
|
||||
xItem rate_mode_item;
|
||||
xItem channel_item;
|
||||
xItem tx_power_item;
|
||||
xItem tx_count_item;
|
||||
xItem tx_mode_item;
|
||||
xItem rx_mode_item;
|
||||
xItem version_item;
|
||||
xItem reset_item;
|
||||
xItem bg_color_item;
|
||||
/* menu */
|
||||
xMenu Menu = {0, &HomeHead_Item, &HomeHead_Item, MENU_INIT, PAGE_STATIC, 0};
|
||||
|
||||
/**
|
||||
* 向指定页面添加一个项目。
|
||||
*
|
||||
* @param Name 项目名称。
|
||||
* @param Type 项目类型。
|
||||
* @param Data 项目关联的数据指针。
|
||||
* @param item 待添加的项目结构体。
|
||||
* @param LocalPage 项目所属的页面。
|
||||
* @param nextpage 项目跳转到的下一个页面。
|
||||
* @param function 项目关联的函数指针。
|
||||
*
|
||||
* 项目会被添加到指定页面的链表中,并且会更新页面的相关信息。
|
||||
*/
|
||||
static void AddItem(const char *Name, Item_Type Type, void *Data, xpItem item, xpPage LocalPage, xpPage nextpage, ItemFunction function)
|
||||
{
|
||||
// 参数检验
|
||||
if (!Name || !item || !LocalPage || (Type == DATA && !Data)) {
|
||||
printf("Invalid parameter(s)\n");
|
||||
return; // 早期返回以避免进一步错误
|
||||
}
|
||||
|
||||
item->itemName = Name; // 设置项目名称
|
||||
item->itemType = Type; // 设置项目类型
|
||||
// 如果项目类型为DATA,则设置数据指针
|
||||
if(Type == DATA)item->data.ptr = (int *)Data;
|
||||
|
||||
item->page.location = LocalPage; // 设置项目所在页面
|
||||
item->itemFunction= function; // 设置项目关联的函数
|
||||
|
||||
/* 初始化项目下一个项为NULL */
|
||||
item->nextItem = NULL;
|
||||
|
||||
/* 设置跳转页面的父级项目 */
|
||||
if (nextpage != NULL)
|
||||
nextpage->item.parent = item;
|
||||
else // 如果没有下一个页面,则设置为当前页面
|
||||
nextpage = LocalPage;
|
||||
item->page.jumpPage = nextpage; // 设置项目跳转页面
|
||||
|
||||
/* 链式结构创建项目 */
|
||||
if (LocalPage->item.head == NULL) // 如果是首个项目
|
||||
{
|
||||
// 初始化项目链表头部和尾部
|
||||
item->lastItem = item;
|
||||
LocalPage->item.head = item;
|
||||
LocalPage->item.tail = item;
|
||||
LocalPage->length = 0; // 初始化项目计数
|
||||
}
|
||||
else // 如果不是首个项目
|
||||
{
|
||||
// 连接新项目到链表尾部
|
||||
item->lastItem = LocalPage->item.tail; // 新项目上一个项指向当前尾项目
|
||||
LocalPage->item.tail->nextItem = item; // 尾项目下一个项指向新项目
|
||||
LocalPage->item.tail = LocalPage->item.tail->nextItem; // 更新尾项目为新项目
|
||||
LocalPage->length++; // 项目计数加一
|
||||
}
|
||||
item->id = LocalPage->length; // 设置项目ID为当前页面项目计数
|
||||
// 关联页面的头尾项目互相指向,用于快速遍历
|
||||
LocalPage->item.tail->nextItem = LocalPage->item.head;
|
||||
LocalPage->item.head->lastItem = LocalPage->item.tail;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向页面中添加一个新页面。
|
||||
*
|
||||
* @param name 新页面的名称。
|
||||
* @param Menu 新页面所在菜单。
|
||||
* @param page 指向新页面结构体的指针。
|
||||
* @param item 新页面对应的项。
|
||||
* @param LocalPage 当前局部页面的指针。
|
||||
* @param nextpage 下一个页面的指针。
|
||||
* @param function 项的功能函数指针。
|
||||
*/
|
||||
static void AddPage(const char *name, xpMenu Menu, xpPage page, xpItem item, xpPage LocalPage, xpPage nextpage, ItemFunction function)
|
||||
{
|
||||
// 初始化新页面的基本信息
|
||||
page->pageName = name;
|
||||
page->item.head = NULL;
|
||||
page->item.tail = NULL;
|
||||
page->menu = Menu;
|
||||
Menu->page_length++;
|
||||
page->id = Menu->page_length; // 分配ID,并递增ID值
|
||||
// 如果是第一个页面,将其头跳转至首页;否则,将其父项设置为上一页
|
||||
if (page->id == 1)AddItem(name, LOOP_FUNCTION, NULL, item, LocalPage, nextpage, function);
|
||||
else AddItem(name, PARENTS, NULL, item, LocalPage, nextpage, function);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用线性插值公式计算当前时间点对应的插值结果。
|
||||
*
|
||||
* @param AllTime 总时间长度,单位为秒。表示从开始到结束的总时间长度。
|
||||
* @param Time_Now 当前时间点,单位为秒。表示在总时间长度中的当前位置。
|
||||
* @param Targrt 目标值。在给定总时间长度和当前时间点的情况下,此函数将计算出达到此目标值的插值。
|
||||
* @param Now 当前值。表示在当前时间点的值。
|
||||
* @return 返回计算出的插值结果。此结果是根据线性插值公式,将目标值和当前值结合当前时间点与总时间长度计算得出的。
|
||||
*/
|
||||
static int8_t Linear(uint8_t AllTime, uint8_t Time_Now, int8_t Targrt, int8_t Now)
|
||||
{
|
||||
// 根据线性插值公式,计算并返回当前时间点对应的插值结果
|
||||
return (Targrt - Now)*Time_Now/AllTime + Now;
|
||||
}
|
||||
|
||||
/**
|
||||
* PID 插值控制器计算函数
|
||||
*
|
||||
* 本函数用于根据目标值、当前值及已设定的PID参数,计算出下一时刻的控制量。
|
||||
*
|
||||
* @param Targrt 目标值,即期望的控制结果。
|
||||
* @param Now 当前值,即当前的控制结果。
|
||||
* @param Obj PID控制器的结构体对象,包含比例、积分、微分系数及误差相关信息。
|
||||
* @return 计算后得到的控制量,用于调整系统状态。
|
||||
*/
|
||||
static int PID(int Targrt, int Now, Pid_Error *Obj)
|
||||
{
|
||||
int x = Now;
|
||||
// 将PID系数从毫单位转换为浮点数
|
||||
float Kp = (float)(Obj->kp)/1000.00, Ki = (float)(Obj->ki)/1000.00, Kd = (float)(Obj->kd)/1000.00;
|
||||
|
||||
// 计算误差
|
||||
Obj->error = Targrt - x;
|
||||
// 积分环节,累加误差
|
||||
Obj->sum_srror += Obj->error;
|
||||
// 微分环节,计算误差变化率
|
||||
float delta_error = Obj->error - Obj->last_error;
|
||||
|
||||
// 计算控制量
|
||||
float velocity = Kp * Obj->error + Ki * Obj->sum_srror + Kd * delta_error;
|
||||
|
||||
// 更新状态
|
||||
x += velocity;
|
||||
Obj->last_error = Obj->error;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static void Change_MenuState(Menu_State state)
|
||||
{
|
||||
Menu.menu_state = state;
|
||||
}
|
||||
|
||||
static void Item_AnimationParam_Init(void)
|
||||
{
|
||||
AnimationParam.Item_NowLine = 0;
|
||||
AnimationParam.Item_NowWide = 0;
|
||||
AnimationParam.Item_TargrtLine = 0;
|
||||
AnimationParam.Item_TargrtWide = 0;
|
||||
AnimationParam.OptionState = false;
|
||||
}
|
||||
|
||||
static void DialogScale_AnimationParam_Init(void)
|
||||
{
|
||||
AnimationParam.DialogScale_InitHigh = 0;
|
||||
AnimationParam.DialogScale_InitWide = 0;
|
||||
AnimationParam.DialogScale_time = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制对话框
|
||||
* @param x 对话框左上角x坐标
|
||||
* @param y 对话框左上角y坐标
|
||||
* @param w 对话框宽度
|
||||
* @param h 对话框高度
|
||||
* 该函数首先绘制对话框的边框,然后绘制对话框的背景盒。
|
||||
* 使用了OLED显示设备的相关函数来完成绘制操作。
|
||||
*/
|
||||
void Draw_DialogBox(uint16_t x,uint16_t y,uint16_t w,uint16_t h)
|
||||
{
|
||||
// 设置绘制边框的颜色,并绘制边框
|
||||
OLED_SetDrawColor(Menu.BgColor^0x01);
|
||||
OLED_DrawFrame(x, y, w, h);
|
||||
|
||||
// 设置绘制背景的颜色,并绘制背景盒
|
||||
OLED_SetDrawColor(Menu.BgColor);
|
||||
OLED_DrawBox(x+1, y+1, w-2, h-2);
|
||||
|
||||
// 设置边框高亮颜色(通常与背景色异或得到),用于强调边框
|
||||
OLED_SetDrawColor(Menu.BgColor^0x01);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 显示一个按指定尺寸缩放的对话框。
|
||||
*
|
||||
* 此函数用于在应用绘制状态时,通过线性动画效果展示一个对话框的缩放过程。函数首先检查当前是否处于应用绘制状态,
|
||||
* 如果是,则根据设定的时间和目标尺寸计算当前对话框的宽度和高度,并进行绘制。当动画时间达到预设的对话框显示时间
|
||||
* 后,将状态切换到应用运行状态,并返回true。整个过程通过OLED发送缓冲区来更新显示。
|
||||
*
|
||||
* @param x 对话框的x坐标。
|
||||
* @param y 对话框的y坐标。
|
||||
* @param Targrt_w 目标对话框的宽度。
|
||||
* @param Targrt_h 目标对话框的高度。
|
||||
* @return bool 如果动画时间达到预设的对话框显示时间,则返回true;否则返回false。
|
||||
*/
|
||||
bool DialogScale_Show(uint8_t x,uint8_t y,uint8_t Targrt_w,uint8_t Targrt_h)
|
||||
{
|
||||
// 当前处于应用绘制状态时,处理对话框的缩放动画
|
||||
if (Menu.menu_state == APP_DRAWING)
|
||||
{
|
||||
AnimationParam.DialogScale_time++; // 动画时间递增
|
||||
// 根据当前时间和目标尺寸计算对话框的当前宽度
|
||||
AnimationParam.DialogScale_InitWide = Linear(AnimationParam.Dialog_AllTime, AnimationParam.DialogScale_time, Targrt_w, AnimationParam.DialogScale_InitWide);
|
||||
// 根据当前时间和目标尺寸计算对话框的当前高度
|
||||
AnimationParam.DialogScale_InitHigh = Linear(AnimationParam.Dialog_AllTime, AnimationParam.DialogScale_time, Targrt_h, AnimationParam.DialogScale_InitHigh);
|
||||
// 绘制当前尺寸的对话框
|
||||
Draw_DialogBox(x, y, AnimationParam.DialogScale_InitWide, AnimationParam.DialogScale_InitHigh);
|
||||
}
|
||||
// 当动画时间达到预设的对话框显示时间时,切换到应用运行状态
|
||||
if (AnimationParam.DialogScale_time == AnimationParam.Dialog_AllTime)
|
||||
{
|
||||
Change_MenuState(APP_RUN);
|
||||
return true;
|
||||
}
|
||||
// 更新OLED显示缓冲区
|
||||
OLED_SendBuffer();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制一个带有圆角的对话框背景框
|
||||
* @param x 对话框左上角x坐标
|
||||
* @param y 对话框左上角y坐标
|
||||
* @param w 对话框宽度
|
||||
* @param h 对话框高度
|
||||
* @param r 对话框圆角半径
|
||||
*/
|
||||
void Draw_DialogRBox(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r)
|
||||
{
|
||||
// 设置绘制边框的颜色,先绘制外边框
|
||||
OLED_SetDrawColor(Menu.BgColor^0x01);
|
||||
OLED_DrawRFrame(x, y, w, h, r);
|
||||
|
||||
// 设置绘制填充颜色,绘制内框,即填充部分
|
||||
OLED_SetDrawColor(Menu.BgColor);
|
||||
OLED_DrawRBox(x + 1, y + 1, w - 2, h - 2, r);
|
||||
|
||||
// 设置边框颜色,用于强调边框,这里使用与背景色异或的方式
|
||||
OLED_SetDrawColor(Menu.BgColor^0x01);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置背景颜色
|
||||
* @param color 要设置的颜色值,类型为uint8_t
|
||||
* 该函数用于将全局背景颜色设置为指定的颜色值。
|
||||
*/
|
||||
void Set_BgColor(uint8_t color)
|
||||
{
|
||||
Menu.BgColor = color; // 设置背景颜色
|
||||
}
|
||||
|
||||
uint8_t Get_BgColor(void)
|
||||
{
|
||||
return Menu.BgColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制一个滚动条
|
||||
* 该函数根据给定的参数,在OLED屏幕上绘制一个滚动条。滚动条的可见部分的长度
|
||||
* 会根据当前值在最小值和最大值之间动态调整。
|
||||
* @param x 滚动条左上角的x坐标
|
||||
* @param y 滚动条左上角的y坐标
|
||||
* @param w 滚动条的宽度
|
||||
* @param h 滚动条的高度
|
||||
* @param r 滚动条圆角的半径
|
||||
* @param min 滚动条代表的最小值
|
||||
* @param max 滚动条代表的最大值
|
||||
* @param step 滚动条的步进值
|
||||
* @param NowValue 滚动条当前的值
|
||||
*/
|
||||
int Draw_Scrollbar(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r, double min, double max, int step, int NowValue)
|
||||
{
|
||||
int value = NowValue;
|
||||
|
||||
// 根据当前值计算滚动条可见部分的长度
|
||||
if ((value <= max) && (value >= min))
|
||||
{
|
||||
value += step;
|
||||
if (value > max)
|
||||
{
|
||||
value = max;
|
||||
}
|
||||
if (value < min)
|
||||
{
|
||||
value = min;
|
||||
}
|
||||
|
||||
double value = (double)(abs(value - min) * ((w - 6)) / (double)((max - min)) + 6);
|
||||
// 绘制滚动条的填充部分
|
||||
OLED_SetDrawColor(Menu.BgColor);
|
||||
OLED_DrawRBox(x + (uint16_t)value, y, w-(uint16_t)value, h, r);
|
||||
OLED_SetDrawColor(Menu.BgColor^0x01);
|
||||
OLED_DrawRBox(x, y, (uint16_t)value, h, r);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 使屏幕上的内容逐渐消失的函数
|
||||
*
|
||||
* @param disapper 一个用于控制消失程度的参数,初始值建议为0,每次调用本函数会自动增加
|
||||
* @return uint8_t 返回调整后的disapper值,用于下次调用时继续消失过程
|
||||
*/
|
||||
static uint8_t ui_disapper(uint8_t disapper)
|
||||
{
|
||||
short disapper_temp = 0;
|
||||
// 计算屏幕缓冲区的总长度
|
||||
int length = 8 * OLED_GetBufferTileHeight() * OLED_GetBufferTileWidth();
|
||||
uint8_t *p = OLED_GetBufferPtr(); // 获取屏幕缓冲区的指针
|
||||
|
||||
// 如果背景色为黑色,那么执行与操作,让像素点逐渐变暗从而消失
|
||||
if(Menu.BgColor==0)
|
||||
{
|
||||
for( int i = 0; i < length; i++)
|
||||
{
|
||||
p[i] = p[i] & (rand()%0xff) >> disapper; // 通过与操作使像素点变暗
|
||||
}
|
||||
}
|
||||
else // 如果背景色不是黑色,执行或操作,让像素点逐渐变亮从而消失
|
||||
{
|
||||
for( int i = 0; i < length; i++)
|
||||
{
|
||||
p[i] = p[i] | (rand()%0xff) >> disapper; // 通过或操作使像素点变亮
|
||||
}
|
||||
}
|
||||
|
||||
disapper += 2; // 每次调用使消失程度增加,以便逐渐完成消失过程
|
||||
if(disapper >= 8) // 当消失程度达到最大值时重置为0,准备下一次调用
|
||||
{
|
||||
disapper = 0;
|
||||
}
|
||||
|
||||
OLED_SendBuffer(); // 将更新后的缓冲区内容发送到OLED显示设备
|
||||
disapper_temp = disapper;
|
||||
return disapper_temp; // 返回调整后的disapper值,供外部调用者使用
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制选项位置
|
||||
*
|
||||
* 该函数用于在OLED屏幕上动态绘制选项的位置,实现类似选项滑动选择的效果。
|
||||
* 根据当前项和下一个项的信息,计算并绘制出选项的滑动过程。
|
||||
*
|
||||
* @param now_item 当前选项项的指针
|
||||
* @param next_item 下一个选项项的指针
|
||||
* @return bool 如果绘制过程完成(达到设定的时间),返回true;否则返回false。
|
||||
*/
|
||||
static bool Draw_OptionPlace(xpItem now_item, xpItem next_item)
|
||||
{
|
||||
static uint8_t t; // 控制绘制过程的时间变量
|
||||
static uint8_t Now_Lenght; // 当前绘制长度
|
||||
static uint8_t Next_Lenght; // 下一个选项的理论绘制长度
|
||||
// 根据下一个项的id和位置长度,计算其理论绘制长度
|
||||
Next_Lenght = (VER_RES / (float)(next_item->page.location->length)) * next_item->id;
|
||||
t++; // 时间变量递增
|
||||
// 使用线性插值计算当前的绘制长度
|
||||
Now_Lenght = Linear(AnimationParam.Dialog_AllTime, t, Next_Lenght, Now_Lenght);
|
||||
// 绘制选项移动的指示线
|
||||
OLED_DrawLine(HOR_RES - 7, 0, HOR_RES - 7, VER_RES);
|
||||
// 根据计算出的长度,绘制当前选项的高亮框
|
||||
OLED_DrawBox(HOR_RES - 10, 0, 6, Now_Lenght);
|
||||
// 如果绘制时间达到预设的Dialog_Time,重置时间变量并返回true
|
||||
if(t == AnimationParam.Dialog_AllTime)
|
||||
{
|
||||
t = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制指定位置的页面
|
||||
*
|
||||
* @param pos 页面绘制的起始位置
|
||||
* @param Page 指向当前页面结构体的指针
|
||||
* @param LineSpacing 行间距
|
||||
* @param now_item 当前选中的项目
|
||||
* @param next_item 下一个将要选中的项目
|
||||
*/
|
||||
static void Draw_Page(uint8_t pos, xpPage Page, xpItem now_item, xpItem next_item)
|
||||
{
|
||||
char Data[10] = {0}; // 用于临时存储数据字符串
|
||||
static int16_t first_line = FirstLine; // 页面中第一行的起始位置
|
||||
|
||||
xpItem temp = Page->item.head; // 从页面的头部开始遍历
|
||||
|
||||
// 初始化或计算页面滚动时的起始绘制位置
|
||||
if(Menu.menu_state == MENU_RUN)
|
||||
{
|
||||
// 页面切换时重置第一行位置
|
||||
if(next_item->page.location != now_item->page.location)first_line = FirstLine;
|
||||
|
||||
// 计算页面滚动的距离
|
||||
if (Menu.page_state == PAGE_MOVING)
|
||||
{
|
||||
if ((next_item->id - now_item->id) > 0)first_line -= ((next_item->id - now_item->id) > (Page->length - MaxVisible_Number)) ? ((Page->length - MaxVisible_Number) * Font_Size) : Font_Size;
|
||||
else first_line += ((now_item->id - next_item->id) > (Page->length - MaxVisible_Number)) ? ((Page->length - MaxVisible_Number) * Font_Size) : Font_Size;
|
||||
Menu.page_state = PAGE_STATIC; // 更新页面状态为静态显示
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历页面中的所有项目并绘制
|
||||
for (uint16_t i = 0; i <= Page->length; i++)
|
||||
{
|
||||
OLED_DrawStr(pos, first_line + i * Font_Size, temp->itemName); // 绘制项目名称
|
||||
|
||||
// 根据项目类型进行特殊绘制处理
|
||||
if(temp->itemType == SWITCH)
|
||||
{
|
||||
// 绘制开关状态
|
||||
if(temp->switchState == false)OLED_DrawFrame(pos + 95, first_line + i * Font_Size - Font_Size + 3, 10, 10);
|
||||
else OLED_DrawBox(pos + 95, first_line + i * Font_Size - Font_Size + 3, 10, 10);
|
||||
}
|
||||
if(temp->itemType == DATA)
|
||||
{
|
||||
// 格式化并绘制数据
|
||||
sprintf(Data, "%d", *temp->data.ptr);
|
||||
OLED_DrawStr(pos + 95, first_line + i * Font_Size, Data);
|
||||
}
|
||||
|
||||
temp = temp->nextItem; // 移动到下一个项目
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制菜单界面
|
||||
* 该函数负责在 OLED 屏幕上绘制菜单界面,包括计算各项的位置、绘制背景、选项及其高亮显示。
|
||||
* 根据不同的菜单状态(如页面移动、选项切换),动态调整选项的显示位置,实现平滑的动画效果。
|
||||
* @param pos 当前页面位置
|
||||
* @param Page 当前页面结构体
|
||||
* @param LineSpacing 行间距
|
||||
* @param now_item 当前选中项
|
||||
* @param next_item 下一个将要选中的项
|
||||
*/
|
||||
static void Draw_Menu(uint8_t pos, xpPage Page, xpItem now_item,xpItem next_item)
|
||||
{
|
||||
// 初始化或更新动画参数及页面状态
|
||||
if(Menu.menu_state == MENU_RUN)
|
||||
{
|
||||
// 计算当前项名称的宽度
|
||||
AnimationParam.Item_NowWide = strlen(now_item->itemName)*6 + 4;
|
||||
|
||||
// 切换页面时进行初始化并设置页面状态为静态
|
||||
if(next_item->page.location != now_item->page.location)
|
||||
{
|
||||
Item_AnimationParam_Init();
|
||||
Menu.page_state = PAGE_STATIC;
|
||||
}
|
||||
else // 在同一页面内切换选项时的处理
|
||||
{
|
||||
// 根据选项的id差值计算目标行位置,并限制在可视范围内
|
||||
if (next_item->id > now_item->id)
|
||||
{
|
||||
AnimationParam.Item_TargrtLine += ((next_item->id - now_item->id)*Font_Size);
|
||||
if (AnimationParam.Item_TargrtLine > LINE_MAX) // 防止光标溢出可视范围
|
||||
{
|
||||
Menu.page_state = PAGE_MOVING;
|
||||
AnimationParam.Item_TargrtLine = LINE_MAX;
|
||||
}
|
||||
}
|
||||
else if(next_item->id < now_item->id)
|
||||
{
|
||||
AnimationParam.Item_TargrtLine -= ((now_item->id - next_item->id)*Font_Size);
|
||||
if (AnimationParam.Item_TargrtLine < 0) // 防止光标溢出可视范围
|
||||
{
|
||||
Menu.page_state = PAGE_MOVING;
|
||||
AnimationParam.Item_TargrtLine = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 计算下一个将要选中项的名称宽度
|
||||
AnimationParam.Item_TargrtWide = OLED_GetStrWidth(next_item->itemName) + 3;
|
||||
|
||||
// 开始绘制菜单界面
|
||||
OLED_ClearBuffer(); // 清除屏幕缓冲区
|
||||
OLED_SetDrawColor(Menu.BgColor); // 设置背景颜色
|
||||
OLED_DrawBox(0, 0, 128, 64); // 绘制屏幕背景框
|
||||
OLED_SetDrawColor(Menu.BgColor^0x01); // 设置绘制颜色为高亮或低亮
|
||||
AnimationParam.OptionState = Draw_OptionPlace(now_item, next_item); // 绘制选项及其位置
|
||||
Draw_Page(pos, Page, now_item, next_item); // 绘制页面内容
|
||||
OLED_SetDrawColor(2); // 设置特定的颜色,通常用于高亮显示
|
||||
// 根据目标位置和当前位置,以及PID算法计算并更新当前选项的位置和宽度
|
||||
AnimationParam.Item_NowLine = PID(AnimationParam.Item_TargrtLine, AnimationParam.Item_NowLine, &Cursor_Line);
|
||||
AnimationParam.Item_NowWide = PID(AnimationParam.Item_TargrtWide, AnimationParam.Item_NowWide, &Cursor_Wide);
|
||||
// 绘制选中项的高亮边框
|
||||
OLED_DrawBox(pos+1, AnimationParam.Item_NowLine+2, AnimationParam.Item_NowWide, Font_Size);
|
||||
OLED_SendBuffer(); // 将缓冲区的内容发送到OLED屏幕显示
|
||||
|
||||
// 更新菜单状态为绘制中
|
||||
Change_MenuState(MENU_DRAWING);
|
||||
// 如果动画参数达到目标值且选项绘制完成,则更新菜单状态为运行中
|
||||
if ((AnimationParam.Item_NowLine == AnimationParam.Item_TargrtLine) && (AnimationParam.Item_NowWide == AnimationParam.Item_TargrtWide) && (AnimationParam.OptionState == true))
|
||||
{
|
||||
Change_MenuState(MENU_RUN);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* 菜单构建函数
|
||||
* 该函数不接受参数,也不返回任何值。
|
||||
* 功能:静态地构建一个菜单系统。
|
||||
*/
|
||||
static void Menu_Team(void)
|
||||
{
|
||||
AddPage("[Home]", &Menu, &Home_Page, &HomeHead_Item, &Home_Page, NULL, logo_callback );
|
||||
AddItem(" +Setting", PARENTS, NULL, &setting_item, &Home_Page, &setting_page, NULL);
|
||||
AddPage("[Exit]", &Menu, &setting_page, &setting_exit_item, &setting_page, &Home_Page, NULL);
|
||||
AddItem(" -Work Mode", DATA, &user_config.work_mode, &work_mode_item, &setting_page, NULL, work_mode_callback );
|
||||
AddItem(" -Rate Mode", DATA, &user_config.rate_mode, &rate_mode_item, &setting_page, NULL, rate_mode_callback );
|
||||
AddItem(" -Channel", DATA, &user_config.channel, &channel_item, &setting_page, NULL, channel_callback );
|
||||
AddItem(" -TX Power", DATA, &user_config.tx_power, &tx_power_item, &setting_page, NULL, tx_power_callback);
|
||||
AddItem(" -TX Count", DATA, &user_config.tx_count, &tx_count_item, &setting_page, NULL, tx_count_callback);
|
||||
AddItem(" -Back Color", SWITCH, NULL, &bg_color_item, &setting_page, NULL, background_color_callback );
|
||||
AddItem(" -Tx XTELL", LOOP_FUNCTION, NULL, &tx_mode_item, &Home_Page, NULL, tx_mode_callback);
|
||||
AddItem(" -Rx XTELL", LOOP_FUNCTION, NULL, &rx_mode_item, &Home_Page, NULL, rx_mode_callback);
|
||||
AddItem(" -Version", LOOP_FUNCTION, NULL, &version_item, &Home_Page, NULL, version_callback);
|
||||
AddItem(" -Reset", LOOP_FUNCTION, NULL, &reset_item, &Home_Page, NULL, reset_callback);
|
||||
}
|
||||
|
||||
/* 在此填入按键扫描程序
|
||||
* 功能:执行按键扫描,根据接收到的数据确定按键方向
|
||||
* 参数:无
|
||||
* 返回值:Menu_Direction 枚举类型,表示按键的方向,没有按键按下时返回MENU_NONE
|
||||
*/
|
||||
static Menu_Direction BtnScan(void)
|
||||
{
|
||||
if( key_check_press( KEY_NAME_UP ) == true )
|
||||
{
|
||||
buzzer_button_press();
|
||||
return MENU_UP;
|
||||
}
|
||||
|
||||
if( key_check_press( KEY_NAME_DOWN ) == true )
|
||||
{
|
||||
buzzer_button_press();
|
||||
return MENU_DOWN;
|
||||
}
|
||||
|
||||
if( key_check_press( KEY_NAME_ENTER ) == true )
|
||||
{
|
||||
buzzer_button_press();
|
||||
return MENU_ENTER;
|
||||
}
|
||||
|
||||
return MENU_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据菜单方向运行处理菜单逻辑
|
||||
*
|
||||
* @param Dir 菜单操作方向,包括上、下、进入等操作
|
||||
*/
|
||||
void Process_Menu_Run(Menu_Direction Dir)
|
||||
{
|
||||
uint8_t disapper = 0;
|
||||
switch (Menu.menu_state) // 根据当前菜单状态进行不同的操作
|
||||
{
|
||||
case MENU_RUN:
|
||||
switch (Dir) // 根据操作方向更新菜单项
|
||||
{
|
||||
case MENU_UP:
|
||||
// 向上移动菜单项,确保当前项和上一项非空
|
||||
if (Menu.now_item != NULL && Menu.now_item->lastItem != NULL)
|
||||
{
|
||||
Draw_Menu(FirstPos, Menu.now_item->page.location, Menu.now_item, Menu.now_item->lastItem);
|
||||
Menu.old_item = Menu.now_item;
|
||||
Menu.now_item = Menu.now_item->lastItem;
|
||||
}
|
||||
break;
|
||||
case MENU_DOWN:
|
||||
// 向下移动菜单项,确保当前项和下一项非空
|
||||
if (Menu.now_item != NULL && Menu.now_item->nextItem != NULL)
|
||||
{
|
||||
Draw_Menu(FirstPos, Menu.now_item->page.location, Menu.now_item, Menu.now_item->nextItem);
|
||||
Menu.old_item = Menu.now_item;
|
||||
Menu.now_item = Menu.now_item->nextItem;
|
||||
}
|
||||
break;
|
||||
case MENU_ENTER:
|
||||
// 当前项非空且为父项时,进入下一级菜单
|
||||
if(Menu.now_item != NULL && Menu.now_item->itemType == PARENTS)
|
||||
{
|
||||
// 避免重复状态改变
|
||||
if(Menu.menu_state != MENU_ENTER) Change_MenuState(MENU_RUN);
|
||||
|
||||
for (size_t i = 0; i < 8; i++) // 执行UI淡出操作
|
||||
{
|
||||
disapper = ui_disapper(disapper);
|
||||
}
|
||||
|
||||
// 如果存在跳转页面且不为空,则绘制跳转页面并更新当前项
|
||||
if(Menu.now_item->page.jumpPage != NULL && Menu.now_item->page.jumpPage->item.head != NULL)
|
||||
{
|
||||
Draw_Menu(FirstPos, Menu.now_item->page.jumpPage, Menu.now_item, Menu.now_item->page.jumpPage->item.head);
|
||||
Menu.old_item = Menu.now_item;
|
||||
Menu.now_item = Menu.now_item->page.jumpPage->item.head;
|
||||
}
|
||||
}
|
||||
else // 如果当前项为空或非父项,则进入应用绘制状态
|
||||
{
|
||||
ui_disapper(1);
|
||||
Change_MenuState(APP_DRAWING);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Draw_Menu(FirstPos, Menu.now_item->page.location, Menu.now_item, Menu.now_item);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case APP_QUIT:
|
||||
// 退出应用时的初始化操作,并返回菜单运行状态
|
||||
DialogScale_AnimationParam_Init();
|
||||
Change_MenuState(MENU_RUN);
|
||||
for (size_t i = 0; i < 8; i++)
|
||||
{
|
||||
disapper = ui_disapper(disapper); // 执行UI淡出操作
|
||||
}
|
||||
if(Menu.now_item != NULL) // 确保now_item非空
|
||||
{
|
||||
Draw_Menu(FirstPos, Menu.now_item->page.location, Menu.now_item, Menu.now_item);
|
||||
}
|
||||
break;
|
||||
case MENU_DRAWING:
|
||||
// 如果当前正在绘制菜单,则根据方向进行状态更新和菜单重绘
|
||||
if(Menu.now_item != NULL && Menu.old_item != NULL)
|
||||
{
|
||||
Draw_Menu(FirstPos, Menu.now_item->page.location, Menu.old_item, Menu.now_item);
|
||||
if (Dir != MENU_NONE)
|
||||
{
|
||||
Change_MenuState(MENU_RUN);
|
||||
Process_Menu_Run(Dir);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 处理应用程序的运行状态。
|
||||
* 对给定的项目(item)根据其类型(ItemType)和当前的菜单状态(State)执行相应的操作。
|
||||
* @param item 指向要处理的项目的指针。
|
||||
* @param State 当前菜单的方向或状态。
|
||||
*/
|
||||
void Process_App_Run(xpItem item, Menu_Direction State)
|
||||
{
|
||||
if (item == NULL) return; // 检查空指针,避免未定义行为
|
||||
|
||||
item->state = State; // 设置项目的状态为当前菜单状态
|
||||
|
||||
switch (item->itemType) // 根据项目类型执行不同的操作
|
||||
{
|
||||
case DATA:
|
||||
case LOOP_FUNCTION:
|
||||
if (item->itemFunction != NULL)(item->itemFunction)(item); // 执行项目的函数
|
||||
if(item->state == MENU_ENTER)Change_MenuState(APP_QUIT); // 如果项目状态为进入菜单,则改变菜单状态为函数退出
|
||||
break;
|
||||
case SWITCH:
|
||||
item->switchState = ! item->switchState; // 切换开关状态
|
||||
case ONCE_FUNCTION:
|
||||
if (item->itemFunction != NULL)(item->itemFunction)(item); // 如果项目有函数,则执行该函数
|
||||
Change_MenuState(APP_QUIT); // 改变菜单状态为函数退出
|
||||
break;
|
||||
default:
|
||||
break; // 对未知类型不执行任何操作
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 菜单任务处理函数
|
||||
* 该函数负责根据当前按钮扫描结果更新菜单状态,并进行相应的绘制或处理操作。
|
||||
* 无参数
|
||||
* 无返回值
|
||||
*/
|
||||
void Menu_Task(void)
|
||||
{
|
||||
Menu_Direction Dir = BtnScan(); // 扫描按钮方向,确定菜单操作方向
|
||||
if (Menu.menu_state == MENU_INIT && Dir != MENU_NONE)
|
||||
{
|
||||
// 初始化状态下,非空检查now_item并绘制当前菜单项
|
||||
if (Menu.now_item != NULL)
|
||||
{
|
||||
Draw_Menu(FirstPos, Menu.now_item->page.location, Menu.now_item, Menu.now_item);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Menu.now_item is NULL\n"); // 打印错误信息,now_item为空
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (Menu.menu_state)
|
||||
{
|
||||
case MENU_INIT:break;
|
||||
case APP_RUN:
|
||||
case APP_DRAWING:
|
||||
// 在这两个状态下,处理应用程序运行逻辑
|
||||
Process_App_Run(Menu.now_item, Dir);
|
||||
if (Menu.menu_state == APP_DRAWING)
|
||||
{
|
||||
break; // 在绘制状态下,终止进一步流程执行
|
||||
}
|
||||
// 故意不写 break,以允许流程进入下方的共同逻辑处理(如果存在)
|
||||
|
||||
case MENU_RUN:
|
||||
case APP_QUIT:
|
||||
case MENU_DRAWING:
|
||||
// 处理菜单运行、应用退出和菜单绘制状态
|
||||
Process_Menu_Run(Dir);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Menu_Init(void)
|
||||
{
|
||||
Disp_Init();
|
||||
|
||||
Menu_Team();
|
||||
|
||||
logo_callback( NULL );
|
||||
}
|
||||
16
Middlewares/MultMenu/menu/menu.h
Normal file
16
Middlewares/MultMenu/menu/menu.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef __MENU_H__
|
||||
#define __MENU_H__
|
||||
|
||||
#include "stdbool.h"
|
||||
#include "menuConfig.h"
|
||||
|
||||
void Draw_DialogBox(uint16_t x,uint16_t y,uint16_t w,uint16_t h);
|
||||
void Draw_DialogRBox(uint16_t x,uint16_t y,uint16_t w,uint16_t h,uint16_t r);
|
||||
bool DialogScale_Show(uint8_t x,uint8_t y,uint8_t Targrt_w,uint8_t Targrt_h);
|
||||
void Set_BgColor(uint8_t color);
|
||||
uint8_t Get_BgColor(void);
|
||||
int Draw_Scrollbar(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r, double min, double max, int step, int NowValue);
|
||||
void Menu_Task(void);
|
||||
void Menu_Init(void);
|
||||
|
||||
#endif
|
||||
178
Middlewares/MultMenu/menu/menuConfig.h
Normal file
178
Middlewares/MultMenu/menu/menuConfig.h
Normal file
@ -0,0 +1,178 @@
|
||||
#ifndef _MENUCONFIG_H_
|
||||
#define _MENUCONFIG_H_
|
||||
|
||||
#include "u8g2.h"
|
||||
#include "stdbool.h"
|
||||
|
||||
// 屏幕分辨率定义
|
||||
#define HOR_RES 128 // 水平分辨率
|
||||
#define VER_RES 64 // 垂直分辨率
|
||||
|
||||
// 菜单字体定义
|
||||
#define MENU_FONT u8g2_font_profont12_mf
|
||||
|
||||
// 字体尺寸定义
|
||||
#define Font_Size 12 // 字体高度
|
||||
|
||||
// 起始Y坐标,基于字体大小设定的第一行位置
|
||||
#define FirstLine Font_Size
|
||||
|
||||
// 起始X坐标
|
||||
#define FirstPos 0
|
||||
|
||||
// 最大可见项目数,除去标题栏
|
||||
#define MaxVisible_Number 4 // 可见菜单项数量
|
||||
|
||||
// 最大Y坐标,根据字体大小和最大可见项目数计算得出
|
||||
#define LINE_MAX Font_Size*MaxVisible_Number
|
||||
|
||||
// 最小Y坐标,即第一行的位置
|
||||
#define LINE_MIN Font_Size
|
||||
|
||||
/**
|
||||
* Pid_Error 结构体定义
|
||||
* 用于存储PID控制器的误差及调整参数
|
||||
*/
|
||||
typedef struct PidError
|
||||
{
|
||||
int kp; // 比例增益
|
||||
int ki; // 积分增益
|
||||
int kd; // 微分增益
|
||||
float error; // 当前误差
|
||||
float sum_srror; // 积累的误差
|
||||
float last_error; // 上一次的误差
|
||||
}Pid_Error;
|
||||
|
||||
// 菜单状态枚举: 定义了菜单及应用程序的不同运行状态
|
||||
typedef enum MenuState
|
||||
{
|
||||
MENU_INIT, // 菜单初始化状态
|
||||
MENU_DRAWING, // 菜单绘制状态
|
||||
MENU_RUN, // 菜单运行状态
|
||||
APP_RUN, // 应用程序运行状态
|
||||
APP_DRAWING, // 应用程序绘制状态
|
||||
APP_QUIT // 应用程序退出状态
|
||||
} Menu_State;
|
||||
|
||||
// 页面状态枚举
|
||||
// 用于表示页面的两种状态:移动和静止
|
||||
typedef enum PageState
|
||||
{
|
||||
PAGE_MOVING, // 页面正在移动
|
||||
PAGE_STATIC // 页面处于静止状态
|
||||
}Page_State;
|
||||
|
||||
// 菜单运动方向枚举
|
||||
// 这个枚举定义了菜单系统中可能的方向和操作,包括向上、向下、进入和退出等操作。
|
||||
typedef enum MenuDirection
|
||||
{
|
||||
MENU_NONE, // 无操作
|
||||
MENU_UP, // 向上
|
||||
MENU_DOWN, // 向下
|
||||
MENU_ENTER // 进入或选择
|
||||
} Menu_Direction;
|
||||
|
||||
// 菜单项目类型枚举
|
||||
typedef enum ItemType
|
||||
{
|
||||
// 父菜单项: 代表菜单中的顶级项或父级项,通常不直接与用户交互,而是作为其他菜单项的容器。
|
||||
PARENTS = 0,
|
||||
// 循环功能项: 代表一种循环执行的功能,在菜单系统中用于循环播放、轮询等操作。
|
||||
LOOP_FUNCTION,
|
||||
// 一次性功能项: 代表仅执行一次的功能,执行后即被标记为完成,不再重复执行。
|
||||
ONCE_FUNCTION,
|
||||
// 开关切换项: 代表菜单中的开关选项,可用于启用或禁用某个功能或设置。
|
||||
SWITCH,
|
||||
// 数据项: 代表菜单中用于显示或设置数据的项,可以是数值、文本等各种形式的数据。
|
||||
DATA
|
||||
} Item_Type;
|
||||
|
||||
//菜单页面类型枚举
|
||||
typedef enum
|
||||
{
|
||||
FIGURE,
|
||||
TEXT
|
||||
}Page_Type;
|
||||
|
||||
// 动画参数
|
||||
typedef struct AnimationParam
|
||||
{
|
||||
// 对话框总时间(单位:毫秒)
|
||||
uint8_t Dialog_AllTime;
|
||||
// 对话框缩放时间(单位:毫秒)
|
||||
uint8_t DialogScale_time;
|
||||
// 对话框初始宽度(单位:像素)
|
||||
uint8_t DialogScale_InitWide;
|
||||
// 对话框初始高度(单位:像素)
|
||||
uint8_t DialogScale_InitHigh;
|
||||
// 当前项宽度(单位:像素)
|
||||
int Item_NowWide;
|
||||
// 当前项高度(单位:行数)
|
||||
int Item_NowLine;
|
||||
// 目标项高度(单位:行数)
|
||||
int Item_TargrtLine;
|
||||
// 目标项宽度(单位:像素)
|
||||
int Item_TargrtWide;
|
||||
// 选项条状态
|
||||
bool OptionState;
|
||||
} Animation_Param;
|
||||
|
||||
typedef struct Page *xpPage;
|
||||
typedef struct Item *xpItem;
|
||||
typedef struct Menu *xpMenu;
|
||||
typedef void (*ItemFunction)(xpItem);
|
||||
|
||||
/**
|
||||
* 定义一个名为Page的结构体类型
|
||||
* 用于表示页面信息
|
||||
*/
|
||||
typedef struct Page {
|
||||
const char *pageName; // 页面名称,使用指针存储
|
||||
uint8_t length; // 页面长度
|
||||
uint8_t id; // 页面ID
|
||||
// 使用内联函数封装成员变量,以提供更高的数据封装性和保护性
|
||||
struct {
|
||||
xpItem parent; // 父级项
|
||||
xpItem head; // 头部项
|
||||
xpItem tail; // 尾部项
|
||||
} item;
|
||||
Page_Type pageType; // 页面类型
|
||||
xpMenu menu; // 页面关联的菜单
|
||||
} xPage;
|
||||
|
||||
// 定义一个名为Item的结构体类型
|
||||
typedef struct Item {
|
||||
const char *itemName; // 结构体成员变量:项目名称,使用const char*类型
|
||||
Item_Type itemType; // 结构体成员变量:项目类型,自定义的Item_Type类型
|
||||
bool switchState; // 结构体成员变量:开关状态,使用bool类型
|
||||
// 封装data指针,以确保数据的完整性
|
||||
struct {
|
||||
int *ptr; // 指向整型数据的指针
|
||||
size_t size; // 指针指向数据的大小,使用size_t类型
|
||||
} data;
|
||||
uint8_t id; // 结构体成员变量:项目ID,使用uint8_t类型
|
||||
// 使用内联函数封装page结构体,以保护成员变量
|
||||
struct {
|
||||
xpPage location; // 页面位置
|
||||
xpPage jumpPage; // 跳转页面
|
||||
} page;
|
||||
xpItem lastItem, nextItem; // 上一个项目和下一个项目的指针
|
||||
ItemFunction itemFunction; // 函数指针,指向一个接受xpItem类型参数的函数
|
||||
Menu_Direction state; // 菜单方向状态
|
||||
uint8_t *logo; // 结构体成员变量:项目关联的图片指针
|
||||
} xItem;
|
||||
|
||||
/**
|
||||
* xMenu结构体定义
|
||||
* 用于表示一个菜单的相关信息
|
||||
*/
|
||||
typedef struct Menu {
|
||||
size_t page_length; // 菜单页面的数量
|
||||
xpItem now_item; // 当前选中的item
|
||||
xpItem old_item; // 上一个选中的item
|
||||
Menu_State menu_state; // 菜单的状态
|
||||
Page_State page_state; // 页面的状态
|
||||
uint8_t BgColor; // 菜单的背景颜色
|
||||
} xMenu;
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user