目录

UART通信协议的介绍

实现串口数据发送

CubeMX配置

printf重定向代码编写

实现串口数据接收

轮询方式实现串口数据接收

接收单个字符

接收不定长字符串(接收的字符串以\n结尾)

中断方式实现串口数据接收

CubeMX配置

UART中断方式接收数据函数是一次性的

HAL_UART_Receive_IT() 调用位置

接收单个字符

接收不定长字符串


UART通信协议的介绍

UART (Universal Asynchronous Receiver/Transmitter) 是一种串行异步全双工通信协议

UART通信的核心思想是异步串行,全双工

  • 异步 (Asynchronous):通信双方不需要共享一个时钟信号来同步数据传输。取而代之的是,通过起始位 (Start Bit) 标记数据帧的开始,通过停止位 (Stop Bit) 标记数据帧的结束,以及预先约定好的波特率 (Baud Rate) 来协调数据的采样时间。
     

  • 串行 (Serial):数据一位一位地按顺序在线路上传输,而不是并行多位同时传输。这使得只需要两根线。

异步详细介绍

  • 发送方: 按照预设的波特率,精确地控制每个数据位、起始位和停止位的持续时间,并将其串行发送出去。
     

  • 接收方: 同样按照预设的波特率,在检测到起始位后,精确地计算每个数据位的采样时间点,从而正确读取数据。

进行异步通信,通信的每一方都必须拥有自己的内部时钟,如果没有各自的内部时钟,发送方就无法知道何时发送下一个比特,接收方也无法知道何时去读取数据线上的电平。

通信双方的波特率必须相同,否则将导致数据错乱。

使用串口助手进行串口通信的时候,是满足这里的要求的,电脑上面有时钟,同时开发板内部的UART也有时钟。

串行,全双工详细介绍

标准的UART通信通常只需要两根信号线:

  • TX (Transmit):发送数据线,用于发送数据。

  • RX (Receive):接收数据线,用于接收数据。

连接方式是交叉连接:发送方的TX连接到接收方的RX,发送方的RX连接到接收方的TX。

由于发送和接收使用不同的物理线路,它们互不干扰,所以发送方可以在向接收方发送数据的同时,接收方也可以向发送方发送数据。UART协议全双工通信协议

实现串口数据发送

CubeMX配置

配置好时钟源之后,选择USART1之后选择模式为异步模式就可以了,剩下的配置不需要动。

选完之后我们会发现这里多了两个选中的引脚, TX(发送)RX(接收)

如果选择同步通信方式的话还会有一根时钟线用于同步操作。

在USART协议中我们其实是可以选择使用同步方式(synchronous)或者异步方式(Asynchronous)进行数据的发送和接收的 ,不过一般异步方式用的多,同步方式通信一般会选择其他类型协议如 SPI、I²C。

printf重定向代码编写

串口调试助手在没有显示屏的嵌入式系统中有着很好的应用,可以利用函数重定向功能,调用printf函数,将开发板中获取到的数据通过串口刷出到PC,为程序调试和串口通信提供了很大的便利。

我们不能直接调用printf将数据输出到串口,要想实现printf重定向功能,还需要进行重写一下fputc函数

为什么 printf 默认不能输出到串口?

在 C 标准库中,printf() 的本质是将格式化后的字符串输出到一个默认的标准输出设备,这个设备在 PC 上通常是终端(屏幕),但在 MCU(如 STM32)里:

  • 没有默认的标准输出设备(没有屏幕、没有操作系统);

  • 所以 printf() 其实调用的是底层函数如 fputc()_write(),但这些在裸机环境下是 空实现报错实现

fputc的函数原型照抄就行,这里的第二个参数用不到,不需要处理。

fputc函数的作用是输出单个字符,所以这里使用HAL_UART_Transmit实现fputc输出字符的时候,参数选择字节数为1就行。这样实现出来的输出字符串到串口助手的效果非常好,还很简便,不需要我们判断发送到串口的字符串长度逻辑(printf帮我们做了,我们只需要实现单个字符发送就可以!)

int fputc(int ch, FILE *f)
{HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, HAL_MAX_DELAY);return ch;
}

 HAL_UART_Transmit函数介绍

  1. UART_HandleTypeDef *huart (第一个参数):

    这是一个指向 UART_HandleTypeDef 结构体的指针。这个结构体包含了特定 UART 外设的所有配置信息和状态。

     
  2. uint8_t *pData (第二个参数):

    这是一个指向要发送数据的缓冲区的指针。uint8_t 表示数据是以字节(8位)的形式传输。函数会从这个地址开始读取数据并发送出去。

     
  3. uint16_t Size (第三个参数):

    这是一个 uint16_t 类型的变量,表示要发送的数据的字节数(长度)。

     
  4. uint32_t Timeout (第四个参数):
  • 这是一个 uint32_t 类型的变量,表示数据发送操作的超时时间,单位是毫秒(ms)。
  • 如果在指定的时间内数据没有发送完成,函数将返回 HAL_TIMEOUT。
  • 使用 HAL_MAX_DELAY 表示无限等待,直到数据发送完成(或发生错误),这在不希望有超时限制的情况下很常用。

由于使用了printf这个函数,所以我们需要在main.c文件中包含对应的头文件:

#include "stdio.h"

  /* Initialize all configured peripherals */MX_GPIO_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */uint16_t cnt=0;/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */printf("this is a message from stm32 cnt : %d\n", cnt++);/* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

Keil中对文件勾选配置:Use MicroLIB

效果展示: 

实现串口数据接收

轮询方式实现串口数据接收

接收单个字符

uint8_t receive_data;/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */HAL_UART_Receive(&huart1, &receive_data, 1, HAL_MAX_DELAY);printf("receive data: %c\r\n", receive_data);/* USER CODE BEGIN 3 */}

接收不定长字符串(接收的字符串以\n结尾)

    uint8_t receive_data;uint8_t receive_buf[256] = {0};uint8_t index = 0;/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */HAL_UART_Receive(&huart1, &receive_data, 1, HAL_MAX_DELAY);if(receive_data != '\n'){receive_buf[index++] = receive_data;}else{receive_buf[index++] = '\0';printf("receive data: %s\r\n", receive_buf);index = 0;memset(receive_buf, 0, sizeof(receive_buf));}/* USER CODE BEGIN 3 */}

代码介绍 

这段代码是典型的使用 HAL 库的轮询(阻塞)模式接收串口数据,并以换行符 \n 作为结束标志 的实现。

这段代码的主要功能是:

  1. 在无限循环 while(1) 中,阻塞式地等待 接收 UART1 的一个字节数据。
     
  2. 如果接收到的字节不是换行符 \n,则将其存储到 receive_buf 缓冲区中。
     
  3. 如果接收到换行符 \n,则认为一帧数据接收完毕:
    • 在缓冲区末尾添加字符串结束符 \0。
    • 通过 printf 打印接收到的字符串。
    • 重置 index 为 0,准备接收下一帧数据。
    • 清空 receive_buf 缓冲区。

代码优缺点:

优点

  1. 简单易懂: 对于初学者来说,这种轮询加阻塞的模式是最容易理解和实现的。逻辑直接,容易跟踪。

  2. 便于调试: 由于是阻塞式的,每次接收一个字节,单步调试时可以清晰地看到数据流。

  3. 处理明确的结束符: 使用 \n 作为帧结束符是文本协议中常见且有效的方式,使得数据包的边界清晰。

缺点

CPU 效率极低(最主要的问题):

  • HAL_UART_Receive(&huart1, &receive_data, 1, HAL_MAX_DELAY); 这行代码会无限期阻塞,直到接收到一个字节。这意味着在没有数据到达时,CPU 会一直停在这里等待,无法执行其他任何任务

  • 这对于任何需要做其他事情(比如控制LED、读取传感器、处理按键等)的实时嵌入式系统来说都是不可接受的。CPU 的大部分时间都会被浪费在等待串口数据上。

注意看,我们在使用串口助手向开发板发送数据的时候,需要加上一个换行符,表示发送的这串字符串结束了。开发板内部的串口处理程序,顺序收到/n之后,根据判断逻辑就会输出缓冲区积攒的字符串。

中断方式实现串口数据接收

CubeMX配置

相比于上面采用非中断模式来实现串口数据接收,采用中断方式的话,需要将Uart1对应的中断打开

UART中断方式接收数据函数是一次性的

HAL_StatusTypeDef  HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

函数作用:启动 UART1 的中断接收,期望接收 uint16_t Size 个字节

HAL_UART_Receive_IT(&huart1, rx_buffer, 1); // 推荐每次只接收一个字节

虽然调用一次函数可以选择接收多个字节数据,但是我们通常选择调用一次UART中断接收数据函数只接收一个字节,会在中断回调里处理并再次启动接收函数

为什么说UART 中断接收函数为何说是“一次性的”?

  1. 这句话的意思是,当你调用 HAL_UART_Receive_IT(&huart, pData, Size); 这个函数后,它只会启动一次中断接收过程,并等待接收指定数量(Size)的字节
     
  2. 一旦 UART 接收到这 Size 个字节的数据,这个函数所启动的当前接收任务就完成了。UART 接收中断会相应地被触发,执行你的回调函数 HAL_UART_RxCpltCallback()。
     
  3. 但是,此时 UART 并不会自动开始接收下一组数据 如果你想继续接收数据,你需要再次调用 HAL_UART_Receive_IT() 来“重新武装”UART 硬件,让它准备好接收下一批数据,通常我们会选择在回调函数HAL_UART_RxCpltCallback中再次启动接收函数

HAL_UART_Receive_IT() 调用位置

HAL_UART_Receive_IT() 函数推荐在以下几个地方调用:

1. main() 函数的初始化部分

这是最常见和推荐的调用位置。 在你的 main.c 文件中,通常在所有硬件初始化完成(例如 MX_GPIO_Init()、MX_USARTx_UART_Init() 等)之后,while(1) 无限循环之前,调用一次 HAL_UART_Receive_IT() 来启动串口的首次接收。

int main(void)
{// ... 系统初始化 ...HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_USART1_UART_Init();// ... 其他外设初始化 .../* USER CODE BEGIN 2 */// 启动 UART1 的中断接收,期望接收 SOME_BUFFER_SIZE 个字节// 或者通常只接收一个字节,在中断回调里处理并再次启动HAL_UART_Receive_IT(&huart1, rx_buffer, 1); // 推荐每次只接收一个字节/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */

2. UART 接收完成回调函数 HAL_UART_RxCpltCallback() 中

// 这个函数是弱声明,你需要重写它
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if (huart->Instance == USART1){// 假设这里处理了接收到的数据 rx_buffer// Process_Received_Data(rx_buffer);// 重新启动下一次中断接收HAL_UART_Receive_IT(&huart1, rx_buffer, 1); // 再次启动接收一个字节}
}

接收单个字符

让我们用一个小栗子来进行实现一下中断接收单个字符吧。

代码功能

这里我们想要实现的是通过串口助手,每次发送一个字符1/2/3/4来控制LED1/2/3/4,比如发送一个1,LED1电平就翻转,再次输入1LED1电平就再次翻转。LED2/3/4同理。

这里为了展现出中断方式接收数据不阻塞主程序执行,我们在main函数中还持续用向串口发送字符串"hello world"

代码实现如下:

在main.c中定义成一个全局变量
/* USER CODE BEGIN PV */uint8_t receive_data;//存放UART1接收到的数据
/* USER CODE END PV */函数声明部分
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
int fputc(int ch, FILE *f);
/* USER CODE END PFP */main函数里面
/* Initialize all configured peripherals */MX_GPIO_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */HAL_UART_Receive_IT(&huart1, &receive_data, 1);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */printf("hello world\r\n");HAL_Delay(1000);/* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}main函数中定义的函数的具体实现
/* USER CODE BEGIN 4 */
int fputc(int ch, FILE *f)
{HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, HAL_MAX_DELAY);return ch;
}void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){if(huart->Instance == USART1){if(receive_data == '1'){HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_10);}else if(receive_data == '2'){HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_2);}else if(receive_data == '3'){HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_1);}else if(receive_data == '4'){HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0);}}HAL_UART_Receive_IT(&huart1, &receive_data, 1);
}
/* USER CODE END 4 */

代码编写时候需要注意的就是

  • HAL_UART_Receive_IT()需要在main函数初始化的时候调用,
     
  • 还需要在 HAL_UART_RxCpltCallback中调用

接收不定长字符串

代码实现思路

  1. 每次只接收一个字节: 在中断模式下,将 HAL_UART_Receive_IT() 的 Size 参数设置为 1。这样每接收到一个字节,就会触发一次接收完成中断。
     
  2. 使用缓冲区 (Buffer): 在中断服务程序中,将接收到的每一个字节存入缓冲区。
     
  3. 在主循环中判断数据完整性: 主循环会不断地检查缓冲区中是否有完整的字符串帧(通常通过查找特定的结束符,如 \n )。
     
  4. 重新启动接收: 在每次接收完成中断回调函数中,都需要再次调用 HAL_UART_Receive_IT() 来“重新武装”串口,准备接收下一个字节。

CubeMX配置

上面已经说过了,主要需要注意的是记得在NVIC 设置中,勾选开启对应 UART 全局中断的 Enabled

代码实现

额外包含头文件
#include "stdio.h"
#include "string.h"main.c中定义的全局变量
/*
这里定义成全局变量的原因:
回调函数的实现以及main函数中都要用到这些变量
*/
/* USER CODE BEGIN PV */uint8_t receive_data;uint8_t receive_buf[256] = {0};uint8_t receive_buf_index = 0;
/* USER CODE END PV */函数声明
/* USER CODE BEGIN PFP */
int fputc(int ch, FILE* f);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
/* USER CODE END PFP */main函数中代码
HAL_UART_Receive_IT(&huart1, &receive_data, 1);/* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */printf("hello world\r\n");HAL_Delay(1000);/* USER CODE BEGIN 3 */}代码实现部分
int fputc(int ch, FILE* f){HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, HAL_MAX_DELAY);	return ch;
}void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){if(huart->Instance == USART1){if(receive_data != '\n'){receive_buf[receive_buf_index++] = receive_data;}else{receive_buf[receive_buf_index++] = '\0';printf("receive data: %s\r\n", receive_buf);receive_buf_index = 0;memset(receive_buf, 0, sizeof(receive_buf));}HAL_UART_Receive_IT(&huart1, &receive_data, 1);}
}

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

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

相关文章

Kafka 生产者和消费者高级用法

Kafka 生产者和消费者高级用法 1 生产者的事务支持 Kafka 从版本0.11开始引入了事务支持,使得生产者可以实现原子操作,确保消息的可靠性。 // 示例代码:使用 Kafka 事务 producer.initTransactions(); try {producer.beginTransaction();pr…

k8s中crictl命令常报错解决方法

解决使用crictl命令时报默认端点弃用的报错 报错核心原因 默认端点弃用: crictl 会默认尝试多个容器运行时端点(如 dockershim.sock、containerd.sock 等),但这种 “自动探测” 方式已被 Kubernetes 弃用(官方要求手动…

回转体水下航行器简单运动控制的奥秘:PID 控制和水动力方程的运用

在水下航行器的控制领域中,回转体水下航行器的运动控制是一个关键课题。 今天,就来深入探讨一下其简单运动控制中,PID 控制以及水动力方程的相关运用。 PID 控制的基本原理PID 控制(比例 - 积分 - 微分控制)是一种广…

从入门到精通:npm、npx、nvm 包管理工具详解及常用命令

目录 1. 引言2. npm (Node Package Manager)2.1 定义与用途2.2 常见命令2.3 使用示例 3. npx (Node Package Execute)3.1 定义与用途3.2 常见命令3.3 使用示例3.4 npm 与 npx 的区别 4. nvm (Node Version Manager)4.1 定义与用途4.2 安装 nvm4.3 常见命令4.4 使用示例 5. 工具…

es6特性-第二部分

Promise 介绍和基本使用 Promise是ES6引入的异步编程的新解决方案,主要用来解决回调地狱问题。语法上 Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。 Promise构造函数:new Promise() Promise.prototype.then方法 Promise.prototype.ca…

java:如何用 JDBC 连接 TDSQL 数据库

要使用JDBC连接TDSQL数据库&#xff08;腾讯云分布式数据库&#xff0c;兼容MySQL协议&#xff09;&#xff0c;请按照以下步骤编写Java程序&#xff1a; 1. 添加MySQL JDBC驱动依赖 在项目的pom.xml中添加依赖&#xff08;Maven项目&#xff09;&#xff1a; <dependenc…

2025年四川省高考志愿填报深度分析与专业导向策略报告——基于599分/24000位次考生-AI

2025年四川省高考志愿填报深度分析与专业导向策略报告——基于599分/24000位次考生 摘要 本报告旨在为预估高考成绩599分、全省物理类位次在24,000名左右的2025年四川考生&#xff0c;提供一份兼具科学性、前瞻性与专业深度的志愿填报策略方案。报告严格遵循“位次法”为核心…

spring boot项目整合百度翻译

本片文章教大家怎样在spring boot项目中引入百度翻译&#xff0c;并且优雅的使用百度翻译。 首先&#xff0c;我们要了解为什么要使用翻译插件。为了支持多语言的国际化&#xff1b; 目前市面上最常见的后端国际化就是在resource资源目录下设置多个语言文档&#xff0c;这些文…

凌晨2点自动备份mysql 数据库,mysql_backup.sh

1、编写备份脚本&#xff1a;vim mysql_backup.sh #!/bin/bash DATE$(date %Y%m%d_%H%M%S) BACKUP_DIR"/data/mysql/backup" USER"backup_user" PASSWORD"backup**"# 逻辑备份所有数据库 mysqldump -u$USER -p$PASSWORD eblp | gzip > $BA…

Linux系统之Tomcat服务

目录 一、Tomcat概述 1、Tomcat介绍 2、Tomcat历史 二、Tomcat原理分析 1、Http工作原理 2、Tomcat整体架构 3、Coyote连接器架构 4、Catalina容器架构 5、Jasper处理流程 6、JSP编译过程 7、Tomcat启动流程 8、Tomcat请求处理流程 三、Tomcat安装与配置 1、单实…

FPGA芯片的供电

FPGA芯片的供电 文章目录 FPGA芯片的供电1. 外部端口供电机制2. 内部逻辑供电机制3. 专有电路供电机制4. 电源稳定性讨论总结 1. 外部端口供电机制 FPGA是专门用于数字系统设计的芯片&#xff0c;能够正确、可靠、高效地和外界其他数字电路进行通信是FPGA芯片必备的一个功能。…

构建可无限扩展的系统:基于 FreeMarker + 存储过程 + Spring Boot 的元数据驱动架构设计

在构建面向多行业、多客户的大型业务系统时&#xff0c;系统的灵活性与扩展能力成为架构设计的核心目标。传统硬编码的开发方式在面对高频变化、复杂组合查询、多租户自定义字段时&#xff0c;往往难以适应。 为了解决上述问题&#xff0c;我们提出一种 以 FreeMarker 脚本托管…

2-深度学习挖短线股-3-训练数据计算

2-3 合并输入特征 首先定义了数据预处理函数&#xff0c;将连续 n 天的 K 线数据&#xff08;如开盘价、收盘价、成交量等&#xff09;合并为一行特征&#xff0c;同时保留对应的目标标签&#xff08;buy 列&#xff0c;表示是否应该买入&#xff09;&#xff1b;然后读取股票代…

SpringMVC系列(四)(请求处理的十个实验(下))

0 引言 作者正在学习SpringMVC相关内容&#xff0c;学到了一些知识&#xff0c;希望分享给需要短时间想要了解SpringMVC的读者朋友们&#xff0c;想用通俗的语言讲述其中的知识&#xff0c;希望与诸位共勉&#xff0c;共同进步&#xff01; 本系列会持续更新&#xff01;&…

产线通信“变形记”:PROFIBUS-DP与ETHERNET/IP的食品饮料跨界融合

在食品饮料加工行业&#xff0c;为实现不同设备间高效通信&#xff0c;JH-PB-EIP疆鸿智能PROFIBUS DP转ETHERNET/IP网关发挥着关键作用。西门子PLC常采用PROFIBUS DP协议&#xff0c;而码垛机器人等设备多使用ETHERNET/IP协议&#xff0c;网关成为连接二者的桥梁。 将DP作为从站…

设计模式-观察者模式(发布订阅模式)

一、需要的类 一个发布类&#xff1a;里面一个是别人需要订阅的属性&#xff0c;以及用于存储订阅者的list&#xff0c;attach方法是往list集合里面添加元素&#xff0c;notifyObservers通知方法&#xff0c;也就是循环调用订阅者里面的一个方法&#xff0c;这个notifyObserve…

Linux测试是否能联网

ping百度看是否有返回包&#xff1a; ping www.baidu.com ping -c可以通过参数提前设置发送的包数量&#xff1a; ping -c 4 www.baidu.com 终止ping快捷键&#xff1a; 按下 Ctrl C&#xff1a;立即终止ping进程&#xff0c;并显示统计信息。按下 Ctrl Z&#xff1a;将进…

TOGAF® 架构分区:优秀架构的秘密

TOGAF &#xff08;The Open Group架构框架&#xff09;已成为企业架构事实上的全球标准, 是世界上使用最广泛的企业架构框架。 它为企业 IT 架构的设计、规划、实施和管理提供了一套全面的方法和工具。但是&#xff0c;即使是经验丰富的架构师也经常会忽略 TOGAF 中隐藏的宝…

如何让视频在特定的网站上播放/禁止播放?(常见的视频防盗链技术之一)

一、需求背景 在各行各业中,不论是教育、贸易还是医疗领域,视频内容都存在被盗用的风险。为加强视频安全性,我们可以采取特殊设置措施,例如限制视频仅在高安全性网站播放,或屏蔽高风险网站。那么,具体有哪些方法可以有效保护视频安全呢? 二、需求解决 通过OVP防盗链技…

如何调鼠标的灵敏度 快速调节超简单

鼠标灵敏度是指鼠标在移动时&#xff0c;指针在屏幕上移动的速度。适当的鼠标灵敏度不仅能够提高工作效率&#xff0c;还能减少手部疲劳&#xff0c;优化游戏体验。那么不同的使用场景&#xff0c;鼠标灵敏度怎么调呢&#xff1f;本文将详细探讨如何调整鼠标灵敏度&#xff0c;…