AIR32F103(十) 在无系统环境和FreeRTOS环境集成LVGL
目录
- AIR32F103(一) 合宙AIR32F103CBT6开发板上手报告
- AIR32F103(二) Linux环境和LibOpenCM3项目模板
- AIR32F103(三) Linux环境基于标准外设库的项目模板
- AIR32F103(四) 27倍频216MHz,CoreMark跑分测试
- AIR32F103(五) FreeRTOSv202112核心库的集成和示例代码
- AIR32F103(六) ADC,I2S,DMA和ADPCM实现的录音播放功能
- AIR32F103(七) AIR32F103CBT6/CCT6启用96K内存
- AIR32F103(八) 集成Helix MP3解码库播放MP3
- AIR32F103(九) CAN总线的通信和ID过滤机制及实例
- AIR32F103(十) 在无系统环境和FreeRTOS环境集成LVGL
LVGL简介
嵌入式常用的图形显示库
- 官网: https://lvgl.io/
- GitHub仓库: https://github.com/lvgl/lvgl
对设备的要求是 “all you need is at least 32kB RAM and 128 kB Flash, a C compiler, a frame buffer, and at least an 1/10 screen sized buffer for rendering”. 最低要求是128KB Flash, 但实际上这个大小基本上什么也做不了, 所以直接用256K Flash 的 AIR32F103CCT6 和 AIR32F103RPT6.
集成LVGL到AIR32F103
Principle 大佬写过一篇 Air32F103试玩-移植LVGL+FreeRTOS Keil5 用户可以参考. 基于STM32标准库, 用的屏幕是 GC9306X 320x240LCD.
我没有这个型号的屏幕, 手里能找到现成的串口屏只有一个128x160的ST7735, 就用这个做测试吧.
基本步骤
参考LVGL的文档, 这两片内容差不多的, 第二篇会更细节一点
- https://docs.lvgl.io/master/get-started/quick-overview.html
- https://docs.lvgl.io/master/porting/project.html
需要做的步骤为
- 将 lvgl 库目录放到项目里
- 复制一份 lvgl/lv_conf_template.h , 改名为 lv_conf.h 并修改定制
- 在项目中需要使用lvgl的地方, 包含 lvgl/lvgl.h 头文件
- 建一个定时器, 每隔1到10毫秒调用一次 lv_tick_inc(x) 用于lvgl内部定时. 如果不用这个方法, 就要定义 LV_TICK_CUSTOM 让 LVGL 可以直接读取时间.
- 调用 lv_init() 执行初始化
- 创建一个图像缓冲, 最小为1/10个屏幕尺寸所需要的数据大小.
- 实现一个绘图函数, 用于LVGL调用后往设备的指定区域写入显示内容.
- 如果有输入设备, 还可以再实现一个输入读取函数
- 在主循环 main while(1) 中, 如果是RTOS环境则在一个循环任务中, 每隔几个毫秒调用一次 lv_timer_handler(), 用于LVGL绘制更新图像显示.
最小化实现
1.将LVGL添加到项目中
从 https://github.com/lvgl/lvgl/releases 下载LVGL, 当前版本是v8.3.5, 解压.
在项目 Libraries 下创建lvgl目录, 复制必须的文件到这个目录下
demos/
examples/
src/
LICENCE.txt
lv_conf_template.h
lvgl.h
lvgl.mk
复制后的 Libraries 目录结构为
Libraries
├───AIR32F10xLib
├───CMSIS
├───Debug
├───DeviceSupport
├───EPaper
├───FreeRTOS
├───Helix
├───LDScripts
├───lvgl
│ ├───demos
│ ├───examples
│ └───src
│ ├───core
│ ├───draw
│ ├───extra
│ ├───font
│ ├───hal
│ ├───misc
│ └───widgets
在 Makefile 中添加 LVGL 选项
# Build with lvgl, y:yes, n:no
USE_LVGL ?= n
LVGL的编译列表和头文件路径都已经在 lvgl.mk 里定义好了, 这里只需要把它 include 进来, 再合并到项目的列表中.
ifeq ($(USE_LVGL),y)
LVGL_DIR ?= Libraries
LVGL_DIR_NAME ?= lvglinclude Libraries/lvgl/lvgl.mkCFILES += $(CSRCS)
INCLUDES += Libraries/lvglelseCFLAGS ?= endif
将 USE_LVGL 设为 y 之后, make 就会带上 LVGL 一起编译. 因为 LVGL 文件很多, 编译时间较长, 可以根据自己电脑的CPU个数设置并发编译, 例如对于8个逻辑核的L480, 可以执行
make -j8
因为编译结果有200多KByte, 写入的速度也很慢, 暂时没有什么好办法.
2. 定制 lv_conf.h
将 lvgl/lv_conf_template.h, 复制到 user 目录下, 改名为 lv_conf.h, 编辑
将#if 0
改为#if 1
/* clang-format off */
#if 1 /*Set it to "1" to enable content*/
因为ST7735支持的是2byte的像素, 色深设为 16
/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/
#define LV_COLOR_DEPTH 16
再往下, 都是用0和1代表对应功能项的关和开, 可以保持默认. 因为ST7735屏幕分辨率较小, 所以再修改一下字体, 将 LV_FONT_MONTSERRAT_10
改为1, 将LV_FONT_MONTSERRAT_14
改为0 启用10像素字体
#define LV_FONT_MONTSERRAT_10 0
#define LV_FONT_MONTSERRAT_12 0
#define LV_FONT_MONTSERRAT_14 1
再设置一下LV_FONT_DEFAULT
, 改为&lv_font_montserrat_10
, 替换为刚才启用的 10像素字体
/*Always set a default font*/
#define LV_FONT_DEFAULT &lv_font_montserrat_14
3. 创建 lv_tick_inc(x) 定时器
这里使用TIM3, 将定时间隔设为1毫秒, 开启 TIM_IT_Update 中断
void TIM3_Configuration(void)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);// Set counter limit to 100 -- interval will be 1msTIM_TimeBaseStructure.TIM_Period = 100 - 1;/*** Clock source of TIM2,3,4,5,6,7: if(APB1 prescaler =1) then PCLK1 x1, else PCLK1 x2* */if (clocks.HCLK_Frequency == clocks.PCLK1_Frequency){// clock source is PCLK1 x1.// Note: TIM_Prescaler is 16bit, [0, 65535], given PCLK1 is 36MHz, divider should > 550TIM_TimeBaseStructure.TIM_Prescaler = clocks.PCLK1_Frequency / 100000 - 1;}else{// clock source is PCLK1 x2TIM_TimeBaseStructure.TIM_Prescaler = clocks.PCLK1_Frequency * 2 / 100000 - 1;}TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);// Enable interrupt from 'TIM update'TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);// NVIC configNVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);TIM_Cmd(TIM3, ENABLE);
}
创建TIM3的中断回调函数, 因为定时器间隔为1毫秒, 因此使用lv_tick_inc(1)
void TIM3_IRQHandler(void)
{if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET){// Clear INT flagTIM_ClearITPendingBit(TIM3, TIM_IT_Update);// Required for the internal timing of LVGLlv_tick_inc(1);}
}
如果提示找不到 lv_tick_inc(), 需要加上对头文件 lvgl/lvgl.h 的 include
4. 创建绘图函数
这里涉及到三部分: 初始化 SPI 和对应的 GPIO, 初始化 ST7735, 最后才是 ST7735 的绘图函数.
初始化 GPIO, 这4个pin是需要声明为推挽输出的 PA2:BL, PA3:CS, PA4:DC(Data/Command), PA6:RESET
void APP_GPIO_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_6;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_SetBits(GPIOA, GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_6);
}
初始化 SPI, 这里还需要设置 PA5:SCK/SCL 和 PA7:SI/SDA
void APP_SPI_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;SPI_InitTypeDef SPI_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_SetBits(GPIOA,GPIO_Pin_5 | GPIO_Pin_7);SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;SPI_InitStructure.SPI_Mode = SPI_Mode_Master;SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 0;SPI_Init(SPI1, &SPI_InitStructure);SPI_Cmd(SPI1, ENABLE);
}
初始化 ST7735, 这部分已经在 st7735.c 中封装, 直接在main()中调用即可
ST7735_Init();
创建 ST7735 的区域绘图函数
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{ST7735_WriteAddrWindow(area->x1, area->y1, area->x2, area->y2, (uint16_t *)color_p);// Indicate you are ready with the flushinglv_disp_flush_ready(disp);
}
对应的 ST7735_WriteAddrWindow() 函数实现, 因为来源是16bit, SPI接口是8bit, 每一次调用分别写入两次
void ST7735_WriteAddrWindow(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t *data)
{uint32_t tmp, i;if (x1 > x2){tmp = x1; x1 = x2; x2 = tmp;}if (y1 > y2){tmp = y1; y1 = y2; y2 = tmp;}tmp = (x2 - x1 + 1) * (y2 - y1 + 1);ST7735_CS_LOW;ST7735_SetAddrWindow(x1, y1, x2, y2);while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);for(i = 0; i < tmp; i ++) {SPI_I2S_SendData(SPI1, (uint8_t)(*data >> 8));while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);SPI_I2S_SendData(SPI1, (uint8_t)(*data & 0xFF));while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);data++;}ST7735_CS_HIGH;
}
5. 创建图像缓冲, 初始化LVGL
最小为1/10个屏幕尺寸所需数据大小
static lv_disp_draw_buf_t draw_buf;
// Declare a buffer for 1/10 screen size
static lv_color_t buf1[ST7735_WIDTH * ST7735_HEIGHT / 10];
// Descriptor of a display driver
static lv_disp_drv_t disp_drv;
在 main() 中进行初始化, 注意这部分官网给代码里的类型不太对, 这部分的代码已经修改
lv_init();
// Initialize the display buffer.
lv_disp_draw_buf_init(&draw_buf, buf1, NULL, ST7735_WIDTH * ST7735_HEIGHT / 10);lv_disp_drv_init(&disp_drv); /*Basic initialization*/
disp_drv.flush_cb = my_disp_flush; /*Set your driver function*/
disp_drv.draw_buf = &draw_buf; /*Assign the buffer to the display*/
disp_drv.hor_res = ST7735_WIDTH; /*Set the horizontal resolution of the display*/
disp_drv.ver_res = ST7735_HEIGHT; /*Set the vertical resolution of the display*/
lv_disp_drv_register(&disp_drv); /*Finally register the driver*/
6. 主循环添加 lv_timer_handler()
因为这个 ST7735 没有触屏功能, 所以输入读取函数就省了. 在 main() while(1)主循环中加上 lv_timer_handler()
while (1){lv_timer_handler();Delay_Ms(10);}
6. 执行示例
经过以上的设置, LVGL就已经集成到项目中了, 可以运行LVGL自带的一些例子查看控件的显示效果
文字标签, 居中和滚动的效果
lv_example_label_1();
按钮效果
lv_example_btn_1();
源代码
以上LVGL整合示例的完整源代码已经提交到 GitHub: https://github.com/IOsetting/air32f103-template/tree/master/Examples/NonFreeRTOS/SPI/ST7735_LVGL
修改为 DMA 输出
上面的例子是使用 SPI_I2S_SendData()
函数传输图像数据的, 可以修改为 DMA 传输, 因为传输方式的变化, 外设初始化和图像更新要做对应的调整, 这里没有使用中断.
1. 外设调整
GPIO 不变, 启用 SPI 的 DMA
在 APP_SPI_Config()
中启用SPI1 DMA
/* Enable SPI1 DMA TX request */SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
开启 DMA 时钟
void APP_DMA_Configuration(void)
{RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
}
因为DMA每次传输的数量在变化, 所以DMA的初始化在图像输出的方法里
2. 修改图像更新方法
图像更新方法的变化比较大, 这里需要根据输入的坐标, 计算实际的数据长度, 并对DMA进行初始化, 然后启动传输, 等待完成后关闭DMA
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{uint16_t len;DMA_InitTypeDef initStructure;len = (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1) * 2;ST7735_CS_LOW;ST7735_SetAddrWindow(area->x1, area->y1, area->x2, area->y2);/* DMA1 Channel3 (triggered by SPI1 Tx event) Config */DMA_DeInit(DMA1_Channel3);initStructure.DMA_BufferSize = len;initStructure.DMA_M2M = DMA_M2M_Disable;initStructure.DMA_DIR = DMA_DIR_PeripheralDST;initStructure.DMA_MemoryBaseAddr = (uint32_t)color_p;initStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;initStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;initStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;initStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;initStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;initStructure.DMA_Priority = DMA_Priority_High;initStructure.DMA_Mode = DMA_Mode_Normal;DMA_Init(DMA1_Channel3, &initStructure);// Start transferDMA_Cmd(DMA1_Channel3, ENABLE);while (!DMA_GetFlagStatus(DMA1_FLAG_TC3));DMA_ClearFlag(DMA1_FLAG_TC3);DMA_Cmd(DMA1_Channel3, DISABLE);ST7735_CS_HIGH;// Indicate you are ready with the flushinglv_disp_flush_ready(disp);
}
3. 修改色彩字节顺序
上面修改完成后, 再次运行LVGL示例, 会发现颜色不正确, 这是因为在DMA传输中, 将一个 16bit 强转为两个 8bit 了, ST7735收到的两个字节的顺序有变化, 需要编辑 lv_conf.h, 将LV_COLOR_16_SWAP
设为1
/*Swap the 2 bytes of RGB565 color. Useful if the display has an 8-bit interface (e.g. SPI)*/
#define LV_COLOR_16_SWAP 1
源代码
以上LVGL DMA 示例的完整源代码已经提交到 GitHub: https://github.com/IOsetting/air32f103-template/tree/master/Examples/NonFreeRTOS/SPI/ST7735_LVGL_DMA
集成到 FreeRTOS
进一步, 在 FreeRTOS 中运行 DMA 传输的 LVGL. 在 FreeRTOS 中 LVGL 的初始化是一样的, 有变化的是初始化的时间点, 还有延时函数的修改
1. 将初始化从 main() 移入任务handler
新建lvglTaskHandler()
用于处理LVGL初始化, 缓存初始化和执行benchmark, 并用固定间隔调用lv_timer_handler()
static void lvglTaskHandler(void *pvParameters)
{TickType_t xLastWakeTime = xTaskGetTickCount();const TickType_t xPeriod = pdMS_TO_TICKS(10);(void)(pvParameters); // Suppress "unused parameter" warningST7735_Init();lv_init();// Initialize the display buffer.lv_disp_draw_buf_init(&draw_buf, buf1, NULL, ST7735_WIDTH * ST7735_HEIGHT / 10);lv_disp_drv_init(&disp_drv); /*Basic initialization*/disp_drv.flush_cb = my_disp_flush; /*Set your driver function*/disp_drv.draw_buf = &draw_buf; /*Assign the buffer to the display*/disp_drv.hor_res = ST7735_WIDTH; /*Set the horizontal resolution of the display*/disp_drv.ver_res = ST7735_HEIGHT; /*Set the vertical resolution of the display*/lv_disp_drv_register(&disp_drv); /*Finally register the driver*/lv_demo_benchmark();while (1){lv_timer_handler();vTaskDelayUntil(&xLastWakeTime, xPeriod);}
}
在 main() 中创建任务, 栈深度1024, 需要 4KByte 内存
xTaskCreate(lvglTaskHandler, // Task function point"LVGL Task", // Task name1024, // Stack size, each take 4 bytes(32bit)NULL, // ParametersLVGL_TASK_PRORITY, // PriorityNULL); // Task handler
2. 修改延时函数
更新图像的方法不变, 但是需要修改 ST7735 的延时函数, 修改 st7735.c, 引入FreeRTOS.h
, 将Delay_Ms(ms);
替换为 vTaskDelay(ms);
3. 中断设置
在 FreeRTOSConfig.h 中, 设置系统最高的, 可以安全使用FreeRTOS方法的中断优先级为1
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 0x01
因为 AIR32F103 的中断为 3 bit, 可用的优先级为 0 到 7, 这样对于优先级为 0 的中断是不受FreeRTOS控制的, 小于等于 1 的是受FreeRTOS控制的, 可以在中断处理中调用 FreeRTOS 的方法.
将TIM3的中断优先级设置为2
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
4. 裁剪 LVGL
因为集成FreeRTOS, 加上运行 Benchmark, 256KB 的 Flash 容量就捉襟见肘了, 默认配置下编译出来会有300多KB, 需要进行压缩
首先确认编译参数已经优化, rules.mk 中, 优化项改为-O3
或-Os
# c flags
OPT ?= -O3
编辑 lv_conf.h 关闭一切不必要的组件, 使用尽可能小的字体(可以用10像素字体), 具体的改动可以参考示例代码.
源代码
以上LVGL+FreeRTO 示例的源代码已经提交到 GitHub: https://github.com/IOsetting/air32f103-template/tree/master/Examples/FreeRTOS/LVGL/ST7735_128x160
最后
以上就是在 AIR32F103 上集成 LVGL 的步骤和说明, ST7735 也是常见模块. 对于 DMA 的例子, 可以进一步修改为使用中断判断 DMA 传输结束. 留有空再改了.
相关文章:
AIR32F103(十) 在无系统环境和FreeRTOS环境集成LVGL
目录 AIR32F103(一) 合宙AIR32F103CBT6开发板上手报告AIR32F103(二) Linux环境和LibOpenCM3项目模板AIR32F103(三) Linux环境基于标准外设库的项目模板AIR32F103(四) 27倍频216MHz,CoreMark跑分测试AIR32F103(五) FreeRTOSv202112核心库的集成和示例代码AIR32F103(六) ADC,I2S…...
SpringBoot接口 - 如何统一异常处理
SpringBoot接口如何对异常进行统一封装,并统一返回呢?以上文的参数校验为例,如何优雅的将参数校验的错误信息统一处理并封装返回呢?为什么要优雅的处理异常如果我们不统一的处理异常,经常会在controller层有大量的异常…...
如何使用Python进行数据可视化
数据可视化是一种将数据呈现为图形或图表的技术,它有助于理解和发现数据中的模式和趋势。Python是一种流行的编程语言,有很多库可以帮助我们进行数据可视化。在本文中,我们将介绍使用Python进行数据可视化的基本步骤。 第一步:导…...
vue -- 自定义指令钩子函数补充 自定义过滤器filter参数
自定义指令补充 自定义指令通过钩子函数的形式来实现自定义的功能 这里是几个常用的钩子函数以及它的方法: bind:只调用一次,指令第一次绑定到元素时调用,在这里可以进行一次性的初始化设置。 inserted:被绑定元素插…...
Qt不会操作?Qt原理不知道? | Qt详细讲解
文章目录Qt界面开发必备知识UI界面与控件类型介绍Qt设计器原理控件类型的介绍信号与槽机制处理常用控件创建与设置常见展示型控件创建与设置常见动作型控件创建与设置常见输入型控件创建与设置常见列表控件创建于设置Qt中对象树的介绍项目源码结构刨析.pro.hmain.cpp.cppQt界面…...
LeetCode-面试题 17.05. 字母与数字【前缀和,哈希表】
LeetCode-面试题 17.05. 字母与数字【前缀和,哈希表】题目描述:解题思路一:前缀和。数字为-1,字母为1。我们需要找到的子数组是前缀和之差为0的,例如s[right]-s[left]0,那么s[right]s[left],变为…...
华为OD机试题 - 叠放书籍(JavaScript)| 机考必刷
更多题库,搜索引擎搜 梦想橡皮擦华为OD 👑👑👑 更多华为OD题库,搜 梦想橡皮擦 华为OD 👑👑👑 更多华为机考题库,搜 梦想橡皮擦华为OD 👑👑👑 华为OD机试题 最近更新的博客使用说明本篇题解:叠放书籍题目输入输出示例一输入输出Code解题思路版权说明华为O…...
【数据库概论】第十一章 数据库并发控制
第十一章 并发控制 在多处理机系统中,每个处理机可以运行一个事务,多个处理机可以同时运行多个事务,实现多个事务并行运行,这就是同时并发方式。当多个用户并发存取数据库时会产生多个事务同时存取同一事务的情况,如果…...
Nginx配置实例-反向代理案例二
实现效果:使用nginx反向代理,根据访问的路径跳转到不同端口服务 nginx监听端口为9000, 访问 http://127.0.0.1:9000/edu/ 直接跳转到127.0.0.1:8080 访问 http://127.0.0.1:9000/vod/ 直接跳转到127.0.0.1:8081 一、准备工作 1. 准备两个tom…...
HTML 字符集
为了正确显示 HTML 页面,Web 浏览器必须知道要使用哪个字符集。 从 ASCII 到 UTF-8 ASCII 是第一个字符编码标准。ASCII 定义了 128 种可以在互联网上使用的字符:数字(0-9)、英文字母(A-Z)和一些特殊字符…...
【C语言】每日刷题 —— 牛客语法篇(3)
前言 大家好,继续更新专栏c_牛客,不出意外的话每天更新十道题,难度也是从易到难,自己复习的同时也希望能帮助到大家,题目答案会根据我所学到的知识提供最优解。 🏡个人主页:悲伤的猪大肠9的博客…...
基于Vue3和element-plus实现一个完整的登录功能
先看一下最终要实现的效果:登录页面:注册页面:(1)引入element-plus组件库引入组件库的方式有好多种,在这里我就在main.js全局引入了.npm i element-plus -Smain.js中代码:import { createApp } from "vue"; //element-plus import ElementPlus from "element-pl…...
【java】Java 中泛型的实现原理
文章目录前序1. 泛型1.1 泛型方法1.2 泛型类1.3 泛型接口2. 泛型的基本原理3. 小结前序 泛型是 Java 开发中常用的技术,了解泛型的几种形式和实现泛型的基本原理,有助于写出更优质的代码。本文总结了 Java 泛型的三种形式以及泛型实现原理。 1. 泛型 …...
【C++提高编程】C++全栈体系(二十七)
C提高编程 第五章 STL- 常用算法 三、常用排序算法 算法简介: sort //对容器内元素进行排序random_shuffle //洗牌 指定范围内的元素随机调整次序merge // 容器元素合并,并存储到另一容器中reverse // 反转指定范围的元素 1. sort 功能描述&#…...
软考高级信息系统项目管理师系列之三十九:项目集管理
软考高级信息系统项目管理师系列之三十九:项目集管理 一、项目集管理内容二、项目集管理基础概述1.项目集定义2.项目集活动3.项目集管理三、项目集的管理过程四、项目集治理1.项目集治理概述2.项目集指导委员会的职责3.项目集治理功能五、项目集生命周期1.项目集生命周期三个阶…...
44-Golang中的channel
Golang中的channel为什么要使用channelchannel的介绍channel的基本使用定义/声明channel管道的遍历和关闭channel的关闭channel的遍历goroutine和channel结合应用实例1应用实例2案例注意事项为什么要使用channel 前面使用全局变量加锁同步来解决goroutine的通讯,但…...
80/20法则
80/20法则(The 80/20 Rule)又称为帕累托法则(Pareto Principle)、二八定律、帕累托定律、最省力法则、不平衡原则、犹太法则、马特莱法则等一、什么是80/20法则80/20法则(The 80/20 Rule),又称为帕累托法则…...
计算机网络高频面试题(四)
一、什么是计算机网络 是一个将分散的、具有独立功能的计算机系统,通过通信设备与线路连接起来,由功能完善的软件实现资源共享和信息传递的系统 按分布范围,计算机网络里有局域网LAN和广域网WAN, 其中局域网的代表以太网,以及这…...
[计算机组成原理(唐朔飞 第2版)]第三章 系统总线(学习复习笔记)
3.1 总线的基本概念 计算机系统的五大部件之间的互连方式有两种 各部件之间使用单独的连线,称为分散连接将各部件连到一组公共信息传输线上,称为总线连接 总线是连接多个部件的信息传输线,是各部件共享的传输介质。 当多个部件与总线相连时&…...
华为OD机试题 - 计算堆栈中的剩余数字(JavaScript)| 机考必刷
更多题库,搜索引擎搜 梦想橡皮擦华为OD 👑👑👑 更多华为OD题库,搜 梦想橡皮擦 华为OD 👑👑👑 更多华为机考题库,搜 梦想橡皮擦华为OD 👑👑👑 华为OD机试题 最近更新的博客使用说明本篇题解:计算堆栈中的剩余数字题目输入输出描述示例一输入输出说明示例二…...
VB实现点爆炸效果
需在窗体放置以下 4 个控件,所有控件不用设置任何属性,均采用默认设置: ’ Picture1,Command1,Check1,Timer1 Option Explicit Dim I Dim ctD() As tyD, ctDs As Long, ctR As Single Private Type tyD x…...
ICG-alkyne,吲哚菁绿-炔基结构式,实验室科研试剂,CAS号:1622335-41-4
ICG-alkyne,吲哚菁绿-炔基 中文名称:吲哚菁绿-炔基 CAS号:1622335-41-4 英文名称:ICG-alkyne 英文别名:ICG-alk 性状:绿色粉末 化学式:C48H53N3O4S 分子量:768.03 溶剂:溶于…...
【并发编程】volatile的原理我好像又懂了
文章目录优秀引用1、概述2、可见性保证2.1、什么是可见性2.2、例子举证2.3、结果解析3、有序性保证3.1、什么是有序性3.2、什么是重排序3.3、例子举证4、无法保证原子性4.1、什么是原子性4.2、例子举证5、内存屏障5.1、什么是内存屏障5.2、不同内存屏障的作用6、volatile和sync…...
【已更新实例】Java网络爬虫-HttpClient工具类
关于用Java进行爬虫的资料网上实在少之又少,但作为以一名对Java刚刚初窥门径建立好兴趣的学生怎么能静得下心用新学的Python去写,毕竟Java是世界上最好的语言嘛 (狗头)关于Java爬虫最受欢迎的一个框架Jsoup常常搭配HttpClient来使用,因为Jsou…...
7.2 向量的坐标
🙌作者简介:数学与计算机科学学院出身、在职高校高等数学专任教师,分享学习经验、生活、 努力成为像代码一样有逻辑的人! 🌙个人主页:阿芒的主页 ⭐ 高等数学专栏介绍:本专栏系统地梳理高等数学…...
公式编写1000问21-22
21.问: 求助——(周,日,60分钟,30分钟)MACD同时向上的公式怎么表达 答(知无不言): z:“macd.dea#week”; r:“macd.dea#day”; f:“macd.dea#min60”; f1:“macd.dea#min30”; rz:“macd.dea##week”; rr:“macd.dea##day”; rf:“…...
1041 考试座位号
每个 PAT 考生在参加考试时都会被分配两个座位号,一个是试机座位,一个是考试座位。正常情况下,考生在入场时先得到试机座位号码,入座进入试机状态后,系统会显示该考生的考试座位号码,考试时考生需要换到考试…...
2023年3月北京/广州/杭州/深圳数据治理工程师认证DAMA-CDGA/CDGP
DAMA认证为数据管理专业人士提供职业目标晋升规划,彰显了职业发展里程碑及发展阶梯定义,帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力,促进开展工作实践应用及实际问题解决,形成企业所需的新数字经济下的核心职业…...
【AICG】2、扩散模型 | 到底什么是扩散模型?
文章目录一、什么是扩散模型二、扩散模型相关定义2.1 符号和定义2.2 问题规范化三、可以提升的点参考论文:A Survey on Generative Diffusion Model github:https://github.com/chq1155/A-Survey-on-Generative-Diffusion-Model 一、什么是扩散模型 已…...
高等数学——多元函数微分学
文章目录多元函数微分学多元函数的极限多元函数的连续性偏导数定义高阶偏导数全微分定义全微分存在的必要条件全微分存在的充分条件多元函数的微分法复合函数微分法隐函数微分法多元函数的极值与最值无约束极值条件极值及拉格朗日乘数法最大值最小值二重积分概念性质计算利用直…...
为什么都用java做网站/百度一下百度
问题场景: 测试中需要造几百个账号,写了个脚本可以自动生成账号,但想把生成的账号写入一个文件, 开始用的如下的write()方法,发下会先把原文件的内容清空再写入新的东西,文件里面每次都是最新生成的一个账号…...
wordpress设置主导航无法点击/长沙百度网站推广优化
10天没写代码了啊。,一个这样的搜索写了两小时。。我擦。。 搜索部分没什么好说的。。主要就是visited标记位。。申明类型为int。以后每次visited就1,回溯就-1。。这样就可以避免交叉的问题出现(感谢春哥的方法。) #include<io…...
购物网站怎么做推广/市场推广策略 包括哪些
lambda使用案例: 需求1:对List集合中的User按照age的大小进行排序输出: 1.普通的写法: private static List<User> listnew ArrayList<User>();public static void main(String[] args) {list.add(new User(34));li…...
python h5网站开发/企业营销策划有限公司
以下代码是在学习过程中,网上查到的。如果有版权问题,请联系删帖!!! 在网上找到了两种方法 一种是直接使用 .Net的类,测试后发现比如输入数字 8, 会自动变成 0.0.0.8 而这种格式并非我们所要的。…...
深圳专业做网站哪家专业/职业技能培训中心
部署的Web应用突然无法登录系统,后台尝试重新启动看能不能恢复,发现启动时在数据库连接池部分报错,怀疑无法连接数据库。使用的是oracle数据库,通过plsql发现也无法连接,从报错可以看出应该是用户密码过期了࿰…...
网上设计接单的网站/网站推广软文范例
最近看到蛮多网友反映,自己修改Dos下用户名后出现了很多的问题--今天抽了时间,再次修改测试、、、 提前说明:我自己修改了很多次没发现任何问题,<为避免修改可能会出问题:请修改前先把桌面上的文件备份到除C盘以外…...