中科微电子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.678900printf( "b=%lf\n", strtod(b,&endptr) );   //结果为b=1234.567000printf( "endptr=%s\n", endptr );         //结果为endptr=qwerprintf( "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	TXDgpioInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;gpioInitStruct.GPIO_Pin = GPIO_Pin_9;gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &gpioInitStruct);//PA10	RXDgpioInitStruct.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	TXDgpioInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;gpioInitStruct.GPIO_Pin = GPIO_Pin_2;gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &gpioInitStruct);//PA3	RXDgpioInitStruct.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。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode算法题(移除链表中的元素)

题目如下&#xff1a; 思路1&#xff1a;创建一个新的带头链表 &#xff08;newhead&#xff09;&#xff0c;遍历头结点对应的值分别于x进行比较&#xff0c;将不等于x的节点尾插到新的带头链表中&#xff0c;返回新的带头链表的下一个节点。 代码如下&#xff1a; typedef …

路由数据获取及封装方法

数据库设计 自联表 定义tree字段 public class LabelValue{public int label { get; set; }public string? value { get; set; }public List<LabelValue> children { get; set; }}获取路由方法 public Response<object> getMenuList() {Response<object>…

RK3568笔记四十:设备树

若该文为原创文章&#xff0c;转载请注明原文出处。 一、介绍 设备树 (Device Tree) 的作用就是描述一个硬件平台的硬件资源&#xff0c;一般描述那些不能动态探测到的设备&#xff0c;可以被动态探测到的设备是不需要描述。 设备树可以被 bootloader(uboot) 传递到内核&#x…

反爬虫策略中的IP地址轮换如何实现?挑战与对策

当今互联网时代&#xff0c;各类网站、网络平台背后隐藏着大量数据&#xff0c;广告数据收集、市场数据收集都需要依托爬虫技术&#xff0c;但很多网站通过反爬虫技术限制或屏蔽爬虫的访问&#xff0c;这给数据收集带来不小的挑战。 为了规避这些反爬虫策略&#xff0c;开发人…

FastAPI 学习之路(六十)打造系统的日志输出

我们要搭建日志系统&#xff0c;可以使用loguru&#xff0c;很不错的一个开源日志系统 pip install loguru 我们在common创建log.py&#xff0c;使用方式也很简单 import os import timefrom loguru import logger# 日志的路径 log_path os.path.join(os.getcwd(), "log…

数据的力量:Facebook如何通过数据分析驱动创新

在当今数字化和信息化的时代&#xff0c;数据被认为是推动企业创新和发展的关键因素之一。作为全球最大的社交媒体平台&#xff0c;Facebook不仅积累了庞大的用户数据&#xff0c;还利用先进的数据分析技术&#xff0c;不断探索和实现新的创新。本文将深入探讨Facebook如何通过…

[iOS]内存分区

[iOS]内存分区 文章目录 [iOS]内存分区五大分区栈区堆区全局区常量区代码区验证内存使用注意事项总结 函数栈堆栈溢出栈的作用 参考博客 在iOS中&#xff0c;内存主要分为栈区、堆区、全局区、常量区、代码区五大区域 还记得OC是C的超类 所以C的内存分区也是一样的 iOS系统中&a…

引领小模型潮流!OpenAI发布功能强大且成本低的GPT-4o mini

GPT-4o mini的成本比GPT-3.5 Turbo低了超过60%&#xff0c;其聊天表现优于Google的Gemini Flash和Anthropic的Claude Haiku。该模型从周四开始对ChatGPT的免费用户、ChatGPT Plus用户和团队订阅用户开放&#xff0c;并将在下周向企业用户开放。OpenAI计划未来将图像、视频和音频…

学懂C#编程:精通C#、.NET开发之核心编程知识学习指南

无论你是编程新手&#xff0c;还是想要深化.NET技能的开发者&#xff0c;本文都将为你提供一条清晰的学习路径&#xff0c;从C#基础到高级特性&#xff0c;每一站都配有详尽解析和实用示例&#xff0c;旨在帮助你建立坚实的知识体系&#xff0c;并激发你对C#及.NET生态的热情。…

【CMU博士论文】结构化推理增强大语言模型(Part 0)

问题 &#xff1a;语言生成和推理领域的快速发展得益于围绕大型语言模型的用户友好库的普及。这些解决方案通常依赖于Seq2Seq范式&#xff0c;将所有问题视为文本到文本的转换。尽管这种方法方便&#xff0c;但在实际部署中存在局限性&#xff1a;处理复杂问题时的脆弱性、缺乏…

成为CMake砖家(5): VSCode CMake Tools 插件基本使用

大家好&#xff0c;我是白鱼。 之前提到过&#xff0c;白鱼的主力 编辑器/IDE 是 VSCode&#xff0c; 也提到过使用 CMake Language Support 搭配 dotnet 执行 CMakeLists.txt 语法高亮。 对于阅读 CMakeLists.txt 脚本&#xff0c; 这足够了。 而在 C/C 开发过程中&#xff…

【Django】网上蛋糕项目商城-注册,登录,修改用户信息,退出功能

概念 通过以上多篇文章的讲解&#xff0c;对该项目的功能已经实现了很多&#xff0c;本文将对该项目的用户注册&#xff0c;登录&#xff0c;修改用户信息&#xff0c;以及退出等功能的实现。 注册功能实现 点击head.html头部页面的注册按钮&#xff0c;触发超链接跳转至use…

开源模型应用落地-FastAPI-助力模型交互-进阶篇(三)

一、前言 FastAPI 的高级用法可以为开发人员带来许多好处。它能帮助实现更复杂的路由逻辑和参数处理&#xff0c;使应用程序能够处理各种不同的请求场景&#xff0c;提高应用程序的灵活性和可扩展性。 在数据验证和转换方面&#xff0c;高级用法提供了更精细和准确的控制&#…

离散数学,汉密尔顿图判定的实际问题,平面图,平面图的判定,欧拉公式,对偶图,五色定理的证明

目录 1.汉密尔顿图判定的实际问题 判断是否是汉密尔顿图 思考&#xff1a;下图中哪些是汉密尔顿图 例子 2.平面图 平面图的基本概念 并非所有的图都能嵌入平面 平面图的面与次数 欧拉公式 欧拉公式的证明 3.平面图的判定 同胚 kuratowski定理 ​4.对偶图 四…

从0到1搭建数据中台(4):neo4j初识及安装使用

在数据中台中&#xff0c;neo4j作为图数据库&#xff0c;可以用于数据血缘关系的存储 图数据库的其他用于主要用于知识图谱&#xff0c;人物关系的搭建&#xff0c;描述实体&#xff0c;关系&#xff0c;以及实体属性 安装 在官网 https://neo4j.com/ 下载安装包 neo4j-co…

TikTok内嵌跨境商城全开源_搭建教程/前端uniapp+后端源码

多语言跨境电商外贸商城 TikTok内嵌商城&#xff0c;商家入驻一键铺货一键提货 全开源完美运营&#xff0c;接在tiktok里面的商城内嵌&#xff0c;也可单独分开出来当独立站运营 二十一种语言&#xff0c;可以做很多国家的市场&#xff0c;支持商家入驻&#xff0c;多店铺等等…

基于Python+Django+MySQL的心理咨询预约系统

心理咨询预约系统 DjangoMySQL 基于PythonDjangoMySQL的心理咨询预约系统 项目主要依赖Django3.2&#xff0c;MySQL 支持随机验证码生成与登录验证 简介 基于PythonDjangoMySQL的心理咨询预约系统通过连接数据库获取数据&#xff0c;登录新增随机数字验证码验证。具体可以看…

[Python库](4) time库

1.time库简介 time库可以进行时间相关的处理&#xff0c;如访问当前日期和时间&#xff0c;输出不同格式的时间以及等待指定的时间等。time不需要下载&#xff0c;直接导入就可以用( 因为它是Python自带的 )。更多功能可以看另一篇文章[Python库](3) Arrow库。 2.使用 2.1.返…

大数据之数据抽取架构演变过程

架构演变之Flink架构的演变过程 一、 起初搭建整个大数据平台是基于CDH这一套资源管理和整合的CM资源管理器搭建的 整个平台包括了&#xff1a; HDFS&#xff0c;YARN&#xff0c;HIVE&#xff0c;zoozie,FLINK,Spark,Zookeeper等组件搭建而成&#xff0c; 刚开始搭建的时候&am…

如何通过企业微信会话存档保护企业利益?

赵总: 张经理&#xff0c;最近行业内频发数据泄露事件&#xff0c;我们的客户资料和内部沟通记录安全吗&#xff1f; 张经理: 赵总&#xff0c;我们已经采取了一系列措施来加强数据安全。特别是针对企业微信的沟通记录&#xff0c;我们最近引入了安企神软件&#xff0c;它能很…