STM32USART串口数据包

news2024/9/23 15:26:48

文章目录

  • 前言
  • 一、介绍部分
    • 数据包两种包装方式(分割数据)
      • HEX数据包
      • 文本数据包
    • 数据包的收发流程
      • 数据包的发送
      • 数据包的接收
        • 固定包长的hex数据包接收
        • 可变包长的文本数据包接收
  • 二、实例部分
    • 固定包长的hex数据包接收
      • 连接线路
      • 代码实现
    • 可变包长的文本数据包接收
      • 连接线路
      • 代码实现
      • 补充


前言

当串口需要发送多个字节的数据时,使用数据包的形式来发送和接收是更加方便的,还可以更好的区分各个字节数据所对应的内容。例如需要发送X,Y,Z来控制陀螺仪传感器的X,Y,Z,就可以使用数据包的格式。


一、介绍部分

数据包两种包装方式(分割数据)

发送一连串数据时,无法精准的确定此数据对应哪一位,所以需要分割数据来使其位置一一对应。或者限制数据的大小来避免数据与包头包尾重复。

1. 使用包头加包尾把数据给包裹起来
在数据与包头包尾有重复时,尽量使用固定包长的方法,以免错误的识别到包头或包尾导致数据错误。
2. 使用一位标志位来确定数据开始

HEX数据包

在这里插入图片描述

文本数据包

在这里插入图片描述

数据包的收发流程

数据包的发送

和普通的数据发送一致,使用一个数组来接收这个数据包,然后使用相关的发送函数即可。

数据包的接收

每接收一个字节的数据,程序就会进入一次中断然后退出中断,所以每个数据的接收是独立的,所以要针对不同的状态进行对应的判断和进行相关的偏移,使这些数据关联起来,也就是状态机思路。

固定包长的hex数据包接收

如图,判断包头为状态s=1,判断成功使状态s=2,则接收数据状态,接收满4个数据后,使状态s=3,判断包尾,判断成功后进入下一轮。
在这里插入图片描述

可变包长的文本数据包接收

在这里插入图片描述

二、实例部分

固定包长的hex数据包接收

使按下按键可以发送递增数据包,将接收的数据包与发送的数据包都显示到OLED上

连接线路

在这里插入图片描述

代码实现

串口配置Serial.c

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

uint8_t TxData[4];	// 发送数据包
uint8_t RxData[4];  // 接收数据包
uint8_t RxFlag;

void Serial_Init(void){
	// 开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	// 初始化引脚
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;		// 复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;	// A9 发送数据
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 50Hz翻转速度
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;		// 上拉输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;	// A10 接收数据
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 50Hz翻转速度
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	// 初始化串口配置
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate = 9600; // 串口波特率
	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);
	
	// 开启中断
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
	
	//初始化NVIC
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	// 分组
	NVIC_InitTypeDef NVIC_InitStructure;
	// 中断通道
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	// 中断通道使能
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	// 抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	// 响应优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);

	
	// USART1使能
	USART_Cmd(USART1,ENABLE);
}

// 发送函数
void USART_SendByte(uint8_t Byte){
	USART_SendData(USART1,Byte);
	// 等待写入完成,写入完成之后会将标志位自动清0
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}

// 发送数组函数
void USART_SendArray(uint8_t *Array,uint16_t Length){
	uint8_t i = 0;
	for(i=0;i<Length;i++){
		USART_SendData(USART1,Array[i]);
		// 等待写入完成,写入完成之后会将标志位自动清0
		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
	}
}

// 发送字符串函数
void USART_SendString(uint8_t *String){
	uint8_t i = 0;
	for(i=0;String[i]!='\0';i++){
		USART_SendData(USART1,String[i]);
		// 等待写入完成,写入完成之后会将标志位自动清0
		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
	}
}

// 返回X的Y次方
uint32_t Serial_Pow(uint32_t X,uint32_t Y){
	uint32_t Result = 1;
	while(Y--){
		Result *= X;
	}
	return Result;
}
// 发送数字函数
void USART_SendNum(uint32_t Num,uint16_t Length){
	uint8_t i = 0;
	for(i=0;i<Length;i++){
		USART_SendByte(Num / Serial_Pow(10,Length-i-1) % 10 + 0x30);
		// 等待写入完成,写入完成之后会将标志位自动清0
		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
	}
}

//重定向fputc函数,fputc是printf函数的底层,printf通过不停的调用fputc来达到输出的效果
//重定向到串口
int fputc(int ch,FILE *f){
	USART_SendByte(ch);
	return ch;
}

// 封装使用sprintf输出到串口
void Serial_Printf(char *format, ...)
{
	char String[100];
	va_list arg;							// 可变参数列表
	va_start(arg, format);		// 从format开始接收可变参数
	vsprintf(String, format, arg);
	va_end(arg);
	USART_SendString((uint8_t*)String);
}

// 获取RxFlag
uint8_t USART_GetRxFlag(void){
	if(RxFlag == 1){
		RxFlag = 0;
		return 1;
	}
	return 0;
}


void USART_SendPacket(void){
	USART_SendByte(0xff);				// 发送包头
	USART_SendArray(TxData,4);	// 发送数据
	USART_SendByte(0xfe);				// 发送包尾
}

//中断函数
void USART1_IRQHandler(void){
	static uint8_t RxStatus = 0;		// 数据包状态
	static uint8_t RxCount = 0;
	if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET){
		uint8_t RXDATA = USART_ReceiveData(USART1);	// 获取接收到的数据
		if(RxStatus == 0){
			if(RXDATA == 0xff){
				RxStatus = 1;
			}
		}else if(RxStatus == 1){
			RxData[RxCount] = RXDATA;
			RxCount++;
			if(RxCount >= 4){
				RxCount = 0;
				RxStatus = 2;
			}
		}else if(RxStatus == 2){
			if(RXDATA == 0xfe){
				RxStatus = 0;
				RxFlag = 1;
			}
		}
	}
}


按键button.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

/**
  * @brief  初始化Button相关端口
  * @param 	无
  * @retval 无
  */
void Button_Init(void){
	// 初始化时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;		// 上拉输出,按下为0
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;	
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 50Hz翻转速度
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	// 使这两个端口默认高电平,不然初始化后默认是低电平
	GPIO_SetBits(GPIOB, GPIO_Pin_1);
}
/**
  * @brief  返回所按按键值
  * @param 	无
  * @retval KeyNum 按键值
  */
uint8_t Key_Num(void){
	uint8_t KeyNum = 0;
	if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1)==0){
		Delay_ms(20);
		while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1)==0);
		Delay_ms(20);
		KeyNum = 1;
	}
	if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11)==0){
		Delay_ms(20);
		while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11)==0);
		Delay_ms(20);
		KeyNum = 11;
	}
	return KeyNum;
}

主函数main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include "button.h"

uint8_t KeyNum;

int main(void)
{
	OLED_Init();
	OLED_ShowString(1, 1, "TxData:");
	OLED_ShowString(3, 1, "RxData:");
	Button_Init();
	Serial_Init();
	TxData[0] = 0x01;
	TxData[1] = 0x02;
	TxData[2] = 0x03;
	TxData[3] = 0x04;
	
	//USART_SendPacket();
	while (1)
	{
		KeyNum = Key_Num();
		if(KeyNum == 1){
			TxData[0] ++;
			TxData[1] ++;
			TxData[2] ++;
			TxData[3] ++;
			USART_SendPacket();
			OLED_ShowHexNum(2,1,TxData[0],2);
			OLED_ShowHexNum(2,4,TxData[1],2);
			OLED_ShowHexNum(2,7,TxData[2],2);
			OLED_ShowHexNum(2,10,TxData[3],2);
		}
		if(USART_GetRxFlag() == 1){
			OLED_ShowHexNum(4,1,RxData[0],2);
			OLED_ShowHexNum(4,4,RxData[1],2);
			OLED_ShowHexNum(4,7,RxData[2],2);
			OLED_ShowHexNum(4,10,RxData[3],2);
		}
	}
}

可变包长的文本数据包接收

主要功能为接收字符串,通过特定的字符串来实现led的点亮和关闭,并把相关信息显示在OLED上

连接线路

在这里插入图片描述

代码实现

led配置led.c

#include "stm32f10x.h"                  // Device header


/**
  * @brief  初始化LED相关端口,让LED所在端口可以被直接赋值
  * @param 	无
  * @retval 无
  */
void LED_Init(void){
	// 初始化时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	// 配置LED所在端口
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		// 通用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 50Hz翻转速度
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	// 使这两个端口默认高电平,不然初始化后默认是低电平
	GPIO_SetBits(GPIOA, GPIO_Pin_1);
}
/**
  * @brief  LED1亮
  * @param 	无
  * @retval 无
  */
void LED1_On(void){
	GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}
/**
  * @brief  LED1关
  * @param 	无
  * @retval 无
  */
void LED1_Off(void){
	GPIO_SetBits(GPIOA, GPIO_Pin_1);
}
/**
  * @brief  LED2亮
  * @param 	无
  * @retval 无
  */
void LED2_On(void){
	GPIO_ResetBits(GPIOA, GPIO_Pin_2);
}
/**
  * @brief  LED2关
  * @param 	无
  * @retval 无
  */
void LED2_Off(void){
	GPIO_SetBits(GPIOA, GPIO_Pin_2);
}
/**
  * @brief  LED1取反
  * @param 	无
  * @retval 无
  */
void LED1_Reverse(void){
	// 读取端口状态,根据状态取反
	if(GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_1) == 0)
		GPIO_SetBits(GPIOA, GPIO_Pin_1);
	else
		GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}
/**
  * @brief  LED2取反
  * @param 	无
  * @retval 无
  */
void LED2_Reverse(void){
	// 读取端口状态,根据状态取反
	if(GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_2) == 0)
		GPIO_SetBits(GPIOA, GPIO_Pin_2);
	else
		GPIO_ResetBits(GPIOA, GPIO_Pin_2);
}

串口配置serial.c

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

char RxData[100];  // 接收数据包
uint8_t RxFlag;

void Serial_Init(void){
	// 开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	// 初始化引脚
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;		// 复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;	// A9 发送数据
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 50Hz翻转速度
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;		// 上拉输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;	// A10 接收数据
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 50Hz翻转速度
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	// 初始化串口配置
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate = 9600; // 串口波特率
	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);
	
	// 开启中断
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
	
	//初始化NVIC
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	// 分组
	NVIC_InitTypeDef NVIC_InitStructure;
	// 中断通道
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	// 中断通道使能
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	// 抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	// 响应优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);

	
	// USART1使能
	USART_Cmd(USART1,ENABLE);
}

// 发送函数
void USART_SendByte(uint8_t Byte){
	USART_SendData(USART1,Byte);
	// 等待写入完成,写入完成之后会将标志位自动清0
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}

// 发送数组函数
void USART_SendArray(uint8_t *Array,uint16_t Length){
	uint8_t i = 0;
	for(i=0;i<Length;i++){
		USART_SendData(USART1,Array[i]);
		// 等待写入完成,写入完成之后会将标志位自动清0
		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
	}
}

// 发送字符串函数
void USART_SendString(uint8_t *String){
	uint8_t i = 0;
	for(i=0;String[i]!='\0';i++){
		USART_SendData(USART1,String[i]);
		// 等待写入完成,写入完成之后会将标志位自动清0
		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
	}
}

// 返回X的Y次方
uint32_t Serial_Pow(uint32_t X,uint32_t Y){
	uint32_t Result = 1;
	while(Y--){
		Result *= X;
	}
	return Result;
}
// 发送数字函数
void USART_SendNum(uint32_t Num,uint16_t Length){
	uint8_t i = 0;
	for(i=0;i<Length;i++){
		USART_SendByte(Num / Serial_Pow(10,Length-i-1) % 10 + 0x30);
		// 等待写入完成,写入完成之后会将标志位自动清0
		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
	}
}

//重定向fputc函数,fputc是printf函数的底层,printf通过不停的调用fputc来达到输出的效果
//重定向到串口
int fputc(int ch,FILE *f){
	USART_SendByte(ch);
	return ch;
}

// 封装使用sprintf输出到串口
void Serial_Printf(char *format, ...)
{
	char String[100];
	va_list arg;							// 可变参数列表
	va_start(arg, format);		// 从format开始接收可变参数
	vsprintf(String, format, arg);
	va_end(arg);
	USART_SendString((uint8_t*)String);
}


//中断函数
void USART1_IRQHandler(void){
	static uint8_t RxStatus = 0;		// 数据包状态
	static uint8_t RxCount = 0;
	if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET){
		uint8_t RXDATA = USART_ReceiveData(USART1);	// 获取接收到的数据
		if(RxStatus == 0){
			if(RXDATA == '@' && RxFlag == 0){
				RxStatus = 1;
				RxCount = 0;		// 初始化之前的数据长度
			}
		}else if(RxStatus == 1){
			if(RXDATA == '\r')
				RxStatus = 2;
			else{
				RxData[RxCount] = RXDATA;
				RxCount++;
			}
		}else if(RxStatus == 2){
			if(RXDATA == '\n'){
				RxStatus = 0;
				RxFlag = 1;
				RxData[RxCount] = '\0';		// 加入字符串结束标志位
			}
		}
		USART_ClearITPendingBit(USART1, USART_IT_RXNE); // 清除标志位
	}
}


主函数mian.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include "LED.h"
#include <string.h>


int main(void)
{
	OLED_Init();
	Serial_Init();
	LED_Init();
	OLED_ShowString(1, 1, "TxData:");
	OLED_ShowString(3, 1, "RxData:");
	
	while (1)
	{
		if(RxFlag == 1){
			OLED_ShowString(4,1,"                "); // 显示前擦除这行
			OLED_ShowString(4,1,RxData);
			
			if(strcmp(RxData,"LED_ON")==0){
				LED1_On();
				USART_SendString((uint8_t*)"LED_ON_OK\r\n");
				OLED_ShowString(2,1,"                ");
				OLED_ShowString(2,1,"LED_ON_OK");
			}
			else if(strcmp(RxData,"LED_OFF")==0){
				LED1_Off();
				USART_SendString((uint8_t*)"LED_OFF_OK\r\n");
				OLED_ShowString(2,1,"                ");
				OLED_ShowString(2,1,"LED_OFF_OK");
			}
			else{
				USART_SendString((uint8_t*)"ERR_CMD\r\n");
				OLED_ShowString(2,1,"                ");
				OLED_ShowString(2,1,"ERR_CMD");
			}
			RxFlag = 0;
		}
	}
}

补充

这里没有使用函数封装标志位自动清除,在许多读写操作进行时可能因为读取速度太慢导致数据接收错位,所以在主函数中手动把标志位清0,保证把每个数据包接收完毕后才可以开始下一次接收,同时把serial.c的包头判断时加入标志位判断即if(RXDATA == ‘@’ && RxFlag == 0)。


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

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

相关文章

AWS的RDS数据库开启慢查询日志

#开启慢日志两个参数 slow_query_log 1 设置为1&#xff0c;来启用慢查询日志 long_query_time 5 &#xff08;单位秒&#xff09; sql执行多长时间被定义为慢日志1. 点击RDS然后点击参数组&#xff0c;选择slow_query_log&#xff0c;设置为1【表示开启慢日志】点击保存…

[cg] Games 202 - NPR 非真实感渲染

NPR特性&#xff08;基于真实感渲染&#xff09; 真实感--》翻译成非真实感的过程 NPR风格 需要转换为渲染中的操作 1.描边 B-->普通边界&#xff08;不是下面几种的&#xff09; C-->折痕 M-->材质边界 S-->需要在物体外面一圈上&#xff0c;并且是多个面共享…

使用GitHub API 查询开源项目信息

一、GitHub API介绍 GitHub API 是一组 RESTful API 接口&#xff0c;用于与 GitHub 平台进行交互。通过使用 GitHub API&#xff0c;开发人员可以访问和操作 GitHub 平台上的各种资源&#xff0c;如仓库、提交记录、问题等。 GitHub API 提供了多种功能和端点&#xff0c;以…

gin gorm学习笔记

代码仓库 https://gitee.com/zhupeng911/go-advanced.git https://gitee.com/zhupeng911/go-project.git 1. gin介绍 Gin 是使用纯 Golang 语言实现的 HTTP Web框架&#xff0c;Gin接口设计简洁&#xff0c;提供类似Martini的API&#xff0c;性能极高&#xff0c;现在被广泛使用…

SpringBoot接口防抖(防重复提交)的一些实现方案

前言 啥是防抖 思路解析 分布式部署下如何做接口防抖&#xff1f; 具体实现 请求锁 唯一key生成 重复提交判断 前言 作为一名老码农&#xff0c;在开发后端Java业务系统&#xff0c;包括各种管理后台和小程序等。在这些项目中&#xff0c;我设计过单/多租户体系系统&a…

如何制作一个分销商城小程序_揭秘分销商城小程序的制作秘籍

打造赚钱神器&#xff01;揭秘分销商城小程序的制作秘籍 在这个数字化高速发展的时代&#xff0c;拥有一个属于自己的分销商城小程序&#xff0c;已成为众多商家和创业者的必备利器。它不仅能够快速搭建起自己的在线销售渠道&#xff0c;还能够利用分销模式&#xff0c;迅速裂…

机器学习专项课程03:Unsupervised Learning, Recommenders, Reinforcement Learning笔记 Week02

Week 02 of Unsupervised Learning, Recommenders, Reinforcement Learning 课程地址&#xff1a; https://www.coursera.org/learn/unsupervised-learning-recommenders-reinforcement-learning 本笔记包含字幕&#xff0c;quiz的答案以及作业的代码&#xff0c;仅供个人学习…

无人机遥感在农林信息提取中的实现方法与GIS融合应用

在新一轮互联网信息技术大发展的现今&#xff0c;无人机、大数据、人工智能、物联网等新兴技术在各行各业都处于大爆发的前夜。为了将人工智能方法引入农业生产领域。首先在种植、养护等生产作业环节&#xff0c;逐步摆脱人力依赖&#xff1b;在施肥灌溉环节构建智慧节能系统&a…

centos7安装kafka、zookeeper

安装jdk 安装jdk8 安装zookeeper 在指定目录执行下载命令 我是在/newdisk/zookeeper目录下 wget https://archive.apache.org/dist/zookeeper/zookeeper-3.5.8/apache-zookeeper-3.5.8-bin.tar.gz --no-check-certificate下载好后并解压 tar -zxvf apache-zookeeper-3.5…

Kali Linux 2024.1

Kali Linux 2024.1刚刚发布&#xff0c;标志着这个备受欢迎的安全重点Linux发行版在今年的首次重大更新。以其先进的渗透测试和安全审计功能而闻名&#xff0c;它是安全专业人员和爱好者的首选工具。 Kali 2024.1 亮点 本次发布由 Linux 内核 6.6 提供支持&#xff0c;突出了…

Git分布式管理-头歌实验本地版本库

一、本地版本库创建 任务描述 本地Git操作三部曲是“修改-添加-提交”&#xff0c;即先要在本地仓库进行添加、删除或编辑等修改&#xff0c;然后将本地所做的修改添加至暂存区。添加至暂存区的这些本地修改&#xff0c;并未提交到本地仓库&#xff0c;需要执行提交命令才能将暂…

详解Java中集合的List接口实现的ArrayList方法 | Set接口实现的HashSet方法

集合的概念 当我们需要保存一组一样&#xff08;类型相同&#xff09;的元素的时候&#xff0c;我们应该使用一个容器来存储&#xff0c;数组就是这样一个容器。 ● 数组的特点&#xff1a; 数组是一组数据类型相同的元素集合&#xff1b; 创建数组时&#xff0c;必须给定…

【CSP试题回顾】202212-1-现值计算

CSP-202212-1-现值计算 解题代码 #include <iostream> #include <vector> #include <cmath> using namespace std;int main() {int n;double k, sumPrice 0;cin >> n >> k;vector<double>priceList(n 1);for (int i 0; i < n; i){…

分享7款前端动画特效(附效果图及在线演示)

分享7款好玩的前端动画特效 其中有CSS动画、SVG动画、js小游戏等等 下方效果图可能不是特别的生动 那么你可以点击在线预览进行查看相应的动画特效 同时也是可以下载该资源的 canvas彩色画树特效 基于canvas实现的画树特效 同时还可选择树枝的初始数目进行彩色树生成 以下效果…

用docker部署后端项目

一、搭建局域网 1.1、介绍前后端项目搭建 需要4台服务器&#xff0c;在同一个局域网中 1.2、操作 # 搭建net-ry局域网&#xff0c;用于部署若依项目 net-ry&#xff1a;名字 docker network create net-ry --subnet172.68.0.0/16 --gateway172.68.0.1#查看 docker network ls…

【力扣精选算法100道】——存在重复元素 1 or 2 (哈希)

目录 &#x1f6a9;存在重复元素1 &#x1f388;了解题意 &#x1f388;算法原理 &#x1f388;实现代码 &#x1f6a9;存在重复元素2 &#x1f388;了解题意 &#x1f388;算法原理 &#x1f388;代码实现 217. 存在重复元素 - 力扣&#xff08;LeetCode&#xff09; …

Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验(二)

Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验&#xff08;前导&#xff09; Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验&#xff08;一&#xff09; 五、实验目的 本次实验使用电脑上的网络调试助手&#xff0c;将命令帧通过以太网芯片RTL8211&#xff08;RGMII接口…

C#,最小代价多边形三角剖分MCPT(Minimum Cost Polygon Triangulation)算法与源代码

1 最小代价多边形三角剖分算法 凸多边形的三角剖分是通过在非相邻顶点&#xff08;角点&#xff09;之间绘制对角线来形成的&#xff0c;这样对角线就不会相交。问题是如何以最小的代价找到三角剖分的代价。三角剖分的代价是其组成三角形的权重之和。每个三角形的重量是其周长…

FPFH特征提取以及匹配(matlab代码免费)

FPFH特征提取时谁提出的&#xff0c;尊重一下原创&#xff1a; [1] Rusu, Radu Bogdan, Nico Blodow, and Michael Beetz. “Fast point feature histograms (FPFH) for 3D registration.” In 2009 IEEE International Conference on Robotics and Automation, pp. 3212-3217…

websocket在java中的使用教程

本文从websocket服务端和客户端两个方面简单介绍下websocket在java中的使用。 一、websocket服务端&#xff08;WebSocketServer&#xff09; websocket服务端是以本机作为消息的接受端&#xff0c;用于接受客户端websocket发送过来的消息&#xff0c;并可以通过客户端的webs…