STM32单片机——DMA数据传输

news2024/11/16 11:57:58

STM32单片机——DMA数据传输

  • DMA相关概述
  • 实验一:内存到内存搬运
    • Cubemx工程配置
    • Hal库程序设计及实现
    • 固件库程序设计及实现
  • 实验二:内存到外设(DMA串口发送)
    • Cubemx工程配置
    • Hal库程序设计及实现
    • 固件库程序设计
  • 实验三:外设到内存(DMA串口接收)
    • DMA接收Cubemx工程配置
    • 串口DMA接收相关函数解析
    • DMA串口接收Hal库代码实现
    • DMA串口接收固件库程序设计
  • 写在最后

DMA相关概述

  • 参考文章:STM32 DMA详解

  • 1. 什么是DMA
    令人头秃的描述
      DMA(Direct Memory Access,直接存储器访问) 提供在外设与内存、存储器和存储器、外设与外设之间的高速数据传输使用。它允许不同速度的硬件装置来沟通,而不需要依赖于CPU,在这个时间中,CPU对于内存的工作来说就无法使用。
    简单描述:
      就是一个数据搬运工!!

  • 2. DMA的意义
    代替 CPU 搬运数据,为 CPU 减负。
    (1)数据搬运的工作比较耗时间;
    (2) 数据搬运工作时效要求高(有数据来就要搬走);
    (3) 没啥技术含量(CPU 节约出来的时间可以处理更重要的事)。

  • 3. 搬运什么数据
      存储器: spi、usart、iic、adc 等基于APB1 、APB2或AHB时钟的外设
      外设: 自身的闪存(flash)或者内存(SRAM)以及外设的存储设备都可以作为访问地源或者目的
    三种搬运方式:

    搬运方式用途(案例)
    存储器→存储器复制某特别大的数据buf
    存储器→外设将某数据buf写入串口TDR寄存器
    外设→存储器将串口RDR寄存器写入某数据buf

存储器→存储器

   存储器→外设

   外设→存储器

  • 4. DMA 控制器
      STM32F103有2个 DMA 控制器,DMA1有7个通道,DMA2有5个通道。
      一个通道每次只能搬运一个外设的数据!! 如果同时有多个外设的 DMA 请求,则按照优先级进行响应。
      DMA1有7个通道:
      
      DMA2有5个通道:
        
  • 5. DMA及通道的优先级
    (1)软件: 每个通道的优先级可以在DMA_CCRx寄存器中设置,有4个等级最高级>高级>中级>低级
    (2)硬件: 如果2个请求,它们的软件优先级相同,则较低编号的通道比较高编号的通道有较高的优先权
  • 6. DMA传输方式
    模式传输方式
    DMA_Mode_Normal(正常模式)一次DMA数据传输完后,停止DMA传送 ,也就是只传输一次
    DMA_Mode_Circular(循环传输模式)当传输结束时,硬件自动会将传输数据量寄存器进行重装,进行下一轮的数据传输。 也就是多次传输模式
  • 7. 指针递增模式
      外设和存储器指针在每次传输后可以自动向后递增或保持常量。当设置为增量模式时,下一个要传输的地址将是前一个地址加上增量值。

实验一:内存到内存搬运

Cubemx工程配置

  • 时钟配置
    1. 采用外部高速晶振
    2. 时钟树配置
  • DMA配置
  • 打开串口

Hal库程序设计及实现

  • 常用库函数解析

    1. 开启DMA传输
      HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
      
      参数解析
      参数解析
      返回值HAL_StatusTypeDef,HAL状态(OK,busy,ERROR,TIMEOUT
      DMA_HandleTypeDef *hdmaDMA通道句柄
      uint32_t SrcAddress源内存地址
      uint32_t DstAddress目标内存地址
      uint32_t DataLength传输数据长度。注意:需要乘以sizeof(uint32_t)
    2. 获取DMA Flag的值
      #define __HAL_DMA_GET_FLAG(__HANDLE__, __FLAG__)   (DMA1->ISR & (__FLAG__))
      
      参数解析
      参数解析
      返回值FLAG的值(SET/RESET
      __HANDLE__DMA通道句柄
      __FLAG__数据传输标志。DMA_FLAG_TCx表示数据传输完成标志,x表通道数
  • Hal库程序设计

    // 源数组  放在flash内部
    const uint32_t srcBuf[16] = {
    		0x00000000,0x11111111,0x22222222,0x33333333,
    		0x44444444,0x55555555,0x66666666,0x77777777,
    		0x88888888,0x99999999,0xAAAAAAAA,0xBBBBBBBB,
    		0xCCCCCCCC,0xDDDDDDDD,0xEEEEEEEE,0xFFFFFFFF
    };
    // 目标数组	放置在SRAM内
    uint32_t desBuf[16];
    
    
    //开启数据传输
     HAL_DMA_Start(&hdma_memtomem_dma1_channel1, (uint32_t)srcBuf, (uint32_t)desBuf, 16 * sizeof(uint32_t));
    
    //等待数据传输完成
     while( __HAL_DMA_GET_FLAG(&hdma_memtomem_dma1_channel1, DMA_FLAG_TC1) == RESET );
     
     //打印目标数组内容
     HAL_UART_Transmit(&huart1,(const uint8_t *)desBuf, 16 * sizeof(uint32_t), 200);
    
  • 串口打印目标数组

固件库程序设计及实现

  • dma.c存储器和外设变量定义
    #defien BUF_SIZE 16
    //源数组  const表常量类型,数组buf放在flash中
    const uint32_t src_buf[BUF_SIZE]={
    		0x00000000,0x11111111,0x22222222,0x33333333,
    		0x44444444,0x55555555,0x66666666,0x77777777,
    		0x88888888,0x99999999,0xAAAAAAAA,0xBBBBBBBB,
    		0xCCCCCCCC,0xDDDDDDDD,0xEEEEEEEE,0xFFFFFFFF
    };
    //目标数组   放置在SRAM中
    uint32_t des_buf[BUF_SIZE];
    
  • M2M结构体配置
    void DMA_MTM_Init(void)
    {
    	DMA_InitTypeDef DMA_InitStructure;
    	
    	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	//使能DMA时钟
    	
    	DMA_InitStructure.DMA_PeripheralBaseAddr =	(uint32_t)src_buf;		//外设地址
    	DMA_InitStructure.DMA_MemoryBaseAddr 	 = (uint32_t)des_buf;		//内存地址
    	DMA_InitStructure.DMA_DIR 				 = DMA_DIR_PeripheralSRC;	//传输方向
    	
    	DMA_InitStructure.DMA_BufferSize 		= BUF_SIZE  * 4;				//传输数量
    	DMA_InitStructure.DMA_PeripheralInc 	= DMA_PeripheralInc_Enable;		//外设地址增量
    	DMA_InitStructure.DMA_MemoryInc 		= DMA_MemoryInc_Enable;			//存储器地址递增
    	DMA_InitStructure.DMA_PeripheralDataSize= DMA_PeripheralDataSize_Byte;	//外设数据宽度 1字节 
    	DMA_InitStructure.DMA_MemoryDataSize 	= DMA_MemoryDataSize_Byte;		//存储器数据宽度 1字节
    	
    	DMA_InitStructure.DMA_Mode 				= DMA_Mode_Normal;			//正常模式,发送一次
    	DMA_InitStructure.DMA_Priority 			= DMA_Priority_Low;			//优先级 低
    	DMA_InitStructure.DMA_M2M 				= DMA_M2M_Enable;			//使能MTM
    	
    	DMA_Init(DMA1_Channel1, &DMA_InitStructure);	//结构体初始化
    	DMA_ClearFlag(DMA1_FLAG_TC1);	 				//清除对应标志位
    	DMA_Cmd(DMA1_Channel1, ENABLE);					//使能DMA1 通道1
    }
    
  • M2M传输函数
    uint8_t Buffercmp(const uint32_t *pBuffer1, uint32_t *pBuffer2, uint32_t BufferLen )
    {
    	while(BufferLen--)
    	{
    		if( *pBuffer1 !=  *pBuffer2)	//对应的两个源数组不相等,返回0
    			return 0;
    		pBuffer1++;						//递增两个数据源的地址指针
    		pBuffer2++;
    	}
    	return 1;							//完成判断 并且对应数据相对
    }	
    
  • 主函数程序设计
    //外部源数组、目标数组变量定义
    extern const uint32_t src_buf[BUF_SIZE];
    extern uint32_t des_buf[BUF_SIZE];
    int main(void)
    {	
    	
    	LED_Init();
    	Usart1_Init(115200);		//串口初始化
    	DMA_MTM_Init();				//M2M初始化																
    	Buffercmp(src_buf, des_buf, BUF_SIZE * 4);	//M2M传输数据
    	//串口打印目标数组数据
    	Usart_SendString(USART1,(unsigned char *)des_buf, BUF_SIZE * 4);
    	while(1)
    	{
    	
    	}
    }
    

实验二:内存到外设(DMA串口发送)

Cubemx工程配置

  • 时钟及串口配置(同上)
  • 串口DMA配置

Hal库程序设计及实现

  • 串口DMA发送函数解析

    HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size)
    

    参数解析

    参数解析
    返回值HAL_StatusTypeDef,HAL状态(OK,busy,ERROR,TIMEOUT
    UART_HandleTypeDef *huart串口句柄
    const uint8_t *pData待发送数据首地址
    uint16_t Size发送数据长度
  • DMA串口发送程序设计

    #include <string.h>
    
    //发送缓存
    unsigned char sendBuf[128] = "send by DMA\r\n";
    unsigned char sendBuf[128] = "send by DMA\r\n";
    
    //DMA发送数据,此过程不消耗CPU
    HAL_UART_Transmit_DMA(&huart1, sendBuf, strlen((const char *)sendBuf));
    

固件库程序设计

  • 参考博文:STM32—DMA功能讲解串口发送
  • dma.c dma结构体配置
    #define SEND_SIZE	16							//USART_DMA
    #define USART1_DR_ADDR 	(USART1_BASE + 0x04)	//串口发送寄存器
    
    //发送数据变量定义
    uint8_t send_buf[SEND_SIZE] = "0123456789ABCDEF";
    
    void USART1_DMATx_Init(void)
    {
    	DMA_InitTypeDef DMA_InitStructure;
    	
    	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	//使能DMA时钟
    	
    	DMA_InitStructure.DMA_MemoryBaseAddr 	= (uint32_t)send_buf;			//内存地址
    	DMA_InitStructure.DMA_PeripheralBaseAddr= (uint32_t)USART1_DR_ADDR;		//外设地址
    	DMA_InitStructure.DMA_DIR 				= DMA_DIR_PeripheralDST;		//传输方向
    	
    	DMA_InitStructure.DMA_BufferSize 		= SEND_SIZE ;					//传输数量
    	DMA_InitStructure.DMA_PeripheralInc 	= DMA_PeripheralInc_Disable;	//外设地址不变
    	DMA_InitStructure.DMA_MemoryInc 		= DMA_MemoryInc_Enable;			//存储器地址递增
    	DMA_InitStructure.DMA_PeripheralDataSize= DMA_PeripheralDataSize_Byte;	//外设数据宽度 1字节 
    	DMA_InitStructure.DMA_MemoryDataSize 	=	DMA_MemoryDataSize_Byte;	//存储器数据宽度 1字节
    	
    	DMA_InitStructure.DMA_Mode 				= DMA_Mode_Normal;				//正常模式,发送一次
    	DMA_InitStructure.DMA_Priority 			= DMA_Priority_Low;				//优先级 低
    	DMA_InitStructure.DMA_M2M 				= DMA_M2M_Disable;				//失能MTM
    	
    	DMA_Init(DMA1_Channel4, &DMA_InitStructure);	//结构体初始化
    	DMA_ClearFlag(DMA1_FLAG_TC4);	 				//清除对应标志位
    	DMA_Cmd(DMA1_Channel4, ENABLE);					//使能DMA1 通道4
    	
    }
    
  • main.c 使能串口DMA数据传输
    USART1_DMATx_Init();					//串口DMA发送初始化
    USART_DMACmd(USART1, USART_DMAReq_Tx , ENABLE );	//使能串口DMA发送请求
    

实验三:外设到内存(DMA串口接收)

DMA接收Cubemx工程配置

  • 时钟及串口配置(同上)
  • 串口DMA配置
  • 开启串口中断

串口DMA接收相关函数解析

  • 1使能IDLE空闲中断

    #define __HAL_UART_ENABLE_IT(__HANDLE__, __INTERRUPT__)   ............
    

    参数解析

    参数解析
    __HANDLE__串口句柄
    __INTERRUPT__需要使能的中断
    返回值
  • 串口DMA接收函数

    HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
    

    参数解析

    参数解析
    返回值HAL_StatusTypeDef,HAL状态(OK,busy,ERROR,TIMEOUT
    UART_HandleTypeDef *huart串口句柄
    uint8_t *pData接收缓存首地址
    uint16_t Size接收缓存长度
  • 获取串口 Flag的值

    #define __HAL_UART_GET_FLAG(__HANDLE__, __FLAG__) (((__HANDLE__)->Instance->SR & (__FLAG__)) == (__FLAG__))
    

    参数解析

    参数解析
    返回值FLAG的值(SET/RESET
    __HANDLE__串口句柄
    __FLAG__需要查看的FLAG
  • 清除串口IDLE标识

    #define __HAL_UART_CLEAR_IDLEFLAG(__HANDLE__) __HAL_UART_CLEAR_PEFLAG(__HANDLE__)
    
    参数解析
    __HANDLE__串口句柄
    返回值
  • 关闭串口DMA

    HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart)
    
    参数解析
    UART_HandleTypeDef *huart串口句柄
    返回值HAL_StatusTypeDef,HAL状态(OK,busy,ERROR,TIMEOUT
  • 获取未传输数据大小

    #define __HAL_DMA_GET_COUNTER(__HANDLE__) ((__HANDLE__)->Instance->CNDTR)
    
    参数解析
    __HANDLE__串口句柄
    返回值未传输数据大小

DMA串口接收Hal库代码实现

如何判断串口接收是否完成?如何知道串口收到数据的长度?
使用串口空闲中断(IDLE)!

  • 串口空闲时,触发空闲中断;
  • 空闲中断标志位由硬件置1,软件清零

利用串口空闲中断,可以用如下流程实现DMA控制的任意长数据接收:

  1. 使能IDLE空闲中断;
  2. 使能DMA接收中断;
  3. 收到串口接收中断,DMA不断传输数据到缓冲区;
  4. 一帧数据接收完毕,串口暂时空闲,触发串口空闲中断;
  5. 在中断服务函数中,清除中断标志位,关闭DMA传输(防止干扰);
  6. 计算刚才收到了多少个字节的数据。
  7. 处理缓冲区数据,开启DMA传输,开始下一帧接收
#define BUF_SIZE 128

//DMA接收缓存变量定义
unsigned char rcvBuf[BUF_SIZE] = {0};
unsigned char rcvLen = 0;		//接收字节数

main.c初始化
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);			//使能IDLE空闲中断
HAL_UART_Receive_DMA(&huart1, rcvBuf, BUF_SIZE);		//使能DMA接收中断	

//中断服务函数中,清除中断标志位,关闭DMA传输,计算数据接收长度并操作数据
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
	if( __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)  == SET )	// 判断IDLE标志位是否被置位)
  {
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);			//清除中断标志位
		HAL_UART_DMAStop(&huart1);					//关闭DMA传输
		rcvLen = BUF_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);		//计算收到的字节数
		
		//处理缓冲区数据 若程序复杂可立flag 在 while(1) 中处理
		HAL_UART_Transmit_DMA(&huart1,rcvBuf,rcvLen);	
		if(strstr((const char *)rcvBuf,"open") != NULL)
			HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_RESET);
		if(strstr((const char *)rcvBuf,"close") != NULL)
			HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_SET);
		
		HAL_UART_Receive_DMA(&huart1, rcvBuf, BUF_SIZE);	//开启DMA传输
	}	
  /* USER CODE END USART1_IRQn 1 */
}

DMA串口接收固件库程序设计

  • 参考博文1:STM32_串口的DMA接收
  • 参考博文2:STM32实现DMA接收串口数据
  • dma结构体配置
    //USART_DMA_R 接收缓存
    uint8_t receive_buf[16] ={'\0'};
    
    //USART1_DMA_Receive
    void USART1_DMARx_Init(void)
    {
    	DMA_InitTypeDef DMA_InitStructure;
    	
    	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	//使能DMA时钟
    	
    	DMA_InitStructure.DMA_MemoryBaseAddr 	 = (uint32_t)receive_buf;	//内存地址
    	DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t)USART1_DR_ADDR;	//外设地址
    	DMA_InitStructure.DMA_DIR 				 = DMA_DIR_PeripheralSRC;	//传输方向
    	
    	DMA_InitStructure.DMA_BufferSize 		 = 16;						   //传输数量
    	DMA_InitStructure.DMA_PeripheralInc 	 = DMA_PeripheralInc_Disable;  //外设地址不变
    	DMA_InitStructure.DMA_MemoryInc 		 = DMA_MemoryInc_Enable;	   //存储器地址递增
    	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据宽度 1字节 
    	DMA_InitStructure.DMA_MemoryDataSize 	 = DMA_MemoryDataSize_Byte;	  //存储器数据宽度 1字节
    	
    	DMA_InitStructure.DMA_Mode 			= DMA_Mode_Normal;		//循环接收
    	DMA_InitStructure.DMA_Priority 		= DMA_Priority_High;	//优先级 高
    	DMA_InitStructure.DMA_M2M 			= DMA_M2M_Disable;		//失能MTM
    	
    	DMA_Init(DMA1_Channel5, &DMA_InitStructure);	//结构体初始化
    	DMA_ClearFlag(DMA1_FLAG_TC5);	 				//清除对应标志位
    	DMA_Cmd(DMA1_Channel5, ENABLE);					//使能DMA1 通道5
    }
    
  • 主函数程序设计
    uint8_t DMARx_flag = 0;					//中断标志
    extern uint8_t receive_buf[128];		//外部USART_DMA 接收缓存
    int main()
    {
    	Usart1_Init(115200);				//串口初始化 115200
    	//USRAT_DMA
    	USART1_DMARx_Init();				//初始化DMA接收
    	USART_DMACmd(USART1, USART_DMAReq_Rx , 	ENABLE);//使能串口DMA接收请求
    	USART_ITConfig(USART1, USART_IT_IDLE,  ENABLE);	//使能空闲中断
    	while(1)
    	{
    		
    	}
    }
    
  • 串口中断程序设计
    void USART1_IRQHandler ( void ) 
    {
        u16 Usart1_Rec_Cnt = 0;
    
        if ( USART_GetITStatus ( USART1, USART_IT_IDLE ) != RESET )	//检查是否发生空闲中断
    	{
            USART1->SR;
            USART1->DR;					// 清USART_IT_IDLE标志
    		USART_ClearITPendingBit ( USART1, USART_IT_IDLE ); 	// 清除中断标志
            DMA_Cmd ( DMA1_Channel5, DISABLE );		//关闭DMA传输,进行数据处理,数据处理完再开启
     
            // 计算接收到的数据帧长度
            Usart1_Rec_Cnt = 16 - DMA_GetCurrDataCounter ( DMA1_Channel5);
            printf ( "The length is %d\r\n", Usart1_Rec_Cnt );
            printf ( "The data is %s", receive_buf );
    		Usart1_Rec_Cnt = 0;
    		memset(receive_buf,'\0',16);
    			
            DMA_SetCurrDataCounter( DMA1_Channel5, 16 );	//清除counter计数器
            DMA_Cmd ( DMA1_Channel5, ENABLE );
    			
    		//		DMARx_flag = 1;							//中断标志位
        }
    }
    

写在最后

  • 以上就是关于STM32单片机——DMA数据传输的相关理论及例程验证,欢迎评论区友好交流批评指正!!!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FPGA-结合协议时序实现UART收发器(六):仿真模块SIM_uart_drive_TB

FPGA-结合协议时序实现UART收发器&#xff08;六&#xff09;&#xff1a;仿真模块SIM_uart_drive_TB 仿真模块SIM_uart_drive_TB&#xff0c;仿真实现。 vivado联合modelsim进行仿真。 文章目录 FPGA-结合协议时序实现UART收发器&#xff08;六&#xff09;&#xff1a;仿真模…

2023-09-17 LeetCode每日一题(打家劫舍 II)

2023-09-17每日一题 一、题目编号 213. 打家劫舍 II二、题目链接 点击跳转到题目位置 三、题目描述 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋&#xff0c;每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 &#xff0c;这意味着第一个房屋和最后一个房…

C#,《小白学程序》第二十六课:大数乘法(BigInteger Multiply)的Toom-Cook 3算法及源程序

凑数的&#xff0c;仅供参考。 1 文本格式 /// <summary> /// 《小白学程序》第二十六课&#xff1a;大数&#xff08;BigInteger&#xff09;的Toom-Cook 3乘法 /// Toom-Cook 3-Way Multiplication /// </summary> /// <param name"a"></par…

如何隐藏windows10系统任务栏右下角的语言输入法图标?

勾选“使用桌面语言栏(如果可用)”&#xff0c;任务栏的输入法图标立刻消失

【Java基础夯实】我消化后的ThreadLocal是怎样的?

&#x1f9d1;‍&#x1f4bb;作者名称&#xff1a;DaenCode &#x1f3a4;作者简介&#xff1a;CSDN实力新星&#xff0c;后端开发两年经验&#xff0c;曾担任甲方技术代表&#xff0c;业余独自创办智源恩创网络科技工作室。会点点Java相关技术栈、帆软报表、低代码平台快速开…

面试题:jwt 是什么?java-jwt 呢?

文章目录 JWT概念JWT流程&#xff1a;JWT的构成JWT与开发语言JWT官网java-jwt产生加密Token解密Token获取负载信息并验证Token是否有效 JWT概念 JWT &#xff0c; 全写JSON Web Token, 是开放的行业标准RFC7591&#xff0c;用来实现端到端安全验证. 简单来说&#xff0c; 就是…

OpenCV Series : Target Box Outline Border

角点 P1 [0] (255, 000, 000) P2 [1] (000, 255, 000) P3 [2] (000, 000, 255) P4 [3] (000, 000, 000)垂直矩形框 rect cv2.minAreaRect(cnt)targetColor roi_colortargetThickness 1targetColor (255, 255, 255)if lineVerbose:if …

【斗破年番】紫研新形象,萧炎终成翻海印,救援月媚,三宗决战

Hello,小伙伴们&#xff0c;我是小郑继续为大家深度解析斗破年番。 斗破苍穹年番动画更新了&#xff0c;小医仙帅气回归&#xff0c;萧炎紫妍成功进入山谷闭关苦修&#xff0c;美杜莎女王守护没多久&#xff0c;就因蛇人族求救离开。从官方公布的最新预告来看&#xff0c;萧炎紫…

地图结构 | 详解八叉树Octomap原理与Rviz可视化

目录 0 专栏介绍1 点云地图的局限性2 八叉树基本原理3 Octovis可视化4 点云转化octomap5 ROS Rviz可视化 0 专栏介绍 &#x1f525;附C/Python/Matlab全套代码&#x1f525;课程设计、毕业设计、创新竞赛必备&#xff01;详细介绍全局规划(图搜索、采样法、智能算法等)&#x…

Web 器学习笔记(基础)

Filter 过滤器 概念&#xff1a;表示过滤器&#xff0c;是 JavaWeb 三大组件&#xff08;Servlet、Filter、Listener&#xff09;之一 作用&#xff1a;顾名思义可以过滤资源的请求&#xff0c;并实现特殊的需求 Filter 接口及它核心的 doFilter() 方法&#xff08;执行前就是…

JVM 第一章:Java运行时数据区

目录 一.了解JVM 1.1什么是JVM 1.2JRE/JDK/JVM 1.3JVM的整体结构 二.Java运行时数据区 2.1程序计数器(PC寄存器) 2.2Java虚拟机栈&#xff08;Java Virtual Machine Stacks&#xff09; 2.2.1栈帧的组成 2.2.2问题辨析 2.2.3逃逸分析 ①栈上分配 ②标量分析 ③同步…

深入探究Spring自动配置原理及SPI机制:实现灵活的插件化开发

文章目录 前言SpringBootApplication 注解AutoConfigurationPackage 注解AutoConfigurationImportSelector SPI 机制和 SpringFactoriesLoaderJDK 中的 SPI 机制SpringFactoriesLoader ConditionalOn 系列条件注解ConditionalOn 系列条件注解的示例ConditionalOn 系列条件注解的…

MySQL中如何识别低效的索引

我是一个目录 前言(可以跳过直接看正文)索引的基本原理索引设计的原则创建索引的原则 正文使用索引查询一定能提高查询的性能吗&#xff1f;怎样查看索引是否有高选择性&#xff1f;用一条SQL查看低效的索引 前言(可以跳过直接看正文) 索引的基本原理 索引用来快速地寻找那些…

学习分布式第一天(分布式系统原理和概念)

目录 分布式系统原理和概念 1.分布式系统&#xff1a; 单体架构&#xff1a; 垂直架构&#xff1a; 分布式架构&#xff1a; 2.分布式计算&#xff1a; 3.CAP 原理&#xff1a; 4.BASE 理论&#xff1a; 5.Paxos 算法&#xff1a; 6.Raft 算法&#xff1a; 分布式系统原…

【Transformer系列】深入浅出理解Transformer网络模型(综合篇)

一、参考资料 The Illustrated Transformer 图解Transformer&#xff08;完整版&#xff09; Attention Is All You Need: The Core Idea of the Transformer transformer 总结(超详细-初版) Transformer各层网络结构详解&#xff01;面试必备&#xff01;(附代码实现) 大语言…

zemax球差与消球差

基础设置&#xff1a; 效果&#xff1a; 光线光扇图&#xff1a; 可见存在球差&#xff08;具体分析看我的另一篇文章&#xff0c;专门介绍光线光扇图&#xff09; 弥散的像&#xff1a; 定量计算赛德尔像差系数&#xff1a; 矫正&#xff1a; 凹凸透镜补偿法、非球面校正球差…

线上论坛之单元测试

对线上论坛进行单元测试的测试报告 源码地址&#xff1a;https://gitee.com/coisini-thirty-three/forum 一、用户部分&#xff08;UserServiceImplTest&#xff09; 1.创建普通用户 测试名称 createNormalUser() 测试源码 Test void createNormalUser() { // 构造用户 User …

Linux 系统目录结构 终端

系统目录结构 Linux 或 Unix 操作系统中&#xff0c;所有文件和目录呈一个以根节点为始的倒置的树状结构。文件系统的最顶层是根目录&#xff0c;用 / 来表示根目录。在根目录之下的既可以是目录&#xff0c;也可以是文件&#xff0c;而每一个目录中又可以包含子目录文件。如此…

什么是函数式编程(functional programming)?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 函数式编程⭐ 核心概念⭐ 函数式编程示例⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前…

解决WSL2占用内存过多问题(Docker on WSL2: VmmemWSL)

解决WSL2占用内存过多问题&#xff08;Docker on WSL2: VmmemWSL&#xff09; 一、问题描述二、问题解决2.1 创建.wslconfig文件2.2 重启wsl2 一、问题描述 安装完WSL2后&#xff0c;又安装了Docker&#xff0c;使用了一段时间&#xff0c;发现电脑变卡&#xff0c;进一步查看…