【STM32标准库】USART+DMA

1.背景简介

没有使用DMA的USART,我们在前面已经讲过了。【STM32】USART串口通讯-CSDN博客。现在在该基础上我们加上DMA功能,仅使用DMA进行发送。

2.DMA_TX源码

#ifndef __BSP_USART_H
#define __BSP_USART_H

#ifdef __cplusplus
extern "C"{

#endif

#include "stm32f4xx.h"
#include "stdio.h"

#define LOGGER_USART              USART1
#define LOGGER_USART_BAUDRATE     115200
#define LOGGER_USART_CLK          RCC_APB2Periph_USART1
#define LOGGER_USART_IRQHandler   USART1_IRQHandler
#define LOGGER_USART_IRQ          USART1_IRQn

#define USART1_TX_PIN             GPIO_Pin_9
#define USART1_TX_GPIO_Port       GPIOA
#define USART1_TX_GPIO_CLK        RCC_AHB1Periph_GPIOA
#define USART1_TX_AF              GPIO_AF_USART1
#define USART1_TX_SOURCE          GPIO_PinSource9

#define USART1_RX_PIN             GPIO_Pin_10
#define USART1_RX_GPIO_Port       GPIOA
#define USART1_RX_GPIO_CLK        RCC_AHB1Periph_GPIOA
#define USART1_RX_AF              GPIO_AF_USART1
#define USART1_RX_SOURCE          GPIO_PinSource10


//usart1_tx只能使用到DMA2_Stream7  Channel_4
#define USART1_TX_DMA_STREAM               DMA2_Stream7
#define USART1_TX_DMA_CHANNEL              DMA_Channel_4
#define USART1_TX_DMA_STREAM_CLK           RCC_AHB1Periph_DMA2
#define USART1_TX_DMA_IT_TCIF              DMA_IT_TCIF7
#define USART1_TX_DMA_IT_HTIF              DMA_IT_HTIF7
#define USART1_TX_DMA_FLAG_TCIF            DMA_FLAG_TCIF7
#define USART1_TX_DMA_FLAG_HTIF            DMA_FLAG_HTIF7
#define USART1_TX_DMA_STREAM_IRQn          DMA2_Stream7_IRQn
#define USART1_TX_DMA_STREAM_IRQHandler    DMA2_Stream7_IRQHandler

#define TX_BUFFER_SIZE                     32
#define USART1_TX_DR_BASE                  (USART1_BASE+0x04)

void Init_USART(void);
void Init_USART_DMA(void);
void USART_DMA_SEND(uint8_t* data,uint32_t size);

#ifdef __cplusplus
}
#endif

#endif


#include "bsp_usart.h"
#include "string.h"

void Init_USART(void)
{
	RCC_AHB1PeriphClockCmd(USART1_TX_GPIO_CLK|USART1_RX_GPIO_CLK,ENABLE);//使能GPIOA时钟
	RCC_APB2PeriphClockCmd(LOGGER_USART_CLK,ENABLE);//使能USART1时钟
	
    //USART1对应引脚复用映射
	GPIO_PinAFConfig(USART1_TX_GPIO_Port, USART1_TX_SOURCE,USART1_TX_AF);//PA9复用为USART1
	GPIO_PinAFConfig(USART1_RX_GPIO_Port, USART1_RX_SOURCE,USART1_RX_AF);//PA10复用为USART1
	
	//USART1端口配置
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Pin=USART1_TX_PIN;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;//复用功能
	GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;//推挽复用输出
	GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;//上拉
	GPIO_InitStruct.GPIO_Speed=GPIO_Fast_Speed;//速度50MHz
	GPIO_Init(USART1_TX_GPIO_Port,&GPIO_InitStruct);//初始化PA9
	
	GPIO_InitStruct.GPIO_Pin=USART1_RX_PIN;
	GPIO_Init(USART1_RX_GPIO_Port,&GPIO_InitStruct);//初始化PA10
		
	//配置USART参数
	USART_InitTypeDef USART_Init_Struct;
	USART_Init_Struct.USART_BaudRate=LOGGER_USART_BAUDRATE;
	USART_Init_Struct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
	USART_Init_Struct.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
	USART_Init_Struct.USART_Parity=USART_Parity_No;
	USART_Init_Struct.USART_StopBits=USART_StopBits_1;
	USART_Init_Struct.USART_WordLength=USART_WordLength_8b;
	USART_Init(LOGGER_USART,&USART_Init_Struct);
	
	//配置中断控制器并使能USART接收中断
	NVIC_InitTypeDef NVIC_Init_Struct;
	NVIC_Init_Struct.NVIC_IRQChannel=LOGGER_USART_IRQ;
	NVIC_Init_Struct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init_Struct.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_Init_Struct.NVIC_IRQChannelSubPriority=0;
	NVIC_Init(&NVIC_Init_Struct);
	USART_ITConfig(LOGGER_USART,USART_IT_RXNE,ENABLE);
	
	//使能USART
	USART_Cmd(LOGGER_USART,ENABLE);
	
	//使能USART_DMA
	USART_DMACmd(LOGGER_USART,USART_DMAReq_Tx,ENABLE);
}

uint8_t USART_TX_BUFFER[TX_BUFFER_SIZE]={0};

void USART_DMA_SEND(uint8_t* data,uint32_t size)
{
	while (DMA_GetCmdStatus(USART1_TX_DMA_STREAM) != DISABLE) {
    }

	memcpy(USART_TX_BUFFER,data,size);
  	
	DMA_Cmd(USART1_TX_DMA_STREAM,DISABLE);
	DMA_SetCurrDataCounter(USART1_TX_DMA_STREAM,size);
	DMA_Cmd(USART1_TX_DMA_STREAM,ENABLE);
}

void Init_USART_DMA(void)
{
	/* 使能DMA时钟 */
    RCC_AHB1PeriphClockCmd(USART1_TX_DMA_STREAM_CLK, ENABLE);
	
	 /* 复位初始化DMA数据流 */
    DMA_DeInit(USART1_TX_DMA_STREAM);

    /* 确保DMA数据流复位完成 */
    while (DMA_GetCmdStatus(USART1_TX_DMA_STREAM) != DISABLE) {
    }
	
	DMA_InitTypeDef  DMA_InitStructure;
	DMA_InitStructure.DMA_BufferSize=TX_BUFFER_SIZE;//一次DMA事务传输的数据个数
	DMA_InitStructure.DMA_Channel=USART1_TX_DMA_CHANNEL;
	DMA_InitStructure.DMA_DIR=DMA_DIR_MemoryToPeripheral;
	DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable;
	DMA_InitStructure.DMA_FIFOThreshold=DMA_FIFOThreshold_Full;
	DMA_InitStructure.DMA_Memory0BaseAddr= (uint32_t)USART_TX_BUFFER;
	DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;
	DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;
	DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)USART1_TX_DR_BASE;
	DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;
	DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_Priority=DMA_Priority_Low;
	DMA_Init(USART1_TX_DMA_STREAM,&DMA_InitStructure);
	
	DMA_ITConfig(USART1_TX_DMA_STREAM,DMA_IT_TC|DMA_IT_HT,ENABLE);
	
	DMA_ClearITPendingBit(USART1_TX_DMA_STREAM,USART1_TX_DMA_IT_TCIF);
	
	//配置中断控制器并使能中断
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel=USART1_TX_DMA_STREAM_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;
	NVIC_Init(&NVIC_InitStruct);
	
	//这里没有使能DMA,而是在给buffer赋值后再使能
}

void USART1_TX_DMA_STREAM_IRQHandler(void)
{
	if(SET==DMA_GetITStatus(USART1_TX_DMA_STREAM,USART1_TX_DMA_IT_HTIF))
	{
		//half transfer complete
		//printf("half transfer\r\n");
		DMA_ClearITPendingBit(USART1_TX_DMA_STREAM,USART1_TX_DMA_IT_HTIF);
	}
	else if(SET==DMA_GetITStatus(USART1_TX_DMA_STREAM,USART1_TX_DMA_IT_TCIF))
	{
		//transfer complete
		//printf("transfer complete\r\n");
		DMA_ClearITPendingBit(USART1_TX_DMA_STREAM,USART1_TX_DMA_IT_TCIF);
	}
}

总结:

  1. 这里我们固定了存储器地址,然后需要串口发送的数据都拷贝到这个地址上。DMA模式也是正常模式,所以发送完了后会自动结束。
  2. 我们可以固定DMA发送长度,如果想每次发送实际的长度,我们可以进行修改,DMA_SetCurrDataCounter。但是需要在设置DMA DISABLE(DMA_Cmd函数)的时候才可以配置。
  3. 在DMA初始化的时候,我们没有使能(DMA_Cmd函数),而是在配置好数据后使能的。
  4. 每一次发送数据的时候,需要确认DMA的状态是否还在发送数据。因为可能上一次还在发送数据时,你再次调用发送函数了。
  5. 外设的地址,我们需要查看源码。串口需要查看其结构体定义,其中Data register就是。或者用这种方式也行#define USART1_TX_DR_BASE (&USART1->DR) //(USART1_BASE+0x04)
  6. 配置USART的时候,需要配置USART DMA使能(有TX和RX)。

3.DMA_RX源码

先说一下思路,配置DMA_RX的时候应该是收一个固定的长度,因为你没有办法知道发送的长度是多少。USART_DMA_RX的工作原理大概理解为,当有数据到USART->DR的时候,会触发RXNE事件,这个时候DMA会自动将DR的数据搬运到存储器,否则就等待。所以,我们就在USART_IT_RXNE中断中去读取存储器的数据吗?

个人理解是不行的,实际实验结果也是不行的。因为RXNE中断产生的时候,DMA才开始搬运DR到存储器。

那我们应该在DMA_IT_TC中断服务函数中去读存储器的值吧?其实也不行,因为大概率串口接收的数据不会等于USART_DMA_RX设置的长度,所以不会进入该中断。

我们应该在USART_IT_IDLE中断服务函数中去读取存储器的值。

串口的空闲中断:检测到空闲线路的时候会产生中断,那么何为空闲线路?我们发一堆数据过去,连续的两个数据中肯定有时间间隔,很明显在这段时间内并不叫空闲;空闲中断其实也叫帧中断,即****在总线上在一个字节的时间内没有再次接收到数据****,那么此时就会产生中断,即空闲中断。

然后,在串口空闲中断函数中,我们读到存储器数据后,其实USART_DMA_RX的接收事务还未完成,因为它还没有收够足够的长度,如果下次还有数据,那么就是继续往存储器中写入。但是这样就会造成前一次接收的数据还存在,所以,我们得恢复USART_DMA_RX的接收长度为原大小。然后最好得设置为循环模式,这样我们就不用管收满后DMA重启的情况。

#include "bsp_usart.h"
#include "string.h"

uint8_t USART_TX_BUFFER[TX_BUFFER_SIZE]={0};
uint8_t USART_RX_BUFFER[RX_BUFFER_SIZE]={0};

void Init_USART(void)
{
	RCC_AHB1PeriphClockCmd(USART1_TX_GPIO_CLK|USART1_RX_GPIO_CLK,ENABLE);//使能GPIOA时钟
	RCC_APB2PeriphClockCmd(LOGGER_USART_CLK,ENABLE);//使能USART1时钟
	
    //USART1对应引脚复用映射
	GPIO_PinAFConfig(USART1_TX_GPIO_Port, USART1_TX_SOURCE,USART1_TX_AF);//PA9复用为USART1
	GPIO_PinAFConfig(USART1_RX_GPIO_Port, USART1_RX_SOURCE,USART1_RX_AF);//PA10复用为USART1
	
	//USART1端口配置
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Pin=USART1_TX_PIN;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;//复用功能
	GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;//推挽复用输出
	GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;//上拉
	GPIO_InitStruct.GPIO_Speed=GPIO_Fast_Speed;//速度50MHz
	GPIO_Init(USART1_TX_GPIO_Port,&GPIO_InitStruct);//初始化PA9
	
	GPIO_InitStruct.GPIO_Pin=USART1_RX_PIN;
	GPIO_Init(USART1_RX_GPIO_Port,&GPIO_InitStruct);//初始化PA10
		
	//配置USART参数
	USART_InitTypeDef USART_Init_Struct;
	USART_Init_Struct.USART_BaudRate=LOGGER_USART_BAUDRATE;
	USART_Init_Struct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
	USART_Init_Struct.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
	USART_Init_Struct.USART_Parity=USART_Parity_No;
	USART_Init_Struct.USART_StopBits=USART_StopBits_1;
	USART_Init_Struct.USART_WordLength=USART_WordLength_8b;
	USART_Init(LOGGER_USART,&USART_Init_Struct);
	
	//配置中断控制器并使能USART接收中断
	NVIC_InitTypeDef NVIC_Init_Struct;
	NVIC_Init_Struct.NVIC_IRQChannel=LOGGER_USART_IRQ;
	NVIC_Init_Struct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init_Struct.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_Init_Struct.NVIC_IRQChannelSubPriority=0;
	NVIC_Init(&NVIC_Init_Struct);
	USART_ITConfig(LOGGER_USART,USART_IT_IDLE,ENABLE);
	
	//使能USART
	USART_Cmd(LOGGER_USART,ENABLE);
	
	//使能USART_DMA
	USART_DMACmd(LOGGER_USART,USART_DMAReq_Tx|USART_DMAReq_Rx,ENABLE);
}

void LOGGER_USART_IRQHandler(void)
{
	if(SET==USART_GetITStatus(LOGGER_USART,USART_IT_IDLE))
	{
		//我们配置DMA_RX的长度是32,
		//但是如果收到的实际数据较短,也可以收到,这里也会触发,但是DMA_RX应该还在等待中,没有结束
		//下次如果还有数据来的话,DMA会继续收,还是会存放在RX_BUFFER,但是不是从首地址。知道收到的数据长度为32了,才会结束这一次的DMA_RX事务。
		USART_DMA_SEND(USART_RX_BUFFER,RX_BUFFER_SIZE);
			
		DMA_Cmd(USART1_RX_DMA_STREAM,DISABLE);
	    DMA_SetCurrDataCounter(USART1_RX_DMA_STREAM,RX_BUFFER_SIZE);
	    DMA_Cmd(USART1_RX_DMA_STREAM,ENABLE);
		USART_ReceiveData(LOGGER_USART);//清除USART_IT_IDLE中断标志位
	}
}

//重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
    /* 发送一个字节数据到串口 */
    USART_SendData(LOGGER_USART, (uint8_t) ch);

    /* 等待发送完毕 */
    while (USART_GetFlagStatus(LOGGER_USART, USART_FLAG_TXE) == RESET);

    return (ch);
}


void USART_DMA_SEND(uint8_t* data,uint32_t size)
{
	while (DMA_GetCmdStatus(USART1_TX_DMA_STREAM) != DISABLE) {
    }

	memcpy(USART_TX_BUFFER,data,size);
  	
	DMA_Cmd(USART1_TX_DMA_STREAM,DISABLE);
	DMA_SetCurrDataCounter(USART1_TX_DMA_STREAM,size);
	DMA_Cmd(USART1_TX_DMA_STREAM,ENABLE);
}

void Init_USART_DMA(void)
{
	/* 使能DMA时钟 */
    RCC_AHB1PeriphClockCmd(USART1_TX_DMA_STREAM_CLK, ENABLE);
	RCC_AHB1PeriphClockCmd(USART1_RX_DMA_STREAM_CLK, ENABLE);
	
	 /* 复位初始化DMA数据流 */
    DMA_DeInit(USART1_TX_DMA_STREAM);

    /* 确保DMA数据流复位完成 */
    while (DMA_GetCmdStatus(USART1_TX_DMA_STREAM) != DISABLE) {
    }
	
	DMA_InitTypeDef  DMA_InitStructure;
	DMA_InitStructure.DMA_BufferSize=TX_BUFFER_SIZE;//一次DMA事务传输的数据个数
	DMA_InitStructure.DMA_Channel=USART1_TX_DMA_CHANNEL;
	DMA_InitStructure.DMA_DIR=DMA_DIR_MemoryToPeripheral;
	DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable;
	DMA_InitStructure.DMA_FIFOThreshold=DMA_FIFOThreshold_Full;
	DMA_InitStructure.DMA_Memory0BaseAddr= (uint32_t)USART_TX_BUFFER;
	DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;
	DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;
	DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)USART1_TX_DR_BASE;
	DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;
	DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_Priority=DMA_Priority_Low;
	DMA_Init(USART1_TX_DMA_STREAM,&DMA_InitStructure);
	
	DMA_ITConfig(USART1_TX_DMA_STREAM,DMA_IT_TC|DMA_IT_HT,ENABLE);
	
	DMA_ClearITPendingBit(USART1_TX_DMA_STREAM,USART1_TX_DMA_IT_TCIF);
	
	//配置中断控制器并使能中断
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel=USART1_TX_DMA_STREAM_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;
	NVIC_Init(&NVIC_InitStruct);
	//这里没有使能DMA,而是在给buffer赋值后再使能
	
	
	 /* 复位初始化DMA数据流 */
    DMA_DeInit(USART1_RX_DMA_STREAM);

    /* 确保DMA数据流复位完成 */
    while (DMA_GetCmdStatus(USART1_RX_DMA_STREAM) != DISABLE) {
    }
	DMA_InitTypeDef  RX_DMA_InitStructure;
	RX_DMA_InitStructure.DMA_BufferSize=RX_BUFFER_SIZE;//一次DMA事务传输的数据个数
	RX_DMA_InitStructure.DMA_Channel=USART1_RX_DMA_CHANNEL;
	RX_DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralToMemory;
	RX_DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable;
	RX_DMA_InitStructure.DMA_FIFOThreshold=DMA_FIFOThreshold_Full;
	RX_DMA_InitStructure.DMA_Memory0BaseAddr= (uint32_t)USART_RX_BUFFER;
	RX_DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;
	RX_DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
	RX_DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
	RX_DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;
	RX_DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)USART1_RX_DR_BASE;
	RX_DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;
	RX_DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
	RX_DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
	RX_DMA_InitStructure.DMA_Priority=DMA_Priority_Low;
	DMA_Init(USART1_RX_DMA_STREAM,&RX_DMA_InitStructure);
	
//	DMA_ITConfig(USART1_RX_DMA_STREAM,DMA_IT_TC|DMA_IT_HT,ENABLE);
	
	DMA_ClearITPendingBit(USART1_RX_DMA_STREAM,USART1_RX_DMA_IT_TCIF);
	
	//配置中断控制器并使能中断
	NVIC_InitTypeDef RX_NVIC_InitStruct;
	RX_NVIC_InitStruct.NVIC_IRQChannel=USART1_RX_DMA_STREAM_IRQn;
	RX_NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
	RX_NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
	RX_NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;
	NVIC_Init(&RX_NVIC_InitStruct);
	DMA_Cmd(USART1_RX_DMA_STREAM,ENABLE);
}

void USART1_TX_DMA_STREAM_IRQHandler(void)
{
	if(SET==DMA_GetITStatus(USART1_TX_DMA_STREAM,USART1_TX_DMA_IT_HTIF))
	{
		//half transfer complete
		//printf("half transfer\r\n");
		DMA_ClearITPendingBit(USART1_TX_DMA_STREAM,USART1_TX_DMA_IT_HTIF);
	}
	else if(SET==DMA_GetITStatus(USART1_TX_DMA_STREAM,USART1_TX_DMA_IT_TCIF))
	{
		//transfer complete
		//printf("transfer complete\r\n");
		DMA_ClearITPendingBit(USART1_TX_DMA_STREAM,USART1_TX_DMA_IT_TCIF);
	}
}


还有一点:

  1. 关于清除USART_IT_IDLE中断标志,可以看源码注释,不能使用常规的函数clear。

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

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

相关文章

网络-calico问题分析

项目场景: calico-node日志提示 Failed to auto-detect host MTU - no interfaces matched the MTU interface pattern. To use auto-MTU, set mtuifacePattern to match your hosts’s interfaes. 同时,cali开头网卡的mtu是1440大小 原因分析&#xff…

扁鹊三兄弟的启示,探寻系统稳定的秘诀

一、稳定性的重要性 1. 公司收益的角度 从公司收益的视角审视,系统不稳定可能会引发直接损失。例如,当系统突然出现故障导致交易中断时,可能造成交易款项的紊乱、资金的滞留或损失,这不但会阻碍当前交易的顺利完成,还…

web安全的会议室管理系统-计算机毕业设计源码50331

目 录 摘要 1 绪论 1.1 开发背景与意义 1.2国内外研究现状 1.3 相关技术、工具简介 1.3.1 MySQL数据库的介绍 1.3.2 B/S架构的介绍 1.3.3 Java语言 1.3.4 SpringBoot框架 1.4论文结构与章节安排 2 会议室管理系统需求分析 2.1 可行性分析 2.1.1 技术可行性分析 2…

【Redis】真行,原来是这样啊! --Redis自动序列化和手动序列化的区别(存储结构、内存开销,实际写法)

对于Redis有两种序列化和反序列化的方式, 方式一: 一种是通过 注入RedisTemplate 对象,找个对象,通过配置类进行一定的配置,使得使用RedisTemplate 对象时,便会使用配置的那些键、值的序列化方式&#xff…

深度学习Week19——学习残差网络和ResNet50V2算法

文章目录 深度学习Week18——学习残差网络和ResNet50V2算法 一、前言 二、我的环境 三、论文解读 3.1 预激活设计 3.2 残差单元结构 四、模型复现 4.1 Residual Block 4.2 堆叠Residual Block 4.3. ResNet50V2架构复现 一、前言 🍨 本文为🔗365天深度学…

昇腾910B部署Qwen2-7B-Instruct进行流式输出【pytorch框架】NPU推理

目录 前情提要torch_npu框架mindsport框架mindnlp框架 下载模型国外国内 环境设置代码适配(非流式)MainBranch结果展示 代码适配(流式) 前情提要 torch_npu框架 官方未适配 mindsport框架 官方未适配 mindnlp框架 官方适配…

add_metrology_object_generic 添加测量模型对象。找两条直线,并计算两条线的夹角和两个线的总长度,转换成毫米单位

*添加测量模型对象 *将测量对象添加到测量模型中 *算子参数: *    MeasureHandle:输入测量模型的句柄; *    Shape:输入要测量对象的类型;默认值:‘circle’,参考值:‘circl…

淘宝扭蛋机小程序:打造新的扭蛋体验

扭蛋机行业近年来发展非常迅速,呈现出了明显的增长势头,深受年轻消费者的青睐。当下在消费市场中,年轻人占据了很大的份额,这也推动了扭蛋机市场的发展。如今,扭蛋机也正在向多个方向发展,不再局限于线下扭…

如何利用代理IP打造热门文章

作为内容创作者,我们都知道,有时候地理限制和访问障碍可能会成为我们获取新鲜素材和优质信息的障碍。使用代理IP,正是突破这些限制的好方法! 1. 无缝获取全球视野 如果你还在苦恼看不到其他地区的热点文章,你可以尝试…

保障信息资产:ISO 27001信息安全管理体系的重要性

在当今数字化和全球化的时代,信息安全已经成为企业成功和持续发展的关键因素之一。随着信息技术的快速发展和互联网的普及,企业面临着越来越多的信息安全威胁和挑战,如数据泄露、网络攻击、恶意软件等。为了有效应对这些威胁,企业…

docker集群部署主从mysql

搭建一个mysql集群,1主2从,使用docker容器 一、创建docker的mysql镜像 下次补上,因为现在很多网络不能直接pull,操作下次补上。 二、创建mysql容器 创建容器1 docker run -it -d --name mysql_1 -p 7001:3306 --net mynet --…

Astro新前端框架首次体验

Astro新前端框架首次体验 1、什么是Astro Astro是一个静态网站生成器的前端框架,它提供了一种新的开发方式和更好的性能体验,帮助开发者更快速地构建现代化的网站和应用程序。 简单来说就是:Astro这个是一个网站生成器,可以直接…

生成式人工智能如何改变软件开发:助手还是取代者?

生成式人工智能如何改变软件开发:助手还是取代者? 生成式人工智能(AIGC)正在引领软件开发领域的技术变革。从代码生成、错误检测到自动化测试,AI工具在提高开发效率的同时,也引发了对开发者职业前景的讨论…

标贝语音识别在智能会议系统的应用案例

语音识别是指将语音信号转换成文本或者其他数字信号形式的过程,随着人工智能在人们日常工作生活中的普及,语音识别技术也被广泛的应用在智能家居、智能会议、智能客服、智能驾驶等领域,以语音识别技术在智能会议系统中的应用为例,…

【读点论文】基于二维伽马函数的光照不均匀图像自适应校正算法

基于二维伽马函数的光照不均匀图像自适应校正算法 摘 要:提出了一种基于二维伽马函数的光照不均匀图像自适应校正算法.利用多尺度高斯函数提取出场景的光照分量,然后构造了一种二维伽马函数,并利用光照分量的分布特性调整二维伽马函数的参数,降低光照过强区域图像的亮度值,提高…

服务器U盘安装Centos 7时提示Warning:/dev/root does not exist

这是没有找到正确的镜像路径导致的,我们可以在命令行输入ls /dev看一下有哪些盘符 像图中红色圈起来的就是我插入U盘的盘符,大家的输几盘可能做了多个逻辑盘,这种情况下就可以先将U盘拔掉再ls /dev看一下和刚才相比少了那两个盘符&#xff0c…

Redis高级篇之最佳实践

Redis高级篇之最佳实践 今日内容 Redis键值设计批处理优化服务端优化集群最佳实践 1、Redis键值设计 1.1、优雅的key结构 Redis的Key虽然可以自定义,但最好遵循下面的几个最佳实践约定: 遵循基本格式:[业务名称]:[数据名]:[id]长度不超过…

空调计费系统是什么,你知道吗

空调计费系统是一种通过对使用空调的时间和能源消耗进行监测和计量来进行费用计算的系统。它广泛应用于各种场所,如家庭、办公室、商场等,为用户提供了方便、准确的能源使用管理和费用控制。 可实现功能 智能计费:中央空调分户计费系统通过智…

光电液位传感器在宠物洗澡机的应用

光电液位传感器在宠物洗澡机中的应用,为洗澡机的智能化管理提供了重要支持和保障。这种先进的传感技术不仅提升了设备的操作便捷性,还大幅度提高了洗澡过程的安全性和效率。 宠物洗澡机作为宠物护理的重要设备,其水位的控制至关重要。光电液…

SD16S1Y 符合GB2312标准16X16点阵汉字库芯片IC

一般概述 SD16S1Y是一款内含16x16点阵的汉字库芯片,支持GB2312国标简体汉字(含有国家信标委 合法授权)、ASCII字符。排列格式为竖置横排。用户通过字符内码,利用本手册提供的方法计算出 该字符点阵在芯片中的地址,可从该地址连续读出字…