stm32和python串口数据收发

0 串口基础配置(stm32F103)

void uart_init(u32 bound){//GPIO端口设置GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);	//使能USART1时钟RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1, ENABLE); //复位串口1RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1, DISABLE);RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);  //使能GPIOA时钟//USART1_TX   GPIOA.9GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //TX PA.9GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9//USART1_RX	  GPIOA.10初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//RX PA.10GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  //Usart1 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 3 ;//抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;		//子优先级1NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器//USART 初始化设置USART_InitStructure.USART_BaudRate = 921600;//串口波特率USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式USART_Init(USART1, &USART_InitStructure); //初始化串口1USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断 USART_Cmd(USART1, ENABLE);                    //使能串口1 
}

1-1 串口发送端(stm32)

1字符串发送

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
{/* Check the parameters */assert_param(IS_USART_ALL_PERIPH(USARTx));assert_param(IS_USART_DATA(Data)); /* Transmit Data */USARTx->DR = (Data & (uint16_t)0x01FF);
}
/*****************  发送一个字符 **********************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{/* 发送一个字节数据到USART */USART_SendData(pUSARTx,ch);/* 等待发送数据寄存器为空 */while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}/*****************  发送字符串 **********************/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{unsigned int k=0;do {Usart_SendByte( pUSARTx, *(str + k) );k++;} while(*(str + k)!='\0');/* 等待发送完成 */while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET){}
}
/************状态:电机速度、位置和角位移传感器的速度、位置*****************/	 #define LPF(x, f, c) (c*x + (1-c)*f)  // 滤波motor_position = Read_Encoder_Angle(Encoder);sensor_position = Get_Adc_Average_Angle(Adc);motor_velocity = Read_Encoder_Speed(Encoder);sensor_velocity = Get_Adc_Average_Speed();pc_fil = LPF(motor_position, pc_fil,0.2f); vc_fil = LPF(motor_velocity, vc_fil,0.2f);ec_fil = LPF(sensor_position,ec_fil,0.2f);wc_fil = LPF(sensor_velocity,wc_fil,0.2f);/************** 串口发送数据方式一:使用字符串传输数据(整型和浮点型) **********************/				 sprintf(data_str, "%-8.4f, %-8.4f, %-8.4f, %-8.4f\n", pc_fil, ec_fil, vc_fil, wc_fil);Usart_SendString(USART1, data_str);

2 16进制传输(整型)

/************** 串口发送数据方式二:传输数据打包-16进制传输(整型) **********************/	
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
{/* Check the parameters */assert_param(IS_USART_ALL_PERIPH(USARTx));assert_param(IS_USART_DATA(Data)); /* Transmit Data */USARTx->DR = (Data & (uint16_t)0x01FF);
}uint8_t data_array[10];data_array[0] =  0x12;  // 帧头1data_array[1] =  0x34;  // 帧头2data_array[2] = (int)Encoder & 0xFF;         // 编码器低8位data_array[3] = ((int)Encoder >> 8) & 0xFF;  // 编码器高8位data_array[4] = (int)Adc & 0xFF;             // 编码器低8位data_array[5] = ((int)Adc >> 8) & 0xFF;      // 编码器低8位data_array[6] =  0x56;  // 帧尾1data_array[7] =  0x78;  // 帧尾2for(uint8_t  i = 0 ; i < 8; i++){USART_SendData(USART1, *(data_array + i));while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);  }

3 16进制传输(整型和浮点型)

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
{/* Check the parameters */assert_param(IS_USART_ALL_PERIPH(USARTx));assert_param(IS_USART_DATA(Data)); /* Transmit Data */USARTx->DR = (Data & (uint16_t)0x01FF);
}
/************** 串口发送数据方式三: 串口传输数据打包-16进制传输(整型和浮点型) **********************/		//函数功能:将一个浮点数转换为字节数组   倒序  大小端的问题
//入口参数:浮点数   字节数组
void FloatToByte(float floatNum, unsigned char* byteArry) {char* pchar = (char*)&floatNum;for (int i = 0; i < sizeof(float); i++) {*byteArry = *pchar;pchar++;byteArry++;}
}FloatToByte(motor_velocity, byteArry); // 8个字节数据data_array[0] =  0x12;  // 帧头1data_array[1] =  0x34;  // 帧头2data_array[2] = (int)motor_position & 0xFF;          // 电机位置低字节data_array[3] = ((int)motor_position >> 8) & 0xFF;   // 电机位置高字节/*电机速度为浮点型数据,将其十进制数转换为单精度浮点数是4个字节(32位),转换网站:http://www.styb.cn/cms/ieee_754.php*/data_array[4] = byteArry[0];	// 单精度浮点数第4个字节							data_array[5] = byteArry[1];	// 单精度浮点数第3个字节			 	data_array[6] = byteArry[2];	// 单精度浮点数第2个字节							data_array[7] = byteArry[3];	// 单精度浮点数第1个字节				data_array[8] =  0x56;  // 帧尾1data_array[9] =  0x78;  // 帧尾2for(uint8_t  i = 0 ; i < sizeof(data_array); i++) // 一个字节一个字节发送数据{USART_SendData(USART1, *(data_array + i));while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);  // 注意:此句是为防止数据还来不及发送,数据就被后面来的数据覆盖;等待发送完后继续发送下一个数据,没有过多的等待。}

4 仅发送浮点型小数

/**************串口发送数据方式四: 仅发送浮点型小数 **********************/
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
{/* Check the parameters */assert_param(IS_USART_ALL_PERIPH(USARTx));assert_param(IS_USART_DATA(Data)); /* Transmit Data */USARTx->DR = (Data & (uint16_t)0x01FF);
}//函数功能:将一个浮点数转换为字节数组   倒序  大小端的问题
//入口参数:浮点数   字节数组
void FloatToByte(float floatNum, unsigned char* byteArry) {char* pchar = (char*)&floatNum;for (int i = 0; i < sizeof(float); i++) {*byteArry = *pchar;pchar++;byteArry++;}
}
FloatToByte(motor_velocity, byteArry); // 8个字节数据
for(uint8_t  i = 0 ; i < sizeof(float); i++) // 一个字节一个字节发送数据
{USART_SendData(USART1, *(byteArry + i));while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET); // 注意:此句是为防止数据还来不及发送,数据就被后面来的数据覆盖;等待发送完后继续发送下一个数据,没有过多的等待。
}

1-2 串口接收端-python

接收数据:编码器(整型)、角位移传感器(整型)[对应1-1中的2]

# 从串口接收的数据为:编码器(整型)、角位移传感器(整型)
def read_serial_one_data_encoder_adc(ser):global receive_resultBUF_SIZE = 8buf = bytearray([0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x56, 0x78])c1 = ib = flag = 0while True:R = ser.read(1)# print("data", R)if R == b'':print("Read Fail")ser.close()breakc = int.from_bytes(R, byteorder='big') # 将接收的十六进制数转换为整数;注意,接收的十六进制会进行自动转换,如0x56是十六进制表示法,表示的是十进制数值86。而V是英文字母,它在ASCII码中的十进制表示是86。所以,0x56和V表示的是同一个字符。串口接收时会将0x56转化成V,它们实际上是同一个字符。if flag > 0:if ib < BUF_SIZE: # 位置标记ib要小于缓冲数组的最大值buf[ib] = c   # 将接收的数据保存在缓冲数组当中ib += 1       # 位置+1if ib == 8: # 如果当前位置为8,则说明数据缓冲区已满if buf[6] == 0x56 and buf[7] == 0x78: # 判断帧尾1和2是否满足规定值Encoder = (buf[3] << 8) + buf[2]  # 进行位操作。注意:buf[2]和buf[3]实际为十进制的数值,当进行位操作时,系统自动将其转换为十六进制进行位操作,最后结果仍为十进制数Adc= (buf[5] << 8) + buf[4]receive_result = [Encoder, Adc]  # 返回接收结果breakelse:print("CRC Fail")flag = 0if flag == 0:if c1 == 0x12 and c == 0x34: # 判断:是否接收到的帧头1和帧头2,且帧头1和2是否连续(帧头1在帧头2前面),若满足条件则开始接收flag = 1 # 接收数据标志位ib = 2   # 标记数据缓冲数据从第3位开始,即下标为2c1 = creturn receive_result  # 返回接收到的结果

接收数据:编码器(整型)、角位移传感器(浮点型)[对应1-1中的3]

# 函数功能:将一个字节数组转换为浮点数
# 入口参数:  字节数组
def Byte2Float(byteArry):floatNum = struct.unpack('f', byteArry)[0]return floatNum# 从串口接收的数据为:电机位置(整型)、电机速度(浮点型)
def read_serial_one_data_motor_position_velocity(ser):global receive_resultBUF_SIZE = 10buf = bytearray([0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x78]) # 定义一个字节数组,用于将数据打包,进行串口传输c1 = c2 = ib = flag = 0while True:R = ser.read(1) # 从串口接收一个字节if R == b'':print("Read Fail")ser.close()breakc = int.from_bytes(R, byteorder='big') # 将接收的十六进制数转换为整数;注意,接收的十六进制会进行自动转换,如0x56是十六进制表示法,表示的是十进制数值86。而V是英文字母,它在ASCII码中的十进制表示是86。所以,0x56和V表示的是同一个字符。串口接收时会将0x56转化成V,它们实际上是同一个字符。if flag > 0:if ib < BUF_SIZE: # 位置标记ib要小于缓冲数组的最大值buf[ib] = c   # 将接收的数据保存在缓冲数组当中ib += 1       # 位置+1if ib == 10:       # 如果当前位置为10,则说明数据缓冲区已满if buf[8] == 0x56 and buf[9] == 0x78:motor_position = (buf[3] << 8) + buf[2]motor_veclocity = Byte2Float(buf[4:8])receive_result = [motor_position, motor_veclocity]breakelse:print("CRC Fail")flag = 0if flag == 0:if c1 == 0x12 and c == 0x34:# 判断:是否接收到的帧头1和帧头2,且帧头1和2是否连续(帧头1在帧头2前面),若满足条件则开始接收flag = 1  # 接收数据标志位ib = 2    # 标记数据缓冲数据从第3位开始,即下标为2c1 = creturn receive_result  # 返回接收到的结果

2-1 串口发送端python

action = bytearray([0x12, 0x34, 0x00, 0x00, 0x00, 0x56, 0x78])
action_ = int(control_motor(result[0], result[1]))
print("action_", action_)
# 将action转化成字符串
action[0] = 0x2D   # 帧头
action[1] = 0x01   # 校验位,具体未实现,用0x01替代
if action_ < 0:action[2] = 0x45   # 符号位action[3] = action_  & 0xFF    # 数据位action[4] = (action_ >>8) & 0xFF  # 数据位action[5] = 0x0d   # 0x56是十六进制表示法,表示的是十进制数值86。而V是英文字母,它在ASCII码中的十进制表示是86。所以,0x56和V表示的是同一个字符。action[6] = 0x0a   # 0x78是十六进制表示法,表示的是十进制数值120。而x是英文字母,它在ASCII码中的十进制表示是120。所以,0x78和x表示的是同一个字符。for byte in action: # 一个一个字节发送 ,一次发送多个字节容易出错ser.write(byte.to_bytes(1, 'big'))

2-2 串口接收端stm32

void USART1_IRQHandler(void)                	//串口1中断服务程序{if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾){Res = USART_ReceiveData(USART1);	//读取接收到的数据 0x2D,0x01,0x30,0x30,0x30,0x0D,0x0Aprintf("%02X", Res);if((USART_RX_STA&0x8000)==0)//接收未完成。当接收完成时,最高位会被置为1,表示接收结束。 {if(USART_RX_STA&0x4000)//接收到了0x0D,开始执行以下代码。USART_RX_STA&0x4000判断USART_RX_STA的第14位(bit 14)是否为1。{if(Res!=0x0A){USART_RX_STA=0;//接收错误,重新开始memset(USART_RX_BUF,0,USART_REC_LEN);// 将数据缓冲区清0}else{ //接收到了0x0A,开始执行以下代码USART_RX_STA|=0x8000;	//接收完成了。将 USART_RX_STA 的第15位设置为1。这样做的目的是在接收到完整的数据时,将接收完成标志置为1,以便后续的处理程序可以知道数据已经接收完成,进行后序操作。if(USART_RX_BUF[0] == 0x2D && USART_RX_BUF[1] == 0x01 ) // 判断帧头是否正确、判断奇偶校验位是否正确 || USART_RX_BUF[1] == 0x01(USART_RX_BUF[1]为校验位,此处未定义,使用0x01替代,简化){float value = 0;int16_t sign = 1;  // 符号标记,默认为‘+’if(USART_RX_BUF[2] == 0x45) // USART_RX_BUF[2]为符号位,当其等于0x45,即‘-’,表示其为负数{sign = -1;}value = (USART_RX_BUF[4] << 8) + USART_RX_BUF[3];// 将接收的十六进制数转换为十进制	action = sign * value; // 与符号标记做乘法,等到真实值USART_RX_STA = 0; 	memset(USART_RX_BUF,0,USART_REC_LEN); // 将数据缓冲区清0}else{USART_RX_STA = 0;	memset(USART_RX_BUF,0,USART_REC_LEN);// 将数据缓冲区清0}}								}else //还没收到0X0D{	if(Res==0x0D)USART_RX_STA|=0x4000; //当接收缓冲区溢出时,第14位会被置为1,表示接收缓冲区已满。|0x4000 = 0100 0000 0000 0000else{					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res; // 将接收到的值存放在数据缓冲区中,和0X3FFF(16383)进行与运算。这样做的目的是将索引值限制在0到16383之间,避免超出数组的范围。USART_RX_STA++; // 一个16位的无符号整数变量,用于接收数据的状态变量。// USART_RX_STA 的第15位通常用于表示接收完成标志。if(USART_RX_STA>(USART_REC_LEN-1)) // 接收数据的状态变量USART_RX_STA > 串口接收长度USART_REC_LEN时,则接收数据错误,重新开始接收{USART_RX_STA=0;//接收数据的状态变量归0memset(USART_RX_BUF,0,USART_REC_LEN); // 清空接收数据缓冲区USART_RX_BUF}					}		 }}} 
}

调试过程中的问题总结

1、串口传输数据需按字节传输,不可一次性发送多个字节,如下所示:

action = bytearray([0x12, 0x34, 0x31, 0x32, 0x00, 0x56, 0x78])
ser.write(action )

在实际调试过程中,因为数据还来不及发送,数据就被后面来的数据覆盖了,导致实际接收的结果为0x12, 0x34,或0x12, 0x34, 0x32, 0x78。总之数据不完整。
因此改为每次发送一个字节,如下所示:

action = bytearray([0x12, 0x34, 0x31, 0x32, 0x00, 0x56, 0x78])
for byte in action: ser.write(byte.to_bytes(1, 'big'))

2、串口接收数据丢失,如发送固定数据为6900,偶尔会跳变为244或1等其他数据
经排查,此类情况为波特率设置过低导致的,将波特率设为较大值可解决此类情况。

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

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

相关文章

Acwing.883 高斯消元解线性方程组

题目 输入一个包含n个方程n个未知数的线性方程组。 方程组中的系数为实数。 求解这个方程组。 下图为一个包含m个方程n个未知数的线性方程组示例: 输入格式 第一行包含整数n。 接下来n行&#xff0c;每行包含n1个实数&#xff0c;表示一个方程的n个系数以及等号右侧的常数。 …

《向量数据库指南》——Rockset 为实时数据库添加向量嵌入支持(一)

同样,Venkataramani——除了是 Rockset 的联合创始人外,还担任首席执行官——表示,增加对向量嵌入的支持的关键方面是供应商现在使用户能够在一个位置管理和探索所有类型的数据。 “一个单一的数据库现在可以存储你的结构化数据、半结构化数据和你的向量嵌入来构建丰富的…

‘vue’不是内部或外部命令,也不是可运行的程序或批处理文件的原因及解决方法

今天我在用node.js的时候&#xff0c;结果出现如下错误&#xff1a; C:\Users\xiesj> vue -v vue不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。 原因&#xff1a; 1、确定npm是否已正确安装&#xff1f; 2、确定vue以及vue-cli已正确安装&#xff1f;…

记录线上一次mysql只能查询,不能插入或更新的bug

错误复现 突然有一天产品通知xx服务不可用&#xff0c;想着最近也没有服务更新&#xff0c;就先排查一下服务日志 使用postman测试的时候请求明显超时&#xff0c;查看日志显示是一个锁的问题 使用工具连接到mysql&#xff0c;查看information_schema.INNODB_TRX,发现有一个事…

Bean 和 static的区别

Bean 和 Static Static 没有办法控制在多个并发请求的时候&#xff0c;只生成一个实例。有多少个请求就会生成多少个 实例&#xff0c;那么此时如果用 Bean的方式来注解&#xff0c;就会启用SpringBoot中的单例模式&#xff0c;从始至终都只有一个实例 静态方法我们都知道&am…

Java HTTP client常见库

前言 每种编程语言里最常用的库恐怕是Http请求库了&#xff0c;如python里的requests包&#xff0c;nodejs里的request模块。 在Java世界里&#xff0c;也是百花齐放&#xff0c;山头林立。常用的有&#xff1a; HttpURLConnection: 最早的JDK提供的类Java 11提供的HttpClien…

90 | Python人工智能篇 —— 深度学习算法 Keras基于卷积神经网络的情感分类

情感分类是自然语言处理(NLP)领域的一个重要任务,它旨在将文本划分为积极、消极或中性等不同情感类别。深度学习技术,尤其是卷积神经网络(CNN),在情感分类任务中取得了显著的成果。Keras作为一个高级的深度学习框架,提供了便捷易用的工具来构建和训练情感分类模型。 文…

“从零开始学习Spring Boot:构建高效、可扩展的Java应用程序“

标题&#xff1a;从零开始学习Spring Boot&#xff1a;构建高效、可扩展的Java应用程序 简介&#xff1a; Spring Boot是一种用于简化Java应用程序开发的开源框架&#xff0c;它提供了一种快速、高效的方式来构建可扩展的应用程序。本文将介绍如何从零开始学习Spring Boot&…

【C++】做一个飞机空战小游戏(五)——getch()控制两个飞机图标移动(控制光标位置)

[导读]本系列博文内容链接如下&#xff1a; 【C】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值 【C】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动【C】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动 【C】做一个飞…

二、 MySQL 内部技术架构

二、 MySQL 内部技术架构 047 Mysql内部支持缓存查询吗&#xff1f; 当MySQL接收到客户端的查询SQL之后&#xff0c;仅仅只需要对其进行相应的权限验证之后&#xff0c;就会通过Query Cache来查找结果&#xff0c;甚至都不需要经过Optimizer模块进行执行计划的分析优化&…

腾讯云国际轻量应用服务器怎么使用呢?

腾讯云国际轻量应用服务器怎么使用呢&#xff1f;下面一起来了解一下&#xff1a; 1. 熟悉轻量应用服务器基础知识 ①什么是轻量应用服务器 TencentCloud Lighthouse&#xff1f; ②轻量应用服务器与云服务器 CVM 的区别是什么&#xff1f; ③为什么选择轻量应用服务器&#xf…

杀手锏SwissTable

杀手锏SwissTable 0.导语 最近在研究HashJoin的性能&#xff0c;发现SwissTable的性能真牛逼&#xff0c;对于原生的哈希表采用STL的unordered_multimap&#xff0c;其性能一般&#xff0c;为了加速这个查找&#xff0c;Arrow提供了SwissJoin&#xff0c;其实现原理为SwissTabl…

Java GUI——网页浏览器开发

Java GUI——网页浏览器开发 前言&#xff1a;为了做java课设&#xff0c;学了一手Java GUI。感觉蛮有意思的&#xff0c;写写文章&#xff0c;做个视频记录一下。欢迎大家友善指出我的不足 网页浏览器开发录制视频&#xff0c;从头敲到尾 任务需求 界面需求 菜单栏 文件 【…

接口测试之文件上传

在日常工作中&#xff0c;经常有上传文件功能的测试场景&#xff0c;因此&#xff0c;本文介绍两种主流编写上传文件接口测试脚本的方法。 首先&#xff0c;要知道文件上传的一般原理&#xff1a;客户端根据文件路径读取文件内容&#xff0c;将文件内容转换成二进制文件流的格式…

vue3中使用vue-simple-uploader

vue-simple-uploader本身是基于vue2的&#xff0c;直接npm i vue-simple-uploader -S下载下来版本的是0.7.6。在vue3中无法使用会报错。 解决&#xff1a;使用next安装接下来要发布的版本就会下载1.0.1版本&#xff0c;即可使用vue3 npm i vue-simple-uploadernext -S 注意&…

【linux】ssh 和adb connect区别

问&#xff1a;ssh 与ping的区别 答&#xff1a;SSH&#xff08;Secure Shell&#xff09;和Ping是两种完全不同的网络工具。 SSH是一种加密的网络协议&#xff0c;用于安全地远程管理或访问远程计算机。它提供了一种安全的通信方式&#xff0c;可以在不安全的网络上进行远程登…

SpringMVC的架构有什么优势?——视图与模型(二)

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★ React从入门到精通★ ★前端炫酷代码分享 ★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff…

【go】GIN参数重复绑定报错EOF问题

文章目录 1 问题描述2 解决&#xff1a;替换为ShouldBindBodyWith 1 问题描述 在 Gin 框架中&#xff0c;当多次调用 ShouldBind() 或 ShouldBindJSON() 方法时&#xff0c;会导致请求体的数据流被读取多次&#xff0c;从而出现 “EOF” 错误。 例如在api层绑定了参数&#x…

【数据结构】‘双向链表’冲冲冲

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

Prometheus技术文档-概念

Prometheus是一个开源的项目连接如下&#xff1a; Prometheus首页、文档和下载 - 服务监控系统 - OSCHINA - 中文开源技术交流社区 基本概念&#xff1a; Prometheus是一个开源的系统监控和告警系统&#xff0c;由Google的BorgMon监控系统发展而来。它主要用于监控和度量各种…