DEV_OBJ和 DRI_OBJ 结构

本文详细解析了Windows内核中的设备对象结构,包括结构组成、各域的用途及重要性,帮助开发者深入理解设备驱动开发的基础知识。

struct _DRIVER_OBJECT (sizeof=168)

+00 int16 Type

+02 int16 Size

+04 struct _DEVICE_OBJECT *DeviceObject

+08 uint32 Flags

+0c void *DriverStart

+10 uint32 DriverSize

+14 void *DriverSection

+18 struct _DRIVER_EXTENSION *DriverExtension

+1c struct _UNICODE_STRING DriverName

+1c uint16 Length

+1e uint16 MaximumLength

+20 uint16 *Buffer

+24 struct _UNICODE_STRING *HardwareDatabase

+28 struct _FAST_IO_DISPATCH *FastIoDispatch

+2c function *DriverInit+30 function *DriverStartIo

+34 function *DriverUnload+38 function *MajorFunction[28]

DDK 中有对于一些域的说明

[00] IRP_MJ_CREATE

[01] IRP_MJ_CREATE_NAMED_PIPE

[02] IRP_MJ_CLOSE

[03] IRP_MJ_READ

[04] IRP_MJ_WRITE

[05] IRP_MJ_QUERY_INFORMATION

[06] IRP_MJ_SET_INFORMATION

[07] IRP_MJ_QUERY_EA

[08] IRP_MJ_SET_EA

[09] IRP_MJ_FLUSH_BUFFERS

[0a] IRP_MJ_QUERY_VOLUME_INFORMATION

[0b] IRP_MJ_SET_VOLUME_INFORMATION

[0c] IRP_MJ_DIRECTORY_CONTROL

[0d] IRP_MJ_FILE_SYSTEM_CONTROL

[0e] IRP_MJ_DEVICE_CONTROL

[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL

[10] IRP_MJ_SHUTDOWN

[11] IRP_MJ_LOCK_CONTROL

[12] IRP_MJ_CLEANUP

[13] IRP_MJ_CREATE_MAILSLOT

[14] IRP_MJ_QUERY_SECURITY

[15] IRP_MJ_SET_SECURITY

[16] IRP_MJ_POWER

[17] IRP_MJ_SYSTEM_CONTROL

[18] IRP_MJ_DEVICE_CHANGE

[19] IRP_MJ_QUERY_QUOTA

[1a] IRP_MJ_SET_QUOTA

[1b] IRP_MJ_PNP

 

struct _DRIVER_EXTENSION (sizeof=24)

+00 struct _DRIVER_OBJECT *DriverObject

+04 function *AddDevice

+08 uint32 Count

+0c struct _UNICODE_STRING ServiceKeyName

+0c uint16 Length

+0e uint16 MaximumLength

+10 uint16 *Buffer

+14 struct _IO_CLIENT_EXTENSION *ClientDriverExtension

设备对象结构 DEVICE_OBJECT ,定义如下

struct _DEVICE_OBJECT (sizeof=184)

+00 int16 Type

+02 uint16 Size

+04 int32 ReferenceCount

+08 struct _DRIVER_OBJECT *DriverObject

+0c struct _DEVICE_OBJECT *NextDevice

+10 struct _DEVICE_OBJECT *AttachedDevice

+14 struct _IRP *CurrentIrp

+18 struct _IO_TIMER *Timer

+1c uint32 Flags

+20 uint32 Characteristics

+24 struct _VPB *Vpb

+28 void *DeviceExtension

+2c uint32 DeviceType

+30 char StackSize

+34 union __unnamed62 Queue

+34 struct _LIST_ENTRY ListEntry

+34 struct _LIST_ENTRY *Flink

+38 struct _LIST_ENTRY *Blink

+34 struct _WAIT_CONTEXT_BLOCK Wcb

+34 struct _KDEVICE_QUEUE_ENTRY WaitQueueEntry

+34 struct _LIST_ENTRY DeviceListEntry

+34 struct _LIST_ENTRY *Flink

+38 struct _LIST_ENTRY *Blink

+3c uint32 SortKey

+40 byte Inserted

+44 function *DeviceRoutine

+48 void *DeviceContext

+4c uint32 NumberOfMapRegisters

+50 void *DeviceObject

+54 void *CurrentIrp

+58 struct _KDPC *BufferChainingDpc

+5c uint32 AlignmentRequirement

+60 struct _KDEVICE_QUEUE DeviceQueue

+60 int16 Type+62 int16 Size

+64 struct _LIST_ENTRY DeviceListHead

+64 struct _LIST_ENTRY *Flink

+68 struct _LIST_ENTRY *Blink

+6c uint32 Lock

+70 byte Busy

+74 struct _KDPC Dpc

+74 int16 Type

+76 byte Number

+77 byte Importance

+78 struct _LIST_ENTRY DpcListEntry

+78 struct _LIST_ENTRY *Flink

+7c struct _LIST_ENTRY *Blink

+80 function *DeferredRoutine

+84 void *DeferredContext

+88 void *SystemArgument1

+8c void *SystemArgument2

+90 uint32 *Lock

+94 uint32 ActiveThreadCount

+98 void *SecurityDescriptor

+9c struct _KEVENT DeviceLock

+9c struct _DISPATCHER_HEADER Header

+9c byte Type

+9d byte Absolute

+9e byte Size

+9f byte Inserted

+a0 int32 SignalState

+a4 struct _LIST_ENTRY WaitListHead

+a4 struct _LIST_ENTRY *Flink

+a8 struct _LIST_ENTRY *Blink

+ac uint16 SectorSize+ae uint16 Spare1

+b0 struct _DEVOBJ_EXTENSION *DeviceObjectExtension

+b4 void *Reserved

DDK 中有对于一些域的说明

struct _DEVOBJ_EXTENSION (sizeof=36)

+00 int16 Type

+02 uint16 Size

+04 struct _DEVICE_OBJECT *DeviceObject

+08 uint32 PowerFlags

+0c *Dope+10 uint32 ExtensionFlags

+14 void *DeviceNode

+18 struct _DEVICE_OBJECT *AttachedTo

+1c struct _LIST_ENTRY FileObjectList

+1c struct _LIST_ENTRY *Flink

+20 struct _LIST_ENTRY *Blink

#include "lvgl/lvgl.h" #include "lvgl/demos/lv_demos.h" #include <unistd.h> #include <pthread.h> #include <time.h> #include <stdio.h> #include <stdlib.h> static const char * getenv_default(const char * name, const char * dflt) { return getenv(name) ?: dflt; } #if LV_USE_LINUX_FBDEV static void lv_linux_disp_init(void) { const char * device = getenv_default("LV_LINUX_FBDEV_DEVICE", "/dev/fb0"); lv_display_t * disp = lv_linux_fbdev_create(); lv_linux_fbdev_set_file(disp, device); } #elif LV_USE_LINUX_DRM static void lv_linux_disp_init(void) { const char * device = getenv_default("LV_LINUX_DRM_CARD", "/dev/dri/card0"); lv_display_t * disp = lv_linux_drm_create(); lv_linux_drm_set_file(disp, device, -1); } #elif LV_USE_SDL//当前使用的是SDL框架 static void lv_linux_disp_init(void) { const int width = atoi(getenv("LV_SDL_VIDEO_WIDTH") ?: "800"); const int height = atoi(getenv("LV_SDL_VIDEO_HEIGHT") ?: "480"); lv_sdl_window_create(width, height); } #else #error Unsupported configuration #endif /* //按钮点击事件处理函数 void btn_event(lv_event_t * e) { printf("button clicked\n"); } */ lv_obj_t * label;//把标签定义为全局变量,让所有函数都可以访问 lv_obj_t * img;//把图片定义为全局变量,让所有函数都可以访问 /* //定义一个颜色数组 static lv_color_t colors[10] = {0};//10种颜色 int color_index = 0;//颜色索引 void btn_event_1(lv_event_t * e) { printf("prev button clicked\n"); color_index++; if(color_index > 10)//防止越界 { color_index = 0; } lv_obj_set_style_text_color(label, arry[color_index], 0); } void btn_event_2(lv_event_t * e) { printf("next button clicked\n"); color_index++; if(color_index > 10)//防止越界 { color_index = 0; } lv_obj_set_style_text_color(label, arry[color_index], 0); } //初始化用户的UI界面 void init_ui(void) { //初始化颜色数组 arry[0] = lv_color_make(255, 0, 0); arry[1] = lv_color_make(0, 255, 0); arry[2] = lv_color_make(0, 0, 255); arry[3] = lv_color_make(255, 255, 0); arry[4] = lv_color_make(255, 0, 255); arry[5] = lv_color_make(0, 255, 255); arry[6] = lv_color_make(255, 255, 255); arry[7] = lv_color_make(0, 0, 0); arry[8] = lv_color_make(128, 128, 128); arry[9] = lv_color_make(64, 64, 64); //创建一个标签 lv_obj_t * label = lv_label_create(lv_scr_act()); //标签居中显示 lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); //设置标签的字体大小 lv_obj_set_style_text_font(label, &lv_font_montserrat_16, 0); //设置标签的文本内容 lv_label_set_text(label, "Hello, LVGL!"); //设置两个按钮 lv_obj_t * btn1 = lv_btn_create(lv_scr_act()); lv_obj_t * btn2 = lv_btn_create(lv_scr_act()); //设置按钮的大小 lv_obj_set_size(btn1, 100, 50); lv_obj_set_size(btn2, 100, 50); //设置按钮的位置 lv_obj_align(btn1, LV_ALIGN_CENTER, -100, 50); lv_obj_align(btn2, LV_ALIGN_CENTER, 100, 50); //创建两个标签在按钮上 lv_obj_t * label1 = lv_label_create(btn1); lv_obj_t * label2 = lv_label_create(btn2); //设置标签的文本内容 lv_label_set_text(label1, "prev"); lv_label_set_text(label2, "next"); //设置标签在按钮居中 lv_obj_align(label1, LV_ALIGN_CENTER, 0, 0); lv_obj_align(label2, LV_ALIGN_CENTER, 0, 0); //给按钮事件函数 lv_obj_add_event_cb(btn1, btn_event_1, LV_EVENT_CLICKED, NULL); lv_obj_add_event_cb(btn2, btn_event_2, LV_EVENT_CLICKED, NULL); } */ /* //实现按钮切换图片的例 //初始化用户的UI界面 // 全局图片对象索引 int current_img_index = 0; // 当前图片索引 const char *img_list[] = { // 图片路径列表 "A:./pic/1.bmp", "A:./pic/2.bmp", // 根据实际图片数量扩展 }; int img_count = sizeof(img_list) / sizeof(img_list[0]); // 图片总数 //图片事件 //制作一个图片浏览器,点击按钮实现图片上下切换 // prev按钮:切换到上一张图片(循环) void btn_event_1(lv_event_t *e) { current_img_index = (current_img_index - 1 + img_count) % img_count; lv_image_set_src(img, img_list[current_img_index]); // 更新图片 printf("prev button clicked, show image %d\n", current_img_index + 1); } // next按钮:切换到下一张图片(循环) void btn_event_2(lv_event_t *e) { current_img_index = (current_img_index + 1) % img_count; lv_image_set_src(img, img_list[current_img_index]); // 更新图片 printf("next button clicked, show image %d\n", current_img_index + 1); } void init_ui(void) { img = lv_image_create(lv_screen_active()); // 赋值给全局变量 lv_image_set_src(img, img_list[current_img_index]); // 初始显示第一张 lv_obj_align(img, LV_ALIGN_CENTER, 0, 0); //设置两个按钮 lv_obj_t * btn1 = lv_btn_create(lv_scr_act()); lv_obj_t * btn2 = lv_btn_create(lv_scr_act()); //设置按钮的大小 lv_obj_set_size(btn1, 100, 50); lv_obj_set_size(btn2, 100, 50); //设置按钮的位置 lv_obj_align(btn1, LV_ALIGN_BOTTOM_LEFT, 10, 10); lv_obj_align(btn2, LV_ALIGN_BOTTOM_RIGHT, -10, 10); //创建两个标签在按钮上 lv_obj_t * label1 = lv_label_create(btn1); lv_obj_t * label2 = lv_label_create(btn2); //设置标签的文本内容 lv_label_set_text(label1, "prev"); lv_label_set_text(label2, "next"); //设置标签在按钮居中 lv_obj_align(label1, LV_ALIGN_CENTER, 0, 0); lv_obj_align(label2, LV_ALIGN_CENTER, 0, 0); //给按钮事件函数 lv_obj_add_event_cb(btn1, btn_event_1, LV_EVENT_CLICKED, NULL); lv_obj_add_event_cb(btn2, btn_event_2, LV_EVENT_CLICKED, NULL); } */ // 电脑本地图片路径(替换为实际图片文件名) #define LOGIN_IMG_PATH "A:E:/Users/ASUS/Pictures/5.bmp" // 登录提示图 #define REGISTER_IMG_PATH "A:E:/Users/ASUS/Pictures/4.bmp" // 注册提示图 static void create_auto_del_img(const char *img_path) { // 创建图片对象 lv_obj_t *tips_img = lv_img_create(lv_scr_act()); // 设置图片源(直接使用电脑本地路径) lv_img_set_src(tips_img, img_path); // 图片居中显示 lv_obj_align(tips_img, LV_ALIGN_CENTER, 0, 0); // 调整图片大小(根据实际图片尺寸,这里以300x200为例) lv_obj_set_size(tips_img, 300, 200); // 3秒后自动删除图片 lv_timer_create( [](lv_timer_t *timer) { lv_obj_del(timer->user_data); // 删除图片 lv_timer_del(timer); // 删除定时器 }, 3000, // 3000ms = 3秒 tips_img ); } static void login_btn_event(lv_event_t *e) { printf("登录按钮点击,显示图片:%s\n", LOGIN_IMG_PATH); create_auto_del_img(LOGIN_IMG_PATH); } // 注册按钮点击:显示4.bmp static void register_btn_event(lv_event_t *e) { printf("注册按钮点击,显示图片:%s\n", REGISTER_IMG_PATH); create_auto_del_img(REGISTER_IMG_PATH); } //键盘例子 static void ta_event_cb(lv_event_t * e) { //获取事件号 lv_event_code_t code = lv_event_get_code(e); //获取触发事件的对象 lv_obj_t * ta = lv_event_get_target(e); //获取键盘对象 lv_obj_t * kb = lv_event_get_user_data(e); if(code == LV_EVENT_FOCUSED) //判断焦点是否进入 { lv_keyboard_set_textarea(kb, ta);//把键盘设置到对应的输入框 lv_obj_remove_flag(kb, LV_OBJ_FLAG_HIDDEN);//显示键盘 } if(code == LV_EVENT_DEFOCUSED) //判断是否焦点离开 { lv_keyboard_set_textarea(kb, NULL);//把键盘离开输入框 lv_obj_add_flag(kb, LV_OBJ_FLAG_HIDDEN);//隐藏键盘 } } void my_keyboard(void) { /*Create a keyboard to use it with an of the text areas*/ lv_obj_t * kb = lv_keyboard_create(lv_screen_active());//创建键盘对象 /*Create a text area. The keyboard will write here*/ lv_obj_t * ta1; ta1 = lv_textarea_create(lv_screen_active());//创建文本输入框 lv_obj_align(ta1, LV_ALIGN_CENTER,0, -100);//设置输入框的位置 lv_obj_add_event_cb(ta1, ta_event_cb, LV_EVENT_ALL, kb);//添加文本输入框的事件,传递键盘对象 lv_textarea_set_placeholder_text(ta1, "Hello");//设置文本输入框的提示信息 //lv_obj_set_size(ta1, 140, 30);//设置文本输入框的大小 lv_textarea_set_one_line(ta1, true);//设置文本输入框为单行 lv_obj_t * ta2; ta2 = lv_textarea_create(lv_screen_active()); lv_obj_align(ta2, LV_ALIGN_CENTER, 0, -50); lv_obj_add_event_cb(ta2, ta_event_cb, LV_EVENT_ALL, kb); //lv_obj_set_size(ta2, 140, 30); lv_textarea_set_one_line(ta2, true);//设置文本输入框为单行 lv_obj_add_event_cb(ta2, ta_event_cb, LV_EVENT_ALL, kb);//添加第二个文本输入框的事件,传递键盘对象 lv_obj_add_event_cb(ta1, ta_event_cb, LV_EVENT_ALL, kb);//添加文本输入框的事件,传递键盘对象 //创建一个登录按钮 lv_obj_t *btn = lv_btn_create(lv_screen_active()); lv_obj_align_to(btn, ta2,LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0); lv_obj_t *label = lv_label_create(btn); lv_label_set_text(label, "loin"); //创建一个注册按钮 lv_obj_t *btn2 = lv_btn_create(lv_screen_active()); lv_obj_align_to(btn2, ta2,LV_ALIGN_OUT_BOTTOM_RIGHT, -60, 0); lv_obj_t *label2 = lv_label_create(btn2); lv_label_set_text(label2, "register"); //给按钮事件函数 lv_obj_add_event_cb(btn, btn_event_1, LV_EVENT_CLICKED, NULL); lv_obj_add_event_cb(btn2, btn_event_2, LV_EVENT_CLICKED, NULL); } int main(void) { lv_init();//初始化LVGL库 /*Linux display device init*/ lv_linux_disp_init();//Linux显示设备初始化 #if LV_USE_SDL printf("init input\n"); //初始化输入设备 //init input device lv_sdl_mouse_create(); //初始化鼠标 lv_sdl_keyboard_create(); //初始化键盘 lv_sdl_mousewheel_create(); //初始化鼠标滚轮 printf("init input end\n"); #endif /*Create a Demo*/ //创建一个Demo(例子) // lv_example_button_1(); // lv_demo_widgets(); // lv_demo_widgets_start_slideshow(); //lv_example_ime_pinyin_2(); /*Handle LVGL tasks*/ //在屏幕中创建一个对象 //例子:设置一个对象的位置与大小 //Create a Demo 创建例子 /*lv_obj_t *obj = lv_obj_create(lv_screen_active()); // 在当前显示器中创建一个对象 lv_obj_set_size(obj, 100, 100);// 设置对象的大小 lv_obj_align(obj,LV_ALIGN_CENTER,0,0); //lv_obj_set_pos(obj, 350, 190);// 设置对象的位置 //void lv_obj_set_align(obj, LV_ALIGN_TOP_LEFT,) //快速设置当前对象的位置 //lv_obj_align(obj,LV_ALIGN_BOTTOM_RIGHT,-30,-30); //快速设置当前对象的位置,且可以设置偏移量 lv_obj_t *obj1 = lv_obj_create(lv_screen_active()); // 在当前显示器中创建一个对象 lv_obj_set_size(obj1, 100, 100);// 设置对象的大小 lv_obj_align_to(obj1,obj,LV_ALIGN_OUT_BOTTOM_RIGHT,-100,0); */ /*Create a Demo 创建例子*/ /* lv_obj_t *obj = lv_obj_create(lv_screen_active()); // 在当前显示器中创建一个对象 // 设置对象的大小 lv_obj_set_size(obj, 300, 300); // 设置大对象的位置 lv_obj_align(obj, LV_ALIGN_CENTER, 0, 0); // 在obj对象上再创建一个对象 lv_obj_t *obj1 = lv_obj_create(obj); lv_obj_set_size(obj1, 60, 60); lv_obj_align(obj1, LV_ALIGN_CENTER, 0, 0); lv_obj_t *obj2 = lv_obj_create(obj); lv_obj_set_size(obj2, 60, 60); lv_obj_align_to(obj2, obj1, LV_ALIGN_OUT_LEFT_MID,-40, 0); lv_obj_t *obj3 = lv_obj_create(obj); lv_obj_set_size(obj3, 60, 60); lv_obj_align_to(obj3, obj1, LV_ALIGN_OUT_RIGHT_MID,40, 0); lv_obj_t *obj4 = lv_obj_create(obj); lv_obj_set_size(obj4, 60, 60); lv_obj_align_to(obj4, obj1, LV_ALIGN_OUT_TOP_MID,0, -40); lv_obj_t *obj5 = lv_obj_create(obj); lv_obj_set_size(obj5, 60, 60); lv_obj_align_to(obj5, obj1, LV_ALIGN_OUT_BOTTOM_MID,0, 40); lv_obj_t *obj6 = lv_obj_create(obj); lv_obj_set_size(obj6, 60, 60); lv_obj_align_to(obj6, obj4, LV_ALIGN_OUT_LEFT_MID,-40, 0); lv_obj_t *obj7 = lv_obj_create(obj); lv_obj_set_size(obj7, 60, 60); lv_obj_align_to(obj7, obj4, LV_ALIGN_OUT_RIGHT_MID,40, 0); lv_obj_t *obj8 = lv_obj_create(obj); lv_obj_set_size(obj8, 60, 60); lv_obj_align_to(obj8, obj5, LV_ALIGN_OUT_LEFT_MID,-40, 0); lv_obj_t *obj9 = lv_obj_create(obj); lv_obj_set_size(obj9, 60, 60); lv_obj_align_to(obj9, obj5, LV_ALIGN_OUT_RIGHT_MID,40, 0); */ /* //创建一个标签对象 lv_obj_t *name = lv_label_create(lv_screen_active()); lv_label_set_text(name,"zhangsiman"); lv_obj_align(name,LV_ALIGN_CENTER,0,0); lv_obj_t *class = lv_label_create(lv_screen_active()); lv_label_set_text(class,"wulian4221"); lv_obj_align(class,LV_ALIGN_CENTER,0,30); lv_obj_t *xuehao = lv_label_create(lv_screen_active()); lv_label_set_text_fmt(xuehao,"202244021131"); lv_obj_align(xuehao,LV_ALIGN_CENTER,0,60); */ /* lv_obj_t *xuehao = lv_label_create(lv_screen_active()); lv_label_set_text_fmt(xuehao,"202244021131"); lv_obj_align(xuehao,LV_ALIGN_CENTER,0,0); lv_obj_set_style_text_font(xuehao,&lv_font_montserrat_24,0); lv_obj_set_style_text_color(xuehao, lv_color_make(255,0,0),0); */ /* 按钮事件 lv_obj_t *btn = lv_btn_create(lv_screen_active()); lv_obj_set_size(btn, 100, 50); lv_obj_align(btn, LV_ALIGN_CENTER, 0, 0); lv_obj_t *label = lv_label_create(btn); lv_label_set_text(label, "Click me"); lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); lv_obj_add_event_cb(btn, btn_event, LV_EVENT_CLICKED, NULL); */ /* //图片例子 lv_obj_t *img = lv_image_create(lv_screen_active()); //设置图片路径名 //lv_img_set_src(img, "E:\\Users\\ASUS\\1.bmp"); lv_image_set_src(img, "A:./pic/1.bmp"); lv_obj_align(img, LV_ALIGN_CENTER, 0, 0); */ /*实现按钮切换图片的例子 init_ui(); */ /*触摸屏按钮事件 #if LV_USE_LINUX_FBDEV //创建触摸屏驱动设备 lv_indev_t *touch = lv_evdev_create(LV_INDEV_TYPE_POINTER, "/dev/input/event0"); //校准触摸屏坐标 lv_evdev_set_calibration(touch, 0, 0, 1024, 600);//黑色边框的屏幕 #endif //创建一个按钮 lv_obj_t *btn = lv_button_create(lv_screen_active()); //设置按钮的大小 lv_obj_set_size(btn, 100, 50); //居中显示按钮 lv_obj_align(btn, LV_ALIGN_CENTER, 0, 0); //添加按钮的事件函数 lv_obj_add_event_cb(btn, btn_event, LV_EVENT_CLICKED, NULL); */ my_keyboard(); while(1) { lv_timer_handler(); usleep(5000); } return 0; }
10-24
按照运行顺序逐行解释以下代码 // // Created by yang on 2024/2/21. // #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include "lv_app.h" #include "lv_video.h" #include "ffplay.h" #include "hal_common.h" #include "fbdev.h" #include <unistd.h> #ifndef RESOURCE_DIR #define RESOURCE_DIR "/storage/assets" #endif static lv_app_t app = {0}; static int need_align = 0; lv_app_t * get_lv_app() { return &app; } typedef struct lv_app_cb_ctx_ { lv_obj_t *obj; int posx; int posy; int target_x,target_y; int target_w,target_h; }lv_app_cb_ctx; static volatile int once_end; static volatile uint32_t st = 0; void refresh_ui(lv_timer_t * timer); void video_refresh(void *); int video_eof_proc(void *context, int is_loop) { printf("once video eof, callback!\n"); once_end = 1; if (!st) { if(app.timer) lv_timer_ready(app.timer); else lv_async_call(video_refresh, NULL); } return 0; } static void video_obj_change(void *r) { lv_app_cb_ctx *cbctx = (lv_app_cb_ctx *)r; lv_obj_set_pos(cbctx->obj,cbctx->target_x,cbctx->target_y); lv_obj_set_size(cbctx->obj,cbctx->target_w,cbctx->target_h); } /* video start call back! */ static void update_pos(void *context, ImppRect *vd_rect, ImppRect *trg_rect, ImppRect *crop_rect, int *scaler, int64_t duration_us) { lv_app_cb_ctx *cbctx; cbctx= (lv_app_cb_ctx *)context; int screen_w = trg_rect->w; int screen_h = trg_rect->h; int scaled_w, scaled_h; printf("screen_w: %d screen_h: %d\n",screen_w,screen_h); /* set video source crop rect. */ crop_rect->x = 0; crop_rect->y = 0; crop_rect->w = vd_rect->w; crop_rect->h = vd_rect->h; if (need_align) { /* display position and size setted by lv_obj_set_pos and lv_obj_set_size */ float scale_w = (float)screen_w / vd_rect->w; float scale_h = (float)screen_h / vd_rect->h; float scale = scale_w < scale_h ? scale_w : scale_h; // Apply scaling factor to maintain aspect ratio scaled_w = vd_rect->w * scale; scaled_h = vd_rect->h * scale; trg_rect->x = cbctx->posx + (screen_w - scaled_w) / 2; trg_rect->y = cbctx->posy + (screen_h - scaled_h) / 2; } else { scaled_w = screen_w < vd_rect->w ? screen_w : vd_rect->w; scaled_h = screen_h < vd_rect->h ? screen_h : vd_rect->h; trg_rect->x = cbctx->posx; trg_rect->y = cbctx->posy; } // Center the video in the target rectangle trg_rect->w = scaled_w; trg_rect->h = scaled_h; /* Is do scaler from video size to display size*/ *scaler =1; video_reset_param(vd_rect->w, vd_rect->h); cbctx->target_x = trg_rect->x; cbctx->target_y = trg_rect->y; cbctx->target_w = trg_rect->w; cbctx->target_h = trg_rect->h; lv_async_call(video_obj_change, cbctx); /* dump video duration */ #define US_TIME_BASE 1000000 { int hours, mins, secs, us; int64_t duration = duration_us; secs = duration / US_TIME_BASE; us = duration % US_TIME_BASE; mins = secs / 60; secs %= 60; hours = mins / 60; mins %= 60; printf("[video duration]: %02d:%02d:%02d.%02d\n", hours, mins, secs, (100 * us) / US_TIME_BASE); } } lv_obj_t* build_text(lv_obj_t *parent,const char* text, const lv_font_t *font, lv_color_t color, int align, int x, int y) { lv_obj_t * label = lv_label_create(parent); lv_label_set_text(label, text); lv_obj_set_style_text_color(parent, color, LV_PART_MAIN); lv_obj_set_style_text_font(label,font,LV_PART_MAIN); lv_obj_align(label, align, x, y); return label; } static void lv_obj_img_set_zoom(lv_obj_t * obj_img, const char *src, uint32_t obj_width, uint32_t obj_height) { if (obj_img == NULL || src == NULL || src[0] == '\0') { printf("[%s:%d] param errror\n", __FUNCTION__, __LINE__); return; } if (obj_width == 0 || obj_height == 0) { printf("[%s:%d] param errror\n", __FUNCTION__, __LINE__); return; } uint32_t img_width = 0, img_height = 0; // 获取img对象的信息 lv_img_header_t header; if (lv_img_decoder_get_info(src, &header) != LV_RES_OK) { printf("[%s:%d] lv_img_decoder_get_info errror\n", __FUNCTION__, __LINE__); return; } img_width = header.w; img_height = header.h; // 计算宽高比 float width_ratio = (float)obj_width / img_width; float height_ratio = (float)obj_height / img_height; float zoom_factor = width_ratio < height_ratio ? width_ratio : height_ratio; lv_img_set_zoom(obj_img, (uint16_t)(zoom_factor *256)); } lv_obj_t* build_image(lv_obj_t *parent,char *filename) { lv_obj_t *obj = lv_img_create(parent); lv_img_set_src(obj, filename); if (need_align) { lv_obj_align(obj, LV_ALIGN_TOP_LEFT, 0, 0); printf("image: %d %d\n",LV_HOR_RES, LV_VER_RES); lv_obj_img_set_zoom(obj,filename, LV_HOR_RES, LV_VER_RES); } return obj; } lv_obj_t* build_video(lv_obj_t *parent,char *filename,int x,int y,uint32_t settime) { lv_obj_t *obj = NULL; obj = lv_video_create(parent); if (!obj) { printf("create video obj fail\n"); return NULL; } /* set position and size through callback; TODO: where to free? */ FfplayCallback *cback_info = lv_video_init_cbinfo(obj, sizeof(lv_app_cb_ctx)); if (!cback_info) return NULL; lv_app_cb_ctx* cbctx = (lv_app_cb_ctx*)cback_info->context; cbctx->obj = obj; cbctx->posx = x; cbctx->posy = y; cback_info->sync_start_time_sec = settime; cback_info->update_pos = update_pos; cback_info->video_eof = video_eof_proc; lv_video_register_cb(cback_info); /* start stream */ lv_video_set_filename(obj, filename); lv_video_set_audio_volume(obj, 15); /* Adjusting volume 0-99 */ /* Call lv_video_play in lv_video_event process, to synchronize video playback and image drawing. If want immediately play video, can call lv_video_play here; lv_video_play(obj); */ lv_video_set_loop(obj, 1); return obj; } void* build_br(lv_obj_t *parent, const char* val) { lv_coord_t br_hight = 50; lv_obj_t * obj = lv_barcode_create(parent, br_hight, lv_color_black(), lv_color_white()); lv_barcode_set_scale(obj, 1); lv_barcode_set_direction(obj, LV_DIR_HOR); // lv_barcode_set_direction(obj, LV_DIR_VER); char buff[128]; sprintf(buff,"%s",val); lv_barcode_update(obj, buff); lv_obj_align(obj, LV_ALIGN_BOTTOM_MID, 0, 0); return obj; } void* build_qr(lv_obj_t *parent, const char* val) { lv_coord_t qr_size = 240; qr_size = 80; lv_obj_t * obj = lv_qrcode_create(parent, qr_size, lv_color_black(), lv_color_white()); char buff[128]; sprintf(buff,"lvglDemo:%s",val); lv_qrcode_update(obj, buff, strlen(buff)); lv_obj_align(obj,LV_ALIGN_BOTTOM_RIGHT,0,0); return obj; } void layer_clean_obj(lv_obj_t *obj) { if (obj) lv_obj_del(obj); lv_img_cache_invalidate_src(NULL); } void layer_clean() { lv_obj_clean(app.container); lv_img_cache_invalidate_src(NULL); } #define MAX_RES 4 #define MAST_RES 4 #define SLAVE_RES 4 typedef char* fstring; static fstring mfname[2][MAX_RES] = { {"1.png", "2.png", "1.png", "2.png", }, {"1.mp4", "2.mp4", "1.mp4", "2.mp4",} }; static char *sfname[2][MAX_RES] = { {"1.png", "2.png", "1.png", "2.png",}, {"1.mp4", "radish.mp4", "full-screen.mp4", "2.mp4",} }; static char *get_res_name(char *path,int sz,int res_id,int res_type) { char *v = getenv("MODE"); fstring (*flist)[MAX_RES]; int id; flist = &mfname[0]; id = res_id % MAST_RES; if (v == NULL) v = "MASTER"; else if (strcmp(v, "MASTER")) { flist = &sfname[0]; id = res_id % SLAVE_RES; } if(res_type == 0) snprintf(path, sz, "%s/%s/%s", RESOURCE_DIR,v,flist[0][id]); else if(res_type == 1) snprintf(path, sz, "%s/%s/%s", RESOURCE_DIR,v,flist[1][id]); else if(res_type == 2) return "price app"; else if(res_type == 3) return "iABC-abc-1234"; printf("%d %d path: %s\n",id, res_type, path); return path; } void* build_lable(lv_obj_t *parent) { lv_obj_t *opa_label = lv_label_create(parent); lv_obj_set_style_bg_opa(opa_label, 128, LV_PART_MAIN); lv_obj_set_style_bg_color(opa_label, lv_color_black(), 0); lv_obj_set_style_text_color(opa_label, lv_color_white(), 0); lv_obj_set_style_text_align(opa_label, LV_TEXT_ALIGN_CENTER, 0); lv_obj_set_size(opa_label, 400, 500); lv_obj_set_pos(opa_label, 200, 100); lv_label_set_text(opa_label, "Hello alpha"); return opa_label; } static lv_obj_t *img_obj; static lv_obj_t *video_obj; static lv_obj_t *text_obj; static lv_obj_t *qr_obj, *label_obj; //static lv_obj_t *br_obj; void update_text(lv_timer_t * timer) { static int count = 0; char text[128]; if (text_obj) { sprintf(text, "host,version (%s) - %08d", __DATE__, count++); lv_label_set_text(text_obj, text); } } void video_refresh(void * unused) { refresh_ui(NULL); } void refresh_ui(lv_timer_t * timer) { static int id = 0; /* Eacho refresh clean layers to avoid memory leaks. Once build_xx while alloc some memory. And close pre-video event. Must call layer_clean before build new video */ char buf[128] = {0}; if (!once_end) return; once_end = 0; /* layer_clean_obj(text_obj); */ /* layer_clean_obj(img_obj); */ layer_clean_obj(video_obj); layer_clean_obj(qr_obj); // layer_clean_obj(br_obj); layer_clean_obj(label_obj); lv_img_set_src(img_obj, get_res_name(buf,sizeof(buf),id,0)); /* img_obj = build_image(app.container, get_res_name(buf,sizeof(buf),id,0)); */ /* set alpha to ARGB image */ /* lv_obj_set_style_bg_opa(img_obj, 10, LV_OPA_TRANSP); */ video_obj = build_video(app.container, get_res_name(buf,sizeof(buf),id,1),0,0,0); id++; qr_obj = build_qr(app.container, get_res_name(buf,sizeof(buf),0,2)); // br_obj = build_br(app.container, get_res_name(buf,sizeof(buf),0,3)); // label_obj = build_lable(app.container); lv_obj_set_style_bg_opa(app.container, 127, LV_OPA_TRANSP); lv_obj_set_style_bg_color(app.container, lv_palette_lighten(LV_PALETTE_RED, 3), 0); } void hal_set_rotate(lv_disp_rot_t rotation); static void key_obj_cb(lv_event_t *e) { lv_obj_t * kp = lv_event_get_target(e); lv_event_code_t code = lv_event_get_code(e); static int curkey_angle = 0; static int keycount = 0; if (code == LV_EVENT_KEY) { uint32_t key = lv_event_get_key(e); printf("Received key: %d\n", key); if(key == LV_KEY_BACKSPACE) { if(curkey_angle == 0) { hal_set_rotate(LV_DISP_ROT_90); } else if(curkey_angle == 1) hal_set_rotate(LV_DISP_ROT_180); else if(curkey_angle == 2) { hal_set_rotate(LV_DISP_ROT_270); } else if(curkey_angle == 3) { hal_set_rotate(LV_DISP_ROT_NONE); } curkey_angle++; curkey_angle = curkey_angle % 4; } } } static void add_key_group(lv_obj_t *obj) { lv_app_t *papp = get_lv_app(); if(papp->key_group == 0) { papp->key_group = lv_group_create(); lv_group_set_default(papp->key_group); lv_indev_t * cur_drv = NULL; for(;;) { cur_drv = lv_indev_get_next(cur_drv); if(!cur_drv) { break; } if(cur_drv->driver->type == LV_INDEV_TYPE_KEYPAD) { lv_indev_set_group(cur_drv, papp->key_group); } } } lv_group_add_obj(papp->key_group,obj); lv_obj_add_event_cb(obj, key_obj_cb, LV_EVENT_ALL, obj); } void ui_init(int argc, char* argv[]) { char buf[128] = {0}; int opt; int settime = 0; while ((opt = getopt(argc, argv, "ht:a")) != -1) { switch (opt) { case 't': { char *opt_s = optarg; time_t now; int t,m,s; int hs; int now_hs; struct tm *curtime; if(sscanf(opt_s,"%d %*[: ] %d %*[: ]%d", &t, &m, &s) != 3){ printf("%s -t hh:mm:ss",argv[0]); return; } time(&now); curtime = localtime(&now); hs = t * 3600 + m * 60 + s; now_hs = curtime->tm_hour * 3600 + curtime->tm_min * 60 + curtime->tm_sec; if(hs > now_hs) { settime = now - now_hs + hs; } else { settime = now - now_hs + hs + 24 * 3600; } printf("h:%d m: %d s: %d\n",t,m,s); st = settime; struct timeval val; gettimeofday(&val,NULL); printf("settime: %u,cur: %u time: %u\n",settime,now,val.tv_sec); break; } case 'a': need_align = 1; break; case 'h': default: { printf("Usage: \n"); printf(" -t <time> absolute timed to play video, format like 09:00:00\n"); return; } } } if(settime == 0) app.timer = lv_timer_create(refresh_ui,5*1000, NULL); lv_style_set_radius(&app.style, 0); lv_style_set_pad_all(&app.style,0); lv_style_set_border_width(&app.style,0); app.container = lv_obj_create(lv_scr_act()); add_key_group(app.container); lv_obj_set_style_bg_opa(app.container, 127, LV_OPA_TRANSP); lv_obj_set_style_bg_color(app.container, lv_palette_lighten(LV_PALETTE_RED, 3), 0); lv_obj_set_pos(app.container,0,0); lv_obj_set_size(app.container,lv_obj_get_width(lv_scr_act()),lv_obj_get_height(lv_scr_act())); lv_obj_add_style(app.container,&app.style,LV_PART_MAIN); lv_obj_clear_flag(app.container, LV_OBJ_FLAG_SCROLLABLE); img_obj = build_image(app.container, get_res_name(buf,sizeof(buf),0,0)); video_obj = build_video(app.container, get_res_name(buf,sizeof(buf),0,1),0,0,settime); qr_obj = build_qr(app.container, get_res_name(buf,sizeof(buf),0,2)); //br_obj = build_br(app.container, get_res_name(buf,sizeof(buf),0,3)); /* Note: font support enable in lv_conf.h, like LV_FONT_MONTSERRAT_14; Considering the memory usage during runtime, just enable useful resource. */ text_obj = build_text(app.container, "host, version20240401", &lv_font_montserrat_14, lv_color_black(), LV_ALIGN_BOTTOM_LEFT, 10, -5); lv_timer_create(update_text, 1*1000, NULL); }
07-09
现在根据这个代码,我写在了vscode软件里的demo.cpp文件中,以platformio为插件辅助 #include <app/pages/demo.h> #include <lvgl.h> #include <freertos/FreeRTOS.h> #include <freertos/task.h> // 全局UI对象 static lv_obj_t *tabview; static lv_obj_t *wifi_switch; static lv_obj_t *ssid_textarea; static lv_obj_t *pass_textarea; static lv_obj_t *music_btn; static lv_obj_t *music_btn_stop; static lv_obj_t *music_btn_Previous; static lv_obj_t *music_btn_Next; static lv_obj_t *time_value; /*--- 事件回调函数实现 ---*/ // WiFi开关状态变化 static void wifi_switch_event(lv_event_t *e) { lv_event_code_t code = lv_event_get_code(e); if(code == LV_EVENT_VALUE_CHANGED) { bool en = lv_obj_has_state(wifi_switch, LV_STATE_CHECKED); printf("lv_obj_has_state=[%d]\r\n", en); if(en) { lv_obj_clear_flag(ssid_textarea, LV_OBJ_FLAG_HIDDEN); lv_obj_clear_flag(pass_textarea, LV_OBJ_FLAG_HIDDEN); } else { lv_obj_add_flag(ssid_textarea, LV_OBJ_FLAG_HIDDEN); lv_obj_add_flag(pass_textarea, LV_OBJ_FLAG_HIDDEN); } // 实际开发中需调用系统API启用WiFi } } // 连接WiFi网络 static void connect_wifi_event(lv_event_t *e) { const char *ssid = lv_textarea_get_text(ssid_textarea); const char *pass = lv_textarea_get_text(pass_textarea); // 实际开发中调用网络连接API[6](@ref) printf("Connecting to WiFi: SSID=%s, Password=%s\n", ssid, pass); // wifi_connect(ssid, pass); } // 切换到音乐播放页并开始播放 static void play_music_event(lv_event_t *e) { // lv_tabview_set_act(tabview, 1, LV_ANIM_ON); // 切换到索引1(播放页)[2](@ref) // 实际开发中启动播放逻辑[9,10](@ref) printf("Starting music playback...\n"); // audio_play("/sdcard/music.mp3"); } void build_pages() { /* 1. 创建Tabview容器 */ tabview = lv_tabview_create(lv_scr_act()); // 顶部标签栏高度30px[1,2](@ref) /* 2. 添加三个Tab页 */ lv_obj_t *tab_config = lv_tabview_add_tab(tabview, "Config"); lv_obj_t *tab_music = lv_tabview_add_tab(tabview, "Player"); lv_obj_t *tab_info = lv_tabview_add_tab(tabview, "Infor"); /* 3. 配置页内容:WiFi设置 */ // WiFi开关标签 lv_obj_t *wifi_label = lv_label_create(tab_config); lv_label_set_text(wifi_label, "WiFi:"); lv_obj_align(wifi_label, LV_ALIGN_TOP_LEFT, 10, 20); // WiFi开关控件 wifi_switch = lv_switch_create(tab_config); lv_obj_align_to(wifi_switch, wifi_label, LV_ALIGN_OUT_RIGHT_MID, 20, 0); lv_obj_add_event_cb(wifi_switch, wifi_switch_event, LV_EVENT_VALUE_CHANGED, NULL); // SSID输入框 lv_obj_t *ssid_label = lv_label_create(tab_config); lv_label_set_text(ssid_label, "SSID:"); lv_obj_align(ssid_label, LV_ALIGN_TOP_LEFT, 10, 60); ssid_textarea = lv_textarea_create(tab_config); lv_textarea_set_placeholder_text(ssid_textarea, "WiFi Name"); lv_obj_set_size(ssid_textarea, 200, 40); lv_obj_align_to(ssid_textarea, ssid_label, LV_ALIGN_OUT_RIGHT_MID, 10, 0); // 密码输入框 lv_obj_t *pass_label = lv_label_create(tab_config); lv_label_set_text(pass_label, "Password:"); lv_obj_align(pass_label, LV_ALIGN_TOP_LEFT, 10, 110); pass_textarea = lv_textarea_create(tab_config); lv_textarea_set_password_mode(pass_textarea, true); // 密码模式 lv_textarea_set_placeholder_text(pass_textarea, "Password"); lv_obj_set_size(pass_textarea, 200, 40); lv_obj_align_to(pass_textarea, pass_label, LV_ALIGN_OUT_RIGHT_MID, 10, 0); // 连接按钮 lv_obj_t *connect_btn = lv_btn_create(tab_config); lv_obj_t *connect_label = lv_label_create(connect_btn); lv_label_set_text(connect_label, "Network"); lv_obj_align(connect_btn, LV_ALIGN_TOP_LEFT, 10, 160); lv_obj_add_event_cb(connect_btn, connect_wifi_event, LV_EVENT_CLICKED, NULL); /* 4. 配置页内容:音乐播放按钮 */ music_btn = lv_btn_create(tab_music); lv_obj_t *btn_label = lv_label_create(music_btn); lv_label_set_text(btn_label, "Play"); lv_obj_align(music_btn,LV_ALIGN_TOP_RIGHT, -20, 20); lv_obj_add_event_cb(music_btn, play_music_event, LV_EVENT_CLICKED, NULL); music_btn_stop = lv_btn_create(tab_music); lv_obj_t *btn_label_stop = lv_label_create(music_btn_stop); lv_label_set_text(btn_label_stop, "stop"); lv_obj_align_to(music_btn_stop,tab_music, LV_ALIGN_TOP_RIGHT, -20, 80); lv_obj_add_event_cb(music_btn_stop, play_music_event, LV_EVENT_CLICKED, NULL); music_btn_Previous = lv_btn_create(tab_music); lv_obj_t *btn_label_prev = lv_label_create(music_btn_Previous); lv_label_set_text(btn_label_prev, "Previous"); lv_obj_align_to(music_btn_Previous,tab_music, LV_ALIGN_TOP_RIGHT, -20, 140); lv_obj_add_event_cb(music_btn_Previous, play_music_event, LV_EVENT_CLICKED, NULL); music_btn_Next = lv_btn_create(tab_music); lv_obj_t *btn_label_next = lv_label_create(music_btn_Next); lv_label_set_text(btn_label_next, "Next"); lv_obj_align_to(music_btn_Next,tab_music, LV_ALIGN_TOP_RIGHT, -20, 200); lv_obj_add_event_cb(music_btn_Next, play_music_event, LV_EVENT_CLICKED, NULL); /* 5. 音乐播放页内容 */ lv_obj_t *title_label = lv_label_create(tab_music); lv_label_set_text(title_label, "Music Name"); lv_obj_align(title_label, LV_ALIGN_TOP_MID, 0, 20); lv_obj_t *play_btn = lv_btn_create(tab_music); lv_obj_t *play_symbol = lv_label_create(play_btn); lv_label_set_text(play_symbol, LV_SYMBOL_PLAY); lv_obj_center(play_symbol); lv_obj_align(play_btn, LV_ALIGN_CENTER, 0, 0); lv_obj_t *time_label = lv_label_create(tab_info); lv_label_set_text(time_label, "Time:"); lv_obj_align(time_label, LV_ALIGN_TOP_LEFT, 10, 60); time_value = lv_label_create(tab_info); lv_label_set_text(time_value, "2025-08-04 12:01:02"); lv_obj_align(time_value, LV_ALIGN_TOP_RIGHT, 40, 60); lv_obj_align_to(time_value, time_label, LV_ALIGN_OUT_RIGHT_MID, 10, 0); } void update_time(const char * text) { lv_label_set_text(time_value, text); }我要拓展一个新的领域,通过设置的四个按键分别实现播放,停止,上一首,下一首SD卡中的music文件夹里的1.mp3歌曲, 我的main.cpp文件中代码如下/*Using LVGL with Arduino requires some extra steps: *Be sure to read the docs here: https://docs.lvgl.io/master/get-started/platforms/arduino.html */ #include <lvgl.h> /*To use the built-in examples and demos of LVGL uncomment the includes below respectively. *You also need to copy `lvgl/examples` to `lvgl/src/examples`. Similarly for the demos `lvgl/demos` to `lvgl/src/demos`. Note that the `lv_examples` library is for LVGL v7 and you shouldn't install it for this version (since LVGL v8) as the examples and demos are now part of the main LVGL library. */ // #include <examples/lv_examples.h> // #include <demos/lv_demos.h> // #define DIRECT_MODE // Uncomment to enable full frame buffer // https://blog.youkuaiyun.com/weixin_41589183/article/details/140234622 #include <Arduino_GFX_Library.h> #include "TCA9554.h" #include "TouchDrvFT6X36.hpp" #include "esp_lcd_touch_axs15231b.h" #include "app/pages/demo.h" #include <freertos/FreeRTOS.h> #include <freertos/task.h> #include <examples/lv_examples.h> #include <demos/lv_demos.h> #include "Wire.h" #include "esp_check.h" #include "Arduino.h" #include "WiFiMulti.h" #include "Audio.h" #include "SD_MMC.h" #define LCD35 // 任务优先级定义(数值越大优先级越高) #define TASK_PRIORITY_LVGL 2 // LVGL 任务优先级 #define TASK_PRIORITY_SENSOR 1 // 传感器任务优先级 // 任务栈大小(单位:字节) #define TASK_STACK_LVGL 8192 #define TASK_STACK_SENSOR 4096 #define GFX_BL 6 // default backlight pin, you may replace DF_GFX_BL to actual backlight pin TCA9554 TCA(0x20); #define I2C_SDA 8 #define I2C_SCL 7 #define LCD_HOR_RES 320 #define LCD_VER_RES 480 #ifdef LCD35 #define SPI_MISO 2 #define SPI_MOSI 1 #define SPI_SCLK 5 #define LCD_CS -1 #define LCD_DC 3 #define LCD_RST -1 // I2S GPIOs #define I2S_SDOUT 16 #define I2S_BCLK 13 #define I2S_LRCK 15 #define I2S_MCLK 12 #define EXAMPLE_SAMPLE_RATE (48000) #define EXAMPLE_MCLK_MULTIPLE (256) // If not using 24-bit data width, 256 should be enough #define EXAMPLE_MCLK_FREQ_HZ (EXAMPLE_SAMPLE_RATE * EXAMPLE_MCLK_MULTIPLE) #define EXAMPLE_VOICE_VOLUME (70) Audio audio; #define SD_MMC_CLK 11 #define SD_MMC_CMD 10 #define SD_MMC_D0 9 #define I2C_SDA 8 #define I2C_SCL 7 #ifndef DEMO_H #define DEMO_H // 函数声明 void build_pages(); void update_time(const char *text); #endif Arduino_DataBus *bus = new Arduino_ESP32SPI(LCD_DC /* DC */, LCD_CS /* CS */, SPI_SCLK /* SCK */, SPI_MOSI /* MOSI */, SPI_MISO /* MISO */); Arduino_GFX *gfx = new Arduino_ST7796( bus, LCD_RST /* RST */, 0 /* rotation */, true, LCD_HOR_RES, LCD_VER_RES); #else #define DIRECT_RENDER_MODE // Uncomment to enable full frame buffer #define LCD_QSPI_CS 12 #define LCD_QSPI_CLK 5 #define LCD_QSPI_D0 1 #define LCD_QSPI_D1 2 #define LCD_QSPI_D2 3 #define LCD_QSPI_D3 4 Arduino_DataBus *bus = new Arduino_ESP32QSPI(LCD_QSPI_CS, LCD_QSPI_CLK, LCD_QSPI_D0, LCD_QSPI_D1, LCD_QSPI_D2, LCD_QSPI_D3); Arduino_GFX *gfx = new Arduino_AXS15231B(bus, -1 /* RST */, 0 /* rotation */, false, LCD_HOR_RES, LCD_VER_RES); #endif TouchDrvFT6X36 touch; uint32_t screenWidth; uint32_t screenHeight; uint32_t bufSize; lv_display_t *disp; lv_color_t *disp_draw_buf1; lv_color_t *disp_draw_buf2; #if LV_USE_LOG != 0 void my_print(lv_log_level_t level, const char *buf) { LV_UNUSED(level); Serial.println(buf); Serial.flush(); } #endif uint32_t millis_cb(void) { return millis(); } /* LVGL calls it when a rendered image needs to copied to the display*/ void my_disp_flush(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map) { uint32_t w = lv_area_get_width(area); uint32_t h = lv_area_get_height(area); gfx->draw16bitRGBBitmap(area->x1, area->y1, (uint16_t *)px_map, w, h); //printf("my_disp_flush[%d][%d]\r\n", w, h); /*Call it to tell LVGL you are ready*/ lv_disp_flush_ready(disp); } /*Read the touchpad*/ void my_touchpad_read(lv_indev_t *indev, lv_indev_data_t *data) { #ifdef LCD35 int16_t x[1], y[1]; uint8_t touched = touch.getPoint(x, y, 1); if (touched) { data->state = LV_INDEV_STATE_PR; /*Set the coordinates*/ data->point.x = x[0]; data->point.y = y[0]; } else { data->state = LV_INDEV_STATE_REL; } #else touch_data_t touch_data; bsp_touch_read(); if (bsp_touch_get_coordinates(&touch_data)) { data->state = LV_INDEV_STATE_PR; /*Set the coordinates*/ data->point.x = touch_data.coords[0].x; data->point.y = touch_data.coords[0].y; } else { data->state = LV_INDEV_STATE_REL; } #endif //printf("X:%d, Y:%d, State:%d\n", data->point.x, data->point.y, data->state); } void lcd_reset(void) { TCA.write1(1, 1); delay(10); TCA.write1(1, 0); delay(10); TCA.write1(1, 1); delay(200); } static void event_debug(lv_event_t *e) { // printf("Event: %d\n", lv_event_get_code(e)); } #include"es8311.h" static const char* TAG = "es8311_init"; static esp_err_t es8311_codec_init(void) { /* 初始化es8311芯片 */ es8311_handle_t es_handle = es8311_create(I2C_NUM_0, ES8311_ADDRRES_0); ESP_RETURN_ON_FALSE(es_handle, ESP_FAIL, TAG, "es8311 create failed"); const es8311_clock_config_t es_clk = { .mclk_inverted = false, .sclk_inverted = false, .mclk_from_mclk_pin = true, .mclk_frequency = EXAMPLE_MCLK_FREQ_HZ, .sample_frequency = EXAMPLE_SAMPLE_RATE }; ESP_ERROR_CHECK(es8311_init(es_handle, &es_clk, ES8311_RESOLUTION_16, ES8311_RESOLUTION_16)); // ESP_RETURN_ON_ERROR(es8311_sample_frequency_config(es_handle, EXAMPLE_SAMPLE_RATE * EXAMPLE_MCLK_MULTIPLE, EXAMPLE_SAMPLE_RATE), TAG, "set es8311 sample frequency failed"); ESP_RETURN_ON_ERROR(es8311_voice_volume_set(es_handle, EXAMPLE_VOICE_VOLUME, NULL), TAG, "set es8311 volume failed"); ESP_RETURN_ON_ERROR(es8311_microphone_config(es_handle, false), TAG, "set es8311 microphone failed"); return ESP_OK; } void lvgl_task(void *pvParameters) { Serial.begin(115200); es8311_codec_init(); Wire.begin(I2C_SDA, I2C_SCL); TCA.begin(); TCA.pinMode1(1,OUTPUT); lcd_reset(); printf("Arduino_GFX Hello World example\n\r"); #ifdef LCD35 if (!touch.begin(Wire, FT6X36_SLAVE_ADDRESS)) { printf("Failed to find FT6X36 - check your wiring!\r\n"); while (1) { delay(1000); } } #else bsp_touch_init(&Wire, -1, 0, 320, 480); #endif // Init Display if (!gfx->begin()) { printf("gfx->begin() failed!\r\n"); } gfx->fillScreen(RGB565_BLACK); #ifdef GFX_BL pinMode(GFX_BL, OUTPUT); digitalWrite(GFX_BL, HIGH); #endif lv_init(); /*Set a tick source so that LVGL will know how much time elapsed. */ lv_tick_set_cb(millis_cb); /* register print function for debugging */ #if LV_USE_LOG != 0 lv_log_register_print_cb(my_print); #endif screenWidth = gfx->width(); screenHeight = gfx->height(); #ifdef DIRECT_RENDER_MODE bufSize = screenWidth * screenHeight; disp_draw_buf1 = (lv_color_t *)heap_caps_malloc(bufSize * 2, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); disp_draw_buf2 = (lv_color_t *)heap_caps_malloc(bufSize * 2, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); #else bufSize = screenWidth * 40; disp_draw_buf1 = (lv_color_t *)heap_caps_malloc(bufSize * 2, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); disp_draw_buf2 = (lv_color_t *)heap_caps_malloc(bufSize * 2, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); #endif if (!disp_draw_buf1 || !disp_draw_buf2) { printf("LVGL disp_draw_buf allocate failed!\r\n"); } else { disp = lv_display_create(screenWidth, screenHeight); lv_display_set_flush_cb(disp, my_disp_flush); #ifdef DIRECT_RENDER_MODE lv_display_set_buffers(disp, disp_draw_buf1, disp_draw_buf2, bufSize * 2, LV_DISPLAY_RENDER_MODE_FULL); #else lv_display_set_buffers(disp, disp_draw_buf1, disp_draw_buf2, bufSize * 2, LV_DISPLAY_RENDER_MODE_PARTIAL); #endif /*Initialize the (dummy) input device driver*/ lv_indev_t *indev = lv_indev_create(); lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); /*Touchpad should have POINTER type*/ lv_indev_set_read_cb(indev, my_touchpad_read); #if 0 /* Initialize the (dummy) input device driver */ lv_obj_t *label = lv_label_create(lv_scr_act()); lv_label_set_text(label, "Hello Arduino! (V" GFX_STR(LVGL_VERSION_MAJOR) "." GFX_STR(LVGL_VERSION_MINOR) "." GFX_STR(LVGL_VERSION_PATCH) ")"); lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); lv_obj_t *sw = lv_switch_create(lv_scr_act()); lv_obj_align(sw, LV_ALIGN_TOP_MID, 0, 50); sw = lv_switch_create(lv_scr_act()); lv_obj_align(sw, LV_ALIGN_BOTTOM_MID, 0, -50); #else /* Option 3: Or try out a demo. Don't forget to enable the demos in lv_conf.h. E.g. LV_USE_DEMOS_WIDGETS*/ build_pages(); //lv_demo_widgets(); //lv_demo_benchmark(); //lv_demo_keypad_encoder(); //lv_demo_music(); //lv_demo_stress(); #endif lv_obj_add_event_cb(lv_scr_act(), event_debug, LV_EVENT_ALL, NULL); printf("Setup done\r\n"); } #if 1 while (1) { lv_task_handler(); // 处理 LVGL 事件 vTaskDelay(pdMS_TO_TICKS(5)); // 5ms 延迟,避免 CPU 过载 } #endif } void sensor_task(void *pvParam) { char time[64] = {0}; int i = 0; while (1) { // 读取传感器数据(如温度、加速度) vTaskDelay(pdMS_TO_TICKS(1000)); // 100ms 延迟 i++; sprintf(time, "2025-08-04 12:23:%d", i); update_time(time); if(i>59) i=0; } } void setup() { xTaskCreatePinnedToCore(lvgl_task, "LVGL", TASK_STACK_LVGL, NULL, TASK_PRIORITY_LVGL, NULL, 0); // 1. 串口初始化 Serial.begin(115200); delay(1000); Serial.println("Initializing..."); // 2. I2C 初始化(Codec 用) Wire.begin(8, 7); // 根据硬件调整 SDA/SCL 引脚 // 3. 音频 codec 初始化(ES8311) es8311_codec_init(); // 4. SD 卡初始化(根据硬件调整引脚) SD_MMC.setPins(11, 10, 9); // CLK, CMD, D0 if (!SD_MMC.begin("/sdmmc", true, false, 20000)) { Serial.println("SD Card Mount Failed!"); while (1); } Serial.println("SD Card Mounted."); // 6. 音频初始化(I2S 引脚根据硬件调整) audio.setPinout(13, 15, 16, 44); // BCLK, LRC, DOUT, MCLK audio.setVolume(21); // 音量 0~21 // 启动音频循环 xTaskCreate([](void *arg) { while (1) { audio.loop(); // 音频库主循环 delay(1); } }, "audio_task", 4096, NULL, 2, NULL); } /*创建传感器任务(核心 1) xTaskCreatePinnedToCore(sensor_task, "Sensor", TASK_STACK_SENSOR, NULL, TASK_PRIORITY_SENSOR, NULL, 1); }*/ void loop() { //lv_timer_handler(); /* let the GUI do its work */ // 主循环可处理其他逻辑(如定时更新时间) static unsigned long lastTime = 0; if (millis() - lastTime > 1000) { // 1 秒更新一次时间 update_time("2025-08-04 12:01:03"); // 实际可读取 RTC 或网络时间 lastTime = millis(); } delay(100); } ​现在我有一个可以在Arduino软件上运行的代码,关于播放SD卡中我要求的music文件夹里的音乐的代码如下#include "Arduino.h" #include "WiFiMulti.h" #include "Audio.h" #include "SD_MMC.h" #include "FS.h" #include "es8311.h" #include "esp_check.h" #include "Wire.h" #define SD_MMC_CLK 11 #define SD_MMC_CMD 10 #define SD_MMC_D0 9 #define I2S_MCLK 44 #define I2S_DOUT 16 #define I2S_BCLK 13 #define I2S_LRC 15 #define I2C_SDA 8 #define I2C_SCL 7 #define EXAMPLE_SAMPLE_RATE (16000) #define EXAMPLE_MCLK_MULTIPLE (256) // If not using 24-bit data width, 256 should be enough #define EXAMPLE_MCLK_FREQ_HZ (EXAMPLE_SAMPLE_RATE * EXAMPLE_MCLK_MULTIPLE) #define EXAMPLE_VOICE_VOLUME (75) Audio audio; WiFiMulti wifiMulti; String ssid = ""; String password = ""; static esp_err_t es8311_codec_init(void) { es8311_handle_t es_handle = es8311_create(I2C_NUM_0, ES8311_ADDRRES_0); ESP_RETURN_ON_FALSE(es_handle, ESP_FAIL, TAG, "es8311 create failed"); const es8311_clock_config_t es_clk = { .mclk_inverted = false, .sclk_inverted = false, .mclk_from_mclk_pin = true, .mclk_frequency = EXAMPLE_MCLK_FREQ_HZ, .sample_frequency = EXAMPLE_SAMPLE_RATE }; ESP_ERROR_CHECK(es8311_init(es_handle, &es_clk, ES8311_RESOLUTION_16, ES8311_RESOLUTION_16)); // ESP_RETURN_ON_ERROR(es8311_sample_frequency_config(es_handle, EXAMPLE_SAMPLE_RATE * EXAMPLE_MCLK_MULTIPLE, EXAMPLE_SAMPLE_RATE), TAG, "set es8311 sample frequency failed"); ESP_RETURN_ON_ERROR(es8311_voice_volume_set(es_handle, EXAMPLE_VOICE_VOLUME, NULL), TAG, "set es8311 volume failed"); ESP_RETURN_ON_ERROR(es8311_microphone_config(es_handle, false), TAG, "set es8311 microphone failed"); return ESP_OK; } void setup() { Serial.begin(115200); Wire.begin(I2C_SDA, I2C_SCL); es8311_codec_init(); SD_MMC.setPins(SD_MMC_CLK, SD_MMC_CMD, SD_MMC_D0); if (!SD_MMC.begin("/sdmmc", true, false, 20000)) { esp_rom_printf("Card Mount Failed\n"); while (1) { }; } if (ssid != "" || password != ""){ WiFi.mode(WIFI_STA); wifiMulti.addAP(ssid.c_str(), password.c_str()); wifiMulti.run(); if (WiFi.status() != WL_CONNECTED) { WiFi.disconnect(true); wifiMulti.run(); } } audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT, I2S_MCLK); audio.setVolume(21); // 0...21 audio.connecttoFS(SD_MMC, "music/1.mp3"); // audio.connecttohost("http://www.wdr.de/wdrlive/media/einslive.m3u"); // audio.connecttohost("http://somafm.com/wma128/missioncontrol.asx"); // asx // audio.connecttohost("http://mp3.ffh.de/radioffh/hqlivestream.aac"); // 128k aac // audio.connecttohost("http://mp3.ffh.de/radioffh/hqlivestream.mp3"); // 128k mp3 } void loop() { vTaskDelay(1); audio.loop(); if (Serial.available()) { // put streamURL in serial monitor audio.stopSong(); String r = Serial.readString(); r.trim(); if (r.length() > 5) audio.connecttohost(r.c_str()); log_i("free heap=%i", ESP.getFreeHeap()); } } // optional void audio_info(const char *info) { Serial.print("info "); Serial.println(info); } void audio_id3data(const char *info) { //id3 metadata Serial.print("id3data "); Serial.println(info); } void audio_eof_mp3(const char *info) { //end of file Serial.print("eof_mp3 "); Serial.println(info); } void audio_showstation(const char *info) { Serial.print("station "); Serial.println(info); } void audio_showstreamtitle(const char *info) { Serial.print("streamtitle "); Serial.println(info); } void audio_bitrate(const char *info) { Serial.print("bitrate "); Serial.println(info); } void audio_commercial(const char *info) { //duration in sec Serial.print("commercial "); Serial.println(info); } void audio_icyurl(const char *info) { //homepage Serial.print("icyurl "); Serial.println(info); } void audio_lasthost(const char *info) { //stream URL played Serial.print("lasthost "); Serial.println(info); }请问我如何把他整合到vscode中实现我要求的功能(main.cppdemo.cpp应该都要修改吧)
08-06
#define ACTIVE_TRACK_CNT 3 #define BAR_CNT 20 #define BAND_CNT 4 #define BAR_PER_BAND_CNT (BAR_CNT / BAND_CNT) #define DEG_STEP (180/BAR_CNT) #define BAR_COLOR1_STOP 80 #define BAR_COLOR2_STOP 100 #define BAR_COLOR3_STOP (2 * LV_HOR_RES / 3) #define BAR_COLOR1 lv_color_hex(0xe9dbfc) #define BAR_COLOR2 lv_color_hex(0x6f8af6) #define BAR_COLOR3 lv_color_hex(0xffffff) static bool state_tracks_up = false; static uint32_t time; static uint32_t track_id; static lv_timer_t * sec_counter_timer; static bool playing; static const uint16_t (* spectrum)[4]; static uint32_t spectrum_i = 0; static uint32_t spectrum_len; static uint32_t spectrum_lane_ofs_start = 0; static uint32_t bar_rot = 0; static uint32_t bar_ofs = 0; static bool start_anim; static lv_obj_t *spectrum_area; static uint32_t spectrum_i_pause = 0; static const uint16_t rnd_array[30] = {994, 285, 553, 11, 792, 707, 966, 641, 852, 827, 44, 352, 146, 581, 490, 80, 729, 58, 695, 940, 724, 561, 124, 653, 27, 292, 557, 506, 382, 199}; static void album_gesture_event_cb(lv_event_t * e); static void spectrum_draw_event_cb(lv_event_t * e); static int32_t get_cos(int32_t deg, int32_t a); static int32_t get_sin(int32_t deg, int32_t a); static const char * title_list[] = { "Waiting for true love", "Need a Better Future", "Vibrations", }; static const char * artist_list[] = { "The John Smith Band", "My True Name", "Robotics", }; static const uint32_t time_list[] = { 1*60 + 14, 2*60 + 26, 1*60 + 54, }; static void timer_cb(lv_timer_t *t) { time++; lv_label_set_text_fmt(guider_ui.screen_label_slider_time, "%d:%02d", time / 60, time % 60); lv_slider_set_value(guider_ui.screen_slider_1, time, LV_ANIM_ON); } void custom_init(lv_ui *ui) { LV_IMG_DECLARE(_icn_slider_alpha_25x25); /* Add your codes here */ sec_counter_timer = lv_timer_create(timer_cb, 1000, NULL); lv_timer_pause(sec_counter_timer); lv_obj_add_event_cb(guider_ui.screen_img_album, album_gesture_event_cb, LV_EVENT_GESTURE, NULL); lv_obj_clear_flag(guider_ui.screen_img_album, LV_OBJ_FLAG_GESTURE_BUBBLE); lv_obj_add_flag(guider_ui.screen_img_album, LV_OBJ_FLAG_CLICKABLE); lv_obj_set_style_bg_img_src(guider_ui.screen_slider_1, &_icn_slider_alpha_25x25, LV_PART_KNOB); spectrum = spectrum_1; spectrum_len = sizeof(spectrum_1) / sizeof(spectrum_1[0]); spectrum_area = lv_obj_create(guider_ui.screen_player); lv_obj_remove_style_all(spectrum_area); lv_obj_set_pos(spectrum_area, 80 * LV_HOR_RES_MAX / 480, 60 * LV_VER_RES_MAX / 272); lv_obj_set_size(spectrum_area, 320 * LV_HOR_RES_MAX / 480, 146 * LV_VER_RES_MAX / 272); lv_obj_move_background(spectrum_area); lv_obj_add_event_cb(guider_ui.screen_player, spectrum_draw_event_cb, LV_EVENT_ALL, NULL); } void tracks_up(void) { lv_anim_t screen_player_anim_y; //Write animation: screen_playermove in y direction lv_anim_init(&screen_player_anim_y); lv_anim_set_var(&screen_player_anim_y, guider_ui.screen_player); lv_anim_set_time(&screen_player_anim_y, 1000); lv_anim_set_exec_cb(&screen_player_anim_y, (lv_anim_exec_xcb_t)lv_obj_set_y); lv_anim_set_values(&screen_player_anim_y, 0, -261 * LV_VER_RES_MAX / 272); lv_anim_set_path_cb(&screen_player_anim_y, &lv_anim_path_linear); lv_anim_start(&screen_player_anim_y); state_tracks_up = true; } void tracks_down(void) { lv_anim_t screen_player_anim_y; //Write animation: screen_playermove in y direction lv_anim_init(&screen_player_anim_y); lv_anim_set_var(&screen_player_anim_y, guider_ui.screen_player); lv_anim_set_time(&screen_player_anim_y, 1000); lv_anim_set_exec_cb(&screen_player_anim_y, (lv_anim_exec_xcb_t)lv_obj_set_y); lv_anim_set_values(&screen_player_anim_y, -261 * LV_VER_RES_MAX / 272, 0); lv_anim_set_path_cb(&screen_player_anim_y, &lv_anim_path_linear); lv_anim_start(&screen_player_anim_y); state_tracks_up = false; } bool tracks_is_up(void) { return state_tracks_up; } static void spectrum_anim_cb(void * a, int32_t v) { lv_obj_t * obj = a; // if(start_anim) { // lv_obj_invalidate(obj); // return; // } spectrum_i = v; lv_obj_invalidate(obj); static uint32_t bass_cnt = 0; static int32_t last_bass = -1000; static int32_t dir = 1; if(spectrum[spectrum_i][0] > 12) { if(spectrum_i-last_bass > 5) { bass_cnt++; last_bass = spectrum_i; if(bass_cnt >= 2) { bass_cnt = 0; spectrum_lane_ofs_start = spectrum_i; bar_ofs++; } } } if(spectrum[spectrum_i][0] < 4) bar_rot+= dir; // lv_img_set_zoom(guider_ui.screen_img_album, LV_IMG_ZOOM_NONE + spectrum[spectrum_i][0]); } static void spectrum_end_cb(lv_anim_t * a) { lv_demo_music_album_next(true); } void lv_demo_music_resume(void) { playing = true; spectrum_i = spectrum_i_pause; lv_anim_t a; lv_anim_init(&a); lv_anim_set_values(&a, spectrum_i, spectrum_len - 1); lv_anim_set_exec_cb(&a, spectrum_anim_cb); lv_anim_set_var(&a, spectrum_area); lv_anim_set_time(&a, ((spectrum_len - spectrum_i) * 1000) / 30); lv_anim_set_playback_time(&a, 0); lv_anim_set_ready_cb(&a, spectrum_end_cb); lv_anim_start(&a); lv_timer_resume(sec_counter_timer); lv_slider_set_range(guider_ui.screen_slider_1, 0, time_list[track_id]); lv_obj_add_state(guider_ui.screen_imgbtn_play, LV_STATE_CHECKED); } void lv_demo_music_pause(void) { playing = false; spectrum_i_pause = spectrum_i; spectrum_i = 0; lv_anim_del(spectrum_area, spectrum_anim_cb); lv_obj_invalidate(spectrum_area); lv_img_set_zoom(guider_ui.screen_img_album, LV_IMG_ZOOM_NONE); lv_timer_pause(sec_counter_timer); lv_obj_clear_state(guider_ui.screen_imgbtn_play, LV_STATE_CHECKED); } static void album_gesture_event_cb(lv_event_t * e) { lv_dir_t dir = lv_indev_get_gesture_dir(lv_indev_get_act()); if(dir == LV_DIR_LEFT) lv_demo_music_album_next(true); if(dir == LV_DIR_RIGHT) lv_demo_music_album_next(false); } static lv_obj_t * album_img_create(lv_obj_t * parent) { LV_IMG_DECLARE(_cover_2_alpha_175x175); LV_IMG_DECLARE(_cover_3_alpha_175x175); lv_obj_t * img; img = lv_img_create(parent); lv_obj_set_pos(img, 187 * LV_HOR_RES_MAX / 480, 84 * LV_VER_RES_MAX / 272); switch(track_id) { case 2: lv_img_set_src(img, &_cover_3_alpha_175x175); spectrum = spectrum_3; spectrum_len = sizeof(spectrum_3) / sizeof(spectrum_3[0]); break; case 1: lv_img_set_src(img, &_cover_2_alpha_175x175); spectrum = spectrum_2; spectrum_len = sizeof(spectrum_2) / sizeof(spectrum_2[0]); break; case 0: lv_img_set_src(img, &_cover_1_alpha_175x175); spectrum = spectrum_1; spectrum_len = sizeof(spectrum_1) / sizeof(spectrum_1[0]); break; } lv_img_set_antialias(img, false); lv_obj_add_event_cb(img, album_gesture_event_cb, LV_EVENT_GESTURE, NULL); lv_obj_clear_flag(img, LV_OBJ_FLAG_GESTURE_BUBBLE); lv_obj_add_flag(img, LV_OBJ_FLAG_CLICKABLE); return img; } static void track_load(uint32_t id) { spectrum_i = 0; time = 0; spectrum_i_pause = 0; lv_slider_set_value(guider_ui.screen_slider_1, 0, LV_ANIM_OFF); lv_label_set_text(guider_ui.screen_label_slider_time, "0:00"); if(id == track_id) return; bool next = false; if((track_id + 1) % ACTIVE_TRACK_CNT == id) next = true; lv_demo_music_list_btn_check(track_id, false); track_id = id; lv_demo_music_list_btn_check(id, true); lv_label_set_text(guider_ui.screen_label_title_music, title_list[track_id]); lv_label_set_text(guider_ui.screen_label_title_author, artist_list[track_id]); lv_obj_fade_out(guider_ui.screen_img_album, 500, 0); lv_anim_t a; lv_anim_init(&a); lv_anim_set_var(&a, guider_ui.screen_img_album); lv_anim_set_time(&a, 500); lv_anim_set_path_cb(&a, lv_anim_path_ease_out); if(next) { lv_anim_set_values(&a, 187 * LV_HOR_RES_MAX / 480, 0); } else { lv_anim_set_values(&a, 187 * LV_HOR_RES_MAX / 480, LV_HOR_RES_MAX - 105); } lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t) lv_obj_set_x); lv_anim_set_ready_cb(&a, lv_obj_del_anim_ready_cb); lv_anim_start(&a); lv_anim_set_path_cb(&a, lv_anim_path_linear); lv_anim_set_var(&a, guider_ui.screen_img_album); lv_anim_set_time(&a, 500); lv_anim_set_values(&a, LV_IMG_ZOOM_NONE, LV_IMG_ZOOM_NONE / 2); lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t) lv_img_set_zoom); lv_anim_set_ready_cb(&a, NULL); lv_anim_start(&a); guider_ui.screen_img_album = album_img_create(guider_ui.screen_player); lv_obj_fade_in(guider_ui.screen_img_album, 500, 100); lv_anim_set_path_cb(&a, lv_anim_path_overshoot); lv_anim_set_var(&a, guider_ui.screen_img_album); lv_anim_set_time(&a, 500); lv_anim_set_delay(&a, 100); lv_anim_set_values(&a, LV_IMG_ZOOM_NONE / 4, LV_IMG_ZOOM_NONE); lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t) lv_img_set_zoom); lv_anim_set_ready_cb(&a, NULL); lv_anim_start(&a); } void lv_demo_music_album_next(bool next) { uint32_t id = track_id; if(next) { id++; if(id >= ACTIVE_TRACK_CNT) id = 0; } else { if(id == 0) { id = ACTIVE_TRACK_CNT - 1; } else { id--; } } if(playing) { lv_demo_music_play(id); } else { track_load(id); } } void lv_demo_music_play(uint32_t id) { track_load(id); lv_demo_music_resume(); } static lv_obj_t * lv_demo_music_get_list_img(uint32_t track_id) { switch (track_id) { case 0: return guider_ui.screen_img_1; break; case 1: return guider_ui.screen_img_2; break; case 2: return guider_ui.screen_img_3; break; default: return NULL; break; } } static lv_obj_t * lv_demo_music_get_list_btn(uint32_t track_id) { switch (track_id) { case 0: return guider_ui.screen_btn_1; break; case 1: return guider_ui.screen_btn_2; break; case 2: return guider_ui.screen_btn_3; break; default: return NULL; break; } } void lv_demo_music_list_btn_check(uint32_t track_id, bool state) { lv_obj_t * btn = lv_demo_music_get_list_btn(track_id); lv_obj_t * icon = lv_demo_music_get_list_img(track_id); if(state) { lv_obj_add_state(btn, LV_STATE_PRESSED); lv_img_set_src(icon, &_btn_list_pause_alpha_70x70); lv_obj_scroll_to_view(btn, LV_ANIM_ON); } else { lv_obj_clear_state(btn, LV_STATE_PRESSED); lv_img_set_src(icon, &_btn_list_play_alpha_70x70); } } int32_t get_cos(int32_t deg, int32_t a) { int32_t r = (lv_trigo_cos(deg) * a); r += LV_TRIGO_SIN_MAX / 2; return r >> LV_TRIGO_SHIFT; } int32_t get_sin(int32_t deg, int32_t a) { int32_t r = lv_trigo_sin(deg) * a; r += LV_TRIGO_SIN_MAX / 2; return r >> LV_TRIGO_SHIFT; } static void spectrum_draw_event_cb(lv_event_t * e) { lv_event_code_t code = lv_event_get_code(e); if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) { #if LV_DEMO_MUSIC_LANDSCAPE lv_event_set_ext_draw_size(e, LV_HOR_RES); #else lv_event_set_ext_draw_size(e, LV_VER_RES); #endif } else if(code == LV_EVENT_COVER_CHECK) { lv_event_set_cover_res(e, LV_COVER_RES_NOT_COVER); } else if(code == LV_EVENT_DRAW_POST) { static int32_t center_value = 175; lv_obj_t * obj = lv_event_get_target(e); lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); lv_opa_t opa = lv_obj_get_style_opa(obj, LV_PART_MAIN); if(opa < LV_OPA_MIN) return; lv_point_t poly[4]; lv_point_t center; //center.x = obj->coords.x1 + lv_obj_get_width(obj) / 2; //center.y = obj->coords.y1 + lv_obj_get_height(obj) / 2; center.x = 187 * LV_HOR_RES_MAX / 480 + center_value / 2 + obj->coords.x1; center.y = 84 * LV_VER_RES_MAX / 272 + center_value / 2 + obj->coords.y1; lv_draw_rect_dsc_t draw_dsc; lv_draw_rect_dsc_init(&draw_dsc); draw_dsc.bg_opa = LV_OPA_COVER; uint16_t r[64]; uint32_t i; lv_coord_t min_a = 5; lv_coord_t r_in = 78; r_in = (r_in * lv_img_get_zoom(guider_ui.screen_img_album)) >> 8; for(i = 0; i < BAR_CNT; i++) r[i] = r_in + min_a; uint32_t s; for(s = 0; s < 4; s++) { uint32_t f; uint32_t band_w = 0; /*Real number of bars in this band.*/ switch(s) { case 0: band_w = 20; break; case 1: band_w = 8; break; case 2: band_w = 4; break; case 3: band_w = 2; break; } /* Add "side bars" with cosine characteristic.*/ for(f = 0; f < band_w; f++) { uint32_t ampl_main = spectrum[spectrum_i][s]; int32_t ampl_mod = get_cos(f * 360 / band_w + 180, 180) + 180; int32_t t = BAR_PER_BAND_CNT * s - band_w / 2 + f; if(t < 0) t = BAR_CNT + t; if(t >= BAR_CNT) t = t - BAR_CNT; r[t] += (ampl_main * ampl_mod) >> 9; } } uint32_t amax = 10; int32_t animv = spectrum_i - spectrum_lane_ofs_start; if(animv > amax) animv = amax; for(i = 0; i < BAR_CNT; i++) { uint32_t deg_space = 1; uint32_t deg = i * DEG_STEP + 90; uint32_t j = (i + bar_rot + rnd_array[bar_ofs %10]) % BAR_CNT; uint32_t k = (i + bar_rot + rnd_array[(bar_ofs + 1) % 10]) % BAR_CNT; uint32_t v = (r[k] * animv + r[j] * (amax - animv)) / amax; // if(start_anim) { // v = r_in + start_anim_values[i]; // deg_space = v >> 7; // if(deg_space < 1) deg_space = 1; // } if(v < BAR_COLOR1_STOP) draw_dsc.bg_color = BAR_COLOR1; else if(v > BAR_COLOR3_STOP) draw_dsc.bg_color = BAR_COLOR3; else if(v > BAR_COLOR2_STOP) draw_dsc.bg_color = lv_color_mix(BAR_COLOR3, BAR_COLOR2, ((v - BAR_COLOR2_STOP) * 255) / (BAR_COLOR3_STOP-BAR_COLOR2_STOP)); else draw_dsc.bg_color = lv_color_mix(BAR_COLOR2, BAR_COLOR1, ((v - BAR_COLOR1_STOP) * 255) / (BAR_COLOR2_STOP - BAR_COLOR1_STOP)); // draw_dsc.bg_color = lv_color_make(0xff, 0, 0); uint32_t di = deg + deg_space; int32_t x1_out = get_cos(di, v); poly[0].x = center.x + x1_out; poly[0].y = center.y + get_sin(di, v); int32_t x1_in = get_cos(di, r_in); poly[1].x = center.x + x1_in; poly[1].y = center.y + get_sin(di, r_in); di += DEG_STEP - deg_space * 2; int32_t x2_in = get_cos(di, r_in); poly[2].x = center.x + x2_in; poly[2].y = center.y + get_sin(di, r_in); int32_t x2_out = get_cos(di, v); poly[3].x = center.x + x2_out; poly[3].y = center.y + get_sin(di, v); lv_draw_polygon(draw_ctx, &draw_dsc, poly, 4); poly[0].x = center.x - x1_out; poly[1].x = center.x - x1_in; poly[2].x = center.x - x2_in; poly[3].x = center.x - x2_out; lv_draw_polygon(draw_ctx, &draw_dsc, poly, 4); } } } 上述代码是gui-guider中custom.c中的代码分析一下上述代码的作用是什么
10-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值