STM32单片机USART串口打印和收发数据

文章目录

1. 串口通信

1.1 串口初始化

1.2 库函数

2. 串口打印

2.1 Serial.c

2.2 Serial.h

2.3 main.c

3. 串口收发数据

3.1 Serial.c

3.2 Serial.h

3.3 main.c


1. 串口通信

对于串口通信的详细解析可以看下面这篇文章

STM32单片机USART串口详解-CSDN博客

STM32单片机USART串口收发数据包

STM32单片机USART串口收发数据包-CSDN博客

USART(Universal Synchronous/Asynchronous Receiver/Transmitter)是STM32微控制器内部集成的一个硬件外设,用于串行数据通信。它能够根据数据寄存器中的一个字节数据自动生成数据帧时序,并通过TX引脚发送出去,同时也可以自动接收RX引脚的数据帧时序,将其拼接成一个字节数据并存放在数据寄存器中。

波特率生成器

  • 功能:USART内置波特率发生器,最高支持4.5 Mbps的速率。
  • 工作原理:波特率发生器通过对输入时钟频率进行分频来生成所需的波特率时钟。例如,如果APB2总线提供72 MHz的频率,波特率发生器将对其进行分频,生成所需的波特率时钟。在这个时钟下进行数据的收发,即为指定的通信波特率。

配置选项

  • 数据位长度:可配置为8位或9位数据长度。
  • 停止位长度:可选0.5、1、1.5或2个停止位。
  • 校验位:可选无校验、奇校验或偶校验。
  • 模式支持
  • 同步模式:用于需要时钟信号的通信。
  • 硬件流控制:用于避免数据丢失的问题。
  • DMA(直接存储器访问):用于大量数据传输,减轻CPU负担。
  • 智能卡模式:支持智能卡通信。
  • IrDA(红外数据协会):用于红外通信。
  • LIN(局域网络接口):用于汽车通信网络。

硬件流控制

  • 问题:当A设备通过TX向B设备的RX发送数据,如果A发送太快,B处理不过来,就可能导致数据丢失。
  • 解决方案:硬件流控制在硬件电路上多出一根线,用于反馈B设备的准备状态。
  • 当B设备没有准备好接受数据时,发送高电平信号。
  • 当B设备准备好接受数据时,发送低电平信号。
  • A设备根据B设备的反馈信号决定是否发送数据。
  • 作用:避免数据丢失的问题,确保数据传输的可靠性。
  • 使用:STM32支持硬件流控制,但一般情况下不常用。

DMA支持

  • 功能:USART支持DMA(直接存储器访问)用于数据传输。
  • 优势:在进行大量数据收发时,DMA可以直接将数据从存储器传输到USART外设或从USART外设传输到存储器,减轻了CPU的负担,提高了数据传输效率。

STM32F103C8T6的USART资源

  • USART1:连接在APB2总线上。
  • USART2、USART3:连接在APB1总线上。

1.1 串口初始化

  • 开启时钟:首先,打开USART和GPIO所需的时钟。
  • GPIO初始化:将TX引脚配置为复用输出,将RX引脚配置为输入。
  • 配置USART:使用一个结构体配置所有参数。
  • 启用USART
    • 如果只需要发送功能,直接启用USART。
    • 如果需要接收功能,还需配置中断。在启用USART之前,添加ITConfig和NVIC的相关代码。

1.2 库函数

所需要使用的函数都在文件stm32f10x_usart.h中。

回复缺省值函数
void USART_DeInit(USART_TypeDef* USARTx);
配置结构体函数
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef*
USART_InitStruct);

给结构体配置默认值函数

void USART_StructInit(USART_InitTypeDef* USART_InitStruct);
配置同步时钟输出函数
void USART_ClockInit(USART_TypeDef* USARTx, USART_ClockInitTypeDef*
USART_ClockInitStruct);
void USART_ClockStructInit(USART_ClockInitTypeDef*
USART_ClockInitStruct);
开启串口函数
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);
开启串口中断函数
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);
开启USARTDMA的触发通道函数
void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState);
设置地址函数
void USART_SetAddress(USART_TypeDef* USARTx, uint8_t USART_Address);
唤醒函数
void USART_WakeUpConfig(USART_TypeDef* USARTx, uint16_t USART_WakeUp);
LIN函数
void USART_ReceiverWakeUpCmd(USART_TypeDef* USARTx, FunctionalState NewState);
发送数据函数
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
接收数据
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);

 

2. 串口打印

这个代码实现串口打印,可以使用串口软件查看打印的数据。

2.1 Serial.c

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

//串口初始化
void Serial_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);	//开启USART1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	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);					//将PA9引脚初始化为复用推挽输出
	
	/*USART初始化*/
	USART_InitTypeDef USART_InitStructure;					//定义结构体变量
	USART_InitStructure.USART_BaudRate = 9600;				//波特率
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;	//硬件流控制,不需要
	USART_InitStructure.USART_Mode = USART_Mode_Tx;			//模式,选择为发送模式
	USART_InitStructure.USART_Parity = USART_Parity_No;		//奇偶校验,不需要
	USART_InitStructure.USART_StopBits = USART_StopBits_1;	//停止位,选择1位
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;		//字长,选择8位
	USART_Init(USART1, &USART_InitStructure);				//将结构体变量交给USART_Init,配置USART1
	
	/*USART使能*/
	USART_Cmd(USART1, ENABLE);								//使能USART1,串口开始运行
}

//串口发送一个字节
void Serial_SendByte(uint8_t Byte)
{
	USART_SendData(USART1, Byte);		//将字节数据写入数据寄存器,写入后USART自动生成时序波形
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);	//等待发送完成
	/*下次写入数据寄存器会自动清除发送完成标志位,故此循环后,无需清除标志位*/
}

/**
  * 函    数:串口发送一个数组
  * 参    数:Array 要发送数组的首地址
  * 参    数:Length 要发送数组的长度
  * 返 回 值:无
  */
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
	uint16_t i;
	for (i = 0; i < Length; i ++)		//遍历数组
	{
		Serial_SendByte(Array[i]);		//依次调用Serial_SendByte发送每个字节数据
	}
}

/**
  * 函    数:串口发送一个字符串
  * 参    数:String 要发送字符串的首地址
  * 返 回 值:无
  */
void Serial_SendString(char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i ++)//遍历字符数组(字符串),遇到字符串结束标志位后停止
	{
		Serial_SendByte(String[i]);		//依次调用Serial_SendByte发送每个字节数据
	}
}

/**
  * 函    数:次方函数(内部使用)
  * 返 回 值:返回值等于X的Y次方
  */
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;	//设置结果初值为1
	while (Y --)			//执行Y次
	{
		Result *= X;		//将X累乘到结果
	}
	return Result;
}

/**
  * 函    数:串口发送数字
  * 参    数:Number 要发送的数字,范围:0~4294967295
  * 参    数:Length 要发送数字的长度,范围:0~10
  * 返 回 值:无
  */
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i ++)		//根据数字长度遍历数字的每一位
	{
		Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');	//依次调用Serial_SendByte发送每位数字
	}
}

//使用printf需要重定向的底层函数
int fputc(int ch, FILE *f)
{
	Serial_SendByte(ch);			//将printf的底层重定向到自己的发送字节函数
	return ch;
}

//函    数:封装的prinf函数
void Serial_Printf(char *format, ...)
{
	char String[100];				//定义字符数组
	va_list arg;					//定义可变参数列表数据类型的变量arg
	va_start(arg, format);			//从format开始,接收参数列表到arg变量
	vsprintf(String, format, arg);	//使用vsprintf打印格式化字符串和参数列表到字符数组中
	va_end(arg);					//结束变量arg
	Serial_SendString(String);		//串口发送字符数组(字符串)
}

 

2.2 Serial.h

#ifndef __SERIAL_H
#define __SERIAL_H

#include <stdio.h>

void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array, uint16_t Length);
void Serial_SendString(char *String);
void Serial_SendNumber(uint32_t Number, uint8_t Length);
void Serial_Printf(char *format, ...);

#endif

 

2.3 main.c

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

int main(void)
{
	/*模块初始化*/
	OLED_Init();						//OLED初始化
	
	Serial_Init();						//串口初始化
	
	/*串口基本函数*/
	Serial_SendByte(0x41);				//串口发送一个字节数据0x41
	
	uint8_t MyArray[] = {0x42, 0x43, 0x44, 0x45};	//定义数组
	Serial_SendArray(MyArray, 4);		//串口发送一个数组
	
	Serial_SendString("\r\nNum1=");		//串口发送字符串
	
	Serial_SendNumber(111, 3);			//串口发送数字
	
	/*下述3种方法可实现printf的效果*/
	
	/*方法1:直接重定向printf,但printf函数只有一个,此方法不能在多处使用*/
	printf("\r\nNum2=%d", 222);			//串口发送printf打印的格式化字符串
										//需要重定向fputc函数,并在工程选项里勾选Use MicroLIB
	
	/*方法2:使用sprintf打印到字符数组,再用串口发送字符数组,此方法打印到字符数组,之后想怎么处理都可以,可在多处使用*/
	char String[100];					//定义字符数组
	sprintf(String, "\r\nNum3=%d", 333);//使用sprintf,把格式化字符串打印到字符数组
	Serial_SendString(String);			//串口发送字符数组(字符串)
	
	/*方法3:将sprintf函数封装起来,实现专用的printf,此方法就是把方法2封装起来,更加简洁实用,可在多处使用*/
	Serial_Printf("\r\nNum4=%d", 444);	//串口打印字符串,使用自己封装的函数实现printf的效果
	Serial_Printf("\r\n");
	
	while (1)
	{
		
	}
}

3. 串口收发数据

这个代码可以实现数据的接收,然后再将数据发送回去。

3.1 Serial.c

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

uint8_t Serial_RxData;		//定义串口接收的数据变量
uint8_t Serial_RxFlag;		//定义串口接收的标志位变量

//串口初始化
void Serial_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);	//开启USART1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	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);					//将PA9引脚初始化为复用推挽输出
	
	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);					//将PA10引脚初始化为上拉输入
	
	/*USART初始化*/
	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;	//停止位,选择1位
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;		//字长,选择8位
	USART_Init(USART1, &USART_InitStructure);				//将结构体变量交给USART_Init,配置USART1
	
	/*中断输出配置*/
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);			//开启串口接收数据的中断
	
	/*NVIC中断分组*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);			//配置NVIC为分组2
	
	/*NVIC配置*/
	NVIC_InitTypeDef NVIC_InitStructure;					//定义结构体变量
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;		//选择配置NVIC的USART1线
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//指定NVIC线路使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;		//指定NVIC线路的抢占优先级为1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;		//指定NVIC线路的响应优先级为1
	NVIC_Init(&NVIC_InitStructure);							//将结构体变量交给NVIC_Init,配置NVIC外设
	
	/*USART使能*/
	USART_Cmd(USART1, ENABLE);								//使能USART1,串口开始运行
}

//串口发送一个字节
void Serial_SendByte(uint8_t Byte)
{
	USART_SendData(USART1, Byte);		//将字节数据写入数据寄存器,写入后USART自动生成时序波形
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);	//等待发送完成
	/*下次写入数据寄存器会自动清除发送完成标志位,故此循环后,无需清除标志位*/
}

/**
  * 函    数:串口发送一个数组
  * 参    数:Array 要发送数组的首地址
  * 参    数:Length 要发送数组的长度
  */
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
	uint16_t i;
	for (i = 0; i < Length; i ++)		//遍历数组
	{
		Serial_SendByte(Array[i]);		//依次调用Serial_SendByte发送每个字节数据
	}
}

/**
  * 函    数:串口发送一个字符串
  * 参    数:String 要发送字符串的首地址
  */
void Serial_SendString(char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i ++)//遍历字符数组(字符串),遇到字符串结束标志位后停止
	{
		Serial_SendByte(String[i]);		//依次调用Serial_SendByte发送每个字节数据
	}
}

/**
  * 函    数:次方函数(内部使用)
  * 返 回 值:返回值等于X的Y次方
  */
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;	//设置结果初值为1
	while (Y --)			//执行Y次
	{
		Result *= X;		//将X累乘到结果
	}
	return Result;
}

/**
  * 函    数:串口发送数字
  * 参    数:Number 要发送的数字,范围:0~4294967295
  * 参    数:Length 要发送数字的长度,范围:0~10
  */
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i ++)		//根据数字长度遍历数字的每一位
	{
		Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');	//依次调用Serial_SendByte发送每位数字
	}
}

//使用printf需要重定向的底层函数
int fputc(int ch, FILE *f)
{
	Serial_SendByte(ch);			//将printf的底层重定向到自己的发送字节函数
	return ch;
}

/**
  * 函    数:自己封装的prinf函数
  * 参    数:format 格式化字符串
  * 参    数:... 可变的参数列表
  */
void Serial_Printf(char *format, ...)
{
	char String[100];				//定义字符数组
	va_list arg;					//定义可变参数列表数据类型的变量arg
	va_start(arg, format);			//从format开始,接收参数列表到arg变量
	vsprintf(String, format, arg);	//使用vsprintf打印格式化字符串和参数列表到字符数组中
	va_end(arg);					//结束变量arg
	Serial_SendString(String);		//串口发送字符数组(字符串)
}

/**
  * 函    数:获取串口接收标志位
  * 返 回 值:串口接收标志位,范围:0~1,接收到数据后,标志位置1,读取后标志位自动清零
  */
uint8_t Serial_GetRxFlag(void)
{
	if (Serial_RxFlag == 1)			//如果标志位为1
	{
		Serial_RxFlag = 0;
		return 1;					//则返回1,并自动清零标志位
	}
	return 0;						//如果标志位为0,则返回0
}

/**
  * 函    数:获取串口接收的数据
  * 返 回 值:接收的数据,范围:0~255
  */
uint8_t Serial_GetRxData(void)
{
	return Serial_RxData;			//返回接收的数据变量
}

/**
  * 函    数:USART1中断函数
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
  *           函数名为预留的指定名称,可以从启动文件复制
  *           请确保函数名正确,不能有任何差异,否则中断函数将不能进入
  */
void USART1_IRQHandler(void)
{
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)		//判断是否是USART1的接收事件触发的中断
	{
		Serial_RxData = USART_ReceiveData(USART1);				//读取数据寄存器,存放在接收的数据变量
		Serial_RxFlag = 1;										//置接收标志位变量为1
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);			//清除USART1的RXNE标志位
																//读取数据寄存器会自动清除此标志位
																//如果已经读取了数据寄存器,也可以不执行此代码
	}
}

3.2 Serial.h

#ifndef __SERIAL_H
#define __SERIAL_H

#include <stdio.h>

void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array, uint16_t Length);
void Serial_SendString(char *String);
void Serial_SendNumber(uint32_t Number, uint8_t Length);
void Serial_Printf(char *format, ...);

uint8_t Serial_GetRxFlag(void);
uint8_t Serial_GetRxData(void);

#endif

3.3 main.c

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

uint8_t RxData;			//定义用于接收串口数据的变量

int main(void)
{
	/*模块初始化*/
	OLED_Init();		//OLED初始化
	
	/*显示静态字符串*/
	OLED_ShowString(1, 1, "RxData:");
	
	/*串口初始化*/
	Serial_Init();		//串口初始化
	
	while (1)
	{
		if (Serial_GetRxFlag() == 1)			//检查串口接收数据的标志位
		{
			RxData = Serial_GetRxData();		//获取串口接收的数据
			Serial_SendByte(RxData);			//串口将收到的数据回传回去,用于测试
			OLED_ShowHexNum(1, 8, RxData, 2);	//显示串口接收的数据
		}
	}
}

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

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

相关文章

基于java+springboot+vue实现的智慧生活商城系统(文末源码+Lw)244

摘 要 计算机网络发展到现在已经好几十年了&#xff0c;在理论上面已经有了很丰富的基础&#xff0c;并且在现实生活中也到处都在使用&#xff0c;可以说&#xff0c;经过几十年的发展&#xff0c;互联网技术已经把地域信息的隔阂给消除了&#xff0c;让整个世界都可以即时通…

数据中心:AI范式下的内存挑战与机遇

在过去的十年里&#xff0c;数据中心和服务器行业经历了前所未有的扩张&#xff0c;这一进程伴随着CPU核心数量、内存带宽(BW)&#xff0c;以及存储容量的显著增长。这种超大规模数据中心的扩张不仅带来了对计算能力的急剧需求&#xff0c;也带来了前所未有的内存功率密度挑战&…

BigDataCloud 反向地理编码

在当今数字化飞速发展的时代&#xff0c;地理信息的精确获取和游戏数据的深入分析成为众多领域的关键需求。2024 年的今天&#xff0c;技术的创新为我们带来了更为出色的 API 服务。BigDataCloud 反向地理编码服务&#xff0c;能够将经纬度迅速而准确地转换为详细位置信息&…

iOS 中,autoreleasepool 的底层实现

在 iOS 中&#xff0c;autoreleasepool 的底层实现基于 Objective-C 运行时&#xff08;runtime&#xff09;和内存管理机制。 图解说明 Objective-C Runtime 和 Autoreleasepool 的创建 在 Objective-C 中&#xff0c;每次进入一个 autoreleasepool 块时&#xff0c;都会创建…

MySQL之复制(十)

复制 改变主库 确定期望的日志位置 如果有备库和新主库的位置不相同&#xff0c;则需要找到该备库最后一条执行的时间在新主库的二进制日志中相应的位置&#xff0c;然后再执行CHANGE MASTER TO.可以通过mysqlbinlog工具来找到备库执行的最后一条查询&#xff0c;然后在主库上…

宇宙星空星辰美景素材哪里找?高清无水印分享

宇宙星空的美丽总能激发人们的无限遐想和灵感&#xff0c;不仅在科学教育领域&#xff0c;更在电影制作和视觉艺术中占有一席之地。为了帮助您找到高质量的宇宙星空视频素材&#xff0c;以下平台将成为您获取令人难忘天体视频素材的首选。 蛙学府 蛙学府作为新媒体创作者的宝库…

FEP容量瓶生产厂商半导体行业耐强酸强碱耐高低温

FEP容量瓶&#xff0c;氟四六容量瓶&#xff0c;特氟龙容量瓶&#xff0c;耐腐蚀耐高温。广泛应用于ICP-MS、ICP-OES等痕量分析以及同位素分析等实验。地质、电子化学品、半导体分析测试、疾控中心、制药厂、环境检测中心等一些机构定容用。 规格参考&#xff1a;10ml、25ml、5…

JupyterLab使用指南(七):JupyterLab使用 LaTeX 生成数学公式

在 JupyterLab 中&#xff0c;可以使用 LaTeX 语法生成复杂的数学公式。JupyterLab 内置对 LaTeX 的支持&#xff0c;使得我们可以方便地在 notebook 中编写和展示数学公式。以下是详细的步骤和示例。 1. 使用 LaTeX 生成数学公式 LaTeX 是一种专门用于排版数学公式的语言。J…

React实现列表列宽可拖拽

1.中文文档上没有&#xff0c;英文文档上有&#xff08;这个老六&#xff01;&#xff01;&#xff09; <Tableborderedcomponents{{header: {cell: ResizableTitle,},}}columns{mergedColumns}dataSource{data} />React - Resizable column

TCP 和 UDP 可以同时绑定相同的端口吗?

在网络编程中&#xff0c;TCP和UDP都可以绑定到同一个端口上进行通信。TCP和UDP是OSI模型中的传输层协议&#xff0c;它们分别使用不同的端口号来区分不同的应用程序或服务。 TCP&#xff08;Transmission Control Protocol&#xff09;提供了面向连接的、可靠的传输服务&…

面向服务的架构(Service-Oriented Architecture, SOA)

目录 前言1. SOA的基本概念1.1 定义和特点1.2 核心原则 2. SOA的优势与挑战2.1 优势2.2 挑战 3. SOA的实现技术3.1 Web服务3.2 微服务架构3.3 企业服务总线&#xff08;ESB&#xff09; 4. SOA在现代企业中的应用4.1 金融行业4.2 电子商务4.3 政府和公共服务4.4 医疗健康 结语 …

VBA学习(18):VBA制作任意工作表均可使用的聚光灯

在需要制作聚光的工作簿&#xff0c;按<ALTF11>组合键&#xff0c;打开VBE编辑器。在右侧[工程资源管理器窗格]选中ThisWorkbook模块&#xff0c;将以下代码复制粘贴到该模块的代码窗口。 Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target …

【源码】人力资源管理系统hrm功能剖析及源码

eHR人力资源管理系统&#xff1a;功能强大的人力资源管理工具 随着企业规模的不断扩大和业务需求的多样化&#xff0c;传统的人力资源管理模式已无法满足现代企业的需求。eHR人力资源管理系统作为一种先进的管理工具&#xff0c;能够为企业提供高效、准确、实时的人力资源管理。…

小熊文件工具箱免费版

小熊文件工具箱是一款基于本地离线操作的一系列工具的合集&#xff0c;最大特点是各种批量任务的执行&#xff0c;包含了智能证件照&#xff0c;自动抠图&#xff0c;直播录制&#xff0c;九宫格切图&#xff0c;拼图&#xff0c;视频格式转换及压缩&#xff0c;zip压缩解压缩&…

【Arthas案例】应用包含两个相同全限定类名StaticLoggerBinder,引起log4j.Level类找不到异常

3分钟内解决问题 两个不同的GAV依赖冲突&#xff0c;包含相同全限定类名&#xff0c;引起ClassNotFoundException Maven依赖的三坐标体系GAV(G-groupId&#xff0c;A-artifactId&#xff0c;V-version) 【案例1】某应用依赖两个GAV不同的jar&#xff0c;但包含两个相同全限定类…

如何快速熟悉新公司产品

业务流程图 刚刚入职一家新公司&#xff0c;一般肯定是想快速提现自己的价值&#xff0c;让公司知道招聘到自己真是一件赚到的事情&#xff0c;但是往往我们都是接着上个产品的锅&#xff0c;不知道从何下手。 如果之前了解一点业务还好说&#xff0c;但是大部分时候我们做产品…

linux挂载硬盘(解决linux不显示硬盘问题)

目录 1.查看系统有几块硬盘2.查看挂载情况3.格式化硬盘4.创建挂载目录用于挂载硬盘5.将硬盘挂载到指定的挂载目录6.随系统自启动挂载查看配置文件&#xff0c;看是否已经把这条命令加入配置 帮同门解决挂载失败问题记录 参考视频&#xff1a;只要6步&#xff01;Linux系统下挂载…

WindTerm软件的本地模式和远程模式

WindTerm作为一个多功能的远程终端控制软件&#xff0c;支持本地模式和远程模式两种键盘输入处理方式&#xff0c;这两种模式的主要区别在于键盘输入的处理逻辑和目标&#xff1a; 本地模式&#xff08;Local Mode&#xff09; 在本地模式下&#xff0c;WindTerm不对键盘输入…

Kubernetes(K8s)

K8s是为了解决微服务架构中大量容器部署和管理的问题。 希腊语“舵手”的意思。K8s是一个开源的容器编排平台&#xff0c;用于自动部署、扩展和管理容器化应用程序。最初由Google设计并捐赠给CNCF来维护。 K8s需要部署在至少2台机器的硬件集群环境中&#xff0c;K8s也叫云原生操…

深入解析 iOS 应用启动过程:main() 函数前的四大步骤

深入解析 iOS 应用启动过程&#xff1a;main() 函数前的四大步骤 背景描述&#xff1a;使用 Objective-C 开发的 iOS 或者 MacOS 应用 在开发 iOS 应用时&#xff0c;我们通常会关注 main() 函数及其之后的执行逻辑&#xff0c;但在 main() 函数之前&#xff0c;系统已经为我们…