嵌入式 LVGL移植到STM32F4
目录
LVGL简介
1、特点
2、LVGL的硬件要求
3、相关网站
4、LVGL源码下载
5、LVGL移植要求
5.1 移植过程-添加源码
2、更改接口文件
3、显示实现
4、添加外部中文字体的方法
5、编译下载后有几种情况
6、调用显示
6、GUI-Guider使用
6.1 安装软件
6.2 使用软件
6.3 移植到STM32
LVGL简介
LittlevGL是一个免费的开源图形库,提供了创建嵌入式GUI所需的一切,具有易于使用的图形元素、漂亮的视觉效果和低内存占用。

1、特点
- 强大的构建模组:按钮、图表、列表、滑块、图像等
- 先进的图形:动画、反锯齿、半透明、平滑滚动
- 多样的输入设备:触摸板、鼠标、键盘、编码器等
- 多显示器支持:支持同时使用多个TFT或单色显示器
- 多语言支持:格式文字编码
- 硬件无关:可用于任UTF-8意微控制器或显示器
- 可裁剪:用于小内存(64 KB FLASH,16 KB RAM)操作
- 外部支持:操作系统、外部存储以及GPU
- 单帧缓存:即可实现先进的图形效果
- C语言编写:以最大化兼容(C++ 兼容)
- 模拟器:无需嵌入式硬件就可以在电脑上开始GUI设计
- 文档:在线及离线
- 免费开源:基于MIT协议
2、LVGL的硬件要求

3、相关网站
- LVGL官网:LVGL - Light and Versatile Embedded Graphics Library
- LVGL代码库地址(Simulator、Source、Examples、Esp32、MicroPython):LVGL · GitHub
- LVGL源码下载地址:GitHub - lvgl/lvgl: Embedded graphics library to create beautiful UIs for any MCU, MPU and display type. It's boosted by a professional yet affordable drag and drop UI editor, called SquareLine Studio.
4、LVGL源码下载
在源码链接中下载一份源码,LVGL已经更新迭代了很多个版本,这里我们选择8.0.1版本来移植。

注意:不同版本之间有很大的不同,尽量使用与本文相同的版本,否则不予解释。
下载后得到的目录如下:

源码各文件作用
- github:github的配置文件,忽略即可。
- docs:说明文档。
- examples:示例代码。
- scripts:配置脚本,Linux平台会用到,Windows忽略即可。
- src:源代码。
- tests:测试代码。
5、LVGL移植要求
STM32工程,该工程应具备功能:
LCD显示(必备)
- TOUCH触摸(可选)
- DMA刷屏(可选)
- 内存管理(可选)
- 操作系统(可选)
5.1 移植过程-添加源码
在工程目录下创建LVGL文件夹,

接着, 将LVGL的源码目录(lvgl-8.0.1\src)复制到本工程中的LVGL目录中

接下来,将LVGL的驱动接口文件目录(lvgl-8.0.1\examples\porting)复制到本工程中的LVGL文件夹中。其中共六个文件,disp为显示接口驱动文件(LCD),fs为文件系统接口驱动文件(FATFS),indev为输入设备接口驱动文件(TOUCH)

接着, 将LVGL源码中(lvgl-8.0.1)的lv_conf_template.h更名为lv_conf.h,随后将其与lvgl.h一同拷贝到本地工程中的LVGL目录下;


接着, 打开工程,在工程的目录结构中添加二个文件夹LVGL_SRC和LVGL_PORT,并把源码添加到其中。(可根据需要进行裁剪)。




添加port文件

不知道就全部都添加。本示例只使用disp这个显示的模板。
接着,添加源码头文件路径;

如果工程中没有内存管理,则需要修改启动文件中的堆栈。根据官方推荐我们可以把堆栈修改为4K,假如使用的功能比较多,还需要再适当增大;

LVGL的源码需要C99的支持,否则编译无法通过;

next,编译工程


双击错误定位到错误位置发现,该代码包含的头文件路径层级错误,根据目录层级修改。(原来是../../lv_conf,更改为../ lv_conf)

打开lv_conf文件中的条件编译。lv_conf的条件编译没有打开,去到此文件下打开该文件修改保存即可;

编译。如果出现以下错误:

只剩3个错误了,原因是没有添加主题源文件(..\LVGL\src\extra\themes\default)。把下图中的文件添加到工程。
如果出现以下错误:

不这是因为没有添加控件的源文件,默认所有控件是使能状态的(lv_conf.h),我们把这些源文件(src\extra\widgets目录下)都添加到我们的工程中(如果在添加src文件时已经全部添加则不会出现这些错误)。


最终编译没有错误了。

移植成功了,但是还显示不了,我们还需要去实现显示的相关接口。
2、更改接口文件
默认lv_port_disp_templ.c和lv_port_disp_templ.h的条件编译是关闭的,我们需要把他打开并修改包含目录层级。


更改lv_port_disp_templ.c 文件中lv_port_disp_init驱动函数。此函数提供了三种写缓存方式,保留其中一种即可,本示例采用方式二;
方式一:单缓存显示(10行),主控内存较小时选用此方式。
方式二:双缓存显示(两个10行),此方式支持DMA交替传输,缓存区越大,显示效果越好(有条件两个满屏缓存)。
方式三:双满屏缓存显示,相当于有条件的方式二
注释方式一和方式三,更改第二种方式如下:

方式二更改如下:


更改屏幕大小:

添加DMA实现代码,并在disp_init函数中调用DMA的初始化函数(如果不使用DMA,disp_flush函数中只需要保留LCD_Color_Fill、lv_disp_flush_ready这两个函数即可)。注意添加需要的头文件。如#include "lcd.h"
- 添加一个全局变量static lv_disp_drv_t *disp_drv_p;

把以下代码添加到lv_port_disp_templ.c,
static void DisPlay_SPI_DMA_Init()
{DMA_InitTypeDef DMA_InitStructure = {0};NVIC_InitTypeDef NVIC_InitStruct = {0};RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); //DMA1时钟使能DMA_DeInit(DMA1_Stream7);while(DMA_GetCmdStatus(DMA1_Stream7) != DISABLE) {} //等待DMA可配置/* 配置 DMA Stream */DMA_InitStructure.DMA_Channel = DMA_Channel_0; //通道选择DMA_InitStructure.DMA_PeripheralBaseAddr = (unsigned int)&SPI3->DR; //DMA外设地址DMA_InitStructure.DMA_Memory0BaseAddr = (unsigned int)buf_2_1; //DMA 存储器0地址DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; //存储器到外设模式DMA_InitStructure.DMA_BufferSize = sizeof(buf_2_2); //数据传输量DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设非增量模式DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器增量模式DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据长度:8位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //存储器数据长度:8位DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //使用普通模式DMA_InitStructure.DMA_Priority = DMA_Priority_High; //中等优先级DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; //不使用fifoDMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; //fifo全容量DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输DMA_Init(DMA1_Stream7, &DMA_InitStructure); //初始化DMA StreamSPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Tx, ENABLE); // SPI3使能DMA发送NVIC_InitStruct.NVIC_IRQChannel = DMA1_Stream7_IRQn;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;NVIC_Init(&NVIC_InitStruct);DMA_ITConfig(DMA1_Stream7, DMA_IT_TC, ENABLE);DMA_Cmd(DMA1_Stream7, DISABLE);
}/*********************************************************************************************************
* 函 数 名 : DisPlay_SPI_DMA_Enable
* 功能说明 : 配置DMA并启动一次传输
* 形 参 : buf:需要搬运的数据的指针;size:搬运的数据量
* 返 回 值 : 无
* 备 注 : 无
*********************************************************************************************************/
void DisPlay_SPI_DMA_Enable(void *buf, unsigned int size)
{DMA1_Stream7->CR &= ~(0x01);while((DMA1_Stream7->CR&0X1)){}DMA1_Stream7->M0AR = (unsigned int)buf;DMA1_Stream7->NDTR = size;DMA1_Stream7->CR |= (0x01);
}
/*********************************************************************************************************
* 函 数 名 : DMA1_Stream7_IRQHandler
* 功能说明 : DMA1_Stream7发送完成中断
* 形 参 : 无
* 返 回 值 : 无
* 备 注 : 无
*********************************************************************************************************/
void DMA1_Stream7_IRQHandler(void)
{if(DMA_GetITStatus(DMA1_Stream7, DMA_IT_TCIF7) != RESET)//if(DMA1->HISR & (1<<27)){DMA_ClearITPendingBit(DMA1_Stream7, DMA_IT_TCIF7);//DMA1->HIFCR |= (1<<27);LCD_CS = 1;SPI3->DR; lv_disp_flush_ready(disp_drv_p); /* tell lvgl that flushing is done */}
}
在disp_init函数中调用DMA的初始化函数。

修改disp_flush函数
/* Flush the content of the internal buffer the specific area on the display* You can use DMA or any hardware acceleration to do this operation in the background but* 'lv_disp_flush_ready()' has to be called when finished. */
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{/*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/// int32_t x;
// int32_t y;
// for(y = area->y1; y <= area->y2; y++) {
// for(x = area->x1; x <= area->x2; x++) {
// /* Put a pixel to the display. For example: */
// /* put_px(x, y, *color_p)*/
// color_p++;
// }
// }unsigned int size = (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1) * 2;disp_drv_p = disp_drv;LCD_Address_Set(area->x1, area->y1, area->x2, area->y2+1); LCD_CS = 0;DisPlay_SPI_DMA_Enable(color_p, size);/*不使用DMA的显示方法*/
// LCD_Color_Fill(area->x1, area->y1, area->x2-area->x1, area->y2-area->y1+1, (unsigned short *)color_p);/* IMPORTANT!!!* Inform the graphics library that you are ready with the flushing*/
// lv_disp_flush_ready(disp_drv);
}
最后编译;

还有一个错误;

最终编译无误。
lv_port_disp_templ.c 文件最终更改后如下;
#if 1
#include "lv_port_disp_template.h"
#include "lcd.h"#define MY_DISP_HOR_RES 240 //屏的大小
#define MY_DISP_VER_RES 240
static lv_color_t buf_2_1[MY_DISP_HOR_RES * 10]; /*A buffer for 10 rows*/
static lv_color_t buf_2_2[MY_DISP_VER_RES * 10]; /*An other buffer for 10 rows*/static lv_disp_drv_t *disp_drv_p;static void disp_init(void);static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);/*********************************************************************************************************
* 函 数 名 : DisPlay_SPI_DMA_Init
* 功能说明 : SPI3 DMA1初始化
* 形 参 : 无
* 返 回 值 : 无
* 备 注 : DMA1_Stream7搬运显示数据到SPI3的DR寄存器
*********************************************************************************************************/
static void DisPlay_SPI_DMA_Init()
{DMA_InitTypeDef DMA_InitStructure = {0};NVIC_InitTypeDef NVIC_InitStruct = {0};RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); //DMA1时钟使能DMA_DeInit(DMA1_Stream7);while(DMA_GetCmdStatus(DMA1_Stream7) != DISABLE) {} //等待DMA可配置/* 配置 DMA Stream */DMA_InitStructure.DMA_Channel = DMA_Channel_0; //通道选择DMA_InitStructure.DMA_PeripheralBaseAddr = (unsigned int)&SPI3->DR; //DMA外设地址DMA_InitStructure.DMA_Memory0BaseAddr = (unsigned int)buf_2_1; //DMA 存储器0地址DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; //存储器到外设模式DMA_InitStructure.DMA_BufferSize = sizeof(buf_2_2); //数据传输量DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设非增量模式DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器增量模式DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据长度:8位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //存储器数据长度:8位DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //使用普通模式DMA_InitStructure.DMA_Priority = DMA_Priority_High; //中等优先级DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; //不使用fifoDMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; //fifo全容量DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输DMA_Init(DMA1_Stream7, &DMA_InitStructure); //初始化DMA StreamSPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Tx, ENABLE); // SPI3使能DMA发送NVIC_InitStruct.NVIC_IRQChannel = DMA1_Stream7_IRQn;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;NVIC_Init(&NVIC_InitStruct);DMA_ITConfig(DMA1_Stream7, DMA_IT_TC, ENABLE);DMA_Cmd(DMA1_Stream7, DISABLE);
}
/*********************************************************************************************************
* 函 数 名 : DisPlay_SPI_DMA_Enable
* 功能说明 : 配置DMA并启动一次传输
* 形 参 : buf:需要搬运的数据的指针;size:搬运的数据量
* 返 回 值 : 无
* 备 注 : 无
*********************************************************************************************************/
void DisPlay_SPI_DMA_Enable(void *buf, unsigned int size)
{DMA1_Stream7->CR &= ~(0x01);while((DMA1_Stream7->CR&0X1)){}DMA1_Stream7->M0AR = (unsigned int)buf;DMA1_Stream7->NDTR = size;DMA1_Stream7->CR |= (0x01);
}
/*********************************************************************************************************
* 函 数 名 : DMA1_Stream7_IRQHandler
* 功能说明 : DMA1_Stream7发送完成中断
* 形 参 : 无
* 返 回 值 : 无
* 备 注 : 无
*********************************************************************************************************/
void DMA1_Stream7_IRQHandler(void)
{if(DMA_GetITStatus(DMA1_Stream7, DMA_IT_TCIF7) != RESET)//if(DMA1->HISR & (1<<27)){DMA_ClearITPendingBit(DMA1_Stream7, DMA_IT_TCIF7);//DMA1->HIFCR |= (1<<27);LCD_CS = 1;SPI3->DR; lv_disp_flush_ready(disp_drv_p); /* tell lvgl that flushing is done */}
}void lv_port_disp_init(void)
{disp_init();static lv_disp_draw_buf_t draw_buf_dsc_2;lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2, MY_DISP_HOR_RES * 10); /*Initialize the display buffer*/static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/lv_disp_drv_init(&disp_drv); /*Basic initialization*/disp_drv.hor_res = MY_DISP_HOR_RES;disp_drv.ver_res = MY_DISP_VER_RES;disp_drv.flush_cb = disp_flush;disp_drv.draw_buf = &draw_buf_dsc_2;lv_disp_drv_register(&disp_drv);
}static void disp_init(void)
{/*You code here*/DisPlay_SPI_DMA_Init();
}static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{unsigned int size = (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1) * 2;disp_drv_p = disp_drv;LCD_Address_Set(area->x1, area->y1, area->x2, area->y2+1); LCD_CS = 0;DisPlay_SPI_DMA_Enable(color_p, size);
}#else
typedef int keep_pedantic_happy;
#endif
根据需求修改lv_conf.h的宏定义;
- LV_COLOR_DEPTH:屏幕的色彩深度,支持1bit、8bit、16bit、32bit。
- LV_COLOR_16_SWAP:字节交换,DMA刷屏的时候需要置1。
- LV_MEM_SIZE:GUI可支配的内存空间,根据使用的功能调节。
- LV_FONT_MONTSERRAT_*:字体大小,太小会很模糊。


如果需要更改默认字体大小,则把相应的宏设置为1.


3、显示实现
配置一个定时器为LVGL提供1ms的时钟心跳,该定时器的中断服务函数中调用lv_tick_inc(1);即可

主程序中调用lv_task_handler();函数处理事件

编写显示程序
#include "lvgl.h"
#include "lv_port_disp_template.h"
void Lvgl_Lable_Demo(void)
{_obj_t *scr = lv_scr_act();
lv_obj_t * label1 = lv_label_create(scr);lv_label_set_long_mode(label1, LV_LABEL_LONG_WRAP); lv_label_set_recolor(label1, true); lv_label_set_text(label1, "#0000ff Re-color# #ff00ff words# #ff0000 of a# label, align the lines to the center ""and wrap long text automatically."); lv_obj_set_width(label1, 150); lv_obj_set_style_text_align(label1, LV_TEXT_ALIGN_CENTER, 0); lv_obj_align(label1, LV_ALIGN_CENTER, 0, -40); lv_obj_t * label2 = lv_label_create(scr);lv_label_set_long_mode(label2, LV_LABEL_LONG_SCROLL_CIRCULAR); lv_obj_set_width(label2, 150); lv_label_set_text(label2, "It is a circularly scrolling text. "); lv_obj_align(label2, LV_ALIGN_CENTER, 0, 40);
}int main()
{
…..
Lcd_Init();lv_init(); // 初始化lvgllv_port_disp_init(); // 显示初始化Lvgl_Lable_Demo();….while(1){lv_task_handler();Delay_Ms(1);}
}
4、添加外部中文字体的方法
打开字库生成工具,选择字体,选择TTF字体,加入常用字体,清除重复。目前抗齿距只能使用4,版本选择6.0以上,XBF字体,外部BIN。点击保存可以存出C文件,点击开始转换即可转换出BIN文件。

然后点击加入常用汉字à保存à开始转换;

得到以下两个文件;

myFont.bin烧写到自己的SPI FLASH相应的地址。烧写过程你懂的。
myFont.c添加到自己的LVGL工程中并添加自定义的字体
lvgl.h处添加用户字体声明;

将myFont.c中lv_font_t myFont结构体类型加上const修饰,其他需要修改的代码如。


5、编译下载后有几种情况
(1)乱码:抗齿距不是4,多试几种;FLASH读写异常,先测试是否能正常读写。
(2)只有英文:显示中文的C文件编码不是UTF-8,使用软件修改为UTF-8编码后编译报错,在C/C++选项卡中的Misc Controls选项中添加--locale=english


6、调用显示
void Lvgl_Lable_Demo(void)
{lv_obj_t *scr = lv_scr_act();
lv_obj_t * label1 = lv_label_create(scr);lv_label_set_long_mode(label1, LV_LABEL_LONG_WRAP); lv_label_set_recolor(label1, true); lv_label_set_text(label1, "#0000ff Re-color# #ff00ff words# #ff0000 of a# label, align the lines to the center ""and wrap long text automatically"); lv_obj_set_width(label1, 150); lv_obj_set_style_text_align(label1, LV_TEXT_ALIGN_CENTER, 0); lv_obj_align(label1, LV_ALIGN_CENTER, 0, -40); lv_obj_t * label2 = lv_label_create(scr);lv_label_set_long_mode(label2, LV_LABEL_LONG_SCROLL_CIRCULAR); lv_obj_set_width(label2, 150); lv_label_set_text(label2, "It is a circularly scrolling text.中国"); lv_obj_align(label2, LV_ALIGN_CENTER, 0, 40);
}
6、GUI-Guider使用
GUI Guider是恩智浦为LVGL开发了一个上位机GUI设计工具,可以通过拖放控件的方式设计LVGL GUI页面,加速GUI的设计。
设计完成的GUI页面可以在PC上仿真运行,确认设计完毕之后可以生成C代码,再整合到MCU项目中。
GUI Guider(Version: 1.3.0-GA)的主要特征:
- 支持Windows 10和Ubuntu 20.04。
- 支持中文、英文。
- 兼容LVGL V7和LVGL V8版本。
- 支持拖放的所见即所得(WYSIWYG)用户界面设计。
- 多种字体支持及第三方字体导入。
- 可定制的中文字符范围。
- 小部件对齐方式:左、中、右。
- 自动产生LVGL C语言源代码。
- 支持默认样式和自定义样式。
- 演示应用程序集成。
- 实时日志显示。
- 集成上位机仿真器。
GUI-Guider会依赖JDK,因此需要安装jdk.
6.1 安装软件
GUI-Guider会依赖JDK,因此需要安装jdk.

6.2 使用软件
1、打开GUI-Guider-1.3.0-GA软件;

2、创建工程;

3、创建完成进入设计界面;

左侧是组件区,中间是设计区,右边是控件地属性设置区。按照自己需要设计GUI页面,

上图事件功能是按下按钮是把按钮的背景改为黑色。
运行模拟器预览一下效果

没问题之后就可以生成代码(记得先保存工程),在Guider中也可以在代码窗口查看生成的代码.

生成的代码在Guider工程目录的generated和custom文件夹下


6.3 移植到STM32
把generated和custom文件夹工程整个复制到我们的keil工程目录中:

添加generated和custom文件夹相关源文件;





添加头文件路径

编写测试代码

更改错误:一般都是头文件路径不对,哪里不对改哪里。比如

相关文章:
嵌入式 LVGL移植到STM32F4
目录 LVGL简介 1、特点 2、LVGL的硬件要求 3、相关网站 4、LVGL源码下载 5、LVGL移植要求 5.1 移植过程-添加源码 2、更改接口文件 3、显示实现 4、添加外部中文字体的方法 5、编译下载后有几种情况 6、调用显示 6、GUI-Guider使用 6.1 安装软件 6.2 使用…...
VSCode——SSH免密登录
文章目录本地PC端(一般为Windows)1. 检查自己是否已经生成公钥2. 配置VScode的SSH config远程服务器端1. 服务器新建授权文件2. 赋权限3. 重启远程服务器的ssh服务最全步骤:【设置ssh免密不起作用?彻底搞懂密钥】vscode在remote S…...
python未来应用前景怎么样
Python近段时间一直涨势迅猛,在各大编程排行榜中崭露头角,得益于它多功能性和简单易上手的特性,让它可以在很多不同的工作中发挥重大作用。 正因如此,目前几乎所有大中型互联网企业都在使用 Python 完成各种各样的工作࿰…...
webpack基本使用和开发环境配置
目录 1 webpack 基本使用 01 webpack 简介 02 webpack 初体验 2 webpack开发环境配置 03 打包样式资源 04 打包html资源 05 打包图片资源 06 打包其他资源(以打包icon为例) 07 devServer 08.开发环境配置 1 webpack 基本使用 由于笔记文档没有…...
3.2 http协议
一.HTTP协议1.概述是计算机网络的核心概念,是一种网络协议网络协议种类非常多,其中IP,TCP,UDP...其中还有一个应用非常广泛的协议.HTTPHTTP协议是日常开发中用的最多的协议HTTP处在TCP/IP五层协议栈的应用层HTTP在传输层是基于TCP的,(http/1 HTTP/2是基于TCP,最新版本的HTTP/3是…...
页面访问升级出错怎么解决
相信大家在访问网站的时候时常会遇到页面访问界面升级,暂时不可能进行访问操作,可能遇到这种情况很多小伙伴们都不知道怎么版,其实互联网网页在正常使用过程中是不会出现这种问题的。那么如果遇到页面访问界面升级怎么办?页面访问界面升级通…...
leetcode 181. 超过经理收入的员工
SQL架构 表:Employee ---------------------- | Column Name | Type | ---------------------- | id | int | | name | varchar | | salary | int | | managerId | int | ---------------------- Id是该表的主键。 该表的…...
任务类风险漏洞挖掘思路
任务类风险定义: 大部分游戏都离不开任务,游戏往往也会借助任务,来引导玩家上手,了解游戏背景,增加游戏玩法,提升游戏趣味性。任务就像线索,将游戏的各个章节,各种玩法,…...
2023年Dubbo常见面试题
2023年Dubbo常见面试题 Dubbo 中 zookeeper 做注册中心,如果注册中心集群都挂掉,发布者和订阅者之间还能通信么? 可以通信的,启动 dubbo 时,消费者会从 zk 拉取注册的生产者的地址接口等数据,缓存在本地。…...
星光2开发板使用ECR6600U无线wifi网卡的方法
visionfive2 开发板性能还是不错的,有些人买的时候会带一个无线wifi网卡,但是官方提供的操作系统没有驱动。 所以需要自己编驱动(他大爷的)。 还好有人已经踩过坑了。 星光2之USB无线网卡使用教程【新增RTL8832AU WiFi6双频无线…...
【ArcGIS Pro二次开发】(11):面要素的一键拓扑
在工作中,经常需要对要素进行拓扑检查。 在ArcGIS Pro中正常的工作流程是在数据库中【新建要素数据集——新建拓扑——将要素加入拓扑——添加规则——验证】,工作流程不算短,操作起来比较繁琐。 下面以一个例子演示如何在ArcGIS Pro SDK二次…...
【实现点击下载按钮功能 Objective-C语言】
一、实现点击下载按钮功能, 1.接下来,我们再实现另外一个功能,是什么,点击下载按钮吧: 点击下载按钮,是不是要有效果啊, 就是给大家实现这个功能, 首先,我们要实现单击这个效果,是不是要给按钮注册单击事件吧, 请问,这个按钮在哪里啊,是在控制器里面吗,不是,…...
界面控件DevExpress WinForm——轻松构建类Visual Studio UI(三)
DevExpress WinForm拥有180组件和UI库,能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForm能完美构建流畅、美观且易于使用的应用程序,无论是Office风格的界面,还是分析处理大批量的业务数据,它都能轻松胜任…...
项目实战-瑞吉外卖day01(B站)
瑞吉外卖-Day01课程内容软件开发整体介绍瑞吉外卖项目介绍开发环境搭建后台登录功能开发后台退出功能开发1. 软件开发整体介绍作为一名软件开发工程师,我们需要了解在软件开发过程中的开发流程, 以及软件开发过程中涉及到的岗位角色,角色的分工、职责&am…...
Linux 学习整理(使用 iftop 查看网络带宽使用情况 《端口显示》)
一、命令简介 iftop 是实时流量监控工具,可以用来监控网卡的实时流量(可以指定网段)、反向解析IP、显示端口信息等。 二、命令安装 yum install -y iftop 三、命令相关参数及说明 3.1、相关参数说明 -i:设定监测的网卡&#…...
Vue3创建项目(四)axios封装及接口配置
项目结构: 目录 🍉🍉🍉index.ts 🍉🍉🍉 api.ts 看完需要预计花费10分钟。 请求拦截器与响应拦截器 阅读下面代码需先了解以下内容: 请求拦截器: 请求拦截器的作用是在请求发送前进…...
【算法笔记】递归与回溯
递归与回溯 To Iterate is Human, to Recurse, Divine. —L. Peter Deutsch 人理解迭代,神理解递归。 —L. Peter Deutsch 1.什么是递归呢 递归形象描述: 你打开面前这扇门,看到屋里面还有一扇门。 你走过去,发现手中的钥匙还可以…...
蓝桥杯备赛——Echarts学习
文章目录前言学习 ECharts 的方法快速上手基础知识option 配置选项可选配置title 标题组件tooltip 提示框组件axisPointer 坐标轴指示器legend 图例组件toolbox 工具栏坐标轴xAxis和yAxisseries ([ ]用数组表示,数组里是一个个数据对象)饼状图散点图交互…...
动态规划--最长公共子串
最长公共子串公共子串问题费曼算法动态规划算法思路代码实现公共子串问题 在计算机科学中,最长公共子串问题是寻找两个或多个已知字符串最长的子串。此问题与最长公共子序列问题的区别在于子序列不必是连续的,而子串却必须是。链接: 百度百科 费曼算法…...
【运筹优化】剩余空间法求解带顺序约束的二维矩形装箱问题 + Java代码实现
文章目录一、带顺序约束的二维矩形装箱问题二、剩余空间法三、完整代码实现3.1 Instance 实例类3.2 Item 物品类3.3 PlaceItem 已放置物品类3.4 Solution 结果类3.5 RSPackingWithWeight 剩余空间算法类3.6 Run 运行类3.7 测试案例3.8 ReadDataUtil 数据读取类3.9 运行结果展示…...
解决Modelsim SE 10.6c仿真Vivado 2019乘法器IP核的“.vhd only”难题(附完整脚本)
解决Modelsim SE 10.6c仿真Vivado 2019乘法器IP核的“.vhd only”难题(附完整脚本) 在FPGA设计流程中,Xilinx Vivado与Mentor Modelsim的组合是许多工程师的首选工具链。但当Vivado 2019生成的乘法器IP核仅提供VHDL接口文件(.vhd)时ÿ…...
技术栈选择的跟风陷阱:新潮技术与稳定性的平衡
在软件测试行业,技术迭代的速度如同飞驰的列车,新的测试框架、自动化工具、性能分析平台等层出不穷。从早期的Selenium到如今的Playwright,从JUnit到TestNG,再到新兴的Cypress、Pytest等,每一种新技术的出现都伴随着行…...
PS4游戏存档管理终极指南:如何使用Apollo工具轻松备份和修改游戏进度
PS4游戏存档管理终极指南:如何使用Apollo工具轻松备份和修改游戏进度 【免费下载链接】apollo-ps4 Apollo Save Tool (PS4) 项目地址: https://gitcode.com/gh_mirrors/ap/apollo-ps4 在PlayStation 4游戏体验中,游戏存档管理一直是个让玩家头疼的…...
SpringCloud微服务里,用Zuul网关聚合Swagger文档的完整配置流程(含踩坑记录)
SpringCloud微服务架构下Zuul网关聚合Swagger文档的实战指南 在微服务架构中,API文档的管理一直是个令人头疼的问题。想象一下,当你的系统由十几个甚至几十个微服务组成时,开发人员要记住每个服务的接口地址和文档路径几乎是不可能的任务。更…...
开源数字白板the-board:基于React+Fabric.js的实时协作技术解析
1. 项目概述:一个开源的“数字白板”能做什么?最近在GitHub上看到一个挺有意思的项目,叫the-board。乍一看名字,可能觉得平平无奇,但点进去你会发现,它其实是一个功能相当完整的在线白板应用。简单来说&…...
智能体架构实战:从LangGraph状态机到多智能体协作
1. 从理论到实践:为什么我们需要一个“智能体架构大全”项目如果你在过去一年里关注过AI领域,尤其是大语言模型的应用开发,那么“智能体”这个词一定已经听得耳朵起茧了。从能帮你写代码的Devin,到能自主完成复杂任务的GPT-4o&…...
半导体IP产业变革:从EDA历史看IP组装业务的未来
1. 项目概述:从EDA的剧本看IP产业的未来 在半导体行业摸爬滚打了十几年,我见过太多关于“IP核”和“EDA工具”的讨论,但很少有人能像Arteris的CEO Charlie Janac那样,把这两者的关系与未来看得如此透彻。他有一句话让我印象极深&a…...
别再死记公式了!用Multisim仿真带你玩转反相/同相比例运算电路
用Multisim仿真解锁比例运算电路的实战奥秘 在电子工程的学习中,运算放大器电路一直是让初学者又爱又恨的内容。传统的学习方法往往从公式推导开始,要求学生死记硬背各种电路配置下的增益公式。但今天,我们要打破这种枯燥的学习方式——通过…...
紫光同创Logos系列FPGA实战:BGA封装PCB布局与Fanout布线避坑指南(附示意图)
紫光同创Logos系列FPGA实战:BGA封装PCB布局与Fanout布线避坑指南 第一次拿到紫光同创Logos系列FPGA的BGA封装芯片时,那种密密麻麻的焊盘阵列确实会让人头皮发麻。特别是FBG256和FBG484这类高密度封装,如何在有限的空间内完成高质量的Fanout布…...
从零到上手:用LDAP Browser连接和管理你的OpenLDAP服务器(Windows平台实战)
从零到上手:用LDAP Browser连接和管理你的OpenLDAP服务器(Windows平台实战) 在企业级身份认证体系中,LDAP(轻量级目录访问协议)扮演着核心角色。许多技术团队虽然已经部署了OpenLDAP服务端,却苦…...
