02.FreeRTOS的移植
文章目录
- FreeRTOS移植到STM32F103ZET6上的详细步骤
- 1. 移植前的准备工作
- 2. 添加FreeRTOS文件
- 3. 修改SYSTEM文件
- 4. 修改中断相关文件
- 5. 修改FreeRTOSConfig.h文件
- 6. 可选步骤
FreeRTOS移植到STM32F103ZET6上的详细步骤
1. 移植前的准备工作
-
**基础工程:**内存管理部分的例程源码和基本定时器的例程源码
使用实验8 基本定时器和实验36 内存管理两个实验,内存管理实验做为移植的目标文件,为了获得定时器的功能,需要把基本定时器实验部分的
TIMER
文件夹拷贝到内存管理实验的BSP
文件夹里面。 -
FreeRTOS源码:
本例程使用的是FreeRTOS内核源码的版本V10.4.6,即FreeRTOS v2021.00。获取路径:软件资料→FreeRTOS学习资料→FreeRTOSv2202112.00.zip。
2. 添加FreeRTOS文件
-
添加FreeRTOS源码,在基础工程的Middlewares文件夹中新建一个FreeRTOS子文件夹:
将FreeRTOS内核源码的 Source 文件夹下的所有文件添加到工程的 FreeRTOS 文件夹中:
-
将文件添加到工程
打开基础工程,新建两个文件分组,分别为
Middlewares/FreeRTOS_CORE
和Middlewares/FreeRTOS_PORT
Middlewares/FreeRTOS_CORE
:存放FreeRTOS内核C源码文件Middlewares/FreeRTOS_PORT
:存放FreeRTOS内核的移植文件,分别添加heap_x.c
和port.c
然后把相关文件拷贝到这两个路径下:
-
添加头文件路径
一个是FreeRTOS/include,另一个是port.c的路径
-
添加FreeRTOSConfig.h文件
因为需要对配置文件进行裁剪并且要结合STM32单片机,我们直接从移植好的例程里面拷贝即可
-
3. 修改SYSTEM文件
-
sys.h
文件sys.h文件的修改很简单,在sys.h文件中使用了宏SYS SUPPORT_OS来定义是否支持OS,因为要支持FreeRTOS,因此应当将宏SYS SUPPORT_OS定义为1,具体修改如下所示:
修改前:
/*** SYS_SUPPORT_OS用于定义系统文件夹是否支持OS* 0,不支持OS* 1,支持OS*/ #define SYS_SUPPORT_OS 0
修改后:
/*** SYS_SUPPORT_OS用于定义系统文件夹是否支持OS* 0,不支持OS* 1,支持OS*/ #define SYS_SUPPORT_OS 1
-
usart.c
文件usart.c文件的修改也很简单,一共有两个地方需要修改,首先就是串口的中断服务函数,原本在使用uCOS的时候,进入和退出中断需要添加OSIntEnter()和OSIntExit()两个函数,这是uCOS对于中断的相关处理机制,而FreeRTOS中并没有这种机制,因此将这两行代码删除,修改后串口的中断服务函数如下所示:
修改前:
void USART_UX_IRQHandler(void) { #if SYS_SUPPORT_OS /* 使用OS */OSIntEnter(); #endifHAL_UART_IRQHandler(&g_uart1_handle); /* 调用HAL库中断处理公用函数 */#if SYS_SUPPORT_OS /* 使用OS */OSIntExit(); #endif}
修改后:
void USART_UX_IRQHandler(void) {HAL_UART_IRQHandler(&g_uart1_handle); /* 调用HAL库中断处理公用函数 */while (HAL_UART_Receive_IT( &g_uart1_handle,(uint8_t *)g_rx_buffer,RXBUFFERSIZE) != HAL_OK)/* 重新开启中断并接收数据 */{/* 如果出错会卡死在这里 */}}
接下来usart.c要修改的第二个地方就是导入的头文件,因为在串口的中断服务函数当中已经删除了uCOS的相关代码,并且也没有使用到FreeRTOS的相关代码,因此将usart.c中包含的关于OS的头文件删除,要删除的代码如下所示:
/* 如果使用 os,则包括下面的头文件即可. */ #if SYS_SUPPORT_OS #include "includes.h" /* os 使用 */ #endif
-
delay.c
文件(1)删除适用于 µC/OS 但不适用于 FreeRTOS 的相关代码:
/* 定义 g_fac_ms 变量, 表示 ms 延时的倍乘数, * 代表每个节拍的 ms 数, (仅在使能 os 的时候,需要用到) */ static uint16_t g_fac_ms = 0; /* * 当 delay_us/delay_ms 需要支持 OS 的时候需要三个与 OS 相关的宏定义和函数来支持 * 首先是 3 个宏定义: * delay_osrunning :用于表示 OS 当前是否正在运行,以决定是否可以使用相关函数 * delay_ostickspersec :用于表示 OS 设定的时钟节拍, * delay_init 将根据这个参数来初始化 systick * delay_osintnesting :用于表示 OS 中断嵌套级别,因为中断里面不可以调度, * delay_ms 使用该参数来决定如何运行 * 然后是 3 个函数: * delay_osschedlock :用于锁定 OS 任务调度,禁止调度 * delay_osschedunlock :用于解锁 OS 任务调度,重新开启调度 * delay_ostimedly :用于 OS 延时,可以引起任务调度. * * 本例程仅作 UCOSII 和 UCOSIII 的支持,其他 OS,请自行参考着移植 */ /* 支持 UCOSII */ #ifdef OS_CRITICAL_METHOD /* OS_CRITICAL_METHOD 定义了* 说明要支持 UCOSII*/ #define delay_osrunning OSRunning /* OS 是否运行标记,0,不运行;1,在运行 */ #define delay_ostickspersec OS_TICKS_PER_SEC /* OS 时钟节拍,即每秒调度次数 */ #define delay_osintnesting OSIntNesting /* 中断嵌套级别,即中断嵌套次数 */ #endif /* 支持 UCOSIII */ #ifdef CPU_CFG_CRITICAL_METHOD /* CPU_CFG_CRITICAL_METHOD 定义了* 说明要支持 UCOSIII*/ #define delay_osrunning OSRunning /* OS 是否运行标记,0,不运行;1,在运行 */ #define delay_ostickspersec OSCfg_TickRate_Hz /* OS 时钟节拍,即每秒调度次数 */ #define delay_osintnesting OSIntNestingCtr /* 中断嵌套级别,即中断嵌套次数 */ #endif /** * @brief us 级延时时,关闭任务调度(防止打断 us 级延迟) * @param 无 * @retval 无 */ static void delay_osschedlock(void) { #ifdef CPU_CFG_CRITICAL_METHOD /* 使用 UCOSIII */OS_ERR err;OSSchedLock(&err); /* UCOSIII 的方式,禁止调度,防止打断 us 延时 */ #else /* 否则 UCOSII */OSSchedLock(); /* UCOSII 的方式,禁止调度,防止打断 us 延时 */ #endif } /** * @brief us 级延时时,恢复任务调度 * @param 无 * @retval 无 */ static void delay_osschedunlock(void) { #ifdef CPU_CFG_CRITICAL_METHOD /* 使用 UCOSIII */OS_ERR err;OSSchedUnlock(&err); /* UCOSIII 的方式,恢复调度 */ #else /* 否则 UCOSII */OSSchedUnlock(); /* UCOSII 的方式,恢复调度 */ #endif } /** * @brief us 级延时时,恢复任务调度 * @param ticks: 延时的节拍数 * @retval 无 */ static void delay_ostimedly(uint32_t ticks) { #ifdef CPU_CFG_CRITICAL_METHODOS_ERR err;OSTimeDly(ticks, OS_OPT_TIME_PERIODIC, &err); /* UCOSIII 延时采用周期模式 */ #elseOSTimeDly(ticks); /* UCOSII 延时 */ #endif }
(2)添加 FreeRTOS 的相关代码:
只需要在delay.c文件中使用 extern关键字导入一个FreeRTOS函数一 xPortSysTickHandler()即可,这个函数是用于处理FreeRTOS系统时钟节拍的,本教程是使用 SysTick作为FreeRTOS操作系统的心跳,因此需要在SysTick的中断服务函数中调用这个函数,因此将代码添加到SysTick中断服务函数之前,代码修改如下:
extern void xPortSysTickHandler(void);
(3)修改部分内容
最后要修改的内容包括两个,分别是包含头文件和 4 个函数。
包含头文件:
//修改前: #include "includes.h" //修改后: #include "FreeRTOS.h" #include "task.h"
4个函数:
(1) SysTick_Handler()
修改前:
void SysTick_Handler(void) {/* OS 开始跑了,才执行正常的调度处理 */if (delay_osrunning == OS_TRUE){/* 调用 uC/OS-II 的 SysTick 中断服务函数 */OS_CPU_SysTickHandler();}HAL_IncTick(); }
修改后:
void SysTick_Handler(void) {HAL_IncTick();if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED){xPortSysTickHandler();} }
(2) delay_init()
修改前:
void delay_init(uint16_t sysclk) { #if SYS_SUPPORT_OS /* 如果需要支持OS */uint32_t reload; #endifg_fac_us = sysclk; /* 由于在HAL_Init中已对systick做了配置,所以这里无需重新配置 */ #if SYS_SUPPORT_OS /* 如果需要支持OS. */reload = sysclk; /* 每秒钟的计数次数 单位为M */reload *= 1000000 / delay_ostickspersec; /* 根据delay_ostickspersec设定溢出时间,reload为24位* 寄存器,最大值:16777216,在168M下,约合0.09986s左右*/g_fac_ms = 1000 / delay_ostickspersec; /* 代表OS可以延时的最少单位 */SysTick->CTRL |= 1 << 1; /* 开启SYSTICK中断 */SysTick->LOAD = reload; /* 每1/delay_ostickspersec秒中断一次 */SysTick->CTRL |= 1 << 0; /* 开启SYSTICK */ #endif }
修改后:
void delay_init(uint16_t sysclk) { #if SYS_SUPPORT_OS /* 如果需要支持OS */uint32_t reload; #endifSysTick->CTRL = 0;HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8);g_fac_us = sysclk / 8; /* 由于在HAL_Init中已对systick做了配置,所以这里无需重新配置 */#if SYS_SUPPORT_OS /* 如果需要支持OS. */reload = sysclk / 8; /* 每秒钟的计数次数 单位为M */reload *= 1000000 / configTICK_RATE_HZ; /* 根据delay_ostickspersec设定溢出时间,reload为24位* 寄存器,最大值:16777216,在168M下,约合0.09986s左右*/ /* 代表OS可以延时的最少单位 */SysTick->CTRL |= 1 << 1; /* 开启SYSTICK中断 */SysTick->LOAD = reload; /* 每1/delay_ostickspersec秒中断一次 */SysTick->CTRL |= 1 << 0; /* 开启SYSTICK */ #endif }
(3) delay_us()
修改前:
void delay_us(uint32_t nus) {uint32_t ticks;uint32_t told, tnow, tcnt = 0;uint32_t reload = SysTick->LOAD; /* LOAD的值 */ticks = nus * g_fac_us; /* 需要的节拍数 */#if SYS_SUPPORT_OS /* 如果需要支持OS */delay_osschedlock(); /* 锁定 OS 的任务调度器 */ #endiftold = SysTick->VAL; /* 刚进入时的计数器值 */while (1){tnow = SysTick->VAL;if (tnow != told){if (tnow < told){tcnt += told - tnow; /* 这里注意一下SYSTICK是一个递减的计数器就可以了 */}else{tcnt += reload - tnow + told;}told = tnow;if (tcnt >= ticks) {break; /* 时间超过/等于要延迟的时间,则退出 */}}}#if SYS_SUPPORT_OS /* 如果需要支持OS */delay_osschedunlock(); /* 恢复 OS 的任务调度器 */ #endif }
修改后:
void delay_us(uint32_t nus) {uint32_t ticks;uint32_t told, tnow, tcnt = 0;uint32_t reload = SysTick->LOAD; /* LOAD的值 */ticks = nus * g_fac_us; /* 需要的节拍数 */told = SysTick->VAL; /* 刚进入时的计数器值 */while (1){tnow = SysTick->VAL;if (tnow != told){if (tnow < told){tcnt += told - tnow; /* 这里注意一下SYSTICK是一个递减的计数器就可以了 */}else{tcnt += reload - tnow + told;}told = tnow;if (tcnt >= ticks) {break; /* 时间超过/等于要延迟的时间,则退出 */}}} }
(4) delay_ms()
修改前:
void delay_ms(uint16_t nms) {#if SYS_SUPPORT_OS /* 如果需要支持OS, 则根据情况调用os延时以释放CPU */if (delay_osrunning && delay_osintnesting == 0) /* 如果OS已经在跑了,并且不是在中断里面(中断里面不能任务调度) */{if (nms >= g_fac_ms) /* 延时的时间大于OS的最少时间周期 */{delay_ostimedly(nms / g_fac_ms); /* OS延时 */}nms %= g_fac_ms; /* OS已经无法提供这么小的延时了,采用普通方式延时 */} #endifdelay_us((uint32_t)(nms * 1000)); /* 普通方式延时 */ }
修改后:
void delay_ms(uint16_t nms) {uint32_t i;for(i=0; i<nms; i++){delay_us(1000);} }
4. 修改中断相关文件
FreeRTOS系统时基定时器的中断(SysTick中断)、SVC中断、PendSV中断。
SysTick的中断服务函数在delay.c文件中已经定义了,并且FreeRTOS也提供了SVC和PendSV的中断服务函数,因此需要将HAL库提供的这三个中断服务函数注释掉,这里采用宏开关的方式让HAL库中的这三个中断服务函数不加入编译,使用的宏在sys.h中定义,因此还需要导入Sysh头文件,请读者按照表2.1.4.1找到对应的文件进行修改,修改后的代码如下所示:
/* 导入 sys.h 头文件 */
#include "./SYSTEM/SYS/sys.h"/* 加入宏开关 */
#if (!SYS_SUPPORT_OS)
void SVC_Handler(void)
{
}
#endif#if (!SYS_SUPPORT_OS)
void PendSV_Handler(void)
{
}
#endif#if (!SYS_SUPPORT_OS)
void SysTick_Handler(void)
{HAL_IncTick();
}
#endif
5. 修改FreeRTOSConfig.h文件
在FreeRTOSConfig.h
中
#define configPRIO_BITS __NVIC_PRIO_BITS
在stm32f103xe.h
文件中修改:
#define __NVIC_PRIO_BITS 4U
为:
#define __NVIC_PRIO_BITS 4
6. 可选步骤
-
修改工程目标名称:
本教程是以标准例程-HAL库版本的内存管理实验工程为基础工程,内存管理实验工程的工程日标名为“MALLOC”,为了规范工程,笔者建议将工程目标名修改为“FreeRTOS”或根据读者的实际场景进行修改,修改如下图所示:
-
移出USMART调试组件:
由于本教程并未使用到USMART调试组件,因此建议将USMART调试组件从工程中移除,如果读者需要使用USMART调试组件的话,也可选择保留,移除USAMRT调试组建后工程文件分组如下图所示(这里以正点原子的STM32F1系列开发板为例,其他开发板类似),修改后文件组为:
-
添加定时器驱动:
由于在后续的实验中需要使用到$TM32的基本定时器外设,因此需要向工程中添加定时器的相关驱动文件,读者也可在后续实验需要用到定时器的时候再进行添加。将定时器的相关驱动文件添加到工程的Drivers/BSP文件分组中,如下图所示(这里以正点原子的STM32F1系列开发板为例,其他开发板类似):
)
-
添加应用程序:
添加
freertos_demo.c
和freertos_demo.h
测试文件,对于 main.c 主要是在main()
函数中完成一些硬件的初始化,最后调用freertos_demo.c
文件中的freertos_demo()
函数。main.c
#include "./SYSTEM/sys/sys.h" #include "./SYSTEM/usart/usart.h" #include "./SYSTEM/delay/delay.h" #include "./BSP/LED/led.h" #include "./BSP/LCD/lcd.h" #include "./BSP/KEY/key.h" #include "./BSP/SRAM/sram.h" #include "./MALLOC/malloc.h" #include "freertos_demo.h"const char *SRAM_NAME_BUF[SRAMBANK] = {" SRAMIN ", " SRAMEX "};int main(void) {HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */usart_init(115200); /* 串口初始化为115200 */led_init(); /* 初始化LED */lcd_init(); /* 初始化LCD */key_init(); /* 初始化按键 */sram_init(); /* SRAM初始化 */my_mem_init(SRAMIN); /* 初始化内部SRAM内存池 */my_mem_init(SRAMEX); /* 初始化外部SRAM内存池 */lcd_show_string(30, 50, 200, 16, 16, "YIZHI successed", RED);freertos_demo(); }
freertos_demo.c
#include "freertos_demo.h" #include "./SYSTEM/usart/usart.h" #include "./BSP/LED/led.h" #include "./BSP/LCD/lcd.h"#include "FreeRTOS.h" #include "task.h"#define START_TASK_PRIO 1 // 任务优先级 #define START_STK_SIZE 128 // 任务堆栈大小 TaskHandle_t StartTask_Handler; // 任务句柄 void start_task(void *pvParameters); // 任务函数 #define TASK1_PRIO 2 // 任务优先级 #define TASK1_STK_SIZE 128 // 任务堆栈大小 TaskHandle_t Task1Task_Handler; // 任务句柄 void task1(void *pvParameters); // 任务函数 #define TASK2_PRIO 3 // 任务优先级 #define TASK2_STK_SIZE 128 // 任务堆栈大小 TaskHandle_t Task2Task_Handler; // 任务句柄 void task2(void *pvParameters); // 任务函数 /*创建开始任务*/ void freertos_demo(void) { xTaskCreate((TaskFunction_t )start_task, // 任务函数 (const char* )"start_task", // 任务名称 (uint16_t )START_STK_SIZE, // 任务堆栈大小 (void* )NULL, // 传入给任务函数的参数 (UBaseType_t )START_TASK_PRIO, // 任务优先级 (TaskHandle_t* )&StartTask_Handler); // 任务句柄 vTaskStartScheduler(); }/*创建两任务1和任务2*/ void start_task(void *pvParameters) {taskENTER_CRITICAL(); // 进入临界区 // 创建任务1 xTaskCreate((TaskFunction_t )task1,(const char* )"task1",(uint16_t )TASK1_STK_SIZE,(void* )NULL,(UBaseType_t )TASK1_PRIO,(TaskHandle_t* )&Task1Task_Handler);// 创建任务2 xTaskCreate((TaskFunction_t )task2,(const char* )"task2",(uint16_t )TASK2_STK_SIZE,(void* )NULL,(UBaseType_t )TASK2_PRIO,(TaskHandle_t* )&Task2Task_Handler);vTaskDelete(StartTask_Handler); // 删除开始任务 taskEXIT_CRITICAL(); // 退出临界区 }/*任务一: LED0闪烁*/ void task1(void *pvParameters) { while(1){LED0_TOGGLE(); vTaskDelay(1000); //延时1000ticks } }/*任务二: LED1闪烁*/ void task2(void *pvParameters) { while(1){LED1_TOGGLE();vTaskDelay(500); //延时500ticks } }
freertos_demo.h
#ifndef __FREERTOS_DEMO_H #define __FREERTOS_DEMO_Hvoid freertos_demo(void);#endif
相关文章:

02.FreeRTOS的移植
文章目录 FreeRTOS移植到STM32F103ZET6上的详细步骤1. 移植前的准备工作2. 添加FreeRTOS文件3. 修改SYSTEM文件4. 修改中断相关文件5. 修改FreeRTOSConfig.h文件6. 可选步骤 FreeRTOS移植到STM32F103ZET6上的详细步骤 1. 移植前的准备工作 **基础工程:**内存管理部…...
【个人笔记】一个例子理解工厂模式
工厂模式优点:创建时类名过长或者参数过多或者创建很麻烦等情况时用,可以减少重复代码,简化对象的创建过程,避免暴露创建逻辑,也适用于需要统一管理所有创建对象的情况,比如线程池的工厂类Executors 简单工…...

【C语言】数组栈的实现
栈的概念及结构 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。 压栈&#…...
kafka 各种选举过程
一、kafka 消费者组协调器 如何选举 Kafka 中的消费者组协调器(Group Coordinator)是通过以下步骤选举的: 分区映射: Kafka 使用一个特殊的内部主题 __consumer_offsets 来存储消费者组的元数据。该主题有多个分区,每…...

树与二叉树【数据结构】
前言 之前我们已经学习过了各种线性的数据结构,顺序表、链表、栈、队列,现在我们一起来了解一下一种非线性的结构----树 1.树的结构和概念 1.1树的概念 树是一种非线性的数据结构,它是由n(n>0)个有限结点组成一…...

简单几步,把浏览器书签转换成导航网页
废话不多说直奔主题上干货 Step 1 下载浏览器书签 1,电脑浏览器点击下载Pintree Pintree 是一个开源项目,旨在将浏览器书签导出成导航网站。通过简单的几步操作,就可以将你的书签转换成一个美观且易用的导航页面。 2. 安装 Pintree B…...

Mac安装Hoomebrew与升级Python版本
参考 mac 安装HomeBrew(100%成功)_mac安装homebrew-CSDN博客 /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 安装了Python 3.x版本,你可以使用以下命令来设置默认的Python版本: # 首先找到新安…...
代码审计:Bluecms v1.6
代码审计:Bluecms v1.6 漏洞列表如下(附Exp): 未完待续… 1、include/common.fun.php->getip()存在ip伪造漏洞 2、ad_js.php sql注入漏洞 Exp:view-source:http://127.0.0.3/bluecms/ad_js.php?ad_id12%20UNION%20SELECT1,2,3,4,5,6,database() 3、…...

谷粒商城实战笔记-59-商品服务-API-品牌管理-使用逆向工程的前后端代码
文章目录 一, 使用逆向工程生成的代码二,生成品牌管理菜单三,几个小问题 在本次的技术实践中,我们利用逆向工程的方法成功地为后台管理系统增加了品牌管理功能。这种开发方式不仅能快速地构建起功能模块,还能在一定程度…...

如何利用Jenkins自动化管理、部署数百个应用
目录 1. Jenkins 安装与部署步骤 1.1 系统要求 1.2 安装步骤 1.2.1 Windows 系统 1.2.2 CentOS 系统 1.3 初次配置 2. Gradle 详细配置方式 2.1 安装 Gradle 2.1.1 Windows 系统 2.1.2 CentOS 系统 2.2 配置 Jenkins 中的 Gradle 3. JDK 详细配置方式 3.1 安装 JD…...

Java之归并排序
归并排序 归并排序(Merge Sort)算法,使用的是分治思想。分治,顾名思义,就是分而治之,将一个大问题分解成小的子问题来解决。小的子问题解决了,大问题也就解决了。 核心源码: mergeSort(m->n) merge(mergeSort(m-&g…...
了解ChatGPT API
要了解如何使用 ChatGPT API,可以参考几个有用的资源和教程,这些资源能帮助你快速开始使用 API 进行项目开发。下面是一些推荐的资源: OpenAI 官方文档: 访问 OpenAI 的官方网站可以找到 ChatGPT API 的详细文档。这里包括了 API …...

EasyAnimate - 阿里开源视频生成项目,国产版Sora,高质量长视频生成 本地一键整合包下载
EasyAnimate是阿里云人工智能平台PAI自主研发的DiT-based视频生成框架,它提供了完整的高清长视频生成解决方案,包括视频数据预处理、VAE训练、DiT训练、模型推理和模型评测等。在预训练模型的基础上,EasyAnimate可通过少量图片的LoRA微调来改…...

7月23日JavaSE学习笔记
异常: 程序中一些程序处理不了的特殊情况 异常类 Exception 继承自 Throwable 类(可抛出的) Throwable继承树 Error:错误/事故,Java程序无法处理,如 OOM内存溢出错误、内存泄漏...会导出程序崩溃 常见的…...

Linux——DNS服务搭建
(一)搭建nginx 1.首先布置基本环境 要求能够ping通外网,有yum源 2.安装nginx yum -y install nginx 然后查看验证 3.修改网页配置文件 修改文件,任意编写内容,然后去物理机测试 (二)创建一…...

C#中的wpf基础
在WPF中,Grid 是一种非常强大的布局控件,用于创建网格布局。它允许你将界面划分为行和列,并将控件放置在这些行和列中。 以下是一些关键点和示例,帮助你理解 WPF 中的 Grid: 基本属性 RowDefinitions:定义…...

基于微信小程序+SpringBoot+Vue的刷题系统(带1w+文档)
基于微信小程序SpringBootVue的刷题系统(带1w文档) 基于微信小程序SpringBootVue的刷题系统(带1w文档) 本系统是将网络技术和现代的管理理念相结合,根据试题信息的特点进行重新分配、整合形成动态的、分类明确的信息资源,实现了刷题的自动化,…...
SSH -i的用法
缘起 今天使用ssh -i指定私钥时遇到以下错误: WARNING: UNPROTECTED PRIVATE KEY FILE! Permissions 0644 for /home/ken/.ssh/my.pem are too open. It is required that your private key files are NOT accessible by others. This private key will b…...

小白学习webgis的详细路线
推荐打开boss直聘搜索相关岗位,查看岗位要求,对症下药是最快的。 第一阶段:基础知识准备 计算机基础 操作系统:理解Windows、Linux或macOS等操作系统的基本操作,学会使用命令行界面。网络基础:掌握TCP/I…...
使用ChatGPT来撰写和润色学术论文的教程(含最新升级开通ChatGpt4教程)
现在有了ChatGPT4o更加方便了, 但次数太少了 想要增加次数可以考虑升级开桶ChatGpt4 ( OPENAI4 可以减2刀) 一、引言 在学术研究中,撰写高质量的论文是一项重要的技能。本教程将介绍如何利用ChatGPT来辅助完成从论文构思到润色的全过程…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...

2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...

MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...
Docker拉取MySQL后数据库连接失败的解决方案
在使用Docker部署MySQL时,拉取并启动容器后,有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致,包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因,并提供解决方案。 一、确认MySQL容器的运行状态 …...
华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)
题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...