STM32CUBEMX+STM32H743ZIT6+MPU+DMA+UART下发指令对MPU配置管理

实现stm32H7的IAP过程,没有想象中的顺利。

需要解决串口DMA和MPU配置管理。

查看正点原子的MPU管理例程,想自己用串口下发指令,实现MPU打开,读取和写入指令。

中间遇到很多坑,比如串口DMA方式下发指令,没反应,debug模式,发现数据读不进去。才知道需要配置串口DMAMPUnobuffer,实现 Cache 模式下不使用缓冲。

MCU型号:STM32H743ZIT6

Stm32cubemx版本:6.12.1

用到的知识点梳理:

一、MPU配置管理。

1、MPU:内存保护单元。

其实作用有两个:①加速访问CPUCPU的速率能达到480MHz,但是除了TCMCache480MHz工作,其它AXI SRAMSRAM1SRAM2等都是以240MHz工作。M7内核芯片基本都做了一级Cache支持,Cache又分数据缓存D-Cache和指令缓冲I-CacheSTM32H7的数据缓存和指令缓存大小都是16KB。对于指令缓冲,用户不用管,这里主要说的是数据缓存D-Cache。数据缓存D-Cache就是解决CPU加速访问SRAM如果每次CPU要读写SRAM区的数据,都能够在Cache里面进行,自然是最好的,实现了240MHz480MHz的飞跃,实际是做不到的,因为数据Cache只有16KB大小,总有用完的时候。

②内存保护,防止不受信任的应用程序访问受保护的内存区域。 防止用户应用程序破坏操作系统使用的数据。通过阻止任务访问其它任务的数据区。 允许将内存区域定义为只读,以便保护重要数据。检测意外的内存访问内存保护、外设保护和代码访问保护。

  1. 配置管理规则

结果HALMPU的结构体成员来说,

typedef struct

{

uint8_tEnable;

uint8_tNumber;

uint32_tBaseAddress;

uint8_t Size;

uint8_tSubRegionDisable;

uint8_tTypeExtField;

uint8_t AccessPermission;

uint8_tDisableExec;

uint8_tIsShareable;

uint8_tIsCacheable;

uint8_tIsBufferable;

}MPU_Region_InitTypeDef

前面的5个好理解,后面几个有些抽象。

  1. Enable 使能MPU内存区
  2. Number MPU内存区编号,从015。序号越大,优先级越高。
  3. BaseAddress MPU内存区的起始地址
  4. Size MPU内存区的大小
  5. SubRegionDisable 使能子区域,配置为0使能。配置为1,不使能
  6. TypeExtField 类型扩展域三种,和后面的csb配合使用。常见的是两种level0level1看下图。最常用的是level0
  7. AccessPermission 有六种访问规则。无权限,全部权限,有读写权限,只读权限等。
  8. DisableExec =0使能指令提取, 即这块内存区可以执行程序代码;=1 表示禁止指令提取, 即这块内存区禁止执行程序代码
  9. IsShareable 多总线或者多核访问的共享
  10. IsCacheable 使能Cache
  11. IsBufferable 配合 C 位。实现 Cache 模式下是否使用缓冲。

2、 配置Non-cacheable

这个最好理解,就是正常的读写操作,无Cache

对应四种MPU配置如下:

·TEX = 000  C=0  B=0  S=忽略此位,强制为共享

·TEX = 000  C=0  B=1  S=忽略此位,强制为共享

·TEX = 001  C=0  B=0  S=0

·TEX = 001  C=0  B=0  S=1

由于H7内核达到480Mhz, CPU访问RAM都需要透过cache才能发挥性能. 所以H7芯片做了MPU这个部分来配置内存的访问策略. CPU访问SRAM 中间有CACHE的作用. DMA是直接操作SRAM空间. 所以要进行Cache策略配置.

不使用Cache

3、 配置Write through(透写)read allocateno write allocate

注意,M7内核只要开启了Cacheread allocate就是开启的。

·  使能了此配置的SRAM缓冲区写操作

    如果CPU要写的SRAM区数据在Cache中已经开辟了对应的区域,那么会同时写到Cache里面和SRAM里面;如果没有,就用到配置no write allocate了,意思就是CPU会直接往SRAM里面写数据,而不再需要在Cache里面开辟空间了。

    在写Cache命中的情况下,这个方式的优点是CacheSRAM的数据同步更新了,没有多总线访问造成的数据一致性问题。缺点也明显,Cache在写操作上无法有效发挥性能。

·  使能了此配置的SRAM缓冲区读操作

    如果CPU要读取的SRAM区数据在Cache中已经加载好,就可以直接从Cache里面读取。如果没有,就用到配置read allocate了,意思就是在Cache里面开辟区域,将SRAM区数据加载进来,后续的操作,CPU可以直接从Cache里面读取,从而时间加速。

    安全隐患,如果Cache命中的情况下,DMA写操作也更新了SRAM区的数据,CPU直接从Cache里面读取的数据就是错误的。

·  对应的两种MPU配置如下:

TEX = 000 C=1 B=0  S=1

TEX = 000 C=1 B=0  S=0

4、 配置Write back(回写)read allocateno write allocate

注意,M7内核只要开启了Cacheread allocate就是开启的。

·  使能了此配置的SRAM缓冲区写操作

    如果CPU要写的SRAM区数据在Cache中已经开辟了对应的区域,那么会写到Cache里面,而不会立即更新SRAM;如果没有,就用到配置no write allocate了,意思就是CPU会直接往SRAM里面写数据,而不再需要在Cache里面开辟空间了。

    安全隐患,如果Cache命中的情况下,此时仅Cache更新了,而SRAM没有更新,那么DMA直接从SRAM里面读出来的就是错误的。

·  使能了此配置的SRAM缓冲区读操作

   如果CPU要读取的SRAM区数据在Cache中已经加载好,就可以直接从Cache里面读取。如果没有,就用到配置read allocate了,意思就是在Cache里面开辟区域,将SRAM区数据加载进来,后续的操作,CPU可以直接从Cache里面读取,从而时间加速。

    安全隐患,如果Cache命中的情况下,DMA写操作也更新了SRAM区的数据,CPU直接从Cache里面读取的数据就是错误的。

·  对应两种MPU配置如下:

TEX = 000 C=1 B=1  S=1

TEX = 000 C=1 B=1  S=0

5、串口DMAMPU配置:

MPU_InitStruct.Enable = MPU_REGION_ENABLE;//使能MPU内存区

MPU_InitStruct.Number = MPU_REGION_NUMBER0;//编号0

MPU_InitStruct.BaseAddress = 0x24000000;//对应的内存区起始地址

MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;//大小

MPU_InitStruct.SubRegionDisable = 0x0;//不使能子区域

MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;//

MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;//支持全部访问

MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;//=0使能指令提取, 即这块内存区可以执行程序代码, XN=1 表示禁止指令提取, 即这块内存区禁止执行程序代码。

MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;//多总线或者多核访问的共享

MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;//使能 Cache

MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;//配合 C 位实现 Cache 模式下是否使用缓冲,这里需要设置不使能。

选择下图的模式。能避免CacheSRAM中数据不一致的风险。

二、Stm32cubemx初始化

MPU配置

RCC配置

UART配置

④烧写配置

⑤时钟配置

三、代码部分

/* USER CODE BEGIN Header */

/**

******************************************************************************

* @file : main.c

* @brief : Main program body

******************************************************************************

* @attention

*

* Copyright (c) 2024 STMicroelectronics.

* All rights reserved.

*

* This software is licensed under terms that can be found in the LICENSE file

* in the root directory of this software component.

* If no LICENSE file comes with this software, it is provided AS-IS.

*

******************************************************************************

*/

/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/

#include "main.h"

#include "dma.h"

#include "memorymap.h"

#include "usart.h"

#include "gpio.h"



/* Private includes ----------------------------------------------------------*/

/* USER CODE BEGIN Includes */

#include <stdio.h> //第一步包含头文件

#include "string.h"







/* USER CODE END Includes */



/* Private typedef -----------------------------------------------------------*/

/* USER CODE BEGIN PTD */



/* USER CODE END PTD */



/* Private define ------------------------------------------------------------*/

/* USER CODE BEGIN PD */



/* USER CODE END PD */



/* Private macro -------------------------------------------------------------*/

/* USER CODE BEGIN PM */



#define open_CMD "openmpu" //打开MPU

#define read_CMD"readmpu" //读取MPU

#define write_CMD"writempu" //写入MPU



/* USER CODE END PM */



/* Private variables ---------------------------------------------------------*/



/* USER CODE BEGIN PV */

uint8_t t = 0;

uint16_t times = 0;

uint8_t mpudata[128] __attribute__((at(0X20002000)));//定义一个数组

uint8_t rx_flag = 0; //输入结束的标志位

uint8_t uart_rxbuf[100]; //输入数据的缓存区

uint8_t uart_rx[1];//输入字符缓存区

uint16_t len; //输入字符的个数





/* USER CODE END PV */



/* Private function prototypes -----------------------------------------------*/

void SystemClock_Config(void);

static void MPU_Config(void);

static void MX_NVIC_Init(void);

/* USER CODE BEGIN PFP */



/* USER CODE END PFP */



/* Private user code ---------------------------------------------------------*/

/* USER CODE BEGIN 0 */



int fputc(int c, FILE *stream) //重写fputc函数

{

/*

huart1是工具生成代码定义的UART1结构体,

如果以后要使用其他串口打印,只需要把这个结构体改成其他UART结构体。

*/

HAL_UART_Transmit(&huart1, (unsigned char *)&c, 1, 1000);

return 1;

}



uint8_t mpu_set_protection(uint32_t baseaddr, uint32_t size, uint32_t rnum, uint8_t de, uint8_t ap, uint8_t sen, uint8_t cen, uint8_t ben)

{

MPU_Region_InitTypeDef mpu_region_init_handle;



HAL_MPU_Disable();/* 配置MPU之前先关闭MPU,配置完成以后在使能MPU */



mpu_region_init_handle.Enable = MPU_REGION_ENABLE; /* 使能该保护区域 */

mpu_region_init_handle.Number = rnum; /* 设置保护区域 */

mpu_region_init_handle.BaseAddress = baseaddr; /* 设置基址 */

mpu_region_init_handle.DisableExec = de; /* 是否允许指令访问 */

mpu_region_init_handle.Size = size; /* 设置保护区域大小 */

mpu_region_init_handle.SubRegionDisable = 0X00; /* 禁止子区域 */

mpu_region_init_handle.TypeExtField = MPU_TEX_LEVEL0; /* 设置类型扩展域为level0 */

mpu_region_init_handle.AccessPermission = (uint8_t)ap; /* 设置访问权限, */

mpu_region_init_handle.IsShareable = sen; /* 是否共用? */

mpu_region_init_handle.IsCacheable = cen; /* 是否cache? */

mpu_region_init_handle.IsBufferable = ben; /* 是否缓冲? */

HAL_MPU_ConfigRegion(&mpu_region_init_handle); /* 配置MPU */

HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); /* 开启MPU */

return 0;

}





/* USER CODE END 0 */



/**

* @briefThe application entry point.

* @retval int

*/

int main(void)

{



/* USER CODE BEGIN 1 */



/* USER CODE END 1 */



/* MPU Configuration--------------------------------------------------------*/

MPU_Config();



/* Enable the CPU Cache */



/* Enable I-Cache---------------------------------------------------------*/

SCB_EnableICache();



/* Enable D-Cache---------------------------------------------------------*/

SCB_EnableDCache();



/* MCU Configuration--------------------------------------------------------*/



/* Reset of all peripherals, Initializes the Flash interface and the Systick. */

HAL_Init();



/* USER CODE BEGIN Init */



/* USER CODE END Init */



/* Configure the system clock */

SystemClock_Config();



/* USER CODE BEGIN SysInit */



/* USER CODE END SysInit */



/* Initialize all configured peripherals */

MX_GPIO_Init();

MX_DMA_Init();

MX_USART1_UART_Init();



/* Initialize interrupts */

MX_NVIC_Init();

/* USER CODE BEGIN 2 */





//HAL_MPU_Disable(); //关闭MPU

printf("\r\n<<<<<<<<<<<<<STM32H7 MPU TEST打印>>>>>>>>>>>>>>\r\n");

printf("input \"openmpu\"去打开MPU\t\"writempu\"去写入MPU\t \"readmpu\"去读取MPU\t需要在20s内输入\r\n");//提示输入指令



HAL_Delay(1000);

HAL_UART_Receive_DMA(&huart1, (uint8_t *)uart_rx, 1);//打开串口DMA接收输入



/* USER CODE END 2 */



/* Infinite loop */

/* USER CODE BEGIN WHILE */

while (1)

{

/* USER CODE END WHILE */



/* USER CODE BEGIN 3 */



while (rx_flag == 1) //对输入命令执行判断

{

printf("字符数目是%d,输入内容如下:\r\n", len);//输入字符数

uart_rxbuf[len] = 0x0d;

uart_rxbuf[len + 1] = 0x0a;

// uart_rxbuf[len+2]=0x0d;

// uart_rxbuf[len+3]=0x0a;

HAL_UART_Transmit(&huart1, (uint8_t *)uart_rxbuf, len + 2, 0xffff);//输出输入的命令

{

if (strstr((const char *)uart_rxbuf, open_CMD) != NULL) //

{

// 打开MPU

mpu_set_protection(0X20002000, /* 只读,禁止共用,禁止catch,允许缓冲 */

MPU_REGION_SIZE_128B,

MPU_REGION_NUMBER1, 0,

MPU_REGION_PRIV_RO_URO,

MPU_ACCESS_NOT_SHAREABLE,

MPU_ACCESS_NOT_CACHEABLE,

MPU_ACCESS_BUFFERABLE);

printf("接收到指令openmpu\r\n");

printf("打开MPU 完成\r\n\r\n");



}

else if (strstr((const char *)uart_rxbuf, write_CMD) != NULL)

{

// 写入MPU

printf("接收到指令writempu\r\n");

printf("Start Writing data...\r\n");

sprintf((char *)mpudata, "MPU test array %d", t);//把t写入MPU

printf("Data Write finshed!\r\n\r\n");



}

// 读取MPU

else if (strstr((const char *)uart_rxbuf, read_CMD) != NULL) /* 从数组中读取数据,不管有没有开启MPU保护都不会进入内存访问错误! */

{

printf("接收到指令readmpu\r\n");

printf("Array data is:%s\r\n\r\n", mpudata);



}

else

{

HAL_Delay(1);

printf("不是有效的指令,请重新输入\r\n\r\n");

}



t++;



len = 0;//字符长度清零

rx_flag = 0;//输入状态标志位置零



}

}



HAL_Delay(10);

times++;

if (times % 10000 == 0)//每隔100s

{

printf("\r\ninput \"openmpu\"去打开MPU\t\"writempu\"去写入MPU\t \"readmpu\"去读取MPU\t需要在20s内输入\r\n");//提示输出指令“update”,10s内没接收到指令,开始启动APP



}

}

/* USER CODE END 3 */

}



/**

* @brief System Clock Configuration

* @retval None

*/

void SystemClock_Config(void)

{

RCC_OscInitTypeDef RCC_OscInitStruct = {0};

RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};



/** Supply configuration update enable

*/

HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);



/** Configure the main internal regulator output voltage

*/

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);



while (!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}



__HAL_RCC_SYSCFG_CLK_ENABLE();

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);



while (!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}



/** Initializes the RCC Oscillators according to the specified parameters

* in the RCC_OscInitTypeDef structure.

*/

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;

RCC_OscInitStruct.HSEState = RCC_HSE_ON;

RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;

RCC_OscInitStruct.PLL.PLLM = 1;

RCC_OscInitStruct.PLL.PLLN = 120;

RCC_OscInitStruct.PLL.PLLP = 2;

RCC_OscInitStruct.PLL.PLLQ = 2;

RCC_OscInitStruct.PLL.PLLR = 2;

RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;

RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;

RCC_OscInitStruct.PLL.PLLFRACN = 0;

if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)

{

Error_Handler();

}



/** Initializes the CPU, AHB and APB buses clocks

*/

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK

| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2

| RCC_CLOCKTYPE_D3PCLK1 | RCC_CLOCKTYPE_D1PCLK1;

RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;

RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;

RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;

RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;

RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;

RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;

RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;



if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)

{

Error_Handler();

}

}



/**

* @brief NVIC Configuration.

* @retval None

*/

static void MX_NVIC_Init(void)

{

/* USART1_IRQn interrupt configuration */

HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(USART1_IRQn);

/* DMA1_Stream1_IRQn interrupt configuration */

HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);

/* DMA1_Stream0_IRQn interrupt configuration */

HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);

}



/* USER CODE BEGIN 4 */



void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//uart接收的回调函数

{

if (huart->Instance == USART1)

{

//结束符是换行

if (uart_rx[0] != 0x0A) //统计输入字符长度

{

len ++ ;

uart_rxbuf[len - 1] = uart_rx[0];//写入接收缓冲区

if (len > 255) //字符长度超出最大长度。重新输入

{

len = 0;

}

}

else//接收到换行符,把len的长度减去1,因为"\r"回车占用一个字节。

{

len--;

rx_flag = 1;

}

}

HAL_UART_Receive_DMA(&huart1, (uint8_t *)uart_rx, 1);//再次打开uart接口的DMA函数,循环接收



}



void MemManage_Handler(void)//触发mpu写入保护

{

/* USER CODE BEGIN MemoryManagement_IRQn 0 */

printf("Mem Access Error!!\r\n");//写入失败



printf("Soft Reset……\r\n");



NVIC_SystemReset();//mcu软复位

/* USER CODE END MemoryManagement_IRQn 0 */

while (1)

{

/* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */

/* USER CODE END W1_MemoryManagement_IRQn 0 */

}

}



/* USER CODE END 4 */



/* MPU Configuration */



void MPU_Config(void)

{

MPU_Region_InitTypeDef MPU_InitStruct = {0};



/* Disables the MPU */

HAL_MPU_Disable();



/** Initializes and configures the Region and the memory to be protected

*/

MPU_InitStruct.Enable = MPU_REGION_ENABLE;//使能MPU内存区

MPU_InitStruct.Number = MPU_REGION_NUMBER0;//编号0

MPU_InitStruct.BaseAddress = 0x24000000;//对应的内存起始地址

MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;//大小

MPU_InitStruct.SubRegionDisable = 0x0;//不使能子区域

MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;//

MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;//支持全部访问

MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;//MPU_INSTRUCTION_ACCESS_ENABLE;//=0使能指令提取, 即这块内存区可以执行程序代码, XN=1 表示禁止指令提取, 即这块内存区禁止执行程序代码。

MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;//多总线或者多核访问的共享

MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;//使能 Cache

MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;//配合 C 位实现 Cache 模式下是否使用缓冲,这里需要设置不使能



HAL_MPU_ConfigRegion(&MPU_InitStruct);

/* Enables the MPU */

HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);



}



/**

* @briefThis function is executed in case of error occurrence.

* @retval None

*/

void Error_Handler(void)

{

/* USER CODE BEGIN Error_Handler_Debug */

/* User can add his own implementation to report the HAL error return state */

__disable_irq();

while (1)

{

}

/* USER CODE END Error_Handler_Debug */

}



#ifdef USE_FULL_ASSERT

/**

* @briefReports the name of the source file and the source line number

*where the assert_param error has occurred.

* @paramfile: pointer to the source file name

* @paramline: assert_param error line source number

* @retval None

*/

void assert_failed(uint8_t *file, uint32_t line)

{

/* USER CODE BEGIN 6 */

/* User can add his own implementation to report the file name and line number,

ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

/* USER CODE END 6 */

}

#endif /* USE_FULL_ASSERT */

四、运行结果

输入writempu(见下图)

提示写入成功

输入readmpu

提示读取成功,打印出来

输入writempu

提示写入成功

再输入readmpu

提示读取成功,打印出来。读出的数据发生变化

输入openmpu

提示开启MPU

 

再输入readmpu

读取成功,打印出来。读出的数据不变。

再输入writempu

提示写入失败,系统软复位

 

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

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

相关文章

8. 数组拼接

题目描述 现在有多组整数数组&#xff0c;需要将它们合并成一个新的数组。合并规则&#xff0c;从每个数组里按顺序取出固定长度的内容合并到新的数组中&#xff0c;取完的内容会删除掉&#xff0c;如果该行不足固定长度或者已经为空&#xff0c;则直接取出剩余部分的内容放到新…

Chrome 浏览器原生功能截长屏

我偶尔需要截取一些网页内容作为素材&#xff0c;但偶尔内容很长无法截全&#xff0c;需要多次截屏再拼接&#xff0c;过于麻烦。所以记录下这个通过浏览器原生功能截长屏的方案。 注意 这种方案并不是百分百完美&#xff0c;如果涉及到一些需要滚动加载的数据或者悬浮区块&am…

学技术学英文:代码中的锁:悲观锁和乐观锁

本文导读&#xff1a; 1. 举例说明加锁的场景&#xff1a; 多线程并发情况下有资源竞争的时候&#xff0c;如果不加锁&#xff0c;会出现数据错误&#xff0c;举例说明&#xff1a; 业务需求&#xff1a;账户余额>取款金额&#xff0c;才能取钱。 时间线 两人共有账户 …

深度学习之目标检测——RCNN

Selective Search 背景:事先不知道需要检测哪个类别,且候选目标存在层级关系与尺度关系 常规解决方法&#xff1a;穷举法&#xff0c;在原始图片上进行不同尺度不同大小的滑窗&#xff0c;获取每个可能的位置 弊端&#xff1a;计算量大&#xff0c;且尺度不能兼顾 Selective …

数字人在虚拟展厅中的应用方向有哪些?

数字人在虚拟展厅中的应用日益丰富&#xff0c;为参观者带来了前所未有的互动体验。以下是数字人在虚拟展厅中的几大主要应用方向&#xff1a; 1. 智能导览与讲解 在虚拟展厅中&#xff0c;数字人以其独特的魅力担任着导览员的角色。它们不仅为参观者提供精准的信息和指引&am…

WEB开发: 全栈工程师起步 - Python Flask +SQLite的管理系统实现

一、前言 罗马不是一天建成的。 每个全栈工程师都是从HELLO WORLD 起步的。 之前我们分别用NODE.JS 、ASP.NET Core 这两个框架实现过基于WebServer的全栈工程师入门教程。 今天我们用更简单的来实现&#xff1a; Python。 我们将用Python来实现一个学生管理应用&#xff0…

【我的 PWN 学习手札】IO_FILE 之 stdin任意地址写

我们知道&#xff0c;stdin会往“缓冲区”先读入数据&#xff0c;如果我们劫持这个所谓“缓冲区”到其他地址呢&#xff1f;是否可以读入数据到任意地址&#xff1f;答案是肯定的。 注意&#xff01;代码中的“-------”分隔&#xff0c;是为了区分一条调用链上不同代码片段&am…

从 Dify 到 Rill-Flow:大模型应用平台的进化之路

1. 基于 dify 的大模型应用平台构建 近些年&#xff0c;大语言模型领域的高速发展&#xff0c;涌现出了众多优秀的产品&#xff0c;能够解决很多实际的业务场景&#xff0c;大幅提升工作效率。各公司都纷纷搭建起了自己的大模型应用平台&#xff0c;来统一管理各种大语言模型&…

37. Three.js案例-绘制部分球体

37. Three.js案例-绘制部分球体 实现效果 知识点 WebGLRenderer WebGLRenderer 是Three.js中的一个渲染器类&#xff0c;用于将3D场景渲染到网页上。 构造器 WebGLRenderer( parameters : Object ) 参数类型描述parametersObject渲染器的配置参数&#xff0c;可选。 常用…

基于 SSM 框架 Vue 电脑测评系统:赋能电脑品质鉴定

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;作为一个一般的用户都开始注重与自己的信息展示平台&#xff0c;实现基于SSM框架的电脑测评系统在技术上已成熟。本文介绍了基于SSM框架的电脑测评系统的开发全过程。通过分析用户对于基于SSM框架的电脑测评系统的…

二七(vue2-03)、生命周期四个阶段及八个钩子、工程化开发和脚手架、组件注册、拆分组件

1. 生命周期 1.1 生命周期四个阶段 <!-- Vue生命周期&#xff1a;一个Vue实例从 创建 到 销毁 的整个过程。生命周期四个阶段&#xff1a;① 创建 ② 挂载 ③ 更新 ④ 销毁1.创建阶段&#xff1a;创建响应式数据2.挂载阶段&#xff1a;渲染模板3.更新阶段&#xff1a;修改…

Group FLUX - Beta Sprint Essay4

文章目录 I. SCRUMAchievements from yesterday’s stand-up meeting to the presentKey Features Demonstrated in Beta PM ReportBurnup mapRunning image of our current program I. SCRUM Achievements from yesterday’s stand-up meeting to the present Zhong Haoyan: …

c++-----------------类和对象(中)

1.类的默认成员函数 默认的成员函数就是用户没有显示实现&#xff0c;编译器会自动生成的成员函数称为默认的成员函数。一个类我们在不写的情况下编译器会自动生成以下6个默认的成员函数&#xff0c;这6个最重要的是前面4个&#xff0c;后面的了解一下就可以了。默认成员函数很…

Qt中的异步相关类

Qt中的异步相关类 今天在学习别人的项目时&#xff0c;看到别人包含了QFuture类&#xff0c;我没有见过&#xff0c;于是记录一下。 直接在AI助手中搜索QFuture,得到的时Qt中异步相关的类。于是直接查询一下Qt异步中相关的类。 在Qt中&#xff0c;异步编程是一个重要的概念&…

WPF DataTemplate 数据模板

DataTemplate 顾名思义&#xff0c;数据模板&#xff0c;在 wpf 中使用非常频繁。 它一般用在带有 DataTemplate 依赖属性的控件中&#xff0c;如 ContentControl、集合控件 ListBox、ItemsControl 、TabControls 等。 1. 非集合控件中使用 <UserControl.Resources>&l…

爬虫案例学习6

获取淘宝商品数据2024-12-18 参考学习&#xff1a; 大佬博客 视频教程 通过搜索发现&#xff0c;数据是通过发送请求过来的&#xff0c;不是静态存在源代码的 所以我们需要请求这个接口获取数据&#xff1a;比如标题&#xff0c;价格&#xff0c;图片等信息 https://h5api.m…

Linux学习——9_Ubuntu Linux操作系统

Ubuntu Linux操作系统 Ubuntu简介 Ubuntu Linux是由南非人马克沙特尔沃思(Mark Shuttleworth)创办的基于Debian Linux的操作系统&#xff0c;于2004年10月公布 Ubuntu是一个以桌面应用为主的Linux发行版操作系统 Ubuntu拥有庞大的社区力量&#xff0c;用户可以方便地从社区…

springboot449教学资源共享平台(论文+源码)_kaic

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统教学资源共享平台信息管理难度大&#xff0c;容错率低&am…

各向同性重建(3D荧光图像)

文章目录 一、基本知识1.1、各向同性&#xff08;isotropic&#xff09; 各向异性&#xff08;anisotropic&#xff09;1.2、像素尺寸 像素间距 像素分辨率1.3、点扩散函数&#xff08;PSF&#xff09;1.3.1、高斯函数 二维高斯PSF1.3.2、二维高斯PSF&#xff1a;代码生成 …

计算机毕业设计论文指导

计算机毕业设计论文指导 计算机毕业设计辅导一站式&#xff01;太香了&#x1f4aa; [赞R][赞R][赞R]嗨喽&#xff01;计算机专业的宝子们&#xff01; 计算机毕设辅导专业靠谱的他来了&#xff01;&#xff01; 是不是还在为选题程序不会做而感到苦难&#xff1f; 论文没思路赶…