Stm32_串口的帧(不定长)数据接收

目录标题

  • 前言
  • 1、串口中断接收固定帧头帧尾数据
    • 1.1、任务需求
    • 1.2、实现思路
    • 1.3、程序源码:
  • 2、串口中断接收+用定时器来判断帧结束
  • 3、串口中断接收数据+空闲中断
    • 3.1、串口的空闲中断
    • 3.2、实现思路
    • 3.3、程序源码
  • 4、串口的空闲中断+DMA转运
    • 4.1、DMA简介
    • 4.2、DMA模式
    • 4.3、DMA资源
    • 4.4、DMA主要特征
    • 4.5、实现思路
    • 4.6程序源码:
  • 报错及解决:

前言

使用串口传输数据时,因为串口是异步通信协议,所以我们需要去判断哪是一帧完整的数据,并进行数据的处理。


接收不定长的数据以下几个主要有以下方法:

  • 加固定的帧头和帧尾
  • 串口中断接收+用定时器来判断帧结束
  • 串口中断接收+利用串口空闲中断来判断帧结束

1、串口中断接收固定帧头帧尾数据

1.1、任务需求

1、PC端通过串口1发送给单片机一个有固定帧头帧尾的数据包。
2、单片机利用串口中断接收数据并判断帧头帧尾。
3、当识别到对应的帧头帧尾时,将接收到的数据再发送给PC端。
4、清除接收缓存。

1.2、实现思路

  • 1、使能相关时钟
    使能相关GPIO所在APB2总线的时钟
    使能串口所在APB2总线的时钟

  • 2、初始化串口
    配置数据位个数、停止位个数、校验位、波特率等

  • 3、初始化GPIO
    配置RX、TX对应GPIO口。

  • 4、初始化串口中断
    配置中断通道,中断优先级等

  • 4、使能串口中断

  • 5、使能串口

  • 6、编写中断服务程序:

    • ①判断接收到的数据是否是帧头
    • ②若是帧头则将数据写入到缓冲区;若不是则无视,等待下一个数据。
    • ③当有帧头后,不断在后面接收到的数据中找帧尾。找到了则说明这一帧数据接收完成了。
    • ④将这一帧数据再通过printf发送回PC端。
    • ⑤清楚缓冲区数据,将索引清零。

1.3、程序源码:

usart.h

#ifndef __SERIAL_H__
#define __SERIAL_H__

#include "stm32f10x.h"                  // Device header
#include <stdarg.h>
#include "stdio.h"
#include "string.h"

#define USART1_ENABLE  1          //使能串口1      
#define USART1_BAUDRATE 9600      //串口1波特率
#define USART1_INTERRUPT_ENABLE 1  //使能串口1中断

#define RECEIVE_BUF_MAX_SIZE 100  //单次最大接收字节数

typedef struct{
	uint8_t Buffer[RECEIVE_BUF_MAX_SIZE];
	uint16_t Lenth;
}usart_data;
void Serial_Init(void);//串口初始化
#endif

usart.c

void Serial_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_Structure;
	
#if USART1_ENABLE  
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//串口1在APB2总线上,串口2、3在APB1总线上
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;     //复用推挽输出
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;     //读。上拉输入
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	
	USART_InitStructure.USART_BaudRate= USART1_BAUDRATE;
	USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode= USART_Mode_Tx|USART_Mode_Rx;
	USART_InitStructure.USART_Parity= USART_Parity_No;
	USART_InitStructure.USART_StopBits= USART_StopBits_1;
	USART_InitStructure.USART_WordLength= USART_WordLength_8b;
	USART_Init(USART1,&USART_InitStructure);
#if USART1_INTERRUPT_ENABLE	
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//使能串口1接受中断
	
	NVIC_Structure.NVIC_IRQChannel=USART1_IRQn;
	NVIC_Structure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Structure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级
	NVIC_Structure.NVIC_IRQChannelSubPriority=3;//响应优先级
	NVIC_Init(&NVIC_Structure);
#endif
	USART_Cmd(USART1,ENABLE);
#endif
}

int fputc(int ch,FILE *f)        //重构定向,printf直接打印到串口1
{
	USART_SendData(USART1,ch);	
	while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE)==RESET);
	return ch;
}

//串口一中断处理函数
usart_data usart1_rxdata;

uint16_t data;
void USART1_IRQHandler(void)
{
	if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET) //若发生串口中断
	{
		usart1_rxdata.Buffer[usart1_rxdata.Lenth++] = USART_ReceiveData(USART1);
		if(usart1_rxdata.Buffer[0]!='h') //判断帧头
			usart1_rxdata.Lenth =0;
		if((usart1_rxdata.Buffer[0]=='h')&&(usart1_rxdata.Buffer[usart1_rxdata.Lenth-1]=='e'))
		//判断帧头帧尾
		{
			printf("rx_data:%s\r\n",usart1_rxdata.Buffer);//将接收到的一帧数据再发送回去,做验证
			memset(usart1_rxdata.Buffer,'\0',usart1_rxdata.Lenth);
			usart1_rxdata.Lenth = 0;
		}	
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清中断标志位
	}
}

2、串口中断接收+用定时器来判断帧结束

暂时不写

3、串口中断接收数据+空闲中断

3.1、串口的空闲中断

空闲中断USART_IT_IDLE,俗称帧中断,即第一帧数据接收完毕到第二帧数据开始接收期间存在一个空闲状态(就是没数据接收的状态),检测到此空闲状态后即执行中断程序。进入中断程序即意味着已经接收到一组完整帧数据,仅需及时对数据处理或将数据转移出缓冲区即可。
相较于上面的利用固定帧头和帧尾来判断完整数据帧,这种方法更为使用,通过利用空闲中断,对于没有固定帧头和帧尾的数据我们也能准确接收了。

3.2、实现思路

  • 1、使能相关时钟
    使能相关GPIO所在APB2总线的时钟
    使能串口所在APB2总线的时钟
  • 2、初始化串口
    配置数据位个数、停止位个数、校验位、波特率等
  • 3、初始化GPIO
    配置RX、TX对应GPIO口。
  • 4、初始化串口中断
    配置中断通道,中断优先级等
  • 4、使能串口中断
  • 5、使能串口的空闲中断
  • 5、使能串口
  • 6、编写中断服务程序:
    • ①判断中断类型:串口中断、串口的空闲中断
    • ②若是串口中断,就将接收的数据存入缓冲区。然后清除中断标志
    • ③若是串口的空闲中断,则说明这一帧数据接收完了后面就是数据处理了。
    • ④数据处理完后,就将数据缓冲区清除,将索引号清零。
    • ⑤清除串口空闲中断标志位(通过读串口的SR和DR寄存器)

3.3、程序源码

usart.h

#ifndef __SERIAL_H__
#define __SERIAL_H__

#include "stm32f10x.h"                  // Device header
#include <stdarg.h>
#include "stdio.h"
#include "string.h"

#define USART1_ENABLE  1                
#define USART1_BAUDRATE 9600
#define USART1_INTERRUPT_ENABLE 1
#define USART1_IDLE_INTERRUPT_ENABLE 1

#define RECEIVE_BUF_MAX_SIZE 100  //单次最大接收字节数

typedef struct{
   uint8_t Buffer[RECEIVE_BUF_MAX_SIZE];
   uint16_t Lenth;
}usart_data;

void Serial_Init(void);//串口初始化
#endif

usart.c

#include "Serial.h"
void Serial_Init(void)
{
   GPIO_InitTypeDef GPIO_InitStructure;
   USART_InitTypeDef USART_InitStructure;
   NVIC_InitTypeDef NVIC_Structure;
   
#if USART1_ENABLE  
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//串口1在APB2总线上,串口2、3在APB1总线上
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
   
   
   GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;     //复用推挽输出
   GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
   GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
   GPIO_Init(GPIOA,&GPIO_InitStructure);
   
   GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;     //读。上拉输入
   GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
   GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
   GPIO_Init(GPIOA,&GPIO_InitStructure);
   
   
   USART_InitStructure.USART_BaudRate= USART1_BAUDRATE;
   USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None;
   USART_InitStructure.USART_Mode= USART_Mode_Tx|USART_Mode_Rx;
   USART_InitStructure.USART_Parity= USART_Parity_No;
   USART_InitStructure.USART_StopBits= USART_StopBits_1;
   USART_InitStructure.USART_WordLength= USART_WordLength_8b;
   USART_Init(USART1,&USART_InitStructure);
   
#if USART1_INTERRUPT_ENABLE	
  
   USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//使能串口1接受中断
   
   NVIC_Structure.NVIC_IRQChannel=USART1_IRQn;
   NVIC_Structure.NVIC_IRQChannelCmd=ENABLE;
   NVIC_Structure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级
   NVIC_Structure.NVIC_IRQChannelSubPriority=3;//响应优先级
   NVIC_Init(&NVIC_Structure);

#if USART1_IDLE_INTERRUPT_ENABLE  
   USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);//使能串口1的空闲中断
#endif

#endif
   USART_Cmd(USART1,ENABLE);
#endif
}
//=================================================================
int fputc(int ch,FILE *f)        //重构定向,printf直接打印到串口1
{
   Serial_Sendbyte(USART1,ch);
   return ch;
}

//串口一中断
usart_data usart1_rxdata;

uint16_t data;
void USART1_IRQHandler(void)
{
   uint16_t clear;
   if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)
   {
   	usart1_rxdata.Buffer[usart1_rxdata.Lenth++] = USART_ReceiveData(USART1);
   	if(usart1_rxdata.Lenth>RECEIVE_BUF_MAX_SIZE)
   		usart1_rxdata.Lenth =0;
   	USART_ClearITPendingBit(USART1,USART_IT_RXNE);
   }
   else if(USART_GetITStatus(USART1,USART_IT_IDLE)==SET)//串口空闲中断
   {
   	printf("rx_data:%s\r\n",usart1_rxdata.Buffer);
   	memset(usart1_rxdata.Buffer,'\0',usart1_rxdata.Lenth);
   	usart1_rxdata.Lenth = 0;
   	clear = USART1->SR;
   	clear = USART1->DR;
   }
   
}

4、串口的空闲中断+DMA转运

4.1、DMA简介

直接存储器访问(Direct Memory Access),简称DMA。DMA是CPU一个用于数据从一个地址空间到另一地址空间“搬运”(拷贝)的组件,数据拷贝过程不需CPU干预,数据拷贝结束则通知CPU处理。因此,大量数据拷贝时,使用DMA可以释放CPU资源。

4.2、DMA模式

DMA数据拷贝过程,典型的有:
(1)内存—>内存,内存间拷贝;
(2)外设—>内存,如uart、spi、i2c等总线接收数据过程;
(3)内存—>外设,如uart、spi、i2c等总线发送数据过程。

4.3、DMA资源

STM32F1系列的MCU有两个DMA控制器(DMA2只存在于大容量产品中),DMA1有7个通道,DMA2有5个通道,每个通道专门用来管理来自于一个或者多个外设对存储器的访问请求。还有一个仲裁器来协调各个DMA请求的优先权。
在这里插入图片描述
在这里插入图片描述

4.4、DMA主要特征

  • 每个通道都直接连接专用的硬件 DMA 请求,每个通道都同样支持软件触发。这些功能通过软件来配置。
  • 在同一个 DMA 模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),优先权设置相等时由硬件决定(请求 0 优先于请求 1 ,依此类推,可以参考STM32数据手册)。
  • 独立的源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。
  • 支持循环的缓冲器管理(会把原来的数据覆盖)。
  • 每个通道都有 3 个事件标志(DMA 半传输, DMA 传输完成和 DMA 传输出错),这 3 个事件标志逻辑或成为一个单独的中断请求。
  • 存储器和存储器间的传输(仅 DMA2 可以)。
  • 外设和存储器、存储器和外设之间的传输
  • 闪存、SRAM 、外设的 SRAM 、APB1 、APB2 和 AHB 外设均可作为访问的源和目标。
  • 可编程的数据传输数目:最大为65535。

高波特率传输场景下,串口非常有必要使用DMA。

4.5、实现思路

  • 1、使能相关时钟
    使能相关GPIO所在APB2总线的时钟
    使能串口所在APB2总线的时钟
    使能DMA1时钟
  • 2、初始化串口
    配置数据位个数、停止位个数、校验位、波特率等
  • 3、初始化GPIO
    配置RX、TX对应GPIO口。
  • 4、初始化串口空闲中断
    配置中断通道,中断优先级等
  • 5、使能串口的空闲中断
  • 6、配置初始化DMA1。
  • 7、使能串口1的DMA接收;使能DMA1的TX通道(DMA1_Channel4)
  • 8、使能串口
  • 9、编写中断服务程序:
    • ①判断中断类型:串口的空闲中断
    • ②清除串口空闲中断标志位(通过读串口的SR和DR寄存器)
    • ③关闭DMA通道
    • ④进行数据处理(置标志位等)
    • ⑤重新设置 DMA 传输数据长度
    • ⑥使能DMA通道

4.6程序源码:

usart.h

#ifndef __SERIAL_H__
#define __SERIAL_H__

#include "stm32f10x.h"                  // Device header
#include <stdarg.h>
#include "stdio.h"
#include "string.h"

#define USART1_ENABLE  1                
#define USART1_BAUDRATE 9600
#define USART1_INTERRUPT_ENABLE 1
#define USART1_IDLE_INTERRUPT_ENABLE 1
#define USART1_DMA_TX_ENABLE 0
#define USART1_DMA_RX_ENABLE 1

#define USART_BUF_MAX_SIZE 100  //单次最大接收字节数

typedef struct{
	uint8_t Buffer[USART_BUF_MAX_SIZE];
	uint16_t Lenth;
}usart_data;

void Serial_Init(void);//串口初始化
#endif

usart.c

#include "Serial.h"



usart_data usart1_rxdata;
usart_data usart_txdata;

void Serial_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_Structure;
	DMA_InitTypeDef DMA_InitStructure;
#if USART1_ENABLE  
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//串口1在APB2总线上,串口2、3在APB1总线上
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;     //复用推挽输出
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;     //读。上拉输入
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	
	USART_InitStructure.USART_BaudRate= USART1_BAUDRATE;
	USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode= USART_Mode_Tx|USART_Mode_Rx;
	USART_InitStructure.USART_Parity= USART_Parity_No;
	USART_InitStructure.USART_StopBits= USART_StopBits_1;
	USART_InitStructure.USART_WordLength= USART_WordLength_8b;
	USART_Init(USART1,&USART_InitStructure);
	
#if USART1_INTERRUPT_ENABLE	|USART1_IDLE_INTERRUPT_ENABLE
   
	NVIC_Structure.NVIC_IRQChannel=USART1_IRQn;
	NVIC_Structure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Structure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级
	NVIC_Structure.NVIC_IRQChannelSubPriority=3;//响应优先级
	NVIC_Init(&NVIC_Structure);
#if USART1_INTERRUPT_ENABLE
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//使能串口1接受中断
#endif 

#if USART1_IDLE_INTERRUPT_ENABLE  
	USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);//使能串口1的空闲中断
#endif

#endif

#if USART1_DMA_TX_ENABLE
	/*Usart1_TX_DMA_config,从存储区到USART1->DR*/
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

	DMA_DeInit(DMA1_Channel4);
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR);   //外设站点起始地址
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设站点地址不自增
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)usart_txdata.Buffer;//存储器站点起始地址
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器站点自增
	
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;    //存储器站点到外设站点   //传输方向
	DMA_InitStructure.DMA_BufferSize = USART_BUF_MAX_SIZE;//缓冲区大小,传输计数器
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //普通模式,不循环
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //失能(不是存储器到存储器)
	DMA_InitStructure.DMA_Priority = DMA_Priority_High; //优先级
	DMA_Init(DMA1_Channel4, &DMA_InitStructure);
	
	USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE); //使能串口1的DMA发送
	
	DMA_Cmd(DMA1_Channel4,ENABLE); //使能DMA1的TX通道(DMA1_Channel4)
	
#endif
#if USART1_DMA_RX_ENABLE
	/*Usart1_RX_DMA_config,从USART1->DR到存储区*/
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

	DMA_DeInit(DMA1_Channel5);
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR);   //外设站点起始地址
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设站点地址不自增
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)usart1_rxdata.Buffer;//存储器站点起始地址
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器站点自增
	
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;    //外设站点到存储器站点   //传输方向
	DMA_InitStructure.DMA_BufferSize = USART_BUF_MAX_SIZE;//缓冲区大小,传输计数器
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //普通模式,不循环
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //失能(不是存储器到存储器)
	DMA_InitStructure.DMA_Priority = DMA_Priority_High; //优先级
	DMA_Init(DMA1_Channel5, &DMA_InitStructure);
	
	USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //使能串口1的DMA接收

	DMA_Cmd(DMA1_Channel5,ENABLE); //使能DMA1的TX通道(DMA1_Channel4)
	
#endif

	USART_Cmd(USART1,ENABLE);
#endif
}

//串口一中断
void USART1_IRQHandler(void)
{
	uint16_t clear;
	if(USART_GetITStatus(USART1,USART_IT_IDLE)==SET)
	{
		clear = USART1->SR;
		clear = USART1->DR;
		DMA_Cmd(DMA1_Channel5, DISABLE);  // 关闭 DMA 通道
		usart1_rxdata.Lenth = sizeof(usart1_rxdata.Buffer) - DMA_GetCurrDataCounter(DMA1_Channel5);  // 计算接收到的数据长度
		printf("rx_data:%s\r\n",usart1_rxdata.Buffer);
		memset(usart1_rxdata.Buffer,'\0',usart1_rxdata.Lenth);
		DMA_SetCurrDataCounter(DMA1_Channel5, sizeof(usart1_rxdata.Buffer));  // 重新设置 DMA 传输数据长度
		DMA_Cmd(DMA1_Channel5, ENABLE);  // 使能 DMA 通道
	}
	
}

报错及解决:

int fputc(int ch,FILE *f)        //重构定向,printf直接打印到串口1
{
	USART_SendData(USART1,ch);	
	while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE)==RESET);
	return ch;
}

我们在使用上面的程序进行printf重构定向时,需要注意以下两点:
1、在“魔法棒”—>"Target"中,将”USB Micro LIB“勾选上,否则会出现不能正常打印甚至单片机直接进入硬件错误中断宕机的情况。
在这里插入图片描述

2、需要添加头文件 #include “stdio.h”,否则会出现报错“error: unknown type name “FILE” ”。
在这里插入图片描述

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

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

相关文章

【Gradle】mac环境安装Gradle及配置

官网安装说明&#xff1a;Gradle | Installation 由于Gradle运行依赖jvm&#xff0c;所以事先需要安装jdk&#xff0c;并确认你的jdk版本和gradle版本要求的对应关系&#xff0c;这个官网上有说明&#xff0c;但是我试了一下不太准确&#xff0c;供参考&#xff0c;链接如下&a…

CleanMyMac X4.15.0最新官方和谐版下载

Mac系统进行文件清理&#xff0c;一般是直接将文件拖动入“废纸篓”回收站中&#xff0c;然后通过清理回收站&#xff0c;就完成了一次文件清理的操作&#xff0c;但是这么做并无法保证文件被彻底删除了&#xff0c;有些文件通过一些安全恢复手段依旧是可以恢复的&#xff0c;那…

【算法】约瑟夫环

约瑟夫问题是个有名的问题&#xff1a;N个人围成一圈&#xff0c;从第一个开始报数&#xff0c;第M个将被杀掉&#xff0c;最后剩下一个&#xff0c;其余人都将被杀掉。例如N6&#xff0c;M5&#xff0c;被杀掉的顺序是&#xff1a;5&#xff0c;4&#xff0c;6&#xff0c;2&a…

【FPGA图像处理实战】- 图像处理前景如何?就业前景如何?

图像处理是FPGA应用的主要领域之一&#xff0c;图像处理数据量特别大且对实时性处理要求高的场景&#xff0c;这恰好能发挥FPGA流水线可实时处理的优势。 那么FPGA图像处理的前景如何&#xff1f; 一、FPGA开发&#xff08;图像处理&#xff09;招聘就业情况 看FPGA图像处理…

docker基本管理和相关概念

1、docker是什么&#xff1f; docker是开源的应用容器引擎。基于go语言开发的&#xff0c;运行在Linux系统当中开源轻量级的“虚拟机”。 docker可以在一台主机上轻松的为任何应用创建一个轻量级的&#xff0c;可移植的&#xff0c;自给自足的容器。docker的宿主机是Linux系统…

2024年江苏省职业院校技能大赛 信息安全管理与评估 第二阶段教师组 (样卷)

2024年江苏省职业院校技能大赛 信息安全管理与评估 第二阶段教师组 (样卷) 项目竞赛样题 本文件为信息安全管理与评估项目竞赛-第二阶段样题&#xff0c;内容包括&#xff1a;网络安全事件响应、数字取证调查、应用程序安全。 本次比赛时间为180分钟。 介绍 GeekSec专注技能竞…

visual Studio MFC 平台实现拉普拉斯和拉普拉斯与直方图均衡化与中值滤波相结合实现比较

拉普拉斯变换的原理与应用 本文使用visual Studio MFC 平台实现图像增强中的拉普拉斯变换&#xff0c;同时拉普拉斯一般不会单独使用&#xff0c;与其他平滑操作相结合&#xff0c;本文使用了拉普拉斯与直方图均衡化以及与中值滤波相结合&#xff0c;也对三种方式进行了对比 关…

MIT6S081-Lab2总结

大家好&#xff0c;我叫徐锦桐&#xff0c;个人博客地址为www.xujintong.com&#xff0c;github地址为https://github.com/xjintong。平时记录一下学习计算机过程中获取的知识&#xff0c;还有日常折腾的经验&#xff0c;欢迎大家访问。 Lab2就是了解一下xv6的系统调用流程&…

Python 进阶(十三):JSON 序列化和反序列化(json 模块)

大家好&#xff0c;我是水滴~~ 本篇文章主要介绍json模块的功能&#xff0c;包括将Python对象序列化到文件、将Python对象序列化为字符串、序列化时类型的对照表、将文件中JSON数据反序列化为Python对象&#xff0c;将JSON字符串反序列化为Python对象、反序列化时类型的对照表…

Kafka使用指南

Kafka简介架构设计Kafka的架构设计关键概念Kafka的架构设计关键机制 Partition介绍Partition工作机制 应用场景ACK机制介绍ACK机制原理ACK机制对性能的影响ACK控制粒度Kafka分区数对集群性能影响调整分区优化集群性能拓展Kafka数据全局有序 Kafka简介 Kafka是由Apache软件基金…

Spring Boot学习随笔-SpringBoot的引言,回顾传统SSM开发

学习视频&#xff1a;【编程不良人】2021年SpringBoot最新最全教程 第一章、传统SSM开发回顾以及问题 Spring SpringMVC Mybatis SSM 实现一个简单功能 员工添加、查询… SSM项目简单实现 项目 需求分析 —>概要设计 —>&#xff08;库表设计&#xff09; —> 详细…

Linux进程解析(冯诺依曼体系结构,操作系统,进程初步解析)

冯诺依曼体系结构&#xff1a; 我们常见的计算机&#xff0c;如笔记本。我们常见的计算机&#xff0c;服务器&#xff0c;大部分都遵守冯诺依曼体系。 截至目前&#xff0c;我们所认识的计算机&#xff0c;都是有一个个的硬件组件组成&#xff1a; 中央处理器(CPU)&am…

MIT6.5840-2023-Lab1: MapReduce

前置知识 MapReduce&#xff1a;Master 将一个 Map 任务或 Reduce 任务分配给一个空闲的 worker。 Map阶段&#xff1a;被分配了 map 任务的 worker 程序读取相关的输入数据片段&#xff0c;生成并输出中间 k/v 对&#xff0c;并缓存在内存中。 Reduce阶段&#xff1a;所有 ma…

Linux socket编程(12):Unix套接字之socketpair、sendmsg和recvmsg详解

在上一篇文章Unix套接字编程及通信例子中&#xff0c;我们对Unix套接字编程有一个基本的了解。但在Unix套接字编程的领域中&#xff0c;有一组特殊而强大的工具&#xff1a;socketpair、sendmsg 和 recvmsg&#xff0c;它们为实现本地进程间通信提供了便捷的方式。 文章目录 1 …

python二维数组创建赋值问题:更改单个值却更改了所有项的值

test_list [] dic1 {} test_list [dic1 for _ in range(3)] ll [1, 2, 3]for i in range(3):test_list[i][value] ll[i]print(test_list)运行结果&#xff1a;每次赋值都更改了所有项 原因&#xff1a;python的二位数据创建方式就是这样&#xff0c;官方文档中有描述Wha…

大话数据结构-查找-线性索引查找

注&#xff1a;本文同步发布于稀土掘金。 4 线性索引查找 4.1 概述 索引就是把一个关键字与它对应的记录相关联的过程&#xff0c;一个索引由若干个索引项构成&#xff0c;每个索引项至少应包含关键字和其对应的记录在存储器中的位置等信息。 索引按照结构可分为线性索引、树…

【SpringBoot】在SpringBoot中配置序列化的Redis

文章目录 前言展示包结构在SpringBoot中配置Redis测试总结 前言 在使用Java操作Redis时&#xff0c;如果不对Redis进行序列化操作&#xff0c;可能会导致存储的key和value与原来的数据不一致的问题 本文也借此机会来详细讲解一下SpringBoot中配置序列化Redis的步骤 展示包结构 …

AI助力智慧农业,基于YOLOv7【tiny/yolov7/yolov7x】开发构建不同参数量级农田场景下庄稼作物、杂草智能检测识别系统

智慧农业随着数字化信息化浪潮的演变有了新的定义&#xff0c;在前面的系列博文中&#xff0c;我们从一些现实世界里面的所见所想所感进行了很多对应的实践&#xff0c;感兴趣的话可以自行移步阅读即可&#xff1a; 《自建数据集&#xff0c;基于YOLOv7开发构建农田场景下杂草…

绘图 Seaborn 10个示例

绘图 Seaborn 是什么安装使用显示中文及负号散点图箱线图小提琴图堆叠柱状图分面绘图分类散点图热力图成对关系图线图直方图 是什么 Seaborn 是一个Python数据可视化库&#xff0c;它基于Matplotlib。Seaborn提供了高级的绘图接口&#xff0c;可以用来绘制各种统计图形&#xf…

nodejs+vue+微信小程序+python+PHP新闻发布系统的设计与实现-计算机毕业设计推荐

根据现实需要&#xff0c;此系统我们设计出一下功能&#xff0c;主要有以下功能模板。 &#xff08;1&#xff09;新闻发布系统前台&#xff1a;首页、时事新闻、公告资讯、个人中心。 &#xff08;2&#xff09;管理员功能&#xff1a;首页、个人中心、用户管理、新闻分类管理…