中科微电子ATGM336H GPS定位模块STM32应用

文章目录

  • 前言
  • 1. 中科微电子ATGM336H的使用
    • 1.1 ATGM336H引脚说明
    • 1.2 数据帧介绍
    • 1.3 经纬度介绍
    • 1.4 ATGM336H的启动方式
  • 2 数据处理前置C语言知识
    • 2.1 strstr函数
    • 2.2 memset函数
    • 2.3 memcpy函数
    • 2.4strtod函数
  • 3. 开始移植
    • 3.1 usart初始化程序
    • 3.2 串口中断接收函数
    • 3.4 数据帧的解析
    • 3.5数据转换
  • 4 参考资料
  • 5. 总结

前言

GPS定位能够获取自身所在的经纬度信息,进而定位自己的所在位置。GPS模块有很多,这里用到是中科微电子ATGM336H,带陶瓷天线版本。这个在淘宝就可以搜得到。模块具体长下图这样
中科微电子ATGM336H

1. 中科微电子ATGM336H的使用

在使用该模块时,有一下注意事项:

  • 该模块必须在无遮挡的空旷地上使用,室内使用不了
  • 陶瓷天线上的接收小圆点必须朝上,且在这上面不能有遮挡物
  • 不宜在楼距较小的地方使用,楼距小的地方可能导致定位失败

1.1 ATGM336H引脚说明

该GPS模块支持3.3V-5V供电,因此我们即可以将其接到3.3V电源,也可以接到5V电源。数据通过串口的方式,将其发送给主控单元。几个引脚的定义以及接线如下表和下图所示。

管脚定义
VCC电源(3.3V-5V)
GND
TXD模块串口发送引脚,可接单片机的RXD
RXD模块串口接收引脚,可接单片机的TXD
PPS时钟脉冲引脚

在这里插入图片描述
如果单纯做定位,只需要前4个引脚即可,也即PPS引脚用不到,所以我们PPS这个引脚可以不接,空着就行。具体PPS引脚的作用,大家可以自行查阅。

1.2 数据帧介绍

GPS模块通过串口将数据发给主控芯片,ATGM336H会一次性返回多条信息,其中信息头的第一个是消息ID,标示着通过什么定位系统的采集的数据。简单的含义如下,具体含义可以查询使用手册

缩写标识符含义
BDBDS,北斗二代卫星系统
GPGPS
GLGLONASS
GAGalileo
GNGNSS,全球卫星导航系统

在这里插入图片描述
这里我们只需要关注“GNRMC”这条信息就行

$GNRMC,121520.000,A,3438.1766,N,11224.5016,E,0.08,292.36,140816,,,A*77
  • GNRMC:为消息ID
  • 121520.000:为定位点UTC时间戳,不知道可以自行查阅
  • A:定位状态,如果我们要做导航时,此处就应该为V。也就是如果我们做定位,这时此处不为A,就表示此时数据无效
  • 3438.1766:纬度,N表示纬度方向(北纬N)
  • 11224.5016:经度,E表示纬度方向(东经)

一般这里的经纬度是不可以直接拿来地图上直接搜索定位的,得对其进行数据转换,才能用。下面小节将对经纬度数据格式进行介绍。

1.3 经纬度介绍

经纬度格式分为三种:度、度-分、度-分-秒

标识符含义
ddd.ddddd °“度.度”格式,其中小数部分为5位10进制的数据
ddd°mm.mmm’“度.分.分”格式,其中小数部分为3位10进制的数据
ddd°mm’ss’’“度.分.秒”格式

格式之间的转换
(1)度分转换
将度分单位数据转换为度单位数据,主要依据的公式为:度=度+分/60
例如:
经度 = 116°20.12’
纬度 = 39°12.34’
经度 = 116 + 20.12 / 60 = 116.33533°
纬度 = 39 + 12.34 / 60 = 39.20567°
(2)度分秒转换:
将度分秒单位数据转换为度单位数据,主要依据的公式为:度 = 度 + 分 / 60 + 秒 / 60 / 60
例如:
经度 = 116°20’43”
纬度 = 39°12’37”
经度 = 116 + 20 / 60 + 43 / 60 / 60 = 116.34528°
纬度 = 39 + 12 / 60 + 37 / 60 / 60 = 39.21028°
而我们的GPS模块输出为**度-分(ddmm.mmmm)的形式,我们一般使用的是度(dd.dddddd(度))**的形式。所以我们要对齐进行转换,转换主要采取以下步骤

  • Step1: 将ddmm.mmmm的小数点向前移动两位,得到dd.mmmmmm
  • Step2: 将dd.mmmmmm的小数点部分除以60,即mmmmmm/60
  • Step3: 所以所得到结果为dd.(mmmmmm/60)即为我们想要的度的格式
    例如:
    12023.4047 → 120.234047 → 120 + 0.(234047÷60) = 120.390078

1.4 ATGM336H的启动方式

ATGM336H有三种不同的启动模式

启动模式含义
冷启动适用于初次使用时,电池电耗尽星历信息丢失,或者关机后,移动超过1000公里以上距离,这些都属于冷启动,冷启动时间很长,一般需要几分钟才能定位成功
温启动温启动是指在上次关机的地方没有较大的位移变化,且距离上次定位时间超过2h,但不足4h
热启动热启动是指在上次关机的地方没有较大的位移变化,且距离上次定位时间不足2h

2 数据处理前置C语言知识

我们收到数据后,需要对齐进行处理,这里分享几个C语言函数,有助于我们后期数据处理。这些函数都包含在<string.h>头文件中,使用这函数必须包含该头文件。

2.1 strstr函数

strstr的原型如下所示。主要功能是在字符串str1中,查找是否有str2子字符串,也就str1字符串长度必须大于等于str2,否则将失去这个函数的意义。如果存在,将返回str2在str1中第一次出现的地址,不存将返回NULL

char *strstr( const char *str1, const char *str2 );

2.2 memset函数

memset的原型如下所示。主要功能是用于初始化,对指定地址的连续指定的字节赋予指定的值。

void *memset(void *s, int c, size_t n); 
  • s: 为指定的起始地址
  • c: 为期望赋予的值
  • n 期待被赋予的连续字节数
  • 返回类型是一个指向存储区的s的指针

2.3 memcpy函数

strtod的原型如下所示。主要功能是将一块地址指定连续字节数,复制到另一个地址中。

double strtod(const char *nptr, char **endptr);
  • dest: 将src的数据复制到dest中
  • src: 被复制的源目标
  • n 期待被赋予的连续字节数

2.4strtod函数

strtod的原型如下所示。主要功能是将一块地址指定连续字节数,复制到另一个地址中。

double strtod(const char *nptr, char **endptr);
  • strtod()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,到出现非数字或字符串结束时(‘\0’)才结束转换,并将结果返回。
  • src: 被复制的源目标
  • 若endptr不为NULL,则会将遇到不合条件而终止的nptr中的字符指针由endptr传回。参数nptr字符串可包含正负号、小数点或E(e)来表示指数部分。如123.456或123e-2。
    例如
char *endptr;

char a[] = "12345.6789";

char b[] = "1234.567qwer";

char c[] = "-232.23e4";

printf( "a=%lf\n", strtod(a,NULL) );       //结果为a=12345.678900

printf( "b=%lf\n", strtod(b,&endptr) );   //结果为b=1234.567000

printf( "endptr=%s\n", endptr );         //结果为endptr=qwer

printf( "c=%lf\n", strtod(c,NULL) );    //结果为c=-2322300.000000

3. 开始移植

首先GSP是使用的串口通信,我们第一步需要先配置我们单片机的串口,并将我们的串口波特率配置为9600。下面是本次测试的代码。

3.1 usart初始化程序

//硬件驱动
#include "usart.h"
//#include "delay.h"

//C库
#include <stdarg.h>
#include <string.h>
#include <stdio.h>


/*
************************************************************
*	函数名称:	Usart1_Init
*
*	函数功能:	串口1初始化
*
*	入口参数:	baud:设定的波特率
*
*	返回参数:	无
*
*	说明:		TX-PA9		RX-PA10
************************************************************
*/
void Usart1_Init(unsigned int baud)
{

	GPIO_InitTypeDef gpioInitStruct;
	USART_InitTypeDef usartInitStruct;
	NVIC_InitTypeDef nvicInitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	
	//PA9	TXD
	gpioInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
	gpioInitStruct.GPIO_Pin = GPIO_Pin_9;
	gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &gpioInitStruct);
	
	//PA10	RXD
	gpioInitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	gpioInitStruct.GPIO_Pin = GPIO_Pin_10;
	gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &gpioInitStruct);
	
	usartInitStruct.USART_BaudRate = baud;
	usartInitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;		//无硬件流控
	usartInitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;						//接收和发送
	usartInitStruct.USART_Parity = USART_Parity_No;									//无校验
	usartInitStruct.USART_StopBits = USART_StopBits_1;								//1位停止位
	usartInitStruct.USART_WordLength = USART_WordLength_8b;							//8位数据位
	USART_Init(USART1, &usartInitStruct);
	
	USART_Cmd(USART1, ENABLE);														//使能串口
	
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);									//使能接收中断
	
	nvicInitStruct.NVIC_IRQChannel = USART1_IRQn;
	nvicInitStruct.NVIC_IRQChannelCmd = ENABLE;
	nvicInitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	nvicInitStruct.NVIC_IRQChannelSubPriority = 2;
	NVIC_Init(&nvicInitStruct);

}

/*
************************************************************
*	函数名称:	Usart2_Init
*
*	函数功能:	串口2初始化
*
*	入口参数:	baud:设定的波特率
*
*	返回参数:	无
*
*	说明:		TX-PA2		RX-PA3
************************************************************
*/
void Usart2_Init(unsigned int baud)
{

	GPIO_InitTypeDef gpioInitStruct;
	USART_InitTypeDef usartInitStruct;
	NVIC_InitTypeDef nvicInitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
	
	//PA2	TXD
	gpioInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
	gpioInitStruct.GPIO_Pin = GPIO_Pin_2;
	gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &gpioInitStruct);
	
	//PA3	RXD
	gpioInitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	gpioInitStruct.GPIO_Pin = GPIO_Pin_3;
	gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &gpioInitStruct);
	
	usartInitStruct.USART_BaudRate = baud;
	usartInitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;		//无硬件流控
	usartInitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;						//接收和发送
	usartInitStruct.USART_Parity = USART_Parity_No;									//无校验
	usartInitStruct.USART_StopBits = USART_StopBits_1;								//1位停止位
	usartInitStruct.USART_WordLength = USART_WordLength_8b;							//8位数据位
	USART_Init(USART2, &usartInitStruct);
	
	USART_Cmd(USART2, ENABLE);														//使能串口
	
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);									//使能接收中断
	
	nvicInitStruct.NVIC_IRQChannel = USART2_IRQn;
	nvicInitStruct.NVIC_IRQChannelCmd = ENABLE;
	nvicInitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	nvicInitStruct.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&nvicInitStruct);

}

/*
************************************************************
*	函数名称:	Usart_SendString
*
*	函数功能:	串口数据发送
*
*	入口参数:	USARTx:串口组
*				str:要发送的数据
*				len:数据长度
*
*	返回参数:	无
*
*	说明:		
************************************************************
*/
void Usart_SendString(USART_TypeDef *USARTx, unsigned char *str, unsigned short len)
{

	unsigned short count = 0;
	
	for(; count < len; count++)
	{
		USART_SendData(USARTx, *str++);									//发送数据
		while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);		//等待发送完成
	}

}

/*
************************************************************
*	函数名称:	UsartPrintf
*
*	函数功能:	格式化打印
*
*	入口参数:	USARTx:串口组
*				fmt:不定长参
*
*	返回参数:	无
*
*	说明:		
************************************************************
*/
void UsartPrintf(USART_TypeDef *USARTx, char *fmt,...)
{

	unsigned char UsartPrintfBuf[296];
	va_list ap;
	unsigned char *pStr = UsartPrintfBuf;
	
	va_start(ap, fmt);
	vsnprintf((char *)UsartPrintfBuf, sizeof(UsartPrintfBuf), fmt, ap);							//格式化
	va_end(ap);
	
	while(*pStr != 0)
	{
		USART_SendData(USARTx, *pStr++);
		while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);
	}

}

3.2 串口中断接收函数


/*
************************************************************
*	函数名称:	USART1_IRQHandler
*
*	函数功能:	串口1收发中断
*
*	入口参数:	无
*
*	返回参数:	无
*
*	说明:在进行数据接收时,我们一帧一帧地接收,直到接收到我们需要的帧
*	后,将接收数据buffer的数据复制到我们提前定义好的接收数据结构体中		
************************************************************
*/
void USART1_IRQHandler(void)
{
	uint8_t reContent                                			//存储接收内容	

	// 如果串口接收到内容
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) 
	{
		recContent = USART_ReceiveData(USART1);   // 存储接收内容
		
		// 如果接收到的是$($是一帧信息的开始)
		// 保证每接收到新的一帧信息就从缓冲区起始位置开始存储
		if(recContent == '$')
		{
			gReceCunt = 0;   // 清零帧信息计数变量
		}
		
		// 存储接收到的帧信息
		gUart1RcecBuf[gReceCunt ++] = recContent;
		
		// 确定是否收到"GPRMC/GNRMC"这一帧数据
		if(gUart1RcecBuf[0] == '$' && gUart1RcecBuf[4] == 'M' && gUart1RcecBuf[5] == 'C')
		{
			// 接收到换行(接收完了一帧信息)
			if(recContent == '\n')									   
			{
				memset(receDataFrame.Frame_Buffer, 0, Frame_Buffer_Length);   // 初始化接收帧信息数组
				memcpy(receDataFrame.Frame_Buffer, gUart1RcecBuf, gReceCunt);   // 保存GPRMC/GNRMC这帧的数据
				receDataFrame.isGetData = TRUE;   // 接收成功
				gReceCunt = 0;   // 清零接收帧信息接收计数变量
				memset(gUart1RcecBuf, 0, UART1RX_MAX_LENGTH);   // 清空串口1接收Buf				
			}		
		}
		
		// 如果接收内容超出最大长度,不再继续接收
		if(gReceCunt >= UART1RX_MAX_LENGTH)
		{
			gReceCunt = UART1RX_MAX_LENGTH;
		}
	}
}

3.4 数据帧的解析

存储到需要的帧信息后,下一步就是对它进行解析,解析时我们利用每一个数据间的逗号作为分隔符,利用strstr函数寻找逗号对应的地址,将两个逗号之间的信息存储到我们提前定义好的解析信息存储数组中。仔细分析一下"$GNRMC"帧会发现,我们只需要找到七个逗号的地址,提取他们两个相邻逗号中间的字符串就可以得到GPS信息,思路介绍完了,我们来看一下程序设计。

/*
 *==============================================================================
 *函数名称:Uart_Rece_Pares
 *函数功能:解析串口接收内容
 *输入参数:无
 *返回值:无
 *备  注:无
 *==============================================================================
*/
void Uart_Rece_Pares(void)   // 串口接收内容解析函数
{
	// 注意变量类型
	char *point = 0;   // 逗号的地址指针
	char *nextPoint = 0;   // 下一个逗号的地址指针
	u8 tempVar = 0;   // 临时循环变量
	
	// 如果数据接收成功
	if (receDataFrame.isGetData)
	{
		receDataFrame.isGetData = 0;   // 清除接收成功标志位
		
		// for循环解析接收帧
		// 总共需要找到7个逗号
		for (tempVar = 0;tempVar < 7;tempVar ++)
		{
			// 第一次循环
			if (tempVar == 0)
			{
				// 寻找第一个逗号
				if ((point = strstr(receDataFrame.Frame_Buffer,",")) == NULL)
				{
					printf ("Prase Errpr!\r\n");   // 解析错误
				}
			}
			else
			{
				point ++;   // 防止重复找到同一个逗号
				
				// 寻找下一个逗号
				// 注意strstr函数的输入变量,是从上一个逗号之后开始找下一个逗号
				if ((nextPoint = strstr(point,",")) != NULL)
				{
					// 存储信息
					switch (tempVar)
					{
						case 1:   // UTC时间
							memcpy(receDataFrame.UTCTime,point,nextPoint - point);
							break;
						
						case 2:   // 数据有效标识
							memcpy(receDataFrame.UsefullFlag,point,nextPoint - point);
							break;
						
						case 3:   // 纬度
							memcpy(receDataFrame.latitude,point,nextPoint - point);
							break;
						
						case 4:   // 纬度方向
							memcpy(receDataFrame.N_S,point,nextPoint - point);
							break;
						
						case 5:   // 经度
							memcpy(receDataFrame.longitude,point,nextPoint - point);
							break;
						
						case 6:   // 经度方向
							memcpy(receDataFrame.E_W,point,nextPoint - point);
							break;
					}
					
					point = nextPoint;   // 更新上一个逗号地址指针
					
					receDataFrame.isParseData = TRUE;   // 数据解析完成
					
					// 数据有效
					if (receDataFrame.UsefullFlag[0] == 'A')
					{
						printf ("Data is useful!\r\n");
					}
					else if (receDataFrame.UsefullFlag[0] == 'V')
					{
						printf ("Data is invalid!\r\n");
					}
				}
				else
				{
					printf ("Prase Errpr!\r\n");   // 解析错误
				}
			}
		}
	}
}

3.5数据转换

数据读取完后,对其进行解析。

/*
 *==============================================================================
 *函数名称:Data_Transfor
 *函数功能:数据转换
 *输入参数:无
 *返回值:无
 *备  注:无
 *==============================================================================
*/
void Data_Transfor (void)
{
	float latitude_temp1,latitude_temp2_min,latitude = 0, ;    // 存储纬度信息
	float longitude_temp1,longitude_temp2_min,longitude = 0;   // 存储经度信息
	
	latitude = strtod(receDataFrame.latitude,NULL);     		// 字符串转换成浮点数
	longitude = strtod(receDataFrame.longitude,NULL);   		// 字符串转换成浮点数
	
	// 纬度信息处理
	latitude_temp1 = (uint16_t)latitude/100;                   		 //提取度-分中度的不分
	latitude_temp2_min = (latitude%100 )/60					//提取度-分中,分的部分并将其转为度
	latitude = (float)latitude_temp1 + latitude_temp2_min;	
			
	// 经度信息处理
	// 五位经度信息
	longitude_temp1 = (uint16_t)longitude/100;                   		 //提取度-分中度的不分
	longitude_temp2_min = (longitude%100 )/60				//提取度-分中,分的部分并将其转为度
	latitude = (float)longitude_temp1 + longitude_temp2_min;	
}

4 参考资料

[1] 参考博文1: GPS基础知识+模组使用
[2] 参考博文2: 定位模块介绍及使用(GPS、北斗、GLONASS、伽利略、准天顶)
[3] 参考博文3: 嵌入式外设集 – GPS定位模块(ATGM336H)
[4] 参考博文4: 【STM32外设系列】GPS定位模块(ATGM336H)

5. 总结

以上即是本次的内容。如果单片机的功能较多的话,这个串口中断接收函数,可能会一直触发导致无法进行别的函数。推荐如果做功能较多的项目的话,可以用DMA搬运。这也是后续可改进的点。代码大部分来源于参考博文4。

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

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

相关文章

—张pdf怎么分割成多页,怎么把一个pdf分割

在数字化时代&#xff0c;pdf文件已经成为我们工作和生活中不可或缺的一部分。然而&#xff0c;有时候我们可能会遇到需要将一张pdf文件分割成多页的情况。无论是为了便于分享&#xff0c;还是为了满足特定的文档格式要求&#xff0c;这个任务都可能变得相当棘手。但别担心&…

17098 广告牌最佳安放问题

这个问题可以通过动态规划来解决。我们可以定义一个数组d&#xff0c;其中d[i]表示到第i个广告牌地点时可以选择放置广告牌的最大效益值。然后我们可以通过遍历所有可能的j&#xff08;1 < j < i && x[i] - x[j] > 5&#xff09;&#xff0c;然后更新d[i]为ma…

【云原生】ptcpdump捕获任何进程、容器或 Pod 的网络流量的抓包神器——筑梦之路

ptcpdump 是一个使用 eBPF 技术开发的、类 tcpdump 的网络抓包工具。它除了兼容 tcpdump 的常用命令行参数以及包过滤语法外&#xff0c; 还额外提供了如下核心特性&#xff1a; 在输出中记录和显示发送网络流量的进程、容器、Pod 信息。 支持对指定进程、容器以及 Pod 进行抓…

LED显示屏中什么情况下用网线?什么情况下用光纤?

在这个色彩斑斓的数字时代&#xff0c;LED显示屏如同城市的眼睛&#xff0c;闪烁着各种信息与艺术的光芒。而要让这些“眼睛”明亮有神&#xff0c;背后离不开两条重要的“信息高速公路”——网线和光纤。它们就像是LED显示屏的血管&#xff0c;负责输送数据这一“血液”。那么…

实验三:图像的平滑滤波

目录 一、实验目的 二、实验原理 1. 空域平滑滤波 2. 椒盐噪声的处理 三、实验内容 四、源程序和结果 (1) 主程序&#xff08;matlab&#xff09; (2) 函数GrayscaleFilter (3) 函数MeanKernel (4) 函数MedFilter 五、结果分析 1. 空域平滑滤波 2. 椒盐噪声的处理…

Python PDF文件的加密和水印处理使用详解

概要 在日常工作中,处理PDF文件是非常常见的需求。为了保护PDF文件的内容,我们可能需要对其进行加密。同时,为了防止文件被未经授权的复制和使用,添加水印也是一种有效的方法。本文将详细介绍如何使用Python对PDF文件进行加密和添加水印的操作,包含详细的示例代码,帮助全…

嵌入式系统中的GPIO控制与应用

GPIO是嵌入式系统中最常见且功能最强大的接口之一。它允许硬件工程师通过编程来配置和控制芯片上的数字引脚&#xff0c;实现输入和输出的功能。在本文中&#xff0c;我们将从理论和实践两个方面探讨GPIO的工作原理&#xff0c;并通过一个简单的示例项目来演示如何利用GPIO控制…

IP风险画像 金融行业的安全盾牌

在当今数字化时代&#xff0c;金融行业面临着前所未有的安全挑战。随着在线交易和数字银行业务的迅猛发展&#xff0c;欺诈和网络攻击的威胁也在不断增加。金融机构需要高效、可靠的安全解决方案来保护客户的资产和个人信息&#xff0c;防止各种形式的欺诈行为。 IP风险画像是…

CS110L(Rust)

1.Rust 语法总结 数值类型 有符号整数: i8, i16, i32, i64无符号整数: u8, u16, u32, u64 变量声明 声明变量: let i 0; // 类型推断let n: i32 1; // 显式类型声明 可变变量: let mut n 0; n n 1; 字符串 注意&#xff0c;let s: str "Hello world";…

WebSocket、服务器推送技术

WebSocket 是一种在单个 TCP 连接上进行 全双工 通信的协议&#xff0c;它可以让客户端和服务器之间进行实时的双向通信&#xff0c;且不存在同源策略限制 WebSocket 使用一个长连接&#xff0c;在客户端和服务器之间保持持久的连接&#xff0c;从而可以实时地发送和接收数据…

区块链与云计算的融合:新时代数据安全的挑战与机遇

随着信息技术的迅猛发展&#xff0c;云计算和区块链技术作为两大前沿技术在各自领域内展示出了巨大的潜力。而它们的结合&#xff0c;即区块链与云计算的融合&#xff0c;正在成为数据安全领域的新趋势。本文将探讨这一融合对数据安全带来的挑战和机遇&#xff0c;以及其在企业…

django实现用户的注册、登录、注销功能

创建django项目的步骤&#xff1a;Django项目的创建步骤-CSDN博客 一、前置工作 配置数据库&#xff0c;设置数据库引擎为mysql 1、在settings文件中找到DATABASES, 配置以下内容 DATABASES {"default": {ENGINE: django.db.backends.mysql, # 数据库引擎NAME: dja…

【数据结构与算法】希尔排序:基于插入排序的高效排序算法

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《数据结构与算法》 期待您的关注 ​ 目录 一、引言 二、基本原理 三、实现步骤 四、C语言实现 五、性能分析 1. 时间复杂度…

Hadoop3:HDFS-查看logs文件,排查NameNode故障原因。

问题一、NameNode进程退出 我们发现&#xff0c;NameNode进程不存在。 情况1、单独启动NameNode hdfs --daemon start namenode能够正常拉起&#xff0c;那就没问题 情况2、无法独立启动NameNode 先尝试启动NameNode hdfs --daemon start namenode发现&#xff0c;没能成…

el-date-picker手动输入日期,通过设置开始时间和阶段自动填写结束时间

需求&#xff1a;根据开始时间&#xff0c;通过填写阶段时长&#xff0c;自动填写结束时间&#xff0c;同时开始时间和节数时间可以手动输入 代码如下&#xff1a; <el-form ref"ruleForm2" :rules"rules2" :model"formData" inline label-po…

Redis深度解析:从基础到高级特性,剖析关键技术

一、关于Redis Redis介绍 REmote DIctionary Server(Redis) 是一个由 Salvatore Sanfilippo 写的 key-value 存储系统&#xff0c;是跨平台的非关系型数据库。 Redis 是一个开源的使用 ANSIC 语言编写、遵守 BSD&#xff08;开源协议&#xff09; 协议、支持网络、可基于内存…

指令判断数据更改,文本变色

默认数据是这样&#xff0c;如果更改了其中一个&#xff0c;文本框变成红色 <el-form-item label"Activity name"><el-inputv-model"form.name"v-highlight"datas[name]"input"changeValue(name)"/></el-form-item>…

excel系列(二) - 利用 easypoi 快速实现 excel 文件导入导出

一、介绍 在上篇文章中&#xff0c;我们介绍了 apache poi 工具实现 excel 文件的导入导出。 本篇我们继续深入介绍另一款优秀的 excel 工具库&#xff1a;easypoi。 二、easypoi 以前的以前&#xff0c;有个大佬程序员&#xff0c;跳到一家公司之后就和业务人员聊上了&…

智慧水利:迈向水资源管理的新时代,结合物联网、云计算等先进技术,阐述智慧水利解决方案在提升水灾害防控能力、优化水资源配置中的关键作用

本文关键词&#xff1a;智慧水利、智慧水利工程、智慧水利发展前景、智慧水利技术、智慧水利信息化系统、智慧水利解决方案、数字水利和智慧水利、数字水利工程、数字水利建设、数字水利概念、人水和协、智慧水库、智慧水库管理平台、智慧水库建设方案、智慧水库解决方案、智慧…

LLM-阿里 DashVector + langchain self-querying retriever 优化 RAG 实践【Query 优化】

文章目录 前言self querying 简介代码实现总结 前言 现在比较流行的 RAG 检索就是通过大模型 embedding 算法将数据嵌入向量数据库中&#xff0c;然后在将用户的查询向量化&#xff0c;从向量数据库中召回相似性数据&#xff0c;构造成 context template, 放到 LLM 中进行查询…