编程技术分享

分享编程知识,探讨技术创新

0%

简介:一款搭载0.97寸屏幕的墨水屏U盘,集成了诸多功能,快来看看

好的,作为一名高级嵌入式软件开发工程师,我将针对这款0.97寸墨水屏U盘产品,详细阐述一个可靠、高效、可扩展的系统平台架构,并提供相应的C代码示例。考虑到实际嵌入式开发的复杂性,以下代码并非完全可编译运行,但足以体现设计思路和关键技术点。
关注微信公众号,提前获取相关推文

1. 系统需求分析

首先,我们需要明确这款墨水屏U盘的功能需求:

  • 基本功能:
    • U盘存储:作为标准的USB存储设备,提供数据存储功能。
    • 墨水屏显示:能够显示U盘状态信息、文件列表、个性化内容等。
    • 按键交互:至少3个按键,用于菜单导航、选择、确认等操作。
    • 低功耗设计:墨水屏特性决定低功耗,但整体系统需考虑功耗优化。
  • 扩展功能:
    • RTC:实时时钟,用于显示时间信息。
    • 文件系统:支持FAT32等常见文件系统。
    • 升级功能:支持通过USB或其它方式进行固件升级。
    • 用户自定义:提供配置文件的修改功能。
    • 电池管理:如果有内置电池,需要进行电量监控和管理。

2. 系统架构设计

我将采用分层架构来设计这个嵌入式系统,这样可以提高代码的可维护性、可复用性和可扩展性。架构分为以下几层:

  • 硬件抽象层 (HAL): 封装底层硬件操作,提供统一的接口给上层使用。
    • 包括GPIO驱动、SPI驱动 (墨水屏)、USB驱动、RTC驱动等。
  • 设备驱动层 (Device Driver): 在HAL基础上,实现具体设备的驱动逻辑。
    • 包括墨水屏驱动、按键驱动、USB存储驱动、RTC驱动等。
  • 系统服务层 (System Service): 提供系统级的服务。
    • 包括文件系统服务、电源管理服务、配置管理服务等。
  • 应用层 (Application): 实现具体的功能逻辑。
    • 包括主菜单、文件浏览、显示控制、升级管理等。

3. 软件设计细节

3.1. 硬件抽象层 (HAL)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// hal.h
#ifndef HAL_H
#define HAL_H

#include <stdint.h>

// GPIO
typedef enum {
GPIO_PIN_0,
GPIO_PIN_1,
// ...
GPIO_PIN_MAX
} gpio_pin_t;

typedef enum {
GPIO_MODE_INPUT,
GPIO_MODE_OUTPUT
} gpio_mode_t;

typedef enum {
GPIO_STATE_LOW,
GPIO_STATE_HIGH
} gpio_state_t;

void hal_gpio_init(gpio_pin_t pin, gpio_mode_t mode);
void hal_gpio_set(gpio_pin_t pin, gpio_state_t state);
gpio_state_t hal_gpio_get(gpio_pin_t pin);

// SPI
typedef enum {
SPI_MODE_0,
SPI_MODE_1,
// ...
SPI_MODE_MAX
} spi_mode_t;

void hal_spi_init(spi_mode_t mode, uint32_t speed);
void hal_spi_transfer(uint8_t *tx_data, uint8_t *rx_data, uint32_t len);

// USB
void hal_usb_init();
void hal_usb_send_data(uint8_t *data, uint32_t len);
uint32_t hal_usb_receive_data(uint8_t *data, uint32_t max_len);

// RTC
typedef struct {
uint8_t second;
uint8_t minute;
uint8_t hour;
uint8_t day;
uint8_t month;
uint16_t year;
} rtc_time_t;
void hal_rtc_init();
void hal_rtc_get_time(rtc_time_t *time);
void hal_rtc_set_time(rtc_time_t *time);


#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// hal.c (示例,根据具体硬件实现)
#include "hal.h"
#include "stm32f4xx.h" // 假设使用STM32F4系列MCU

// GPIO
void hal_gpio_init(gpio_pin_t pin, gpio_mode_t mode) {
// STM32 GPIO 初始化配置 (示例)
GPIO_InitTypeDef GPIO_InitStruct;
if (pin == GPIO_PIN_0) {
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
} else if (pin == GPIO_PIN_1) {
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
}
if (mode == GPIO_MODE_OUTPUT) {
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
} else {
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
}

GPIO_Init(GPIOA, &GPIO_InitStruct);

}

void hal_gpio_set(gpio_pin_t pin, gpio_state_t state) {
if (pin == GPIO_PIN_0) {
GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)state);
}else if (pin == GPIO_PIN_1){
GPIO_WriteBit(GPIOA, GPIO_Pin_1, (BitAction)state);
}

}

gpio_state_t hal_gpio_get(gpio_pin_t pin) {
if (pin == GPIO_PIN_0) {
return (gpio_state_t)GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0);
}else if (pin == GPIO_PIN_1){
return (gpio_state_t)GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1);
}
return GPIO_STATE_LOW;
}

// SPI
void hal_spi_init(spi_mode_t mode, uint32_t speed) {
// STM32 SPI 初始化配置 (示例)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
SPI_InitTypeDef SPI_InitStruct;

SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStruct.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStruct);

SPI_Cmd(SPI1, ENABLE);
}

void hal_spi_transfer(uint8_t *tx_data, uint8_t *rx_data, uint32_t len) {
// STM32 SPI 数据传输 (示例)
for (int i = 0; i < len; i++)
{
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, tx_data[i]);

while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
rx_data[i] = SPI_I2S_ReceiveData(SPI1);
}
}

// USB (略,具体实现与USB控制器相关)
void hal_usb_init() {
// 初始化USB
return;
}
void hal_usb_send_data(uint8_t *data, uint32_t len) {
// 发送数据到USB端
return;
}
uint32_t hal_usb_receive_data(uint8_t *data, uint32_t max_len) {
// 从USB端接收数据
return 0;
}

// RTC
void hal_rtc_init()
{
// 初始化RTC
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
PWR_BackupAccessCmd(ENABLE);
RCC_LSEConfig(RCC_LSE_ON);
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd(ENABLE);
RTC_InitTypeDef RTC_InitStructure;
RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;
RTC_InitStructure.RTC_AsynchPrediv = 127;
RTC_InitStructure.RTC_SynchPrediv = 255;
RTC_Init(&RTC_InitStructure);
}

void hal_rtc_get_time(rtc_time_t *time)
{
// 读取RTC时间
RTC_TimeTypeDef RTC_TimeStruct;
RTC_DateTypeDef RTC_DateStruct;
RTC_GetTime(RTC_Format_BIN, &RTC_TimeStruct);
RTC_GetDate(RTC_Format_BIN, &RTC_DateStruct);
time->second = RTC_TimeStruct.RTC_Seconds;
time->minute = RTC_TimeStruct.RTC_Minutes;
time->hour = RTC_TimeStruct.RTC_Hours;
time->day = RTC_DateStruct.RTC_Date;
time->month = RTC_DateStruct.RTC_Month;
time->year = RTC_DateStruct.RTC_Year;
}

void hal_rtc_set_time(rtc_time_t *time)
{
// 设置RTC时间
RTC_TimeTypeDef RTC_TimeStruct;
RTC_DateTypeDef RTC_DateStruct;

RTC_TimeStruct.RTC_Seconds = time->second;
RTC_TimeStruct.RTC_Minutes = time->minute;
RTC_TimeStruct.RTC_Hours = time->hour;
RTC_DateStruct.RTC_Date = time->day;
RTC_DateStruct.RTC_Month = time->month;
RTC_DateStruct.RTC_Year = time->year;

RTC_SetTime(RTC_Format_BIN, &RTC_TimeStruct);
RTC_SetDate(RTC_Format_BIN, &RTC_DateStruct);
}

3.2. 设备驱动层 (Device Driver)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// device.h
#ifndef DEVICE_H
#define DEVICE_H

#include "hal.h"

// E-ink Display
#define EINK_WIDTH 128
#define EINK_HEIGHT 32

void eink_init();
void eink_clear_screen();
void eink_draw_pixel(uint16_t x, uint16_t y, uint8_t color);
void eink_display_buffer(uint8_t *buffer);
void eink_draw_text(uint16_t x, uint16_t y, const char *text);

// Keypad
typedef enum {
KEY_NONE,
KEY_UP,
KEY_DOWN,
KEY_OK
} key_event_t;
key_event_t keypad_get_event();

// USB storage
void usb_storage_init();
void usb_storage_read(uint32_t sector, uint8_t *buffer, uint32_t count);
void usb_storage_write(uint32_t sector, uint8_t *buffer, uint32_t count);

// RTC
void rtc_get_time(rtc_time_t *time);
void rtc_set_time(rtc_time_t *time);
#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// device.c (示例)
#include "device.h"
#include "font.h" // 假设有字体数据

// E-ink Display
// 驱动IC型号以及通信方式根据实际情况选择
#define EINK_DC_PIN GPIO_PIN_0 // 数据/命令选择
#define EINK_CS_PIN GPIO_PIN_1 // 片选
#define EINK_RST_PIN GPIO_PIN_2 // 复位

uint8_t eink_buffer[EINK_WIDTH * EINK_HEIGHT / 8];

void eink_init() {
hal_gpio_init(EINK_DC_PIN, GPIO_MODE_OUTPUT);
hal_gpio_init(EINK_CS_PIN, GPIO_MODE_OUTPUT);
hal_gpio_init(EINK_RST_PIN, GPIO_MODE_OUTPUT);
hal_spi_init(SPI_MODE_0, 1000000); // 1MHz SPI Clock
hal_gpio_set(EINK_RST_PIN, GPIO_STATE_LOW);
for (int i = 0; i < 1000; i++); //delay
hal_gpio_set(EINK_RST_PIN, GPIO_STATE_HIGH);
for (int i = 0; i < 1000; i++); //delay


eink_send_command(0x12); // reset
eink_send_command(0x74); // set analog block control
eink_send_data(0x54); // set data 1
eink_send_command(0x7e); // set digital block control
eink_send_data(0x3b); // set data 2
eink_send_command(0x2b); // set display update
eink_send_data(0x02);

eink_clear_screen();
}

void eink_send_command(uint8_t command) {
hal_gpio_set(EINK_CS_PIN, GPIO_STATE_LOW);
hal_gpio_set(EINK_DC_PIN, GPIO_STATE_LOW);
hal_spi_transfer(&command, NULL, 1);
hal_gpio_set(EINK_CS_PIN, GPIO_STATE_HIGH);
}

void eink_send_data(uint8_t data) {
hal_gpio_set(EINK_CS_PIN, GPIO_STATE_LOW);
hal_gpio_set(EINK_DC_PIN, GPIO_STATE_HIGH);
hal_spi_transfer(&data, NULL, 1);
hal_gpio_set(EINK_CS_PIN, GPIO_STATE_HIGH);
}
void eink_clear_screen() {

for(int i=0;i<EINK_WIDTH * EINK_HEIGHT / 8;i++){
eink_buffer[i]=0xFF;
}
eink_display_buffer(eink_buffer);
}
void eink_draw_pixel(uint16_t x, uint16_t y, uint8_t color) {
if (x >= EINK_WIDTH || y >= EINK_HEIGHT) return;
uint16_t index = y * EINK_WIDTH / 8 + x / 8;
uint8_t bit = 7 - (x % 8);
if (color) {
eink_buffer[index] |= (1 << bit);
} else {
eink_buffer[index] &= ~(1 << bit);
}
}


void eink_display_buffer(uint8_t *buffer)
{
eink_send_command(0x24);
hal_gpio_set(EINK_CS_PIN, GPIO_STATE_LOW);
hal_gpio_set(EINK_DC_PIN, GPIO_STATE_HIGH);
hal_spi_transfer(buffer, NULL, EINK_WIDTH * EINK_HEIGHT / 8);
hal_gpio_set(EINK_CS_PIN, GPIO_STATE_HIGH);

eink_send_command(0x22);
eink_send_data(0xC7);
eink_send_command(0x20);
hal_gpio_set(EINK_CS_PIN, GPIO_STATE_LOW);
}

void eink_draw_char(uint16_t x, uint16_t y, char c, uint8_t color)
{
if(c>=' ' && c<='~')
{
uint8_t i,j;
for(i=0;i<16;i++)
{
for(j=0;j<8;j++)
{
if((Font8x16[c-0x20][i] & (0x80>>j)))
{
eink_draw_pixel(x+j,y+i,color);
}
}
}
}

}

void eink_draw_text(uint16_t x, uint16_t y, const char *text) {
uint16_t cursor_x = x;
while (*text) {
eink_draw_char(cursor_x, y, *text, 0);
cursor_x += 8;
text++;
}
eink_display_buffer(eink_buffer);
}

// Keypad
key_event_t keypad_get_event() {
// 从GPIO读取按键状态,进行防抖处理,并返回按键事件
// 这里使用简单的读取方式,实际应该添加防抖
if (hal_gpio_get(GPIO_PIN_3) == GPIO_STATE_LOW) {
for (int i = 0; i < 100000; i++); // delay
if (hal_gpio_get(GPIO_PIN_3) == GPIO_STATE_LOW) return KEY_UP;

}else if (hal_gpio_get(GPIO_PIN_4) == GPIO_STATE_LOW) {
for (int i = 0; i < 100000; i++); // delay
if (hal_gpio_get(GPIO_PIN_4) == GPIO_STATE_LOW) return KEY_DOWN;
}else if (hal_gpio_get(GPIO_PIN_5) == GPIO_STATE_LOW) {
for (int i = 0; i < 100000; i++); // delay
if (hal_gpio_get(GPIO_PIN_5) == GPIO_STATE_LOW) return KEY_OK;
}
return KEY_NONE;
}

// USB storage (略,需要实现USB MSC协议,可以参考相关例程)
void usb_storage_init() {
// USB 初始化
return;
}
void usb_storage_read(uint32_t sector, uint8_t *buffer, uint32_t count) {
// 读取 USB 存储数据
return;
}
void usb_storage_write(uint32_t sector, uint8_t *buffer, uint32_t count) {
// 写入 USB 存储数据
return;
}

// RTC
void rtc_get_time(rtc_time_t *time) {
hal_rtc_get_time(time);
}

void rtc_set_time(rtc_time_t *time)
{
hal_rtc_set_time(time);
}

3.3. 系统服务层 (System Service)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// service.h
#ifndef SERVICE_H
#define SERVICE_H

#include <stdint.h>
#include "device.h"

// File System
typedef struct {
char filename[32];
uint32_t size;
uint32_t address;
} file_info_t;

uint32_t fs_get_file_count();
file_info_t* fs_get_file_info(uint32_t index);
uint32_t fs_read_file(uint32_t index, uint8_t* buffer, uint32_t max_len);
uint32_t fs_write_file(const char* filename, uint8_t* buffer, uint32_t len);
uint32_t fs_delete_file(uint32_t index);

// Power Management
void power_enter_lowpower();

// Config Management
void config_load();
void config_save();
uint32_t config_get_value(const char* key);
void config_set_value(const char* key, uint32_t value);

#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// service.c
#include "service.h"
#include "string.h"
#include "stdio.h"
#include "stdlib.h"

// File System (简化的FAT32实现,可以根据实际情况修改)
#define MAX_FILES 10
file_info_t files[MAX_FILES];
uint32_t file_count = 0;
#define SECTOR_SIZE 512

uint32_t fs_get_file_count() {
return file_count;
}
file_info_t* fs_get_file_info(uint32_t index) {
if (index < file_count) {
return &files[index];
}
return NULL;
}
uint32_t fs_read_file(uint32_t index, uint8_t* buffer, uint32_t max_len) {
if (index >= file_count) return 0;
uint32_t read_size = files[index].size > max_len ? max_len : files[index].size;
usb_storage_read(files[index].address / SECTOR_SIZE, buffer, read_size);
return read_size;
}

uint32_t fs_write_file(const char* filename, uint8_t* buffer, uint32_t len)
{
if (file_count >= MAX_FILES) {
return 0;
}
strncpy(files[file_count].filename, filename, 31);
files[file_count].filename[31]=0;
files[file_count].size = len;
files[file_count].address = file_count * 1024 * 10;
usb_storage_write(files[file_count].address/SECTOR_SIZE, buffer, len);
file_count++;
return len;
}

uint32_t fs_delete_file(uint32_t index)
{
if(index >= file_count){
return 0;
}
for(int i=index;i<file_count-1;i++){
files[i] = files[i+1];
}
file_count--;
return 1;
}
// Power Management
void power_enter_lowpower() {
// 进入低功耗模式(示例,具体实现与MCU相关)
}

// Config Management
// 假设使用简单的KV存储在EEPROM或Flash
#define MAX_CONFIG_ENTRIES 10
typedef struct {
char key[32];
uint32_t value;
} config_entry_t;
config_entry_t config_entries[MAX_CONFIG_ENTRIES];
uint32_t config_count = 0;
void config_load() {
// 从EEPROM/Flash加载配置
// 这里使用简单示例,实际情况可以从文件系统中读取,或者使用其它方式
config_count = 0;
strcpy(config_entries[0].key, "brightness");
config_entries[0].value = 100;
strcpy(config_entries[1].key, "volume");
config_entries[1].value = 50;
config_count = 2;
}

void config_save() {
// 保存配置到EEPROM/Flash
// 这里使用简单示例
}

uint32_t config_get_value(const char* key) {
for(uint32_t i = 0; i < config_count; i++) {
if(strcmp(config_entries[i].key, key) == 0) {
return config_entries[i].value;
}
}
return 0;
}

void config_set_value(const char* key, uint32_t value) {
for(uint32_t i = 0; i < config_count; i++) {
if(strcmp(config_entries[i].key, key) == 0) {
config_entries[i].value = value;
return;
}
}
if(config_count < MAX_CONFIG_ENTRIES)
{
strcpy(config_entries[config_count].key,key);
config_entries[config_count].value = value;
config_count++;
}

}

3.4. 应用层 (Application)

1
2
3
4
5
6
7
8
// app.h
#ifndef APP_H
#define APP_H

void app_init();
void app_run();

#endif
// app.c
#include "app.h"
#include "device.h"
#include "service.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define MAX_MENU_ITEMS 10

typedef enum {
    MENU_MAIN,
    MENU_FILE,
    MENU_SETTINGS,
    MENU_TIME
} menu_state_t;

typedef struct {
    const char *text;
    menu_state_t next_menu;
} menu_item_t;


void show_menu(menu_item_t *menu, int item_count, int current_item);

void main_menu_loop();
void file_menu_loop();
void settings_menu_loop();
void time_menu_loop();

static menu_state_t current_menu = MENU_MAIN;

void app_init() {
  // 系统初始化
  hal_usb_init();
  usb_storage_init();
  eink_init();
  hal_gpio_init(GPIO_PIN_3, GPIO_MODE_INPUT);  //按键1 上
  hal_gpio_init(GPIO_PIN_4, GPIO_MODE_INPUT);  //按键2 下
  hal_gpio_init(GPIO_PIN_5, GPIO_MODE_INPUT); //按键3 确认
  hal_rtc_init();
  config_load();
}

void app_run() {
  // 主循环
  while (1) {
    switch (current_menu) {
        case MENU_MAIN:
            main_menu_loop();
            break;
        case MENU_FILE:
            file_menu_loop();
            break;
        case MENU_SETTINGS:
            settings_menu_loop();
            break;
        case MENU_TIME:
            time_menu_loop();
            break;
      default:
        current_menu = MENU_MAIN;
        break;
    }
  }
}

void main_menu_loop() {
     static int current_item = 0;
    menu_item_t main_menu[] = {
        {"File", MENU_FILE},
        {"Settings", MENU_SETTINGS},
        {"Time", MENU_TIME},
    };
    int item_count = sizeof(main_menu) / sizeof(main_menu[0]);
    
    show_menu(main_menu,item_count,current_item);

    while (1) {
        key_event_t event = keypad_get_event();
        if (event == KEY_UP) {
            current_item = (current_item - 1 + item_count) % item_count;
             show_menu(main_menu,item_count,current_item);
        } else if (event == KEY_DOWN) {
            current_item = (current_item + 1) % item_count;
             show_menu(main_menu,item_count,current_item);
        } else if (event == KEY_OK) {
            current_menu = main_menu[current_item].next_menu;
            current_item = 0; //重置子菜单选项
            break;
        }
    }
}
void file_menu_loop() {
  static int current_item = 0;
    uint32_t file_count = fs_get_file_count();
    if(file_count==0){
         eink_clear_screen();
          eink_draw_text(0, 10, "No Files!");
          
         while (1) {
            key_event_t event = keypad_get_event();
            if (event == KEY_OK){
              current_menu = MENU_MAIN;
                break;
            }
        }
        return;
    }
    menu_item_t file_menu[MAX_MENU_ITEMS];
    for (int i = 0; i < file_count; i++) {
        file_info_t *file_info = fs_get_file_info(i);
        file_menu[i].text = file_info->filename;
        file_menu[i].next_menu = MENU_FILE; //可以扩展成具体的文件操作
    }

    show_menu(file_menu,file_count,current_item);
  while (1) {
    key_event_t event = keypad_get_event();
    if (event == KEY_UP) {
      current_item = (current_item - 1 + file_count) % file_count;
      show_menu(file_menu,file_count,current_item);
    } else if (event == KEY_DOWN) {
      current_item = (current_item + 1) % file_count;
       show_menu(file_menu,file_count,current_item);
    } else if (event == KEY_OK) {
           eink_clear_screen();
        uint8_t buffer[200];
          fs_read_file(current_item, buffer, 200);
         eink_draw_text(0, 10, (char *)buffer);

        while (1) {
           key_event_t event = keypad_get_event();
           if (event == KEY_OK){
              current_menu = MENU_MAIN;
                break;
            }
        }
          break;
    }
  }
}

void settings_menu_loop() {
    static int current_item = 0;
    menu_item_t settings_menu[] = {
        {"Brightness", MENU_SETTINGS},
        {"Volume", MENU_SETTINGS},
    };
    int item_count = sizeof(settings_menu) / sizeof(settings_menu[0]);
     show_menu(settings_menu,item_count,current_item);
  
  while (1) {
    key_event_t event = keypad_get_event();
    if (event == KEY_UP) {
        current_item = (current_item - 1 + item_count) % item_count;
      show_menu(settings_menu,item_count,current_item);
    } else if (event == KEY_DOWN) {
      current_item = (current_item + 1) % item_count;
      show_menu(settings_menu,item_count,current_item);
    } else if (event == KEY_OK) {

        if(current_item==0){
            uint32_t brightness = config_get_value("brightness");
             eink_clear_screen();
            char display_str[20];
            sprintf(display_str,"Brightness:%d",brightness);
              eink_draw_text(0, 10, display_str);
            while(1){
                key_event_t event = keypad_get_event();
                if (event == KEY_UP) {
                    if(brightness <100){
                        brightness +=10;
                         char display_str[20];
                         sprintf(display_str,"Brightness:%d",brightness);
                            eink_clear_screen();
                            eink_draw_text(0, 10, display_str);
                    }
                     
                } else if (event == KEY_DOWN) {
                    if(brightness >0){
                       brightness -=10;
                         char display_str[20];
                         sprintf(display_str,"Brightness:%d",brightness);
                         eink_clear_screen();
                         eink_draw_text(0, 10, display_str);
                    }
                }else if (event == KEY_OK) {
                   config_set_value("brightness",brightness);
                   current_menu = MENU_MAIN;
                   break;
               }
            }

        }else if(current_item == 1){
           uint32_t volume = config_get_value("volume");
            eink_clear_screen();
            char display_str[20];
             sprintf(display_str,"Volume:%d",volume);
              eink_draw_text(0, 10, display_str);
             while(1){
                 key_event_t event = keypad_get_event();
                if (event == KEY_UP) {
                   if(volume<100){
                     volume += 10;
                     char display_str[20];
                     sprintf(display_str,"Volume:%d",volume);
                    eink_clear_screen();
                    eink_draw_text(0, 10, display_str);
                  }
                } else if (event == KEY_DOWN) {
                  if(volume>0){
                     volume -= 10;
                     char display_str[20];
                     sprintf(display_str,"Volume:%d",volume);
                      eink_clear_screen();
                      eink_draw_text(0, 10, display_str);

欢迎关注我的其它发布渠道