【GUI】LVGL无操作系统移植以及移植过程错误处理

 目录    

介绍

1. 删除源码

2. 导入lvgl到项目screen_mcu中

3. keil添加分组和头文件

4. 移植显示

5. 移植触摸

6. 添加测试案例

6.1. 测试按钮

6.2. 测试音乐界面

7. 提供时钟

错误处理

L6218E错误

出现花屏

屏幕颜色不对

内存分配


介绍

        本文 主要介绍GD32移植LVGL的过程,以及移植过程中出现的问题以及解决方法,写的非常详细,基本上都截图了。    移植前需要准备下列:

  1. 准备包含触摸功能的屏幕
  2. 实现触摸屏的显示和触摸驱动,确保屏幕没有问题。
  3. 下载lvgl 8.3版本源码下载地址:https://github.com/lvgl/lvgl

本次移植开发板

  • 立创天空星GD32F407VET6
  • 1.69寸电容触摸屏  触摸芯片CS816t,显示:st7789

1. 删除源码

删除源码中不需要的文件夹,仅保留如下内容

  1. demos : lvgl综合案例
  2. examples :单个功能案例
  3. src : 源代码
  4. lv_conf_template.h : 重要的配置文件,里面存在非常多的开关
  5. lvgl.h : 头文件

将上述内容存放到名为lvgl的文件夹中

2. 导入lvgl到项目screen_mcu中

1、在screen_mcu项目中新建third_party文件夹,该文件夹用于存放第三方驱动。

2、将第1个步骤中的lvgl文件夹拷入其中

3、将lvgl文件夹中的lv_conf_tempalate.h修改lv_conf.h

4、把lv_conf.h的条件编译指令#if 0修改成#if 1

3. keil添加分组和头文件

1、使用keil打开screen_mcu项目,添加如下分组

third_party/lvgl/example/porting
third_party/lvgl/src/core
third_party/lvgl/src/draw
third_party/lvgl/src/extra
third_party/lvgl/src/font
third_party/lvgl/src/gpu
third_party/lvgl/src/hal
third_party/lvgl/src/misc
third_party/lvgl/src/widgets

2、添加LVGL相关的.c文件到相应分组,如下:

3、添加头文件路径

4、开启C99模式

4. 移植显示

把lv_port_disp_template.c/h的条件编译指令#if 0修改成#if 1

lv_port_disp_template.h中包含输出设备驱动头文件

#include "st7789.h"

lv_port_disp_template.h中宏定义水平和竖直分辨率(默认横屏)

#define MY_DISP_HOR_RES 240     //水平分辨率
#define MY_DISP_VER_RES 280     //垂直分辨率

修改 lv_port_disp_template.c中 的 lv_port_disp_init 函数

配置图形数据缓冲模式

在lv_port_disp_init函数中选择一种缓冲模式,注释掉其它两种模式

在lv_port_disp_template.c中void disp_init函数添加 屏幕显示驱动初始化函数,这里也就是 ST7789_Init();

/*Initialize your display and the required peripherals.*/
static void disp_init(void)
{
    /*You code here*/
  ST7789_Init();
}

在disp_flush函数中配置打点输出

static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
    if(disp_flush_enabled) {
    	ST7789_Fill(area->x1,area->y1,area->x2,area->y2,(uint16_t*)color_p);
    }
    /*IMPORTANT!!!
     *Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready(disp_drv);
}

5. 移植触摸

     1、把lv_port_indev_tempalte.c/h的条件编译#if 0修改成# if 1

      2、在lv_port_indev_tempalte.c中裁剪输入设备

  • 只保留touchpad_xxx相关的方法,删除其它方法
  • lv_port_indev_init中只保留touchpad相关的代码
  • 在touchpad_init方法中执行触摸屏初始化CST816T_Init();

(包含驱动)

/*Initialize your touchpad*/
static void touchpad_init(void)
{
    CST816T_Init();            //触摸屏初始化
}

        3、配置触摸检测函数

/*Return true is the touchpad is pressed*/
static bool touchpad_is_pressed(void)
{
    /*Your code comes here*/
		return CST816T_is_pressed();
    // return false;
}

        4、配置坐标获取函数

/*Get the x and y coordinates if the touchpad is pressed*/
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)
{
    /*Your code comes here*/
		CST816T_get_xy((uint16_t*)x,(uint16_t*)y);
    //(*x) = 0;
    //(*y) = 0;
}

lv_port_indev_template.c修改之后代码如下:

/**
 * @file lv_port_indev_templ.c
 *
 */

/*Copy this file as "lv_port_indev.c" and set this value to "1" to enable content*/
#if 1

/*********************
 *      INCLUDES
 *********************/
#include "lv_port_indev_template.h"
//#include "../../lvgl.h"
#include "cst816t.h"

/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/

static void touchpad_init(void);
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static bool touchpad_is_pressed(void);
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y);

static void mouse_init(void);
static void mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static bool mouse_is_pressed(void);
static void mouse_get_xy(lv_coord_t * x, lv_coord_t * y);

static void keypad_init(void);
static void keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static uint32_t keypad_get_key(void);

static void encoder_init(void);
static void encoder_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static void encoder_handler(void);

static void button_init(void);
static void button_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static int8_t button_get_pressed_id(void);
static bool button_is_pressed(uint8_t id);

/**********************
 *  STATIC VARIABLES
 **********************/
lv_indev_t * indev_touchpad;
lv_indev_t * indev_mouse;
lv_indev_t * indev_keypad;
lv_indev_t * indev_encoder;
lv_indev_t * indev_button;

static int32_t encoder_diff;
static lv_indev_state_t encoder_state;

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

void lv_port_indev_init(void)
{
    /**
     * Here you will find example implementation of input devices supported by LittelvGL:
     *  - Touchpad
     *  - Mouse (with cursor support)
     *  - Keypad (supports GUI usage only with key)
     *  - Encoder (supports GUI usage only with: left, right, push)
     *  - Button (external buttons to press points on the screen)
     *
     *  The `..._read()` function are only examples.
     *  You should shape them according to your hardware
     */

    static lv_indev_drv_t indev_drv;

    /*------------------
     * Touchpad
     * -----------------*/

    /*Initialize your touchpad if you have*/
    touchpad_init();

    /*Register a touchpad input device*/
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = touchpad_read;
    indev_touchpad = lv_indev_drv_register(&indev_drv);

 
}

/**********************
 *   STATIC FUNCTIONS
 **********************/

/*------------------
 * Touchpad
 * -----------------*/

/*Initialize your touchpad*/
static void touchpad_init(void)
{
    /*Your code comes here*/
	CST816T_Init();
}

/*Will be called by the library to read the touchpad*/
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
    static lv_coord_t last_x = 0;
    static lv_coord_t last_y = 0;

    /*Save the pressed coordinates and the state*/
    if(touchpad_is_pressed()) {
        touchpad_get_xy(&last_x, &last_y);
        data->state = LV_INDEV_STATE_PR;
    }
    else {
        data->state = LV_INDEV_STATE_REL;
    }

    /*Set the last pressed coordinates*/
    data->point.x = last_x;
    data->point.y = last_y;
}

/*Return true is the touchpad is pressed*/
static bool touchpad_is_pressed(void)
{
    /*Your code comes here*/
		return CST816T_is_pressed();
    // return false;
}

/*Get the x and y coordinates if the touchpad is pressed*/
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)
{
    /*Your code comes here*/
		CST816T_get_xy((uint16_t*)x,(uint16_t*)y);
    //(*x) = 0;
    //(*y) = 0;
}


#else /*Enable this file at the top*/

/*This dummy typedef exists purely to silence -Wpedantic.*/
typedef int keep_pedantic_happy;
#endif

6. 添加测试案例

初始化LVGL,包含LVGL相关头文件

6.1. 测试按钮

#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include <string.h>
#include "USART.h"
#include "I2C.h"

#include "st7789.h"
#include "cst816t.h"

#include "lvgl.h"
#include "lv_port_disp.h"
#include "lv_port_indev.h"

// 事件回调
void event_handler(lv_event_t* e) {
  lv_event_code_t code = lv_event_get_code(e);

  if (code == LV_EVENT_VALUE_CHANGED) {
    printf("toggled btn\n");
  }
}
void demo_button_checkable() {
  // 获取显示图层
  lv_obj_t* screen = lv_scr_act();
  // 创建按钮
  lv_obj_t* btn = lv_btn_create(screen);
  // 设置按钮尺寸
  lv_obj_set_size(btn, 120, 50);

  // 4. 在按钮上创建文本并居中显示
  lv_obj_t* label = lv_label_create(btn);
  lv_label_set_text(label, "Toggle");
  // lv_obj_center(label);
  lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
  // 5. 设置按钮可选中
  lv_obj_add_flag(btn, LV_OBJ_FLAG_CHECKABLE);

  // 默认选中
//  lv_obj_add_state(btn, LV_STATE_CHECKED);

  lv_obj_add_event_cb(btn, event_handler, LV_EVENT_VALUE_CHANGED, NULL);
  // 居中
  lv_obj_center(btn);
}

主函数


int main(void) {
  // 配置全局中断分组
  nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
  // 初始化系统嘀嗒定时器
  systick_config();
  // 初始化USART
  USART_init();
  I2C_init();

  // 1. 初始化LVGL
  lv_init();
  // 2.显示屏驱动初始化
  lv_port_disp_init();
  // 3. 触摸屏(输入设备要在屏幕初始化之后再init,否则会失效)
  lv_port_indev_init();

  demo_button_checkable();

  while(1) {
    // 4. 每隔x毫秒调用一次心跳
    lv_tick_inc(1);
    // 5. 执行定时任务(屏幕渲染,事件处理)
    lv_timer_handler();
    // 休眠1ms
    delay_1ms(1);
  }
}

6.2. 测试音乐界面

        音乐界面需要接近1M的内存,天空星内存小了,无法测试,下载进去会报几百个错误,显示内存不足,可以使用梁山派。

        1、keil添加lvgl/demos/music文件夹下所有.c文件

        2、添加相关头文件路径

..\..\third_party\lvgl\demos
..\..\third_party\lvgl\demos\music

        3、修改lv_conf.h中的

#define LV_USE_DEMO_MUSIC 0改为#define LV_USE_DEMO_MUSIC 1

#define LV_FONT_MONTSERRAT_12 0改为#define LV_FONT_MONTSERRAT_12 1

#define LV_FONT_MONTSERRAT_16 0改为#define LV_FONT_MONTSERRAT_16 1

#define LV_USE_DEMO_MUSIC       0
改为
#define LV_USE_DEMO_MUSIC       1

#define LV_FONT_MONTSERRAT_12 0
改为
#define LV_FONT_MONTSERRAT_12 1

#define LV_FONT_MONTSERRAT_16 0
改为
#define LV_FONT_MONTSERRAT_16 1

main.c主函数

#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "bsp_basic_timer.h"

#include "lcd.h"
#include "touch.h"

#include "lvgl.h"

#include "lv_demo_music.h"
#include "lv_conf.h"
#include "lv_port_disp_template.h"
#include "lv_port_indev_template.h"

int main(void)
{
    nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);  // 优先级分组
    systick_config();	

    lv_init();
    // 这里必须先初始化disp再初始化indev
    lv_port_disp_init();
    lv_port_indev_init();	

    lv_demo_music();
    while(1)
    {
        lv_tick_inc(1);
		lv_timer_handler();
		delay_1ms(1);
    }
}

7. 提供时钟

        可以不用定时器时钟,直接放在while循环中,后面的定时器就不需要配置

while(1) {
        lv_tick_inc(5);
        lv_timer_handler();
        delay_1ms(5);
}

        在Hardware下创建timer文件夹,文件夹下定义bsp_basic_timer.h和bsp_basic_timer.c文件,内容如下

#ifndef _BSP_BASIC_TIMER_H
#define _BSP_BASIC_TIMER_H

#include "gd32f4xx.h"
#include "systick.h"
#include "stdio.h"
#include "lvgl.h"

#define BSP_TIMER_RCU  				RCU_TIMER5            // 定时器时钟
#define BSP_TIMER      				TIMER5                // 定时器
#define BSP_TIMER_IRQ  				TIMER5_DAC_IRQn       // 定时器中断
#define BSP_TIMER_IRQHANDLER  TIMER5_DAC_IRQHandler // 定时器中断服务函数


//#define BSP_TIMER_RCU  				RCU_TIMER2					// 定时器时钟
//#define BSP_TIMER      				TIMER2							// 定时器
//#define BSP_TIMER_IRQ  			  TIMER2_IRQn					// 定时器中断
//#define BSP_TIMER_IRQHANDLER  TIMER2_IRQHandler		// 定时器中断服务函数


void basic_timer_config(uint16_t pre,uint16_t per); // 基本定时器配置

#endif  /* BSP_BASIC_TIMER_H */

#include "bsp_basic_timer.h"
//#include "bsp_led.h"

/************************************************
函数名称 : basic_timer_config
功    能 : 基本定时器配置
参    数 : pre:时钟预分频值
					  per:周期 
*************************************************/
void basic_timer_config(uint16_t pre,uint16_t per)
{
    /* 一个周期的时间T = 1/f, 定时时间time = T * 周期
    设预分频值位pre,周期位per
    time = (pre + 1) * (per + 1) / psc_clk
	*/
    timer_parameter_struct timere_initpara; 							// 定义定时器结构体
    /* 开启时钟 */
    rcu_periph_clock_enable(BSP_TIMER_RCU); 							// 开启定时器时钟
    /* CK_TIMERx = 4 x CK_APB1  = 4x50M = 200MHZ */
    rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4); // 配置定时器时钟


    timer_deinit(BSP_TIMER);														  // 复位定时器
    /* 配置定时器参数 */
    timere_initpara.prescaler = pre-1;                    //  时钟预分频值 0-65535   psc_clk = CK_TIMER / pre
    timere_initpara.alignedmode = TIMER_COUNTER_EDGE;     // 边缘对齐                  
    timere_initpara.counterdirection = TIMER_COUNTER_UP;  // 向上计数    
    timere_initpara.period = per-1;                       // 周期  
    /* 在输入捕获的时候使用  数字滤波器使用的采样频率之间的分频比例 */
    timere_initpara.clockdivision = TIMER_CKDIV_DIV1;     // 分频因子         
    /* 只有高级定时器才有 配置为x,就重复x+1次进入中断 */    
    timere_initpara.repetitioncounter = 0;							  // 重复计数器 0-255  

    timer_init(BSP_TIMER,&timere_initpara);								// 初始化定时器

    /* 配置中断优先级 */
    nvic_irq_enable(BSP_TIMER_IRQ,3,2); 									// 设置中断优先级为 3,2
    /* 使能中断 */
    timer_interrupt_enable(BSP_TIMER,TIMER_INT_UP);       // 使能更新事件中断 
    /* 使能定时器 */
    timer_enable(BSP_TIMER);
}

/************************************************
函数名称 : BSP_TIMER_IRQHandler
功    能 : 基本定时器中断服务函数 
参    数 : 无
返 回 值 : 无
作    者 : LC
*************************************************/
void BSP_TIMER_IRQHANDLER(void)
{
    /* 这里是定时器中断 */
    if(timer_interrupt_flag_get(BSP_TIMER,TIMER_INT_FLAG_UP) == SET)
    {
        timer_interrupt_flag_clear(BSP_TIMER,TIMER_INT_FLAG_UP);  // 清除中断标志位 
        /* 执行功能 */
        lv_tick_inc(1);
    }
}

定义之后,keil添加.c文件和头文件即可

错误处理

L6218E错误

.\Objects\GD32F450.axf: Error: L6218E: Undefined symbol __aeabi_assert (referred from qrcodegen.o).

解决方案:

添加NDEBUG宏定义

设置如下即可

出现花屏

        出现该现象是由于LVGL相对占用内存较大,需要修改内存问题,在startup_gd32f407_427.s中修改内存大小即可

原始:
Stack_Size      EQU     0x00000400
修改后:
Stack_Size      EQU     0x00000800

屏幕颜色不对

        正常颜色应该和下发模拟器图片一致,按钮是蓝色的,出现该问题的原因:LVGL配置的color depth颜色深度参数和屏幕不一致导致,在配置文件lv_conf.h里面修改LV_COLOR_DEPTH、LV_COLOR_16_SWAP的宏定义。

内存分配

         在LVGL中,除了注释不使用相关业务外,有3个位置可以实现修改内存修改,根据自己情况进行来。

1、startup_gd32f407_427.s中修改内存大小,当移植出现花屏的时候,修改这里即可解决。

2、在配置文件lv_conf.h中:LV_MEM_SIZE定义LVGL内部使用的内存池的大小。该内存池用于LVGL的对象、样式、动画等动态分配的内存需求。决定了LVGL可以使用的总内存量

3、显示缓存(Display Buffer)

在配置文件lv_conf.h中,lv_disp_draw_buf_init函数中指定了显示的缓存大小(即MY_DISP_HOR_RES * MY_DISP_VER_RES)直接决定了一次可以绘制的最大像素数量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/731918.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

qt经典界面框架

目的 其实就是一个简单的界面显示&#xff0c;是很常用的形式。 说起来简单也是简单&#xff0c;但当初&#xff0c;刚开始做时&#xff0c;感觉非常的复杂&#xff0c;不知如何下手。 现在感觉简单多了。 这个框架利用了QT的现成的MainWindow与QDockWidget&#xff0c;这样就…

福建聚鼎:装饰画现在做起来难吗

在当代社会&#xff0c;艺术创作已经成为很多人表达自我、追求美学生活的方式之一。装饰画作为家居装饰的重要元素&#xff0c;也受到了越来越多人的喜爱。但做一个优质的装饰画真的容易吗? 从技术层面讲&#xff0c;随着科技的发展&#xff0c;制作装饰画的手段和材料都比以往…

Python基础教程(二十八):pip模块

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; &#x1f49d;&#x1f49…

NUC980-OLED实现全中文字库的方法

1.背景 有一个产品&#xff0c;客户需要屏幕展示一些内容&#xff0c;要带一些中文&#xff0c;实现了OLED12864的驱动&#xff0c;但是它不带字库&#xff0c;现在要实现OLED全字库的显示 2.制作原始字库 下载软件pctolcd2002 设置 制作字库 打开原始文件 用软件自带的&…

Linux常用命令(14)—查看文件内容(有相关截图)

写在前面&#xff1a; 最近在学习Linux命令&#xff0c;记录一下学习Linux常用命令的过程&#xff0c;方便以后复习。仅供参考&#xff0c;若有不当的地方&#xff0c;恳请指正。如果对你有帮助&#xff0c;欢迎点赞&#xff0c;关注&#xff0c;收藏&#xff0c;评论&#xf…

12.爬虫---PyMysql安装与使用

12.PyMysql安装与使用 1.安装 PyMySQL2.使用PyMySQL2.1创建数据表2.2连接数据库2.3增加数据2.4修改数据2.5查询数据2.6删除数据2.7关闭连接 3.总结 MySQL 安装可以看这篇文章MySql 安装与使用&#xff08;非常详细&#xff09; 1.安装 PyMySQL PyMySQL是Python中用于连接MySQL…

【linux】shell脚本中设置字体颜色,背景颜色详细攻略

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…

解决vmware “处理器不支持 XSAVE。无法打开此虚拟机的电源。“

1,打开windows 10-11 的 虚拟机平台 选择 “开始”&#xff0c;输入“Windows 功能”&#xff0c;然后从结果列表中选择“打开或关闭 Windows 功能 ”。 在刚刚打开的 “Windows 功能”窗口中&#xff0c;找到“虚拟机平台 ”并将其选中。 选择“确定”。 可能需要重启电脑。…

【干货】微信小程序免费开源项目合集

前言 2024年了&#xff0c;还有小伙伴在问微信小程序要怎么开发&#xff0c;有什么好的推荐学习项目可以参考的。今天分享一个收集了一系列在微信小程序开发中有用的工具、库、插件和资源&#xff1a;awesome-github-wechat-weapp。 开源项目介绍 它提供了丰富的资源列表&…

华为DCN技术:M-LAG

M-LAG&#xff08;Multichassis Link Aggregation Group&#xff09;即跨设备链路聚合组&#xff0c;是一种实现跨设备链路聚合的机制。M-LAG主要应用于普通以太网络、VXLAN和IP网络的双归接入&#xff0c;可以起到负载分担或备份保护的作用。相较于另一种常见的可靠性接入技术…

[C++][数据结构][B-树][下]详细讲解

目录 1.B-树的实现1.B-树的结点设计2.插入key的过程3.B-树的插入实现4.B-树的简单验证5.B-树的性能分析6.B树的删除 2.B树3.B*树4.B-树总结5.B-树的应用0.B树可以在内存中做内查找吗&#xff1f;1.索引2.MYSQL索引简介1.MyISAM2.InnoDB 3.B树做主键索引相比B树的优势 1.B-树的实…

10.2 JavaEE——Spring MVC入门程序

要求在浏览器发起请求&#xff0c;由Spring MVC接收请求并响应&#xff0c;具体实现步骤如下。 一、创建项目 在IDEA中&#xff0c;创建一个名称为chapter10的Maven Web项目。 &#xff08;一&#xff09;手动设置webapp文件夹 1、单击IDEA工具栏中的File→“Project Structu…

如何用GO语言实现冒泡排序算法?

本章教程,介绍一下如何用GO语言实现基础排序算法中的冒泡排序。 一、程序代码 package mainimport ("fmt""math/rand""time" )// bubbleSort 函数实现冒泡排序算法 func bubbleSort(arr []int) {n

电脑文件夹怎么加密?文件夹加密的5种方法

在数字化时代&#xff0c;信息安全显得尤为重要。对于个人电脑用户来说&#xff0c;文件夹加密是一种有效保护隐私和数据安全的方法。本文将介绍五种文件夹加密的方法&#xff0c;帮助您更好地保护自己的重要文件。 如何设置文件夹密码方法一&#xff1a;利用Windows系统自带的…

不懂就问,开通小程序地理位置接口有那么难吗?

小程序地理位置接口有什么功能&#xff1f; 若提审后被驳回&#xff0c;理由是“当前提审小程序代码包中地理位置相关接口( chooseAddress、getLocation )暂未开通&#xff0c;建议完成接口开通后或移除接口相关内容后再进行后续版本提审”&#xff0c;那么遇到这种情况&#x…

使用Rsbuild构建基于Vue3+Vant4开发h5应用

目录 一、介绍 1.1 Vant介绍 1.2 Rsbuild介绍 1.3 Vue介绍 二、构建应用 1.第一步 2.第二步 3.第三步 4.第四步 5.第五步 6.在项目中使用 Vant4 组件 7.移动端适配Rem 8. 执行 cnpm run dev 启动项目 一、介绍 1.1 Vant介绍 Vant 是一个轻量、可定制的移动端组…

Python连接Redis(简单连接、连接池连接、存取数据示例)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

C语言王国——深入自定义类型(联合体、枚举)

目录 一、引言 二、联合体 2.1 联合体类型的声明 2.2 联合体大小的计算 2.3 联合体的实践运用 2.4 用联合体测试大小端字节序 三、枚举 3.1 枚举类型的声明 3.2 枚举类型的特点 四、总结 一、引言 我们刚学完了结构体&#xff0c;相信大家对自定义类型也有了些许了解&…

【Mac】FxFactory 8 Pro for Mac(视觉特效处理包)及同类型软件介绍

软件介绍 FxFactory Pro 是一款功能强大的插件管理和创作工具&#xff0c;专为视频编辑器和特效艺术家设计&#xff0c;适用于 macOS 系统。它集成了大量的视频特效插件&#xff0c;并与多种主流视频编辑软件无缝兼容&#xff0c;如 Final Cut Pro、Premiere Pro、After Effec…

第二十七篇——通信趋势:5G和IOT的商机在哪里?

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 借势的重要性&#xff0c;但是要做到借势&#xff0c;得先看到&#xff0…